Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
Merge pull request #11020 from EOSIO/kli-EPE-1898-support-read-only-t…
Browse files Browse the repository at this point in the history
…ransactions-develop-boxed

Support read only transactions 📦
  • Loading branch information
softprofe authored Jan 24, 2022
2 parents c1986b8 + 6c7bc39 commit 9320bdf
Show file tree
Hide file tree
Showing 25 changed files with 541 additions and 49 deletions.
6 changes: 3 additions & 3 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1301,8 +1301,8 @@ struct controller_impl {
emit(self.applied_transaction, std::tie(trace, trx->packed_trx()));


if ( read_mode != db_read_mode::SPECULATIVE && pending->_block_status == controller::block_status::incomplete ) {
//this may happen automatically in destructor, but I prefere make it more explicit
if ( (read_mode != db_read_mode::SPECULATIVE && pending->_block_status == controller::block_status::incomplete) || trx->read_only ) {
//this may happen automatically in destructor, but I prefer to make it more explicit
trx_context.undo();
} else {
restore.cancel();
Expand Down Expand Up @@ -1701,7 +1701,7 @@ struct controller_impl {
} else {
packed_transaction_ptr ptrx( b, &pt ); // alias signed_block_ptr
auto fut = transaction_metadata::start_recover_keys(
std::move( ptrx ), thread_pool.get_executor(), chain_id, microseconds::maximum() );
std::move( ptrx ), thread_pool.get_executor(), chain_id, microseconds::maximum(), transaction_metadata::trx_type::input );
trx_metas.emplace_back( transaction_metadata_ptr{}, std::move( fut ) );
}
}
Expand Down
2 changes: 1 addition & 1 deletion libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ namespace eosio { namespace chain {
}

template<typename T>
fc::variant to_variant_with_abi( const T& obj, const abi_serializer::yield_function_t& yield ) {
fc::variant to_variant_with_abi( const T& obj, const abi_serializer::yield_function_t& yield ) const {
fc::variant pretty_output;
abi_serializer::to_variant( obj, pretty_output,
[&]( account_name n ){ return get_abi_serializer( n, yield ); }, yield );
Expand Down
13 changes: 8 additions & 5 deletions libraries/chain/include/eosio/chain/transaction_metadata.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ class transaction_metadata {
enum class trx_type {
input,
implicit,
scheduled
scheduled,
read_only
};

private:
Expand All @@ -34,6 +35,7 @@ class transaction_metadata {
public:
const bool implicit;
const bool scheduled;
const bool read_only;
bool accepted = false; // not thread safe
uint32_t billed_cpu_time_us = 0; // not thread safe

Expand All @@ -53,12 +55,13 @@ class transaction_metadata {
// creation of tranaction_metadata restricted to start_recover_keys and create_no_recover_keys below, public for make_shared
explicit transaction_metadata( const private_type& pt, packed_transaction_ptr ptrx,
fc::microseconds sig_cpu_usage, flat_set<public_key_type> recovered_pub_keys,
bool _implicit = false, bool _scheduled = false)
bool _implicit = false, bool _scheduled = false, bool _read_only = false)
: _packed_trx( std::move( ptrx ) )
, _sig_cpu_usage( sig_cpu_usage )
, _recovered_pub_keys( std::move( recovered_pub_keys ) )
, implicit( _implicit )
, scheduled( _scheduled ) {
, scheduled( _scheduled )
, read_only( _read_only ) {
}

transaction_metadata() = delete;
Expand All @@ -79,13 +82,13 @@ class transaction_metadata {
static recover_keys_future
start_recover_keys( packed_transaction_ptr trx, boost::asio::io_context& thread_pool,
const chain_id_type& chain_id, fc::microseconds time_limit,
uint32_t max_variable_sig_size = UINT32_MAX );
trx_type t, uint32_t max_variable_sig_size = UINT32_MAX );

/// @returns constructed transaction_metadata with no key recovery (sig_cpu_usage=0, recovered_pub_keys=empty)
static transaction_metadata_ptr
create_no_recover_keys( packed_transaction_ptr trx, trx_type t ) {
return std::make_shared<transaction_metadata>( private_type(), std::move(trx),
fc::microseconds(), flat_set<public_key_type>(), t == trx_type::implicit, t == trx_type::scheduled );
fc::microseconds(), flat_set<public_key_type>(), t == trx_type::implicit, t == trx_type::scheduled, t == trx_type::read_only );
}

};
Expand Down
6 changes: 4 additions & 2 deletions libraries/chain/transaction_metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ recover_keys_future transaction_metadata::start_recover_keys( packed_transaction
boost::asio::io_context& thread_pool,
const chain_id_type& chain_id,
fc::microseconds time_limit,
trx_type t,
uint32_t max_variable_sig_size )
{
return async_thread_pool( thread_pool, [trx{std::move(trx)}, chain_id, time_limit, max_variable_sig_size]() mutable {
return async_thread_pool( thread_pool, [trx{std::move(trx)}, chain_id, time_limit, t, max_variable_sig_size]() mutable {
fc::time_point deadline = time_limit == fc::microseconds::maximum() ?
fc::time_point::maximum() : fc::time_point::now() + time_limit;
const vector<signature_type>& sigs = check_variable_sig_size( trx, max_variable_sig_size );
Expand All @@ -20,7 +21,8 @@ recover_keys_future transaction_metadata::start_recover_keys( packed_transaction
const bool allow_duplicate_keys = false;
fc::microseconds cpu_usage =
trx->get_transaction().get_signature_keys(sigs, chain_id, deadline, *context_free_data, recovered_pub_keys, allow_duplicate_keys);
return std::make_shared<transaction_metadata>( private_type(), std::move( trx ), cpu_usage, std::move( recovered_pub_keys ) );
return std::make_shared<transaction_metadata>( private_type(), std::move( trx ), cpu_usage, std::move( recovered_pub_keys ),
t == trx_type::implicit, t == trx_type::scheduled, t == trx_type::read_only);
}
);
}
Expand Down
4 changes: 2 additions & 2 deletions libraries/testing/tester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ namespace eosio { namespace testing {
auto time_limit = deadline == fc::time_point::maximum() ?
fc::microseconds::maximum() :
fc::microseconds( deadline - fc::time_point::now() );
auto fut = transaction_metadata::start_recover_keys( ptrx, control->get_thread_pool(), control->get_chain_id(), time_limit );
auto fut = transaction_metadata::start_recover_keys( ptrx, control->get_thread_pool(), control->get_chain_id(), time_limit, transaction_metadata::trx_type::input );
auto r = control->push_transaction( fut.get(), deadline, billed_cpu_time_us, billed_cpu_time_us > 0, 0 );
if( r->except_ptr ) std::rethrow_exception( r->except_ptr );
if( r->except ) throw *r->except;
Expand All @@ -598,7 +598,7 @@ namespace eosio { namespace testing {
fc::microseconds::maximum() :
fc::microseconds( deadline - fc::time_point::now() );
auto ptrx = std::make_shared<packed_transaction>( signed_transaction(trx), true, c );
auto fut = transaction_metadata::start_recover_keys( std::move( ptrx ), control->get_thread_pool(), control->get_chain_id(), time_limit );
auto fut = transaction_metadata::start_recover_keys( std::move( ptrx ), control->get_thread_pool(), control->get_chain_id(), time_limit, transaction_metadata::trx_type::input );
auto r = control->push_transaction( fut.get(), deadline, billed_cpu_time_us, billed_cpu_time_us > 0, 0 );
if (no_throw) return r;
if( r->except_ptr ) std::rethrow_exception( r->except_ptr );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ class fifo_trx_processing_queue : public std::enable_shared_from_this<fifo_trx_p
void push(chain::packed_transaction_ptr trx, uint64_t delivery_tag, producer_plugin::next_function<chain::transaction_trace_ptr> next) {
fc::microseconds max_trx_cpu_usage = prod_plugin_->get_max_transaction_time();
auto future = chain::transaction_metadata::start_recover_keys( trx, sig_thread_pool_, chain_id_, max_trx_cpu_usage,
configured_subjective_signature_length_limit_ );
chain::transaction_metadata::trx_type::input, configured_subjective_signature_length_limit_ );
q_item i{ .delivery_tag = delivery_tag, .trx = trx, .fut = std::move(future), .next = std::move(next) };
if( !queue_.push( std::move( i ) ) ) {
ilog( "Queue stopped, unable to process transaction ${id}, not ack'ed to AMQP", ("id", trx->id()) );
Expand Down
1 change: 1 addition & 0 deletions plugins/chain_api_plugin/chain_api_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ void chain_api_plugin::plugin_startup() {
CHAIN_RO_CALL(abi_bin_to_json, 200, http_params_types::params_required),
CHAIN_RO_CALL(get_required_keys, 200, http_params_types::params_required),
CHAIN_RO_CALL(get_transaction_id, 200, http_params_types::params_required),
CHAIN_RO_CALL_ASYNC(push_ro_transaction, chain_apis::read_only::push_ro_transaction_results, 200, http_params_types::params_required),
CHAIN_RW_CALL_ASYNC(push_block, chain_apis::read_write::push_block_results, 202, http_params_types::params_required),
CHAIN_RW_CALL_ASYNC(push_transaction, chain_apis::read_write::push_transaction_results, 202, http_params_types::params_required),
CHAIN_RW_CALL_ASYNC(push_transactions, chain_apis::read_write::push_transactions_results, 202, http_params_types::params_required),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ namespace eosio { namespace chain { namespace plugin_interface {
}

namespace methods {
// synchronously push a block/trx to a single provider
// push a block/trx to a single provider
using block_sync = method_decl<chain_plugin_interface, bool(const signed_block_ptr&, const std::optional<block_id_type>&), first_provider_policy>;
using transaction_async = method_decl<chain_plugin_interface, void(const packed_transaction_ptr&, bool, next_function<transaction_trace_ptr>), first_provider_policy>;
using transaction_async = method_decl<chain_plugin_interface, void(const packed_transaction_ptr&, bool, bool, bool, next_function<transaction_trace_ptr>), first_provider_policy>;
}
}

Expand Down
82 changes: 79 additions & 3 deletions plugins/chain_plugin/chain_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1392,7 +1392,7 @@ bool chain_plugin::accept_block(const signed_block_ptr& block, const block_id_ty
}

void chain_plugin::accept_transaction(const chain::packed_transaction_ptr& trx, next_function<chain::transaction_trace_ptr> next) {
my->incoming_transaction_async_method(trx, false, std::move(next));
my->incoming_transaction_async_method(trx, false, false, false, std::move(next));
}

controller& chain_plugin::chain() { return *my->chain; }
Expand Down Expand Up @@ -2794,7 +2794,7 @@ void read_write::push_transaction(const read_write::push_transaction_params& par
fc_add_tag(trx_span, "trx_id", input_trx->id());
fc_add_tag(trx_span, "method", "push_transaction");

app().get_method<incoming::methods::transaction_async>()(input_trx, true,
app().get_method<incoming::methods::transaction_async>()(input_trx, true, false, false,
[this, token=fc_get_token(trx_trace), input_trx, next]
(const std::variant<fc::exception_ptr, transaction_trace_ptr>& result) -> void {

Expand Down Expand Up @@ -2947,7 +2947,7 @@ void read_write::send_transaction(const read_write::send_transaction_params& par
fc_add_tag(trx_span, "trx_id", input_trx->id());
fc_add_tag(trx_span, "method", "send_transaction");

app().get_method<incoming::methods::transaction_async>()(input_trx, true,
app().get_method<incoming::methods::transaction_async>()(input_trx, true, false, false,
[this, token=fc_get_token(trx_trace), input_trx, next]
(const std::variant<fc::exception_ptr, transaction_trace_ptr>& result) -> void {
auto trx_span = fc_create_span_from_token(token, "Processed");
Expand Down Expand Up @@ -3258,6 +3258,82 @@ read_only::get_transaction_id_result read_only::get_transaction_id( const read_o
return params.id();
}

void read_only::push_ro_transaction(const read_only::push_ro_transaction_params& params, chain::plugin_interface::next_function<read_only::push_ro_transaction_results> next) const {
try {
packed_transaction_v0 input_trx_v0;
auto resolver = make_resolver(db, abi_serializer::create_yield_function( abi_serializer_max_time ));
packed_transaction_ptr input_trx;
try {
abi_serializer::from_variant(params.transaction, input_trx_v0, std::move( resolver ), abi_serializer::create_yield_function( abi_serializer_max_time ));
input_trx = std::make_shared<packed_transaction>( std::move( input_trx_v0 ), true );
} EOS_RETHROW_EXCEPTIONS(chain::packed_transaction_type_exception, "Invalid packed transaction")

auto trx_trace = fc_create_trace_with_id("TransactionReadOnly", input_trx->id());
auto trx_span = fc_create_span(trx_trace, "HTTP Received");
fc_add_tag(trx_span, "trx_id", input_trx->id());
fc_add_tag(trx_span, "method", "push_ro_transaction");

app().get_method<incoming::methods::transaction_async>()(input_trx, true, true, static_cast<const bool>(params.return_failure_traces),
[this, token=fc_get_token(trx_trace), input_trx, params, next]
(const std::variant<fc::exception_ptr, transaction_trace_ptr>& result) -> void {
auto trx_span = fc_create_span_from_token(token, "Processed");
fc_add_tag(trx_span, "trx_id", input_trx->id());

if (std::holds_alternative<fc::exception_ptr>(result)) {
auto& eptr = std::get<fc::exception_ptr>(result);
fc_add_tag(trx_span, "error", eptr->to_string());
next(eptr);
} else {
auto& trx_trace_ptr = std::get<transaction_trace_ptr>(result);

fc_add_tag(trx_span, "block_num", trx_trace_ptr->block_num);
fc_add_tag(trx_span, "block_time", trx_trace_ptr->block_time.to_time_point());
fc_add_tag(trx_span, "elapsed", trx_trace_ptr->elapsed.count());
if( trx_trace_ptr->receipt ) {
fc_add_tag(trx_span, "status", std::string(trx_trace_ptr->receipt->status));
}
if( trx_trace_ptr->except ) {
fc_add_tag(trx_span, "error", trx_trace_ptr->except->to_string());
}

try {
fc::variant output;
try {
output = db.to_variant_with_abi( *trx_trace_ptr, abi_serializer::create_yield_function( abi_serializer_max_time ) );
} catch( chain::abi_exception& ) {
output = *trx_trace_ptr;
}
vector<transaction_id_type> pending_transactions;
const auto& accnt_metadata_obj = db.db().get<account_metadata_object,by_name>( params.account_name );
if (db.is_building_block()){
const auto& receipts = db.get_pending_trx_receipts();
pending_transactions.reserve(receipts.size());
for( transaction_receipt const& receipt : receipts ) {
if( std::holds_alternative<transaction_id_type>(receipt.trx) ) {
pending_transactions.push_back(std::get<transaction_id_type>(receipt.trx));
}
else {
pending_transactions.push_back(std::get<packed_transaction>(receipt.trx).id());
}
}
}
next(read_only::push_ro_transaction_results{db.head_block_num(),
db.head_block_id(),
db.last_irreversible_block_num(),
db.last_irreversible_block_id(),
accnt_metadata_obj.code_hash,
std::move(pending_transactions),
output});
} CATCH_AND_CALL(next);
}
});
} catch ( boost::interprocess::bad_alloc& ) {
chain_plugin::handle_db_exhaustion();
} catch ( const std::bad_alloc& ) {
chain_plugin::handle_bad_alloc();
} CATCH_AND_CALL(next);
}

account_query_db::get_accounts_by_authorizers_result read_only::get_accounts_by_authorizers( const account_query_db::get_accounts_by_authorizers_params& args) const
{
EOS_ASSERT(aqdb.has_value(), plugin_config_exception, "Account Queries being accessed when not enabled");
Expand Down
21 changes: 21 additions & 0 deletions plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,24 @@ class read_only {
};
}

struct push_ro_transaction_params {
name account_name;
bool return_failure_traces = true;
fc::variant transaction;
};

struct push_ro_transaction_results {
uint32_t head_block_num = 0;
chain::block_id_type head_block_id;
uint32_t last_irreversible_block_num = 0;
chain::block_id_type last_irreversible_block_id;
chain::digest_type code_hash;
vector<transaction_id_type> pending_transactions;
fc::variant result;
};

void push_ro_transaction(const push_ro_transaction_params& params, chain::plugin_interface::next_function<push_ro_transaction_results> next ) const;

template<typename KeyValueObj>
static void copy_inline_row(const KeyValueObj& obj, vector<char>& data) {
data.resize( obj.value.size() );
Expand Down Expand Up @@ -1166,3 +1184,6 @@ FC_REFLECT( eosio::chain_apis::read_only::get_all_accounts_params, (limit)(lower
FC_REFLECT( eosio::chain_apis::read_only::get_all_accounts_result::account_result, (name)(creation_date))
FC_REFLECT( eosio::chain_apis::read_only::get_all_accounts_result, (accounts)(more))
FC_REFLECT( eosio::chain_apis::read_only::get_consensus_parameters_results, (chain_config)(kv_database_config)(wasm_config))
FC_REFLECT( eosio::chain_apis::read_only::push_ro_transaction_params, (account_name)(return_failure_traces)(transaction) )
FC_REFLECT( eosio::chain_apis::read_only::push_ro_transaction_results, (head_block_num)(head_block_id)(last_irreversible_block_num)(last_irreversible_block_id)(code_hash)(pending_transactions)(result) )

Loading

0 comments on commit 9320bdf

Please sign in to comment.