From 50635a6867c4ec605ac5104441f72d8aa6aaf530 Mon Sep 17 00:00:00 2001 From: arhag Date: Fri, 29 Mar 2019 23:39:22 -0400 Subject: [PATCH 01/15] initial attempt at restructuring transaction traces #6897 --- libraries/chain/CMakeLists.txt | 2 +- libraries/chain/apply_context.cpp | 47 +++++++------ libraries/chain/controller.cpp | 19 +++--- .../include/eosio/chain/abi_serializer.hpp | 1 - .../include/eosio/chain/apply_context.hpp | 8 ++- libraries/chain/include/eosio/chain/trace.hpp | 58 ++++++++-------- .../eosio/chain/transaction_context.hpp | 18 +++-- libraries/chain/trace.cpp | 41 ++++++++++++ libraries/chain/transaction_context.cpp | 67 ++++++++++++++++--- unittests/api_tests.cpp | 66 +++++++++--------- unittests/wasm_tests.cpp | 2 +- 11 files changed, 214 insertions(+), 115 deletions(-) create mode 100644 libraries/chain/trace.cpp diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 15e8bfb0802..f12bdabe70e 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -44,7 +44,7 @@ add_library( eosio_chain # # contracts/chain_initializer.cpp - + trace.cpp transaction_metadata.cpp protocol_state_object.cpp protocol_feature_activation.cpp diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index 37c78ff7c7b..962e138dfa1 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -37,13 +37,6 @@ void apply_context::exec_one( action_trace& trace ) r.receiver = receiver; r.act_digest = digest_type::hash(act); - trace.trx_id = trx_context.id; - trace.block_num = control.head_block_num() + 1; - trace.block_time = control.pending_block_time(); - trace.producer_block_id = control.pending_producer_block_id(); - trace.act = act; - trace.context_free = context_free; - const auto& cfg = control.get_global_properties().configuration; try { try { @@ -71,7 +64,6 @@ void apply_context::exec_one( action_trace& trace ) } } FC_RETHROW_EXCEPTIONS( warn, "pending console output: ${console}", ("console", _pending_console_output) ) } catch( fc::exception& e ) { - trace.receipt = r; // fill with known data trace.except = e; finalize_trace( trace, start ); throw; @@ -90,7 +82,7 @@ void apply_context::exec_one( action_trace& trace ) trace.receipt = r; - trx_context.executed.emplace_back( move(r) ); + trx_context.executed.emplace_back( std::move(r) ); finalize_trace( trace, start ); @@ -112,12 +104,11 @@ void apply_context::finalize_trace( action_trace& trace, const fc::time_point& s void apply_context::exec( action_trace& trace ) { - _notified.push_back(receiver); + _notified.emplace_back( receiver, action_ordinal ); exec_one( trace ); for( uint32_t i = 1; i < _notified.size(); ++i ) { - receiver = _notified[i]; - trace.inline_traces.emplace_back( ); - exec_one( trace.inline_traces.back() ); + std::tie( receiver, action_ordinal ) = _notified[i]; + exec_one( trx_context.get_action_trace( action_ordinal ) ); } if( _cfa_inline_actions.size() > 0 || _inline_actions.size() > 0 ) { @@ -125,14 +116,12 @@ void apply_context::exec( action_trace& trace ) transaction_exception, "max inline action depth per transaction reached" ); } - for( const auto& inline_action : _cfa_inline_actions ) { - trace.inline_traces.emplace_back(); - trx_context.dispatch_action( trace.inline_traces.back(), inline_action, inline_action.account, true, recurse_depth + 1 ); + for( int32_t ordinal : _cfa_inline_actions ) { + trx_context.execute_action( ordinal, recurse_depth + 1 ); } - for( const auto& inline_action : _inline_actions ) { - trace.inline_traces.emplace_back(); - trx_context.dispatch_action( trace.inline_traces.back(), inline_action, inline_action.account, false, recurse_depth + 1 ); + for( int32_t ordinal : _inline_actions ) { + trx_context.execute_action( ordinal, recurse_depth + 1 ); } } /// exec() @@ -172,15 +161,18 @@ void apply_context::require_authorization(const account_name& account, } bool apply_context::has_recipient( account_name code )const { - for( auto a : _notified ) - if( a == code ) + for( const auto& p : _notified ) + if( p.first == code ) return true; return false; } void apply_context::require_recipient( account_name recipient ) { if( !has_recipient(recipient) ) { - _notified.push_back(recipient); + _notified.emplace_back( + recipient, + trx_context.schedule_action( act, recipient, false, action_ordinal, first_receiver_action_ordinal ) + ); } } @@ -271,7 +263,10 @@ void apply_context::execute_inline( action&& a ) { } } - _inline_actions.emplace_back( move(a) ); + auto inline_receiver = a.account; + _inline_actions.emplace_back( + trx_context.schedule_action( std::move(a), inline_receiver, false, action_ordinal, first_receiver_action_ordinal ) + ); } void apply_context::execute_context_free_inline( action&& a ) { @@ -282,7 +277,11 @@ void apply_context::execute_context_free_inline( action&& a ) { EOS_ASSERT( a.authorization.size() == 0, action_validate_exception, "context-free actions cannot have authorizations" ); - _cfa_inline_actions.emplace_back( move(a) ); + + auto inline_receiver = a.account; + _cfa_inline_actions.emplace_back( + trx_context.schedule_action( std::move(a), inline_receiver, true, action_ordinal, first_receiver_action_ordinal ) + ); } diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 2e732c869dc..a32a4ce1b2c 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -966,8 +966,7 @@ struct controller_impl { try { trx_context.init_for_implicit_trx(); trx_context.published = gtrx.published; - trx_context.trace->action_traces.emplace_back(); - trx_context.dispatch_action( trx_context.trace->action_traces.back(), etrx.actions.back(), gtrx.sender ); + trx_context.execute_action( trx_context.schedule_action( etrx.actions.back(), gtrx.sender ) ); trx_context.finalize(); // Automatically rounds up network and CPU usage in trace and bills payers if successful auto restore = make_block_restore_point(); @@ -988,14 +987,13 @@ struct controller_impl { return trace; } - void remove_scheduled_transaction( const generated_transaction_object& gto ) { - resource_limits.add_pending_ram_usage( - gto.payer, - -(config::billable_size_v + gto.packed_trx.size()) - ); + int64_t remove_scheduled_transaction( const generated_transaction_object& gto ) { + int64_t ram_delta = -(config::billable_size_v + gto.packed_trx.size()); + resource_limits.add_pending_ram_usage( gto.payer, ram_delta ); // No need to verify_account_ram_usage since we are only reducing memory db.remove( gto ); + return ram_delta; } bool failure_is_subjective( const fc::exception& e ) const { @@ -1042,7 +1040,7 @@ struct controller_impl { // // IF the transaction FAILs in a subjective way, `undo_session` should expire without being squashed // resulting in the GTO being restored and available for a future block to retire. - remove_scheduled_transaction(gto); + int64_t trx_removal_ram_delta = remove_scheduled_transaction(gto); fc::datastream ds( gtrx.packed_trx.data(), gtrx.packed_trx.size() ); @@ -1064,6 +1062,7 @@ struct controller_impl { trace->producer_block_id = self.pending_producer_block_id(); trace->scheduled = true; trace->receipt = push_receipt( gtrx.trx_id, transaction_receipt::expired, billed_cpu_time_us, 0 ); // expire the transaction + trace->account_ram_delta = account_delta( gtrx.payer, trx_removal_ram_delta ); emit( self.accepted_transaction, trx ); emit( self.applied_transaction, trace ); undo_session.squash(); @@ -1103,6 +1102,8 @@ struct controller_impl { fc::move_append( pending->_block_stage.get()._actions, move(trx_context.executed) ); + trace->account_ram_delta = account_delta( gtrx.payer, trx_removal_ram_delta ); + emit( self.accepted_transaction, trx ); emit( self.applied_transaction, trace ); @@ -1133,6 +1134,7 @@ struct controller_impl { error_trace->failed_dtrx_trace = trace; trace = error_trace; if( !trace->except_ptr ) { + trace->account_ram_delta = account_delta( gtrx.payer, trx_removal_ram_delta ); emit( self.accepted_transaction, trx ); emit( self.applied_transaction, trace ); undo_session.squash(); @@ -1169,6 +1171,7 @@ struct controller_impl { block_timestamp_type(self.pending_block_time()).slot ); // Should never fail trace->receipt = push_receipt(gtrx.trx_id, transaction_receipt::hard_fail, cpu_time_to_bill_us, 0); + trace->account_ram_delta = account_delta( gtrx.payer, trx_removal_ram_delta ); emit( self.accepted_transaction, trx ); emit( self.applied_transaction, trace ); diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index 398f219ced8..1e87cd26ef1 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -248,7 +248,6 @@ namespace impl { std::is_same::value || std::is_same::value || std::is_same::value || - std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || diff --git a/libraries/chain/include/eosio/chain/apply_context.hpp b/libraries/chain/include/eosio/chain/apply_context.hpp index 951422cb753..49721cb0cfe 100644 --- a/libraries/chain/include/eosio/chain/apply_context.hpp +++ b/libraries/chain/include/eosio/chain/apply_context.hpp @@ -570,6 +570,8 @@ class apply_context { account_name receiver; ///< the code that is currently running vector used_authorizations; ///< Parallel to act.authorization; tracks which permissions have been used while processing the message uint32_t recurse_depth; ///< how deep inline actions can recurse + int32_t first_receiver_action_ordinal = -1; + int32_t action_ordinal = -1; bool privileged = false; bool context_free = false; bool used_context_free_api = false; @@ -583,9 +585,9 @@ class apply_context { private: iterator_cache keyval_cache; - vector _notified; ///< keeps track of new accounts to be notifed of current message - vector _inline_actions; ///< queued inline messages - vector _cfa_inline_actions; ///< queued inline messages + vector< std::pair > _notified; ///< keeps track of new accounts to be notifed of current message + vector _inline_actions; ///< action_ordinals of queued inline actions + vector _cfa_inline_actions; ///< action_ordinals of queued inline context-free actions std::string _pending_console_output; flat_set _account_ram_deltas; ///< flat_set of account_delta so json is an array of objects diff --git a/libraries/chain/include/eosio/chain/trace.hpp b/libraries/chain/include/eosio/chain/trace.hpp index 58de120bdd8..07dbbd0fdeb 100644 --- a/libraries/chain/include/eosio/chain/trace.hpp +++ b/libraries/chain/include/eosio/chain/trace.hpp @@ -20,33 +20,34 @@ namespace eosio { namespace chain { friend bool operator<( const account_delta& lhs, const account_delta& rhs ) { return lhs.account < rhs.account; } }; - struct base_action_trace { - base_action_trace( const action_receipt& r ):receipt(r){} - base_action_trace(){} - - action_receipt receipt; - action act; - bool context_free = false; - fc::microseconds elapsed; - string console; + struct transaction_trace; + using transaction_trace_ptr = std::shared_ptr; - transaction_id_type trx_id; ///< the transaction that generated this action - uint32_t block_num = 0; - block_timestamp_type block_time; + struct action_trace { + action_trace( const transaction_trace& trace, const action& act, account_name receiver, bool context_free, + int32_t action_ordinal, int32_t creator_action_ordinal, int32_t parent_action_ordinal ); + action_trace( const transaction_trace& trace, action&& act, account_name receiver, bool context_free, + int32_t action_ordinal, int32_t creator_action_ordinal, int32_t parent_action_ordinal ); + //action_trace( const action_receipt& r ):receipt(r){} + action_trace(){} + + int32_t action_ordinal = 0; + int32_t creator_action_ordinal = -1; + int32_t parent_action_ordinal = -1; + fc::optional receipt; + action_name receiver; + action act; + bool context_free = false; + fc::microseconds elapsed; + string console; + transaction_id_type trx_id; ///< the transaction that generated this action + uint32_t block_num = 0; + block_timestamp_type block_time; fc::optional producer_block_id; flat_set account_ram_deltas; fc::optional except; }; - struct action_trace : public base_action_trace { - using base_action_trace::base_action_trace; - - vector inline_traces; - }; - - struct transaction_trace; - using transaction_trace_ptr = std::shared_ptr; - struct transaction_trace { transaction_id_type id; uint32_t block_num = 0; @@ -56,7 +57,8 @@ namespace eosio { namespace chain { fc::microseconds elapsed; uint64_t net_usage = 0; bool scheduled = false; - vector action_traces; ///< disposable + vector action_traces; + fc::optional account_ram_delta; transaction_trace_ptr failed_dtrx_trace; fc::optional except; @@ -68,13 +70,11 @@ namespace eosio { namespace chain { FC_REFLECT( eosio::chain::account_delta, (account)(delta) ) -FC_REFLECT( eosio::chain::base_action_trace, - (receipt)(act)(context_free)(elapsed)(console)(trx_id) - (block_num)(block_time)(producer_block_id)(account_ram_deltas)(except) ) - -FC_REFLECT_DERIVED( eosio::chain::action_trace, - (eosio::chain::base_action_trace), (inline_traces) ) +FC_REFLECT( eosio::chain::action_trace, + (action_ordinal)(creator_action_ordinal)(parent_action_ordinal)(receipt) + (receiver)(act)(context_free)(elapsed)(console)(trx_id)(block_num)(block_time) + (producer_block_id)(account_ram_deltas)(except) ) FC_REFLECT( eosio::chain::transaction_trace, (id)(block_num)(block_time)(producer_block_id) (receipt)(elapsed)(net_usage)(scheduled) - (action_traces)(failed_dtrx_trace)(except) ) + (action_traces)(account_ram_delta)(failed_dtrx_trace)(except) ) diff --git a/libraries/chain/include/eosio/chain/transaction_context.hpp b/libraries/chain/include/eosio/chain/transaction_context.hpp index b0327dafb18..0182f5a05f0 100644 --- a/libraries/chain/include/eosio/chain/transaction_context.hpp +++ b/libraries/chain/include/eosio/chain/transaction_context.hpp @@ -64,10 +64,20 @@ namespace eosio { namespace chain { void add_ram_usage( account_name account, int64_t ram_delta ); - void dispatch_action( action_trace& trace, const action& a, account_name receiver, bool context_free = false, uint32_t recurse_depth = 0 ); - inline void dispatch_action( action_trace& trace, const action& a, bool context_free = false ) { - dispatch_action(trace, a, a.account, context_free); - }; + int32_t schedule_action( const action& act, account_name receiver, bool context_free = false, + int32_t creator_action_ordinal = -1, int32_t parent_action_ordinal = -1 ); + + int32_t schedule_action( action&& act, account_name receiver, bool context_free = false, + int32_t creator_action_ordinal = -1, int32_t parent_action_ordinal = -1 ); + + action_trace& get_action_trace( int32_t action_ordinal ); + const action_trace& get_action_trace( int32_t action_ordinal )const; + + void execute_action( action_trace& act_trace, uint32_t recurse_depth ); + inline void execute_action( int32_t action_ordinal, uint32_t recurse_depth = 0 ) { + execute_action( get_action_trace( action_ordinal ), recurse_depth ); + } + void schedule_transaction(); void record_transaction( const transaction_id_type& id, fc::time_point_sec expire ); diff --git a/libraries/chain/trace.cpp b/libraries/chain/trace.cpp new file mode 100644 index 00000000000..0b379c89e00 --- /dev/null +++ b/libraries/chain/trace.cpp @@ -0,0 +1,41 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#include + +namespace eosio { namespace chain { + +action_trace::action_trace( + const transaction_trace& trace, const action& act, account_name receiver, bool context_free, + int32_t action_ordinal, int32_t creator_action_ordinal, int32_t parent_action_ordinal +) +:action_ordinal( action_ordinal ) +,creator_action_ordinal( creator_action_ordinal ) +,parent_action_ordinal( parent_action_ordinal ) +,receiver( receiver ) +,act( act ) +,context_free( context_free ) +,trx_id( trace.id ) +,block_num( trace.block_num ) +,block_time( trace.block_time ) +,producer_block_id( trace.producer_block_id ) +{} + +action_trace::action_trace( + const transaction_trace& trace, action&& act, account_name receiver, bool context_free, + int32_t action_ordinal, int32_t creator_action_ordinal, int32_t parent_action_ordinal +) +:action_ordinal( action_ordinal ) +,creator_action_ordinal( creator_action_ordinal ) +,parent_action_ordinal( parent_action_ordinal ) +,receiver( receiver ) +,act( std::move(act) ) +,context_free( context_free ) +,trx_id( trace.id ) +,block_num( trace.block_num ) +,block_time( trace.block_time ) +,producer_block_id( trace.producer_block_id ) +{} + +} } // eosio::chain diff --git a/libraries/chain/transaction_context.cpp b/libraries/chain/transaction_context.cpp index 226e6863a16..da99fd4dbe2 100644 --- a/libraries/chain/transaction_context.cpp +++ b/libraries/chain/transaction_context.cpp @@ -333,17 +333,23 @@ namespace bacc = boost::accumulators; if( apply_context_free ) { for( const auto& act : trx.context_free_actions ) { - trace->action_traces.emplace_back(); - dispatch_action( trace->action_traces.back(), act, true ); + schedule_action( act, act.account, true ); } } if( delay == fc::microseconds() ) { for( const auto& act : trx.actions ) { - trace->action_traces.emplace_back(); - dispatch_action( trace->action_traces.back(), act ); + schedule_action( act, act.account ); } - } else { + } + + auto& action_traces = trace->action_traces; + int32_t num_original_actions_to_execute = action_traces.size(); + for( int32_t i = 0; i < num_original_actions_to_execute; ++i ) { + execute_action( action_traces[i], 0 ); + } + + if( delay != fc::microseconds() ) { schedule_transaction(); } } @@ -566,14 +572,51 @@ namespace bacc = boost::accumulators; return std::make_tuple(account_net_limit, account_cpu_limit, greylisted_net, greylisted_cpu); } - void transaction_context::dispatch_action( action_trace& trace, const action& a, account_name receiver, bool context_free, uint32_t recurse_depth ) { - apply_context acontext( control, *this, a, recurse_depth ); - acontext.context_free = context_free; - acontext.receiver = receiver; + int32_t transaction_context::schedule_action( const action& act, account_name receiver, bool context_free, + int32_t creator_action_ordinal, int32_t parent_action_ordinal ) + { + int32_t action_ordinal = trace->action_traces.size(); + + trace->action_traces.emplace_back( *trace, act, receiver, context_free, + action_ordinal, creator_action_ordinal, parent_action_ordinal ); + + return action_ordinal; + } + + int32_t transaction_context::schedule_action( action&& act, account_name receiver, bool context_free, + int32_t creator_action_ordinal, int32_t parent_action_ordinal ) + { + int32_t action_ordinal = trace->action_traces.size(); + + trace->action_traces.emplace_back( *trace, std::move(act), receiver, context_free, + action_ordinal, creator_action_ordinal, parent_action_ordinal ); + + return action_ordinal; + } + + action_trace& transaction_context::get_action_trace( int32_t action_ordinal ) { + EOS_ASSERT( 0 <= action_ordinal && action_ordinal < trace->action_traces.size() , + transaction_exception, "invalid action_ordinal" ); + return trace->action_traces[action_ordinal]; + } - acontext.exec( trace ); + const action_trace& transaction_context::get_action_trace( int32_t action_ordinal )const { + EOS_ASSERT( 0 <= action_ordinal && action_ordinal < trace->action_traces.size() , + transaction_exception, "invalid action_ordinal" ); + return trace->action_traces[action_ordinal]; } + void transaction_context::execute_action( action_trace& act_trace, uint32_t recurse_depth ) { + apply_context acontext( control, *this, act_trace.act, recurse_depth ); + acontext.receiver = act_trace.receiver; + acontext.first_receiver_action_ordinal = act_trace.action_ordinal; + acontext.action_ordinal = act_trace.action_ordinal; + acontext.context_free = act_trace.context_free; + + acontext.exec( act_trace ); + } + + void transaction_context::schedule_transaction() { // Charge ahead of time for the additional net usage needed to retire the delayed transaction // whether that be by successfully executing, soft failure, hard failure, or expiration. @@ -597,7 +640,9 @@ namespace bacc = boost::accumulators; trx_size = gto.set( trx ); }); - add_ram_usage( cgto.payer, (config::billable_size_v + trx_size) ); + int64_t ram_delta = (config::billable_size_v + trx_size); + add_ram_usage( cgto.payer, ram_delta ); + trace->account_ram_delta = account_delta( cgto.payer, ram_delta ); } void transaction_context::record_transaction( const transaction_id_type& id, fc::time_point_sec expire ) { diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index 889effc9cb3..83f2f20e618 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -330,25 +330,25 @@ BOOST_FIXTURE_TEST_CASE(action_receipt_tests, TESTER) { try { auto result = push_reqauth( config::system_account_name, "active" ); BOOST_REQUIRE_EQUAL( result->receipt->status, transaction_receipt::executed ); - BOOST_REQUIRE( result->action_traces[0].receipt.auth_sequence.find( config::system_account_name ) - != result->action_traces[0].receipt.auth_sequence.end() ); - auto base_global_sequence_num = result->action_traces[0].receipt.global_sequence; - auto base_system_recv_seq_num = result->action_traces[0].receipt.recv_sequence; - auto base_system_auth_seq_num = result->action_traces[0].receipt.auth_sequence[config::system_account_name]; - auto base_system_code_seq_num = result->action_traces[0].receipt.code_sequence.value; - auto base_system_abi_seq_num = result->action_traces[0].receipt.abi_sequence.value; + BOOST_REQUIRE( result->action_traces[0].receipt->auth_sequence.find( config::system_account_name ) + != result->action_traces[0].receipt->auth_sequence.end() ); + auto base_global_sequence_num = result->action_traces[0].receipt->global_sequence; + auto base_system_recv_seq_num = result->action_traces[0].receipt->recv_sequence; + auto base_system_auth_seq_num = result->action_traces[0].receipt->auth_sequence[config::system_account_name]; + auto base_system_code_seq_num = result->action_traces[0].receipt->code_sequence.value; + auto base_system_abi_seq_num = result->action_traces[0].receipt->abi_sequence.value; uint64_t base_test_recv_seq_num = 0; uint64_t base_test_auth_seq_num = 0; call_doit_and_check( N(test), N(test), [&]( const transaction_trace_ptr& res ) { BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.global_sequence, base_global_sequence_num + 1 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.code_sequence.value, 1 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.abi_sequence.value, 0 ); - base_test_recv_seq_num = res->action_traces[0].receipt.recv_sequence; + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->global_sequence, base_global_sequence_num + 1 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->code_sequence.value, 1 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->abi_sequence.value, 0 ); + base_test_recv_seq_num = res->action_traces[0].receipt->recv_sequence; BOOST_CHECK( base_test_recv_seq_num > 0 ); base_test_recv_seq_num--; - const auto& m = res->action_traces[0].receipt.auth_sequence; + const auto& m = res->action_traces[0].receipt->auth_sequence; BOOST_CHECK_EQUAL( m.size(), 1 ); BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); base_test_auth_seq_num = m.begin()->second; @@ -361,11 +361,11 @@ BOOST_FIXTURE_TEST_CASE(action_receipt_tests, TESTER) { try { call_provereset_and_check( N(test), N(test), [&]( const transaction_trace_ptr& res ) { BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.global_sequence, base_global_sequence_num + 4 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.recv_sequence, base_test_recv_seq_num + 2 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.code_sequence.value, 2 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.abi_sequence.value, 0 ); - const auto& m = res->action_traces[0].receipt.auth_sequence; + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->global_sequence, base_global_sequence_num + 4 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->recv_sequence, base_test_recv_seq_num + 2 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->code_sequence.value, 2 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->abi_sequence.value, 0 ); + const auto& m = res->action_traces[0].receipt->auth_sequence; BOOST_CHECK_EQUAL( m.size(), 1 ); BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); BOOST_CHECK_EQUAL( m.begin()->second, base_test_auth_seq_num + 3 ); @@ -377,11 +377,11 @@ BOOST_FIXTURE_TEST_CASE(action_receipt_tests, TESTER) { try { call_doit_and_check( config::system_account_name, N(test), [&]( const transaction_trace_ptr& res ) { BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.global_sequence, base_global_sequence_num + 6 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.recv_sequence, base_system_recv_seq_num + 4 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.code_sequence.value, base_system_code_seq_num + 1 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.abi_sequence.value, base_system_abi_seq_num ); - const auto& m = res->action_traces[0].receipt.auth_sequence; + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->global_sequence, base_global_sequence_num + 6 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->recv_sequence, base_system_recv_seq_num + 4 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->code_sequence.value, base_system_code_seq_num + 1 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->abi_sequence.value, base_system_abi_seq_num ); + const auto& m = res->action_traces[0].receipt->auth_sequence; BOOST_CHECK_EQUAL( m.size(), 1 ); BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); BOOST_CHECK_EQUAL( m.begin()->second, base_test_auth_seq_num + 4 ); @@ -395,11 +395,11 @@ BOOST_FIXTURE_TEST_CASE(action_receipt_tests, TESTER) { try { call_doit_and_check( N(test), N(test), [&]( const transaction_trace_ptr& res ) { BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.global_sequence, base_global_sequence_num + 11 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.recv_sequence, base_test_recv_seq_num + 3 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.code_sequence.value, 4 ); - BOOST_CHECK_EQUAL( res->action_traces[0].receipt.abi_sequence.value, 1 ); - const auto& m = res->action_traces[0].receipt.auth_sequence; + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->global_sequence, base_global_sequence_num + 11 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->recv_sequence, base_test_recv_seq_num + 3 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->code_sequence.value, 4 ); + BOOST_CHECK_EQUAL( res->action_traces[0].receipt->abi_sequence.value, 1 ); + const auto& m = res->action_traces[0].receipt->auth_sequence; BOOST_CHECK_EQUAL( m.size(), 1 ); BOOST_CHECK_EQUAL( m.begin()->first.to_string(), "test" ); BOOST_CHECK_EQUAL( m.begin()->second, base_test_auth_seq_num + 8 ); @@ -701,12 +701,12 @@ BOOST_FIXTURE_TEST_CASE(cf_action_tests, TESTER) { try { // test send context free action auto ttrace = CALL_TEST_FUNCTION( *this, "test_transaction", "send_cf_action", {} ); - BOOST_CHECK_EQUAL(ttrace->action_traces.size(), 1); - BOOST_CHECK_EQUAL(ttrace->action_traces[0].inline_traces.size(), 1); - BOOST_CHECK_EQUAL(ttrace->action_traces[0].inline_traces[0].receipt.receiver, account_name("dummy")); - BOOST_CHECK_EQUAL(ttrace->action_traces[0].inline_traces[0].act.account, account_name("dummy")); - BOOST_CHECK_EQUAL(ttrace->action_traces[0].inline_traces[0].act.name, account_name("event1")); - BOOST_CHECK_EQUAL(ttrace->action_traces[0].inline_traces[0].act.authorization.size(), 0); + BOOST_REQUIRE_EQUAL(ttrace->action_traces.size(), 2); + BOOST_CHECK_EQUAL(ttrace->action_traces[1].creator_action_ordinal, 0); + BOOST_CHECK_EQUAL(ttrace->action_traces[1].receiver, account_name("dummy")); + BOOST_CHECK_EQUAL(ttrace->action_traces[1].act.account, account_name("dummy")); + BOOST_CHECK_EQUAL(ttrace->action_traces[1].act.name, account_name("event1")); + BOOST_CHECK_EQUAL(ttrace->action_traces[1].act.authorization.size(), 0); BOOST_CHECK_EXCEPTION( CALL_TEST_FUNCTION( *this, "test_transaction", "send_cf_action_fail", {} ), eosio_assert_message_exception, diff --git a/unittests/wasm_tests.cpp b/unittests/wasm_tests.cpp index 5335ee037c4..c29ec8da8c4 100644 --- a/unittests/wasm_tests.cpp +++ b/unittests/wasm_tests.cpp @@ -92,7 +92,7 @@ BOOST_FIXTURE_TEST_CASE( basic_test, TESTER ) try { auto result = push_transaction( trx ); BOOST_CHECK_EQUAL(result->receipt->status, transaction_receipt::executed); BOOST_CHECK_EQUAL(result->action_traces.size(), 1u); - BOOST_CHECK_EQUAL(result->action_traces.at(0).receipt.receiver.to_string(), name(N(asserter)).to_string() ); + BOOST_CHECK_EQUAL(result->action_traces.at(0).receiver.to_string(), name(N(asserter)).to_string() ); BOOST_CHECK_EQUAL(result->action_traces.at(0).act.account.to_string(), name(N(asserter)).to_string() ); BOOST_CHECK_EQUAL(result->action_traces.at(0).act.name.to_string(), name(N(procassert)).to_string() ); BOOST_CHECK_EQUAL(result->action_traces.at(0).act.authorization.size(), 1u ); From ed8b7b41c0c80e275b911268ca846113a32c5f16 Mon Sep 17 00:00:00 2001 From: arhag Date: Fri, 29 Mar 2019 23:41:57 -0400 Subject: [PATCH 02/15] fix plugins #6897 Now compiles, but the tests fail due to bugs. --- plugins/history_plugin/history_plugin.cpp | 48 +++++++++---------- plugins/mongo_db_plugin/mongo_db_plugin.cpp | 14 ++---- .../state_history_serialization.hpp | 15 +++++- .../state_history_plugin_abi.cpp | 7 ++- 4 files changed, 45 insertions(+), 39 deletions(-) diff --git a/plugins/history_plugin/history_plugin.cpp b/plugins/history_plugin/history_plugin.cpp index a44321ca0bc..6cdcffcb546 100644 --- a/plugins/history_plugin/history_plugin.cpp +++ b/plugins/history_plugin/history_plugin.cpp @@ -148,34 +148,34 @@ namespace eosio { if (bypass_filter) { pass_on = true; } - if (filter_on.find({ act.receipt.receiver, 0, 0 }) != filter_on.end()) { + if (filter_on.find({ act.receiver, 0, 0 }) != filter_on.end()) { pass_on = true; } - if (filter_on.find({ act.receipt.receiver, act.act.name, 0 }) != filter_on.end()) { + if (filter_on.find({ act.receiver, act.act.name, 0 }) != filter_on.end()) { pass_on = true; } for (const auto& a : act.act.authorization) { - if (filter_on.find({ act.receipt.receiver, 0, a.actor }) != filter_on.end()) { + if (filter_on.find({ act.receiver, 0, a.actor }) != filter_on.end()) { pass_on = true; } - if (filter_on.find({ act.receipt.receiver, act.act.name, a.actor }) != filter_on.end()) { + if (filter_on.find({ act.receiver, act.act.name, a.actor }) != filter_on.end()) { pass_on = true; } } if (!pass_on) { return false; } - if (filter_out.find({ act.receipt.receiver, 0, 0 }) != filter_out.end()) { + if (filter_out.find({ act.receiver, 0, 0 }) != filter_out.end()) { return false; } - if (filter_out.find({ act.receipt.receiver, act.act.name, 0 }) != filter_out.end()) { + if (filter_out.find({ act.receiver, act.act.name, 0 }) != filter_out.end()) { return false; } for (const auto& a : act.act.authorization) { - if (filter_out.find({ act.receipt.receiver, 0, a.actor }) != filter_out.end()) { + if (filter_out.find({ act.receiver, 0, a.actor }) != filter_out.end()) { return false; } - if (filter_out.find({ act.receipt.receiver, act.act.name, a.actor }) != filter_out.end()) { + if (filter_out.find({ act.receiver, act.act.name, a.actor }) != filter_out.end()) { return false; } } @@ -186,17 +186,17 @@ namespace eosio { set account_set( const action_trace& act ) { set result; - result.insert( act.receipt.receiver ); + result.insert( act.receiver ); for( const auto& a : act.act.authorization ) { if( bypass_filter || - filter_on.find({ act.receipt.receiver, 0, 0}) != filter_on.end() || - filter_on.find({ act.receipt.receiver, 0, a.actor}) != filter_on.end() || - filter_on.find({ act.receipt.receiver, act.act.name, 0}) != filter_on.end() || - filter_on.find({ act.receipt.receiver, act.act.name, a.actor }) != filter_on.end() ) { - if ((filter_out.find({ act.receipt.receiver, 0, 0 }) == filter_out.end()) && - (filter_out.find({ act.receipt.receiver, 0, a.actor }) == filter_out.end()) && - (filter_out.find({ act.receipt.receiver, act.act.name, 0 }) == filter_out.end()) && - (filter_out.find({ act.receipt.receiver, act.act.name, a.actor }) == filter_out.end())) { + filter_on.find({ act.receiver, 0, 0}) != filter_on.end() || + filter_on.find({ act.receiver, 0, a.actor}) != filter_on.end() || + filter_on.find({ act.receiver, act.act.name, 0}) != filter_on.end() || + filter_on.find({ act.receiver, act.act.name, a.actor }) != filter_on.end() ) { + if ((filter_out.find({ act.receiver, 0, 0 }) == filter_out.end()) && + (filter_out.find({ act.receiver, 0, a.actor }) == filter_out.end()) && + (filter_out.find({ act.receiver, act.act.name, 0 }) == filter_out.end()) && + (filter_out.find({ act.receiver, act.act.name, a.actor }) == filter_out.end())) { result.insert( a.actor ); } } @@ -204,7 +204,7 @@ namespace eosio { return result; } - void record_account_action( account_name n, const base_action_trace& act ) { + void record_account_action( account_name n, const action_trace& act ) { auto& chain = chain_plug->chain(); chainbase::database& db = const_cast( chain.db() ); // Override read-only access to state DB (highly unrecommended practice!) @@ -216,13 +216,11 @@ namespace eosio { if( itr->account == n ) asn = itr->account_sequence_num + 1; - //idump((n)(act.receipt.global_sequence)(asn)); const auto& a = db.create( [&]( auto& aho ) { aho.account = n; - aho.action_sequence_num = act.receipt.global_sequence; + aho.action_sequence_num = act.receipt->global_sequence; aho.account_sequence_num = asn; }); - //idump((a.account)(a.action_sequence_num)(a.action_sequence_num)); } void on_system_action( const action_trace& at ) { @@ -263,7 +261,7 @@ namespace eosio { aho.packed_action_trace.resize(ps); datastream ds( aho.packed_action_trace.data(), ps ); fc::raw::pack( ds, at ); - aho.action_sequence_num = at.receipt.global_sequence; + aho.action_sequence_num = at.receipt->global_sequence; aho.block_num = chain.head_block_num() + 1; aho.block_time = chain.pending_block_time(); aho.trx_id = at.trx_id; @@ -274,11 +272,8 @@ namespace eosio { record_account_action( a, at ); } } - if( at.receipt.receiver == chain::config::system_account_name ) + if( at.receiver == chain::config::system_account_name ) on_system_action( at ); - for( const auto& iline : at.inline_traces ) { - on_action_trace( iline ); - } } void on_applied_transaction( const transaction_trace_ptr& trace ) { @@ -286,6 +281,7 @@ namespace eosio { trace->receipt->status != transaction_receipt_header::soft_fail) ) return; for( const auto& atrace : trace->action_traces ) { + if( !atrace.receipt ) continue; on_action_trace( atrace ); } } diff --git a/plugins/mongo_db_plugin/mongo_db_plugin.cpp b/plugins/mongo_db_plugin/mongo_db_plugin.cpp index 8131b6a2bb2..3b3b39f4f84 100644 --- a/plugins/mongo_db_plugin/mongo_db_plugin.cpp +++ b/plugins/mongo_db_plugin/mongo_db_plugin.cpp @@ -751,7 +751,7 @@ void mongo_db_plugin_impl::_process_accepted_transaction( const chain::transacti const signed_transaction& trx = t->packed_trx->get_signed_transaction(); if( !filter_include( trx ) ) return; - + auto trans_doc = bsoncxx::builder::basic::document{}; auto now = std::chrono::duration_cast( @@ -830,22 +830,20 @@ mongo_db_plugin_impl::add_action_trace( mongocxx::bulk_write& bulk_action_traces using namespace bsoncxx::types; using bsoncxx::builder::basic::kvp; - if( executed && atrace.receipt.receiver == chain::config::system_account_name ) { + if( executed && atrace.receiver == chain::config::system_account_name ) { update_account( atrace.act ); } bool added = false; const bool in_filter = (store_action_traces || store_transaction_traces) && start_block_reached && - filter_include( atrace.receipt.receiver, atrace.act.name, atrace.act.authorization ); + filter_include( atrace.receiver, atrace.act.name, atrace.act.authorization ); write_ttrace |= in_filter; if( start_block_reached && store_action_traces && in_filter ) { auto action_traces_doc = bsoncxx::builder::basic::document{}; - const chain::base_action_trace& base = atrace; // without inline action traces - // improve data distributivity when using mongodb sharding action_traces_doc.append( kvp( "_id", make_custom_oid() ) ); - auto v = to_variant_with_abi( base ); + auto v = to_variant_with_abi( atrace ); string json = fc::json::to_string( v ); try { const auto& value = bsoncxx::from_json( json ); @@ -871,10 +869,6 @@ mongo_db_plugin_impl::add_action_trace( mongocxx::bulk_write& bulk_action_traces added = true; } - for( const auto& iline_atrace : atrace.inline_traces ) { - added |= add_action_trace( bulk_action_traces, iline_atrace, t, executed, now, write_ttrace ); - } - return added; } diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp index 37c817dd9cc..473e5720ec4 100644 --- a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp @@ -480,7 +480,14 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.receipt))); + fc::raw::pack(ds, as_type(obj.obj.action_ordinal)); + fc::raw::pack(ds, as_type(obj.obj.creator_action_ordinal)); + fc::raw::pack(ds, as_type(obj.obj.parent_action_ordinal)); + fc::raw::pack(ds, bool(obj.obj.receipt)); + if (obj.obj.receipt) { + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(*obj.obj.receipt))); + } + fc::raw::pack(ds, as_type(obj.obj.receiver.value)); fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(obj.obj.act))); fc::raw::pack(ds, as_type(obj.obj.context_free)); fc::raw::pack(ds, as_type(obj.obj.elapsed.count())); @@ -492,7 +499,6 @@ datastream& operator<<(datastream& ds, const history_serial_wrapperto_string(); fc::raw::pack(ds, as_type>(e)); - history_serialize_container(ds, obj.db, as_type>(obj.obj.inline_traces)); return ds; } @@ -519,6 +525,11 @@ datastream& operator<<(datastream& fc::raw::pack(ds, as_type(obj.obj.scheduled)); history_serialize_container(ds, obj.db, as_type>(obj.obj.action_traces)); + fc::raw::pack(ds, bool(obj.obj.account_ram_delta)); + if (obj.obj.account_ram_delta) { + fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(*obj.obj.account_ram_delta))); + } + fc::optional e; if (obj.obj.except) e = obj.obj.except->to_string(); diff --git a/plugins/state_history_plugin/state_history_plugin_abi.cpp b/plugins/state_history_plugin/state_history_plugin_abi.cpp index bdedcc81cd9..af2afb8e1bf 100644 --- a/plugins/state_history_plugin/state_history_plugin_abi.cpp +++ b/plugins/state_history_plugin/state_history_plugin_abi.cpp @@ -93,7 +93,11 @@ extern const char* const state_history_plugin_abi = R"({ }, { "name": "action_trace_v0", "fields": [ - { "name": "receipt", "type": "action_receipt" }, + { "name": "action_ordinal", "type": "int32" }, + { "name": "creator_action_ordinal", "type": "int32" }, + { "name": "parent_action_ordinal", "type": "int32" }, + { "name": "receipt", "type": "action_receipt?" }, + { "name": "receiver", "type": "name" }, { "name": "act", "type": "action" }, { "name": "context_free", "type": "bool" }, { "name": "elapsed", "type": "int64" }, @@ -113,6 +117,7 @@ extern const char* const state_history_plugin_abi = R"({ { "name": "net_usage", "type": "uint64" }, { "name": "scheduled", "type": "bool" }, { "name": "action_traces", "type": "action_trace[]" }, + { "name": "account_ram_delta", "type": "account_delta?" }, { "name": "except", "type": "string?" }, { "name": "failed_dtrx_trace", "type": "transaction_trace?" } ] From 943522e39762c6800373441f943dc44830ba264e Mon Sep 17 00:00:00 2001 From: arhag Date: Mon, 1 Apr 2019 17:38:20 -0400 Subject: [PATCH 03/15] fix dangling reference issues #6897 --- libraries/chain/apply_context.cpp | 91 +++++++++++++------ libraries/chain/eosio_contract.cpp | 18 ++-- .../include/eosio/chain/apply_context.hpp | 40 ++++---- .../eosio/chain/transaction_context.hpp | 17 ++-- libraries/chain/transaction_context.cpp | 42 ++++++--- libraries/chain/wasm_interface.cpp | 15 ++- libraries/chain/webassembly/wabt.cpp | 10 +- libraries/chain/webassembly/wavm.cpp | 6 +- 8 files changed, 145 insertions(+), 94 deletions(-) diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index 962e138dfa1..22b583704e4 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -29,34 +29,53 @@ static inline void print_debug(account_name receiver, const action_trace& ar) { } } -void apply_context::exec_one( action_trace& trace ) +apply_context::apply_context(controller& con, transaction_context& trx_ctx, uint32_t action_ordinal, uint32_t depth) +:control(con) +,db(con.mutable_db()) +,trx_context(trx_ctx) +,recurse_depth(depth) +,first_receiver_action_ordinal(action_ordinal) +,action_ordinal(action_ordinal) +,idx64(*this) +,idx128(*this) +,idx256(*this) +,idx_double(*this) +,idx_long_double(*this) +{ + action_trace& trace = trx_ctx.get_action_trace(action_ordinal); + act = &trace.act; + receiver = trace.receiver; + context_free = trace.context_free; +} + +void apply_context::exec_one() { auto start = fc::time_point::now(); action_receipt r; r.receiver = receiver; - r.act_digest = digest_type::hash(act); + r.act_digest = digest_type::hash(*act); const auto& cfg = control.get_global_properties().configuration; try { try { const auto& a = control.get_account( receiver ); privileged = a.privileged; - auto native = control.find_apply_handler( receiver, act.account, act.name ); + auto native = control.find_apply_handler( receiver, act->account, act->name ); if( native ) { if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) { control.check_contract_list( receiver ); - control.check_action_list( act.account, act.name ); + control.check_action_list( act->account, act->name ); } (*native)( *this ); } if( a.code.size() > 0 - && !(act.account == config::system_account_name && act.name == N( setcode ) && + && !(act->account == config::system_account_name && act->name == N( setcode ) && receiver == config::system_account_name) ) { if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) { control.check_contract_list( receiver ); - control.check_action_list( act.account, act.name ); + control.check_action_list( act->account, act->name ); } try { control.get_wasm_interface().apply( a.code_version, a.code, *this ); @@ -64,6 +83,7 @@ void apply_context::exec_one( action_trace& trace ) } } FC_RETHROW_EXCEPTIONS( warn, "pending console output: ${console}", ("console", _pending_console_output) ) } catch( fc::exception& e ) { + action_trace& trace = trx_context.get_action_trace( action_ordinal ); trace.except = e; finalize_trace( trace, start ); throw; @@ -72,14 +92,15 @@ void apply_context::exec_one( action_trace& trace ) r.global_sequence = next_global_sequence(); r.recv_sequence = next_recv_sequence( receiver ); - const auto& account_sequence = db.get(act.account); + const auto& account_sequence = db.get(act->account); r.code_sequence = account_sequence.code_sequence; // could be modified by action execution above r.abi_sequence = account_sequence.abi_sequence; // could be modified by action execution above - for( const auto& auth : act.authorization ) { + for( const auto& auth : act->authorization ) { r.auth_sequence[auth.actor] = next_auth_sequence( auth.actor ); } + action_trace& trace = trx_context.get_action_trace( action_ordinal ); trace.receipt = r; trx_context.executed.emplace_back( std::move(r) ); @@ -102,13 +123,13 @@ void apply_context::finalize_trace( action_trace& trace, const fc::time_point& s trace.elapsed = fc::time_point::now() - start; } -void apply_context::exec( action_trace& trace ) +void apply_context::exec() { _notified.emplace_back( receiver, action_ordinal ); - exec_one( trace ); + exec_one(); for( uint32_t i = 1; i < _notified.size(); ++i ) { std::tie( receiver, action_ordinal ) = _notified[i]; - exec_one( trx_context.get_action_trace( action_ordinal ) ); + exec_one(); } if( _cfa_inline_actions.size() > 0 || _inline_actions.size() > 0 ) { @@ -131,9 +152,8 @@ bool apply_context::is_account( const account_name& account )const { } void apply_context::require_authorization( const account_name& account ) { - for( uint32_t i=0; i < act.authorization.size(); i++ ) { - if( act.authorization[i].actor == account ) { - used_authorizations[i] = true; + for( uint32_t i=0; i < act->authorization.size(); i++ ) { + if( act->authorization[i].actor == account ) { return; } } @@ -141,7 +161,7 @@ void apply_context::require_authorization( const account_name& account ) { } bool apply_context::has_authorization( const account_name& account )const { - for( const auto& auth : act.authorization ) + for( const auto& auth : act->authorization ) if( auth.actor == account ) return true; return false; @@ -149,10 +169,9 @@ bool apply_context::has_authorization( const account_name& account )const { void apply_context::require_authorization(const account_name& account, const permission_name& permission) { - for( uint32_t i=0; i < act.authorization.size(); i++ ) - if( act.authorization[i].actor == account ) { - if( act.authorization[i].permission == permission ) { - used_authorizations[i] = true; + for( uint32_t i=0; i < act->authorization.size(); i++ ) + if( act->authorization[i].actor == account ) { + if( act->authorization[i].permission == permission ) { return; } } @@ -171,7 +190,7 @@ void apply_context::require_recipient( account_name recipient ) { if( !has_recipient(recipient) ) { _notified.emplace_back( recipient, - trx_context.schedule_action( act, recipient, false, action_ordinal, first_receiver_action_ordinal ) + schedule_action( action_ordinal, recipient, false, action_ordinal, first_receiver_action_ordinal ) ); } } @@ -202,7 +221,7 @@ void apply_context::execute_inline( action&& a ) { bool disallow_send_to_self_bypass = false; // eventually set to whether the appropriate protocol feature has been activated bool send_to_self = (a.account == receiver); - bool inherit_parent_authorizations = (!disallow_send_to_self_bypass && send_to_self && (receiver == act.account) && control.is_producing_block()); + bool inherit_parent_authorizations = (!disallow_send_to_self_bypass && send_to_self && (receiver == act->account) && control.is_producing_block()); flat_set inherited_authorizations; if( inherit_parent_authorizations ) { @@ -219,7 +238,7 @@ void apply_context::execute_inline( action&& a ) { if( enforce_actor_whitelist_blacklist ) actors.insert( auth.actor ); - if( inherit_parent_authorizations && std::find(act.authorization.begin(), act.authorization.end(), auth) != act.authorization.end() ) { + if( inherit_parent_authorizations && std::find(act->authorization.begin(), act->authorization.end(), auth) != act->authorization.end() ) { inherited_authorizations.insert( auth ); } } @@ -265,7 +284,7 @@ void apply_context::execute_inline( action&& a ) { auto inline_receiver = a.account; _inline_actions.emplace_back( - trx_context.schedule_action( std::move(a), inline_receiver, false, action_ordinal, first_receiver_action_ordinal ) + schedule_action( std::move(a), inline_receiver, false, action_ordinal, first_receiver_action_ordinal ) ); } @@ -280,7 +299,7 @@ void apply_context::execute_context_free_inline( action&& a ) { auto inline_receiver = a.account; _cfa_inline_actions.emplace_back( - trx_context.schedule_action( std::move(a), inline_receiver, true, action_ordinal, first_receiver_action_ordinal ) + schedule_action( std::move(a), inline_receiver, true, action_ordinal, first_receiver_action_ordinal ) ); } @@ -403,7 +422,7 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a } ); } - EOS_ASSERT( control.is_ram_billing_in_notify_allowed() || (receiver == act.account) || (receiver == payer) || privileged, + EOS_ASSERT( control.is_ram_billing_in_notify_allowed() || (receiver == act->account) || (receiver == payer) || privileged, subjective_block_production_exception, "Cannot charge RAM to other accounts during notify." ); add_ram_usage( payer, (config::billable_size_v + trx_size) ); } @@ -418,6 +437,26 @@ bool apply_context::cancel_deferred_transaction( const uint128_t& sender_id, acc return gto; } +int32_t apply_context::schedule_action( int32_t ordinal_of_action_to_schedule, account_name receiver, bool context_free, + int32_t creator_action_ordinal, int32_t parent_action_ordinal ) +{ + int32_t scheduled_action_ordinal = trx_context.schedule_action( ordinal_of_action_to_schedule, receiver, context_free, + creator_action_ordinal, parent_action_ordinal ); + + act = &trx_context.get_action_trace( action_ordinal ).act; + return scheduled_action_ordinal; +} + +int32_t apply_context::schedule_action( action&& act_to_schedule, account_name receiver, bool context_free, + int32_t creator_action_ordinal, int32_t parent_action_ordinal ) +{ + int32_t scheduled_action_ordinal = trx_context.schedule_action( std::move(act_to_schedule), receiver, context_free, + creator_action_ordinal, parent_action_ordinal ); + + act = &trx_context.get_action_trace( action_ordinal ).act; + return scheduled_action_ordinal; +} + const table_id_object* apply_context::find_table( name code, name scope, name table ) { return db.find(boost::make_tuple(code, scope, table)); } @@ -461,7 +500,7 @@ bytes apply_context::get_packed_transaction() { void apply_context::update_db_usage( const account_name& payer, int64_t delta ) { if( delta > 0 ) { if( !(privileged || payer == account_name(receiver)) ) { - EOS_ASSERT( control.is_ram_billing_in_notify_allowed() || (receiver == act.account), + EOS_ASSERT( control.is_ram_billing_in_notify_allowed() || (receiver == act->account), subjective_block_production_exception, "Cannot charge RAM to other accounts during notify." ); require_authorization( payer ); } diff --git a/libraries/chain/eosio_contract.cpp b/libraries/chain/eosio_contract.cpp index cc303bb50cd..026efefb4a2 100644 --- a/libraries/chain/eosio_contract.cpp +++ b/libraries/chain/eosio_contract.cpp @@ -68,7 +68,7 @@ void validate_authority_precondition( const apply_context& context, const author * This method is called assuming precondition_system_newaccount succeeds a */ void apply_eosio_newaccount(apply_context& context) { - auto create = context.act.data_as(); + auto create = context.get_action().data_as(); try { context.require_authorization(create.creator); // context.require_write_lock( config::eosio_auth_scope ); @@ -129,7 +129,7 @@ void apply_eosio_setcode(apply_context& context) { const auto& cfg = context.control.get_global_properties().configuration; auto& db = context.db; - auto act = context.act.data_as(); + auto act = context.get_action().data_as(); context.require_authorization(act.account); EOS_ASSERT( act.vmtype == 0, invalid_contract_vm_type, "code should be 0" ); @@ -174,7 +174,7 @@ void apply_eosio_setcode(apply_context& context) { void apply_eosio_setabi(apply_context& context) { auto& db = context.db; - auto act = context.act.data_as(); + auto act = context.get_action().data_as(); context.require_authorization(act.account); @@ -205,7 +205,7 @@ void apply_eosio_setabi(apply_context& context) { void apply_eosio_updateauth(apply_context& context) { - auto update = context.act.data_as(); + auto update = context.get_action().data_as(); context.require_authorization(update.account); // only here to mark the single authority on this action as used auto& authorization = context.control.get_mutable_authorization_manager(); @@ -270,7 +270,7 @@ void apply_eosio_updateauth(apply_context& context) { void apply_eosio_deleteauth(apply_context& context) { // context.require_write_lock( config::eosio_auth_scope ); - auto remove = context.act.data_as(); + auto remove = context.get_action().data_as(); context.require_authorization(remove.account); // only here to mark the single authority on this action as used EOS_ASSERT(remove.permission != config::active_name, action_validate_exception, "Cannot delete active authority"); @@ -301,7 +301,7 @@ void apply_eosio_deleteauth(apply_context& context) { void apply_eosio_linkauth(apply_context& context) { // context.require_write_lock( config::eosio_auth_scope ); - auto requirement = context.act.data_as(); + auto requirement = context.get_action().data_as(); try { EOS_ASSERT(!requirement.requirement.empty(), action_validate_exception, "Required permission cannot be empty"); @@ -318,7 +318,7 @@ void apply_eosio_linkauth(apply_context& context) { const permission_object* permission = nullptr; if( context.control.is_builtin_activated( builtin_protocol_feature_t::only_link_to_existing_permission ) ) { permission = db.find( - boost::make_tuple( requirement.account, requirement.requirement ) + boost::make_tuple( requirement.account, requirement.requirement ) ); } else { permission = db.find(requirement.requirement); @@ -358,7 +358,7 @@ void apply_eosio_unlinkauth(apply_context& context) { // context.require_write_lock( config::eosio_auth_scope ); auto& db = context.db; - auto unlink = context.act.data_as(); + auto unlink = context.get_action().data_as(); context.require_authorization(unlink.account); // only here to mark the single authority on this action as used @@ -374,7 +374,7 @@ void apply_eosio_unlinkauth(apply_context& context) { } void apply_eosio_canceldelay(apply_context& context) { - auto cancel = context.act.data_as(); + auto cancel = context.get_action().data_as(); context.require_authorization(cancel.canceling_auth.actor); // only here to mark the single authority on this action as used const auto& trx_id = cancel.trx_id; diff --git a/libraries/chain/include/eosio/chain/apply_context.hpp b/libraries/chain/include/eosio/chain/apply_context.hpp index 49721cb0cfe..bfbe726da29 100644 --- a/libraries/chain/include/eosio/chain/apply_context.hpp +++ b/libraries/chain/include/eosio/chain/apply_context.hpp @@ -452,34 +452,25 @@ class apply_context { /// Constructor public: - apply_context(controller& con, transaction_context& trx_ctx, const action& a, uint32_t depth=0) - :control(con) - ,db(con.mutable_db()) - ,trx_context(trx_ctx) - ,act(a) - ,receiver(act.account) - ,used_authorizations(act.authorization.size(), false) - ,recurse_depth(depth) - ,idx64(*this) - ,idx128(*this) - ,idx256(*this) - ,idx_double(*this) - ,idx_long_double(*this) - { - } - + apply_context(controller& con, transaction_context& trx_ctx, uint32_t action_ordinal, uint32_t depth=0); /// Execution methods: public: - void exec_one( action_trace& trace ); - void exec( action_trace& trace ); + void exec_one(); + void exec(); void execute_inline( action&& a ); void execute_context_free_inline( action&& a ); void schedule_deferred_transaction( const uint128_t& sender_id, account_name payer, transaction&& trx, bool replace_existing ); bool cancel_deferred_transaction( const uint128_t& sender_id, account_name sender ); bool cancel_deferred_transaction( const uint128_t& sender_id ) { return cancel_deferred_transaction(sender_id, receiver); } + protected: + int32_t schedule_action( int32_t ordinal_of_action_to_schedule, account_name receiver, bool context_free = false, + int32_t creator_action_ordinal = -1, int32_t parent_action_ordinal = -1 ); + int32_t schedule_action( action&& act_to_schedule, account_name receiver, bool context_free = false, + int32_t creator_action_ordinal = -1, int32_t parent_action_ordinal = -1 ); + /// Authorization methods: public: @@ -560,22 +551,29 @@ class apply_context { void add_ram_usage( account_name account, int64_t ram_delta ); void finalize_trace( action_trace& trace, const fc::time_point& start ); + bool is_context_free()const { return context_free; } + bool is_privileged()const { return privileged; } + action_name get_receiver()const { return receiver; } + const action& get_action()const { return *act; } + /// Fields: public: controller& control; chainbase::database& db; ///< database where state is stored transaction_context& trx_context; ///< transaction context in which the action is running - const action& act; ///< message being applied + + private: + const action* act = nullptr; ///< action being applied + // act pointer may be invalidated on call to trx_context.schedule_action account_name receiver; ///< the code that is currently running - vector used_authorizations; ///< Parallel to act.authorization; tracks which permissions have been used while processing the message uint32_t recurse_depth; ///< how deep inline actions can recurse int32_t first_receiver_action_ordinal = -1; int32_t action_ordinal = -1; bool privileged = false; bool context_free = false; - bool used_context_free_api = false; + public: generic_index idx64; generic_index idx128; generic_index idx256; diff --git a/libraries/chain/include/eosio/chain/transaction_context.hpp b/libraries/chain/include/eosio/chain/transaction_context.hpp index 0182f5a05f0..f27a718523b 100644 --- a/libraries/chain/include/eosio/chain/transaction_context.hpp +++ b/libraries/chain/include/eosio/chain/transaction_context.hpp @@ -64,19 +64,22 @@ namespace eosio { namespace chain { void add_ram_usage( account_name account, int64_t ram_delta ); + action_trace& get_action_trace( int32_t action_ordinal ); + const action_trace& get_action_trace( int32_t action_ordinal )const; + + /** invalidates any action_trace references returned by get_action_trace */ int32_t schedule_action( const action& act, account_name receiver, bool context_free = false, int32_t creator_action_ordinal = -1, int32_t parent_action_ordinal = -1 ); - int32_t schedule_action( action&& act, account_name receiver, bool context_free = false, + /** invalidates any action_trace references returned by get_action_trace */ + int32_t schedule_action( action&& act, account_name receiver, bool context_free = false, int32_t creator_action_ordinal = -1, int32_t parent_action_ordinal = -1 ); - action_trace& get_action_trace( int32_t action_ordinal ); - const action_trace& get_action_trace( int32_t action_ordinal )const; + /** invalidates any action_trace references returned by get_action_trace */ + int32_t schedule_action( int32_t action_ordinal, account_name receiver, bool context_free = false, + int32_t creator_action_ordinal = -1, int32_t parent_action_ordinal = -1 ); - void execute_action( action_trace& act_trace, uint32_t recurse_depth ); - inline void execute_action( int32_t action_ordinal, uint32_t recurse_depth = 0 ) { - execute_action( get_action_trace( action_ordinal ), recurse_depth ); - } + void execute_action( int32_t action_ordinal, uint32_t recurse_depth = 0 ); void schedule_transaction(); void record_transaction( const transaction_id_type& id, fc::time_point_sec expire ); diff --git a/libraries/chain/transaction_context.cpp b/libraries/chain/transaction_context.cpp index da99fd4dbe2..138006715b5 100644 --- a/libraries/chain/transaction_context.cpp +++ b/libraries/chain/transaction_context.cpp @@ -346,7 +346,7 @@ namespace bacc = boost::accumulators; auto& action_traces = trace->action_traces; int32_t num_original_actions_to_execute = action_traces.size(); for( int32_t i = 0; i < num_original_actions_to_execute; ++i ) { - execute_action( action_traces[i], 0 ); + execute_action( i, 0 ); } if( delay != fc::microseconds() ) { @@ -575,23 +575,40 @@ namespace bacc = boost::accumulators; int32_t transaction_context::schedule_action( const action& act, account_name receiver, bool context_free, int32_t creator_action_ordinal, int32_t parent_action_ordinal ) { - int32_t action_ordinal = trace->action_traces.size(); + int32_t new_action_ordinal = trace->action_traces.size(); trace->action_traces.emplace_back( *trace, act, receiver, context_free, - action_ordinal, creator_action_ordinal, parent_action_ordinal ); + new_action_ordinal, creator_action_ordinal, parent_action_ordinal ); - return action_ordinal; + return new_action_ordinal; } int32_t transaction_context::schedule_action( action&& act, account_name receiver, bool context_free, int32_t creator_action_ordinal, int32_t parent_action_ordinal ) { - int32_t action_ordinal = trace->action_traces.size(); + int32_t new_action_ordinal = trace->action_traces.size(); trace->action_traces.emplace_back( *trace, std::move(act), receiver, context_free, - action_ordinal, creator_action_ordinal, parent_action_ordinal ); + new_action_ordinal, creator_action_ordinal, parent_action_ordinal ); - return action_ordinal; + return new_action_ordinal; + } + + int32_t transaction_context::schedule_action( int32_t action_ordinal, account_name receiver, bool context_free, + int32_t creator_action_ordinal, int32_t parent_action_ordinal ) + { + int32_t new_action_ordinal = trace->action_traces.size(); + + trace->action_traces.reserve( new_action_ordinal + 1 ); + + const action& provided_action = get_action_trace( action_ordinal ).act; + + // The reserve above is required so that the emplace_back below does not invalidate the provided_action reference. + + trace->action_traces.emplace_back( *trace, provided_action, receiver, context_free, + new_action_ordinal, creator_action_ordinal, parent_action_ordinal ); + + return new_action_ordinal; } action_trace& transaction_context::get_action_trace( int32_t action_ordinal ) { @@ -606,14 +623,9 @@ namespace bacc = boost::accumulators; return trace->action_traces[action_ordinal]; } - void transaction_context::execute_action( action_trace& act_trace, uint32_t recurse_depth ) { - apply_context acontext( control, *this, act_trace.act, recurse_depth ); - acontext.receiver = act_trace.receiver; - acontext.first_receiver_action_ordinal = act_trace.action_ordinal; - acontext.action_ordinal = act_trace.action_ordinal; - acontext.context_free = act_trace.context_free; - - acontext.exec( act_trace ); + void transaction_context::execute_action( int32_t action_ordinal, uint32_t recurse_depth ) { + apply_context acontext( control, *this, action_ordinal, recurse_depth ); + acontext.exec(); } diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index 3414d9dc972..004a7326e83 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -77,9 +77,8 @@ class context_aware_api { context_aware_api(apply_context& ctx, bool context_free = false ) :context(ctx) { - if( context.context_free ) + if( context.is_context_free() ) EOS_ASSERT( context_free, unaccessible_api, "only context free api's can be used in this context" ); - context.used_context_free_api |= !context_free; } void checktime() { @@ -96,7 +95,7 @@ class context_free_api : public context_aware_api { context_free_api( apply_context& ctx ) :context_aware_api(ctx, true) { /* the context_free_data is not available during normal application because it is prunable */ - EOS_ASSERT( context.context_free, unaccessible_api, "this API may only be called from context_free apply" ); + EOS_ASSERT( context.is_context_free(), unaccessible_api, "this API may only be called from context_free apply" ); } int get_context_free_data( uint32_t index, array_ptr buffer, size_t buffer_size )const { @@ -109,7 +108,7 @@ class privileged_api : public context_aware_api { privileged_api( apply_context& ctx ) :context_aware_api(ctx) { - EOS_ASSERT( context.privileged, unaccessible_api, "${code} does not have permission to call this API", ("code",context.receiver) ); + EOS_ASSERT( context.is_privileged(), unaccessible_api, "${code} does not have permission to call this API", ("code",context.get_receiver()) ); } /** @@ -978,21 +977,21 @@ class action_api : public context_aware_api { :context_aware_api(ctx,true){} int read_action_data(array_ptr memory, size_t buffer_size) { - auto s = context.act.data.size(); + auto s = context.get_action().data.size(); if( buffer_size == 0 ) return s; auto copy_size = std::min( buffer_size, s ); - memcpy( memory, context.act.data.data(), copy_size ); + memcpy( memory, context.get_action().data.data(), copy_size ); return copy_size; } int action_data_size() { - return context.act.data.size(); + return context.get_action().data.size(); } name current_receiver() { - return context.receiver; + return context.get_receiver(); } }; diff --git a/libraries/chain/webassembly/wabt.cpp b/libraries/chain/webassembly/wabt.cpp index 2d45fa4ee01..a23919e0ec6 100644 --- a/libraries/chain/webassembly/wabt.cpp +++ b/libraries/chain/webassembly/wabt.cpp @@ -28,7 +28,7 @@ class wabt_instantiated_module : public wasm_instantiated_module_interface { continue; _initial_globals.emplace_back(_env->GetGlobal(i), _env->GetGlobal(i)->typed_value); } - + if(_env->GetMemoryCount()) _initial_memory_configuration = _env->GetMemory(0)->page_limits; } @@ -50,9 +50,9 @@ class wabt_instantiated_module : public wasm_instantiated_module_interface { memcpy(memory->data.data(), _initial_memory.data(), _initial_memory.size()); } - _params[0].set_i64(uint64_t(context.receiver)); - _params[1].set_i64(uint64_t(context.act.account)); - _params[2].set_i64(uint64_t(context.act.name)); + _params[0].set_i64(uint64_t(context.get_receiver())); + _params[1].set_i64(uint64_t(context.get_action().account)); + _params[2].set_i64(uint64_t(context.get_action().name)); ExecResult res = _executor.RunStartFunction(_instatiated_module); EOS_ASSERT( res.result == interp::Result::Ok, wasm_execution_error, "wabt start function failure (${s})", ("s", ResultToString(res.result)) ); @@ -92,7 +92,7 @@ std::unique_ptr wabt_runtime::instantiate_mo wabt::Result res = ReadBinaryInterp(env.get(), code_bytes, code_size, read_binary_options, &errors, &instantiated_module); EOS_ASSERT( Succeeded(res), wasm_execution_error, "Error building wabt interp: ${e}", ("e", wabt::FormatErrorsToString(errors, Location::Type::Binary)) ); - + return std::make_unique(std::move(env), initial_memory, instantiated_module); } diff --git a/libraries/chain/webassembly/wavm.cpp b/libraries/chain/webassembly/wavm.cpp index e614398c74e..a4e519a14e0 100644 --- a/libraries/chain/webassembly/wavm.cpp +++ b/libraries/chain/webassembly/wavm.cpp @@ -30,9 +30,9 @@ class wavm_instantiated_module : public wasm_instantiated_module_interface { {} void apply(apply_context& context) override { - vector args = {Value(uint64_t(context.receiver)), - Value(uint64_t(context.act.account)), - Value(uint64_t(context.act.name))}; + vector args = {Value(uint64_t(context.get_receiver())), + Value(uint64_t(context.get_action().account)), + Value(uint64_t(context.get_action().name))}; call("apply", args, context); } From 28377ed6d5d1285da6b0b00fce3e2a476549b9e8 Mon Sep 17 00:00:00 2001 From: arhag Date: Mon, 1 Apr 2019 18:20:07 -0400 Subject: [PATCH 04/15] update cleos to support new transaction trace structure without inline_traces #6897 Also correct state history ABI for action_trace_v0 to reflect that inline_traces are no longer included. --- .../state_history_plugin/state_history_plugin_abi.cpp | 1 - programs/cleos/main.cpp | 11 +++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/plugins/state_history_plugin/state_history_plugin_abi.cpp b/plugins/state_history_plugin/state_history_plugin_abi.cpp index af2afb8e1bf..3f564e9043c 100644 --- a/plugins/state_history_plugin/state_history_plugin_abi.cpp +++ b/plugins/state_history_plugin/state_history_plugin_abi.cpp @@ -104,7 +104,6 @@ extern const char* const state_history_plugin_abi = R"({ { "name": "console", "type": "string" }, { "name": "account_ram_deltas", "type": "account_delta[]" }, { "name": "except", "type": "string?" }, - { "name": "inline_traces", "type": "action_trace[]" } ] }, { diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index caa24ae5ccf..00c99d17261 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -443,9 +443,11 @@ bytes json_or_file_to_bin( const account_name& account, const action_name& actio void print_action_tree( const fc::variant& action ) { print_action( action ); - const auto& inline_traces = action["inline_traces"].get_array(); - for( const auto& t : inline_traces ) { - print_action_tree( t ); + if( action.get_object().contains( "inline_traces" ) ) { + const auto& inline_traces = action["inline_traces"].get_array(); + for( const auto& t : inline_traces ) { + print_action_tree( t ); + } } } @@ -453,12 +455,13 @@ void print_result( const fc::variant& result ) { try { if (result.is_object() && result.get_object().contains("processed")) { const auto& processed = result["processed"]; const auto& transaction_id = processed["id"].as_string(); - string status = processed["receipt"].is_object() ? processed["receipt"]["status"].as_string() : "failed"; + string status = "failed"; int64_t net = -1; int64_t cpu = -1; if( processed.get_object().contains( "receipt" )) { const auto& receipt = processed["receipt"]; if( receipt.is_object()) { + status = receipt["status"].as_string(); net = receipt["net_usage_words"].as_int64() * 8; cpu = receipt["cpu_usage_us"].as_int64(); } From c62a5f1f7341576202223497bc96a771b3e640a2 Mon Sep 17 00:00:00 2001 From: arhag Date: Tue, 2 Apr 2019 11:57:58 -0400 Subject: [PATCH 05/15] switch ordinal types to fc::unsigned_int and use 1-based indexing #6897 --- libraries/chain/apply_context.cpp | 26 +++++----- .../include/eosio/chain/apply_context.hpp | 16 +++--- libraries/chain/include/eosio/chain/trace.hpp | 10 ++-- .../eosio/chain/transaction_context.hpp | 18 +++---- libraries/chain/trace.cpp | 6 +-- libraries/chain/transaction_context.cpp | 50 +++++++++---------- unittests/api_tests.cpp | 2 +- 7 files changed, 63 insertions(+), 65 deletions(-) diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index 22b583704e4..46ea155aee8 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -137,11 +137,11 @@ void apply_context::exec() transaction_exception, "max inline action depth per transaction reached" ); } - for( int32_t ordinal : _cfa_inline_actions ) { + for( uint32_t ordinal : _cfa_inline_actions ) { trx_context.execute_action( ordinal, recurse_depth + 1 ); } - for( int32_t ordinal : _inline_actions ) { + for( uint32_t ordinal : _inline_actions ) { trx_context.execute_action( ordinal, recurse_depth + 1 ); } @@ -190,7 +190,7 @@ void apply_context::require_recipient( account_name recipient ) { if( !has_recipient(recipient) ) { _notified.emplace_back( recipient, - schedule_action( action_ordinal, recipient, false, action_ordinal, first_receiver_action_ordinal ) + schedule_action( action_ordinal, recipient, false ) ); } } @@ -284,7 +284,7 @@ void apply_context::execute_inline( action&& a ) { auto inline_receiver = a.account; _inline_actions.emplace_back( - schedule_action( std::move(a), inline_receiver, false, action_ordinal, first_receiver_action_ordinal ) + schedule_action( std::move(a), inline_receiver, false ) ); } @@ -299,7 +299,7 @@ void apply_context::execute_context_free_inline( action&& a ) { auto inline_receiver = a.account; _cfa_inline_actions.emplace_back( - schedule_action( std::move(a), inline_receiver, true, action_ordinal, first_receiver_action_ordinal ) + schedule_action( std::move(a), inline_receiver, true ) ); } @@ -437,21 +437,21 @@ bool apply_context::cancel_deferred_transaction( const uint128_t& sender_id, acc return gto; } -int32_t apply_context::schedule_action( int32_t ordinal_of_action_to_schedule, account_name receiver, bool context_free, - int32_t creator_action_ordinal, int32_t parent_action_ordinal ) +uint32_t apply_context::schedule_action( uint32_t ordinal_of_action_to_schedule, account_name receiver, bool context_free ) { - int32_t scheduled_action_ordinal = trx_context.schedule_action( ordinal_of_action_to_schedule, receiver, context_free, - creator_action_ordinal, parent_action_ordinal ); + uint32_t scheduled_action_ordinal = trx_context.schedule_action( ordinal_of_action_to_schedule, + receiver, context_free, + action_ordinal, first_receiver_action_ordinal ); act = &trx_context.get_action_trace( action_ordinal ).act; return scheduled_action_ordinal; } -int32_t apply_context::schedule_action( action&& act_to_schedule, account_name receiver, bool context_free, - int32_t creator_action_ordinal, int32_t parent_action_ordinal ) +uint32_t apply_context::schedule_action( action&& act_to_schedule, account_name receiver, bool context_free ) { - int32_t scheduled_action_ordinal = trx_context.schedule_action( std::move(act_to_schedule), receiver, context_free, - creator_action_ordinal, parent_action_ordinal ); + uint32_t scheduled_action_ordinal = trx_context.schedule_action( std::move(act_to_schedule), + receiver, context_free, + action_ordinal, first_receiver_action_ordinal ); act = &trx_context.get_action_trace( action_ordinal ).act; return scheduled_action_ordinal; diff --git a/libraries/chain/include/eosio/chain/apply_context.hpp b/libraries/chain/include/eosio/chain/apply_context.hpp index bfbe726da29..805bb74e485 100644 --- a/libraries/chain/include/eosio/chain/apply_context.hpp +++ b/libraries/chain/include/eosio/chain/apply_context.hpp @@ -466,10 +466,8 @@ class apply_context { bool cancel_deferred_transaction( const uint128_t& sender_id ) { return cancel_deferred_transaction(sender_id, receiver); } protected: - int32_t schedule_action( int32_t ordinal_of_action_to_schedule, account_name receiver, bool context_free = false, - int32_t creator_action_ordinal = -1, int32_t parent_action_ordinal = -1 ); - int32_t schedule_action( action&& act_to_schedule, account_name receiver, bool context_free = false, - int32_t creator_action_ordinal = -1, int32_t parent_action_ordinal = -1 ); + uint32_t schedule_action( uint32_t ordinal_of_action_to_schedule, account_name receiver, bool context_free = false ); + uint32_t schedule_action( action&& act_to_schedule, account_name receiver, bool context_free = false ); /// Authorization methods: @@ -568,8 +566,8 @@ class apply_context { // act pointer may be invalidated on call to trx_context.schedule_action account_name receiver; ///< the code that is currently running uint32_t recurse_depth; ///< how deep inline actions can recurse - int32_t first_receiver_action_ordinal = -1; - int32_t action_ordinal = -1; + uint32_t first_receiver_action_ordinal = 0; + uint32_t action_ordinal = 0; bool privileged = false; bool context_free = false; @@ -583,9 +581,9 @@ class apply_context { private: iterator_cache keyval_cache; - vector< std::pair > _notified; ///< keeps track of new accounts to be notifed of current message - vector _inline_actions; ///< action_ordinals of queued inline actions - vector _cfa_inline_actions; ///< action_ordinals of queued inline context-free actions + vector< std::pair > _notified; ///< keeps track of new accounts to be notifed of current message + vector _inline_actions; ///< action_ordinals of queued inline actions + vector _cfa_inline_actions; ///< action_ordinals of queued inline context-free actions std::string _pending_console_output; flat_set _account_ram_deltas; ///< flat_set of account_delta so json is an array of objects diff --git a/libraries/chain/include/eosio/chain/trace.hpp b/libraries/chain/include/eosio/chain/trace.hpp index 07dbbd0fdeb..67e7f62a7ee 100644 --- a/libraries/chain/include/eosio/chain/trace.hpp +++ b/libraries/chain/include/eosio/chain/trace.hpp @@ -25,15 +25,15 @@ namespace eosio { namespace chain { struct action_trace { action_trace( const transaction_trace& trace, const action& act, account_name receiver, bool context_free, - int32_t action_ordinal, int32_t creator_action_ordinal, int32_t parent_action_ordinal ); + uint32_t action_ordinal, uint32_t creator_action_ordinal, uint32_t parent_action_ordinal ); action_trace( const transaction_trace& trace, action&& act, account_name receiver, bool context_free, - int32_t action_ordinal, int32_t creator_action_ordinal, int32_t parent_action_ordinal ); + uint32_t action_ordinal, uint32_t creator_action_ordinal, uint32_t parent_action_ordinal ); //action_trace( const action_receipt& r ):receipt(r){} action_trace(){} - int32_t action_ordinal = 0; - int32_t creator_action_ordinal = -1; - int32_t parent_action_ordinal = -1; + fc::unsigned_int action_ordinal; + fc::unsigned_int creator_action_ordinal; + fc::unsigned_int parent_action_ordinal; fc::optional receipt; action_name receiver; action act; diff --git a/libraries/chain/include/eosio/chain/transaction_context.hpp b/libraries/chain/include/eosio/chain/transaction_context.hpp index f27a718523b..636b3a87c82 100644 --- a/libraries/chain/include/eosio/chain/transaction_context.hpp +++ b/libraries/chain/include/eosio/chain/transaction_context.hpp @@ -64,22 +64,22 @@ namespace eosio { namespace chain { void add_ram_usage( account_name account, int64_t ram_delta ); - action_trace& get_action_trace( int32_t action_ordinal ); - const action_trace& get_action_trace( int32_t action_ordinal )const; + action_trace& get_action_trace( uint32_t action_ordinal ); + const action_trace& get_action_trace( uint32_t action_ordinal )const; /** invalidates any action_trace references returned by get_action_trace */ - int32_t schedule_action( const action& act, account_name receiver, bool context_free = false, - int32_t creator_action_ordinal = -1, int32_t parent_action_ordinal = -1 ); + uint32_t schedule_action( const action& act, account_name receiver, bool context_free = false, + uint32_t creator_action_ordinal = 0, uint32_t parent_action_ordinal = 0 ); /** invalidates any action_trace references returned by get_action_trace */ - int32_t schedule_action( action&& act, account_name receiver, bool context_free = false, - int32_t creator_action_ordinal = -1, int32_t parent_action_ordinal = -1 ); + uint32_t schedule_action( action&& act, account_name receiver, bool context_free = false, + uint32_t creator_action_ordinal = 0, uint32_t parent_action_ordinal = 0 ); /** invalidates any action_trace references returned by get_action_trace */ - int32_t schedule_action( int32_t action_ordinal, account_name receiver, bool context_free = false, - int32_t creator_action_ordinal = -1, int32_t parent_action_ordinal = -1 ); + uint32_t schedule_action( uint32_t action_ordinal, account_name receiver, bool context_free = false, + uint32_t creator_action_ordinal = 0, uint32_t parent_action_ordinal = 0 ); - void execute_action( int32_t action_ordinal, uint32_t recurse_depth = 0 ); + void execute_action( uint32_t action_ordinal, uint32_t recurse_depth = 0 ); void schedule_transaction(); void record_transaction( const transaction_id_type& id, fc::time_point_sec expire ); diff --git a/libraries/chain/trace.cpp b/libraries/chain/trace.cpp index 0b379c89e00..2379018518f 100644 --- a/libraries/chain/trace.cpp +++ b/libraries/chain/trace.cpp @@ -8,7 +8,7 @@ namespace eosio { namespace chain { action_trace::action_trace( const transaction_trace& trace, const action& act, account_name receiver, bool context_free, - int32_t action_ordinal, int32_t creator_action_ordinal, int32_t parent_action_ordinal + uint32_t action_ordinal, uint32_t creator_action_ordinal, uint32_t parent_action_ordinal ) :action_ordinal( action_ordinal ) ,creator_action_ordinal( creator_action_ordinal ) @@ -23,8 +23,8 @@ action_trace::action_trace( {} action_trace::action_trace( - const transaction_trace& trace, action&& act, account_name receiver, bool context_free, - int32_t action_ordinal, int32_t creator_action_ordinal, int32_t parent_action_ordinal + const transaction_trace& trace, action&& act, account_name receiver, bool context_free, + uint32_t action_ordinal, uint32_t creator_action_ordinal, uint32_t parent_action_ordinal ) :action_ordinal( action_ordinal ) ,creator_action_ordinal( creator_action_ordinal ) diff --git a/libraries/chain/transaction_context.cpp b/libraries/chain/transaction_context.cpp index 138006715b5..730658538e7 100644 --- a/libraries/chain/transaction_context.cpp +++ b/libraries/chain/transaction_context.cpp @@ -344,8 +344,8 @@ namespace bacc = boost::accumulators; } auto& action_traces = trace->action_traces; - int32_t num_original_actions_to_execute = action_traces.size(); - for( int32_t i = 0; i < num_original_actions_to_execute; ++i ) { + uint32_t num_original_actions_to_execute = action_traces.size(); + for( uint32_t i = 1; i <= num_original_actions_to_execute; ++i ) { execute_action( i, 0 ); } @@ -572,10 +572,22 @@ namespace bacc = boost::accumulators; return std::make_tuple(account_net_limit, account_cpu_limit, greylisted_net, greylisted_cpu); } - int32_t transaction_context::schedule_action( const action& act, account_name receiver, bool context_free, - int32_t creator_action_ordinal, int32_t parent_action_ordinal ) + action_trace& transaction_context::get_action_trace( uint32_t action_ordinal ) { + EOS_ASSERT( 0 < action_ordinal && action_ordinal <= trace->action_traces.size() , + transaction_exception, "invalid action_ordinal" ); + return trace->action_traces[action_ordinal-1]; + } + + const action_trace& transaction_context::get_action_trace( uint32_t action_ordinal )const { + EOS_ASSERT( 0 < action_ordinal && action_ordinal <= trace->action_traces.size() , + transaction_exception, "invalid action_ordinal" ); + return trace->action_traces[action_ordinal-1]; + } + + uint32_t transaction_context::schedule_action( const action& act, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, uint32_t parent_action_ordinal ) { - int32_t new_action_ordinal = trace->action_traces.size(); + uint32_t new_action_ordinal = trace->action_traces.size() + 1; trace->action_traces.emplace_back( *trace, act, receiver, context_free, new_action_ordinal, creator_action_ordinal, parent_action_ordinal ); @@ -583,10 +595,10 @@ namespace bacc = boost::accumulators; return new_action_ordinal; } - int32_t transaction_context::schedule_action( action&& act, account_name receiver, bool context_free, - int32_t creator_action_ordinal, int32_t parent_action_ordinal ) + uint32_t transaction_context::schedule_action( action&& act, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, uint32_t parent_action_ordinal ) { - int32_t new_action_ordinal = trace->action_traces.size(); + uint32_t new_action_ordinal = trace->action_traces.size() + 1; trace->action_traces.emplace_back( *trace, std::move(act), receiver, context_free, new_action_ordinal, creator_action_ordinal, parent_action_ordinal ); @@ -594,12 +606,12 @@ namespace bacc = boost::accumulators; return new_action_ordinal; } - int32_t transaction_context::schedule_action( int32_t action_ordinal, account_name receiver, bool context_free, - int32_t creator_action_ordinal, int32_t parent_action_ordinal ) + uint32_t transaction_context::schedule_action( uint32_t action_ordinal, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, uint32_t parent_action_ordinal ) { - int32_t new_action_ordinal = trace->action_traces.size(); + uint32_t new_action_ordinal = trace->action_traces.size() + 1; - trace->action_traces.reserve( new_action_ordinal + 1 ); + trace->action_traces.reserve( new_action_ordinal ); const action& provided_action = get_action_trace( action_ordinal ).act; @@ -611,19 +623,7 @@ namespace bacc = boost::accumulators; return new_action_ordinal; } - action_trace& transaction_context::get_action_trace( int32_t action_ordinal ) { - EOS_ASSERT( 0 <= action_ordinal && action_ordinal < trace->action_traces.size() , - transaction_exception, "invalid action_ordinal" ); - return trace->action_traces[action_ordinal]; - } - - const action_trace& transaction_context::get_action_trace( int32_t action_ordinal )const { - EOS_ASSERT( 0 <= action_ordinal && action_ordinal < trace->action_traces.size() , - transaction_exception, "invalid action_ordinal" ); - return trace->action_traces[action_ordinal]; - } - - void transaction_context::execute_action( int32_t action_ordinal, uint32_t recurse_depth ) { + void transaction_context::execute_action( uint32_t action_ordinal, uint32_t recurse_depth ) { apply_context acontext( control, *this, action_ordinal, recurse_depth ); acontext.exec(); } diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index 83f2f20e618..b64a97feb7d 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -702,7 +702,7 @@ BOOST_FIXTURE_TEST_CASE(cf_action_tests, TESTER) { try { auto ttrace = CALL_TEST_FUNCTION( *this, "test_transaction", "send_cf_action", {} ); BOOST_REQUIRE_EQUAL(ttrace->action_traces.size(), 2); - BOOST_CHECK_EQUAL(ttrace->action_traces[1].creator_action_ordinal, 0); + BOOST_CHECK_EQUAL(ttrace->action_traces[1].creator_action_ordinal.value, 1); BOOST_CHECK_EQUAL(ttrace->action_traces[1].receiver, account_name("dummy")); BOOST_CHECK_EQUAL(ttrace->action_traces[1].act.account, account_name("dummy")); BOOST_CHECK_EQUAL(ttrace->action_traces[1].act.name, account_name("event1")); From 01d2dbcb68414bfafb3a1eef970906fcd11477e3 Mon Sep 17 00:00:00 2001 From: arhag Date: Tue, 2 Apr 2019 13:56:03 -0400 Subject: [PATCH 06/15] state_history_plugin changes to reflect ordinal type change to fc::unsigned_int #6897 --- .../state_history_plugin/state_history_serialization.hpp | 6 +++--- plugins/state_history_plugin/state_history_plugin_abi.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp index 473e5720ec4..3251abef7fb 100644 --- a/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp +++ b/plugins/state_history_plugin/include/eosio/state_history_plugin/state_history_serialization.hpp @@ -480,9 +480,9 @@ datastream& operator<<(datastream& ds, const history_serial_wrapper datastream& operator<<(datastream& ds, const history_serial_wrapper& obj) { fc::raw::pack(ds, fc::unsigned_int(0)); - fc::raw::pack(ds, as_type(obj.obj.action_ordinal)); - fc::raw::pack(ds, as_type(obj.obj.creator_action_ordinal)); - fc::raw::pack(ds, as_type(obj.obj.parent_action_ordinal)); + fc::raw::pack(ds, as_type(obj.obj.action_ordinal)); + fc::raw::pack(ds, as_type(obj.obj.creator_action_ordinal)); + fc::raw::pack(ds, as_type(obj.obj.parent_action_ordinal)); fc::raw::pack(ds, bool(obj.obj.receipt)); if (obj.obj.receipt) { fc::raw::pack(ds, make_history_serial_wrapper(obj.db, as_type(*obj.obj.receipt))); diff --git a/plugins/state_history_plugin/state_history_plugin_abi.cpp b/plugins/state_history_plugin/state_history_plugin_abi.cpp index 3f564e9043c..95affaf57c2 100644 --- a/plugins/state_history_plugin/state_history_plugin_abi.cpp +++ b/plugins/state_history_plugin/state_history_plugin_abi.cpp @@ -93,9 +93,9 @@ extern const char* const state_history_plugin_abi = R"({ }, { "name": "action_trace_v0", "fields": [ - { "name": "action_ordinal", "type": "int32" }, - { "name": "creator_action_ordinal", "type": "int32" }, - { "name": "parent_action_ordinal", "type": "int32" }, + { "name": "action_ordinal", "type": "varuint32" }, + { "name": "creator_action_ordinal", "type": "varuint32" }, + { "name": "parent_action_ordinal", "type": "varuint32" }, { "name": "receipt", "type": "action_receipt?" }, { "name": "receiver", "type": "name" }, { "name": "act", "type": "action" }, From 7a0ffb3ccca7d91c6791f00fb257d45c81ff180f Mon Sep 17 00:00:00 2001 From: Kayan Date: Thu, 4 Apr 2019 15:56:02 +0800 Subject: [PATCH 07/15] add test cases for 6897-restructure-traces --- unittests/api_tests.cpp | 412 +++++++++++++++++- .../test-contracts/test_api/test_action.cpp | 83 ++++ .../test-contracts/test_api/test_api.cpp | 6 + .../test-contracts/test_api/test_api.hpp | 6 + .../test-contracts/test_api/test_api.wasm | Bin 67533 -> 69149 bytes 5 files changed, 506 insertions(+), 1 deletion(-) diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index b64a97feb7d..367b2c6bcf5 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -245,9 +245,42 @@ transaction_trace_ptr CallFunction(TESTER& test, T ac, const vector& data, } } +template +transaction_trace_ptr CallFunctionExpectFail(TESTER& test, T ac, const vector& data, const vector& scope = {N(testapi)}) { + { + signed_transaction trx; + + auto pl = vector{{scope[0], config::active_name}}; + if (scope.size() > 1) + for (unsigned int i=1; i < scope.size(); i++) + pl.push_back({scope[i], config::active_name}); + + action act(pl, ac); + act.data = data; + act.authorization = {{N(testapi), config::active_name}}; + trx.actions.push_back(act); + + test.set_transaction_headers(trx, test.DEFAULT_EXPIRATION_DELTA); + auto sigs = trx.sign(test.get_private_key(scope[0], "active"), test.control->get_chain_id()); + + flat_set keys; + trx.get_signature_keys(test.control->get_chain_id(), fc::time_point::maximum(), keys); + + auto c = packed_transaction::none; + + if( fc::raw::pack_size(trx) > 1000 ) { + c = packed_transaction::zlib; + } + + auto res = test.control->push_transaction(std::make_shared(trx,c), fc::time_point::maximum(), 100); + return res; + } +} + #define CALL_TEST_FUNCTION(_TESTER, CLS, MTH, DATA) CallFunction(_TESTER, test_api_action{}, DATA) #define CALL_TEST_FUNCTION_SYSTEM(_TESTER, CLS, MTH, DATA) CallFunction(_TESTER, test_chain_action{}, DATA, {config::system_account_name} ) #define CALL_TEST_FUNCTION_SCOPE(_TESTER, CLS, MTH, DATA, ACCOUNT) CallFunction(_TESTER, test_api_action{}, DATA, ACCOUNT) +#define CALL_TEST_FUNCTION_SCOPE_EXPECT_FAIL(_TESTER, CLS, MTH, DATA, ACCOUNT) CallFunctionExpectFail(_TESTER, test_api_action{}, DATA, ACCOUNT) #define CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION(_TESTER, CLS, MTH, DATA, EXC, EXC_MESSAGE) \ BOOST_CHECK_EXCEPTION( \ CALL_TEST_FUNCTION( _TESTER, CLS, MTH, DATA), \ @@ -702,7 +735,7 @@ BOOST_FIXTURE_TEST_CASE(cf_action_tests, TESTER) { try { auto ttrace = CALL_TEST_FUNCTION( *this, "test_transaction", "send_cf_action", {} ); BOOST_REQUIRE_EQUAL(ttrace->action_traces.size(), 2); - BOOST_CHECK_EQUAL(ttrace->action_traces[1].creator_action_ordinal.value, 1); + BOOST_CHECK_EQUAL((int)(ttrace->action_traces[1].creator_action_ordinal), 0); BOOST_CHECK_EQUAL(ttrace->action_traces[1].receiver, account_name("dummy")); BOOST_CHECK_EQUAL(ttrace->action_traces[1].act.account, account_name("dummy")); BOOST_CHECK_EQUAL(ttrace->action_traces[1].act.name, account_name("event1")); @@ -2060,4 +2093,381 @@ BOOST_FIXTURE_TEST_CASE(eosio_assert_code_tests, TESTER) { try { BOOST_REQUIRE_EQUAL( validate(), true ); } FC_LOG_AND_RETHROW() } +/************************************************************************************* ++ * action_ordinal_test test cases ++ *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(action_ordinal_test, TESTER) { try { + + produce_blocks(1); + create_account(N(testapi) ); + set_code( N(testapi), contracts::test_api_wasm() ); + produce_blocks(1); + create_account(N(bob) ); + set_code( N(bob), contracts::test_api_wasm() ); + produce_blocks(1); + create_account(N(charlie) ); + set_code( N(charlie), contracts::test_api_wasm() ); + produce_blocks(1); + create_account(N(david) ); + set_code( N(david), contracts::test_api_wasm() ); + produce_blocks(1); + create_account(N(erin) ); + set_code( N(erin), contracts::test_api_wasm() ); + produce_blocks(1); + + transaction_trace_ptr txn_trace = CALL_TEST_FUNCTION_SCOPE( *this, "test_action", "test_action_ordinal1", + {}, vector{ N(testapi)}); + + BOOST_REQUIRE_EQUAL( validate(), true ); + + BOOST_REQUIRE_EQUAL( txn_trace != nullptr, true); + BOOST_REQUIRE_EQUAL( txn_trace->action_traces.size(), 11); + + auto &atrace = txn_trace->action_traces; + BOOST_REQUIRE_EQUAL((int)atrace[0].action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[0].creator_action_ordinal, 0); + BOOST_REQUIRE_EQUAL((int)atrace[0].parent_action_ordinal, 0); + BOOST_REQUIRE_EQUAL(atrace[0].receipt.valid(), true); + int start_gseq = atrace[0].receipt->global_sequence; + + BOOST_REQUIRE_EQUAL((int)atrace[1].action_ordinal,2); + BOOST_REQUIRE_EQUAL((int)atrace[1].creator_action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[1].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[1].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[1].receipt->global_sequence, start_gseq + 1); + + BOOST_REQUIRE_EQUAL((int)atrace[2].action_ordinal, 3); + BOOST_REQUIRE_EQUAL((int)atrace[2].creator_action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[2].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[2].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[2].receipt->global_sequence, start_gseq + 4); + + BOOST_REQUIRE_EQUAL((int)atrace[3].action_ordinal, 4); + BOOST_REQUIRE_EQUAL((int)atrace[3].creator_action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[3].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[3].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[3].receipt->global_sequence, start_gseq + 8); + + BOOST_REQUIRE_EQUAL((int)atrace[4].action_ordinal, 5); + BOOST_REQUIRE_EQUAL((int)atrace[4].creator_action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[4].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[4].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[4].receipt->global_sequence, start_gseq + 2); + + BOOST_REQUIRE_EQUAL((int)atrace[5].action_ordinal, 6); + BOOST_REQUIRE_EQUAL((int)atrace[5].creator_action_ordinal, 2); + BOOST_REQUIRE_EQUAL((int)atrace[5].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[5].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[5].receipt->global_sequence, start_gseq + 9); + + BOOST_REQUIRE_EQUAL((int)atrace[6].action_ordinal, 7); + BOOST_REQUIRE_EQUAL((int)atrace[6].creator_action_ordinal,2); + BOOST_REQUIRE_EQUAL((int)atrace[6].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[6].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[6].receipt->global_sequence, start_gseq + 3); + + BOOST_REQUIRE_EQUAL((int)atrace[7].action_ordinal, 8); + BOOST_REQUIRE_EQUAL((int)atrace[7].creator_action_ordinal, 5); + BOOST_REQUIRE_EQUAL((int)atrace[7].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[7].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[7].receipt->global_sequence, start_gseq + 10); + + BOOST_REQUIRE_EQUAL((int)atrace[8].action_ordinal, 9); + BOOST_REQUIRE_EQUAL((int)atrace[8].creator_action_ordinal, 3); + BOOST_REQUIRE_EQUAL((int)atrace[8].parent_action_ordinal, 3); + BOOST_REQUIRE_EQUAL(atrace[8].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[8].receipt->global_sequence, start_gseq + 5); + + BOOST_REQUIRE_EQUAL((int)atrace[9].action_ordinal, 10); + BOOST_REQUIRE_EQUAL((int)atrace[9].creator_action_ordinal, 3); + BOOST_REQUIRE_EQUAL((int)atrace[9].parent_action_ordinal, 3); + BOOST_REQUIRE_EQUAL(atrace[9].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[9].receipt->global_sequence, start_gseq + 6); + + BOOST_REQUIRE_EQUAL((int)atrace[10].action_ordinal, 11); + BOOST_REQUIRE_EQUAL((int)atrace[10].creator_action_ordinal, 3); + BOOST_REQUIRE_EQUAL((int)atrace[10].parent_action_ordinal, 3); + BOOST_REQUIRE_EQUAL(atrace[10].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[10].receipt->global_sequence, start_gseq + 7); +} FC_LOG_AND_RETHROW() } + + +/************************************************************************************* ++ * action_ordinal_failtest1 test cases ++ *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest1, TESTER) { try { + + produce_blocks(1); + create_account(N(testapi) ); + set_code( N(testapi), contracts::test_api_wasm() ); + produce_blocks(1); + create_account(N(bob) ); + set_code( N(bob), contracts::test_api_wasm() ); + produce_blocks(1); + create_account(N(charlie) ); + set_code( N(charlie), contracts::test_api_wasm() ); + produce_blocks(1); + create_account(N(david) ); + set_code( N(david), contracts::test_api_wasm() ); + produce_blocks(1); + create_account(N(erin) ); + set_code( N(erin), contracts::test_api_wasm() ); + produce_blocks(1); + + create_account(N(fail1) ); // <- make first action fails in the middle + produce_blocks(1); + + transaction_trace_ptr txn_trace = + CALL_TEST_FUNCTION_SCOPE_EXPECT_FAIL( *this, "test_action", "test_action_ordinal1", + {}, vector{ N(testapi)}); + + BOOST_REQUIRE_EQUAL( validate(), true ); + + BOOST_REQUIRE_EQUAL( txn_trace != nullptr, true); + BOOST_REQUIRE_EQUAL( txn_trace->action_traces.size(), 3); + + auto &atrace = txn_trace->action_traces; + + // fails here after creating one notify action and one inline action + BOOST_REQUIRE_EQUAL((int)atrace[0].action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[0].creator_action_ordinal, 0); + BOOST_REQUIRE_EQUAL((int)atrace[0].parent_action_ordinal, 0); + BOOST_REQUIRE_EQUAL(atrace[0].receipt.valid(), false); + BOOST_REQUIRE_EQUAL(atrace[0].except.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[0].except->code(), 3050003); + + // not executed + BOOST_REQUIRE_EQUAL((int)atrace[1].action_ordinal, 2); + BOOST_REQUIRE_EQUAL((int)atrace[1].creator_action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[1].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[1].receipt.valid(), false); + BOOST_REQUIRE_EQUAL(atrace[1].except.valid(), false); + + // not executed + BOOST_REQUIRE_EQUAL((int)atrace[2].action_ordinal, 3); + BOOST_REQUIRE_EQUAL((int)atrace[2].creator_action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[2].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[2].receipt.valid(), false); + BOOST_REQUIRE_EQUAL(atrace[2].except.valid(), false); + +} FC_LOG_AND_RETHROW() } + +/************************************************************************************* ++ * action_ordinal_failtest2 test cases ++ *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest2, TESTER) { try { + + produce_blocks(1); + create_account(N(testapi) ); + set_code( N(testapi), contracts::test_api_wasm() ); + produce_blocks(1); + create_account(N(bob) ); + set_code( N(bob), contracts::test_api_wasm() ); + produce_blocks(1); + create_account(N(charlie) ); + set_code( N(charlie), contracts::test_api_wasm() ); + produce_blocks(1); + create_account(N(david) ); + set_code( N(david), contracts::test_api_wasm() ); + produce_blocks(1); + create_account(N(erin) ); + set_code( N(erin), contracts::test_api_wasm() ); + produce_blocks(1); + + create_account(N(fail3) ); // <- make action 3 fails in the middle + produce_blocks(1); + + transaction_trace_ptr txn_trace = + CALL_TEST_FUNCTION_SCOPE_EXPECT_FAIL( *this, "test_action", "test_action_ordinal1", + {}, vector{ N(testapi)}); + + BOOST_REQUIRE_EQUAL( validate(), true ); + + BOOST_REQUIRE_EQUAL( txn_trace != nullptr, true); + BOOST_REQUIRE_EQUAL( txn_trace->action_traces.size(), 8); + + auto &atrace = txn_trace->action_traces; + + // executed + BOOST_REQUIRE_EQUAL((int)atrace[0].action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[0].creator_action_ordinal, 0); + BOOST_REQUIRE_EQUAL((int)atrace[0].parent_action_ordinal, 0); + BOOST_REQUIRE_EQUAL(atrace[0].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[0].except.valid(), false); + int start_gseq = atrace[0].receipt->global_sequence; + + // executed + BOOST_REQUIRE_EQUAL((int)atrace[1].action_ordinal,2); + BOOST_REQUIRE_EQUAL((int)atrace[1].creator_action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[1].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[1].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[1].receipt->global_sequence, start_gseq + 1); + + // not executed + BOOST_REQUIRE_EQUAL((int)atrace[2].action_ordinal, 3); + BOOST_REQUIRE_EQUAL((int)atrace[2].creator_action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[2].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[2].receipt.valid(), false); + BOOST_REQUIRE_EQUAL(atrace[2].except.valid(), false); + + // not executed + BOOST_REQUIRE_EQUAL((int)atrace[3].action_ordinal, 4); + BOOST_REQUIRE_EQUAL((int)atrace[3].creator_action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[3].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[3].receipt.valid(), false); + BOOST_REQUIRE_EQUAL(atrace[3].except.valid(), false); + + // hey exception is here + BOOST_REQUIRE_EQUAL((int)atrace[4].action_ordinal, 5); + BOOST_REQUIRE_EQUAL((int)atrace[4].creator_action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[4].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[4].receipt.valid(), false); + BOOST_REQUIRE_EQUAL(atrace[4].except.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[4].except->code(), 3050003); + + // not executed + BOOST_REQUIRE_EQUAL((int)atrace[5].action_ordinal, 6); + BOOST_REQUIRE_EQUAL((int)atrace[5].creator_action_ordinal, 2); + BOOST_REQUIRE_EQUAL((int)atrace[5].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[5].receipt.valid(), false); + BOOST_REQUIRE_EQUAL(atrace[5].except.valid(), false); + + // not executed + BOOST_REQUIRE_EQUAL((int)atrace[6].action_ordinal, 7); + BOOST_REQUIRE_EQUAL((int)atrace[6].creator_action_ordinal,2); + BOOST_REQUIRE_EQUAL((int)atrace[6].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[6].receipt.valid(), false); + BOOST_REQUIRE_EQUAL(atrace[6].except.valid(), false); + + // not executed + BOOST_REQUIRE_EQUAL((int)atrace[7].action_ordinal, 8); + BOOST_REQUIRE_EQUAL((int)atrace[7].creator_action_ordinal, 5); + BOOST_REQUIRE_EQUAL((int)atrace[7].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[7].receipt.valid(), false); + BOOST_REQUIRE_EQUAL(atrace[7].except.valid(), false); + +} FC_LOG_AND_RETHROW() } + +/************************************************************************************* ++ * action_ordinal_failtest3 test cases ++ *************************************************************************************/ +BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest3, TESTER) { try { + + produce_blocks(1); + create_account(N(testapi) ); + set_code( N(testapi), contracts::test_api_wasm() ); + produce_blocks(1); + create_account(N(bob) ); + set_code( N(bob), contracts::test_api_wasm() ); + produce_blocks(1); + create_account(N(charlie) ); + set_code( N(charlie), contracts::test_api_wasm() ); + produce_blocks(1); + create_account(N(david) ); + set_code( N(david), contracts::test_api_wasm() ); + produce_blocks(1); + create_account(N(erin) ); + set_code( N(erin), contracts::test_api_wasm() ); + produce_blocks(1); + + create_account(N(failnine) ); // <- make action 9 fails in the middle + produce_blocks(1); + + transaction_trace_ptr txn_trace = + CALL_TEST_FUNCTION_SCOPE_EXPECT_FAIL( *this, "test_action", "test_action_ordinal1", + {}, vector{ N(testapi)}); + + for (auto &at : txn_trace->action_traces) { + std::cout << "\n\n"; + std::cout << FC_LOG_MESSAGE(info, "${t}", ("t", at)).get_message(); + } + + BOOST_REQUIRE_EQUAL( validate(), true ); + + BOOST_REQUIRE_EQUAL( txn_trace != nullptr, true); + BOOST_REQUIRE_EQUAL( txn_trace->action_traces.size(), 11); + + auto &atrace = txn_trace->action_traces; + + // executed + BOOST_REQUIRE_EQUAL((int)atrace[0].action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[0].creator_action_ordinal, 0); + BOOST_REQUIRE_EQUAL((int)atrace[0].parent_action_ordinal, 0); + BOOST_REQUIRE_EQUAL(atrace[0].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[0].except.valid(), false); + int start_gseq = atrace[0].receipt->global_sequence; + + // executed + BOOST_REQUIRE_EQUAL((int)atrace[1].action_ordinal,2); + BOOST_REQUIRE_EQUAL((int)atrace[1].creator_action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[1].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[1].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[1].receipt->global_sequence, start_gseq + 1); + + // executed + BOOST_REQUIRE_EQUAL((int)atrace[2].action_ordinal, 3); + BOOST_REQUIRE_EQUAL((int)atrace[2].creator_action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[2].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[2].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[2].receipt->global_sequence, start_gseq + 4); + + // fails here + BOOST_REQUIRE_EQUAL((int)atrace[3].action_ordinal, 4); + BOOST_REQUIRE_EQUAL((int)atrace[3].creator_action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[3].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[3].receipt.valid(), false); + BOOST_REQUIRE_EQUAL(atrace[3].except.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[3].except->code(), 3050003); + + // executed + BOOST_REQUIRE_EQUAL((int)atrace[4].action_ordinal, 5); + BOOST_REQUIRE_EQUAL((int)atrace[4].creator_action_ordinal, 1); + BOOST_REQUIRE_EQUAL((int)atrace[4].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[4].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[4].receipt->global_sequence, start_gseq + 2); + + // not executed + BOOST_REQUIRE_EQUAL((int)atrace[5].action_ordinal, 6); + BOOST_REQUIRE_EQUAL((int)atrace[5].creator_action_ordinal, 2); + BOOST_REQUIRE_EQUAL((int)atrace[5].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[5].receipt.valid(), false); + BOOST_REQUIRE_EQUAL(atrace[5].except.valid(), false); + + // executed + BOOST_REQUIRE_EQUAL((int)atrace[6].action_ordinal, 7); + BOOST_REQUIRE_EQUAL((int)atrace[6].creator_action_ordinal,2); + BOOST_REQUIRE_EQUAL((int)atrace[6].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[6].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[6].receipt->global_sequence, start_gseq + 3); + + // not executed + BOOST_REQUIRE_EQUAL((int)atrace[7].action_ordinal, 8); + BOOST_REQUIRE_EQUAL((int)atrace[7].creator_action_ordinal, 5); + BOOST_REQUIRE_EQUAL((int)atrace[7].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[7].receipt.valid(), false); + BOOST_REQUIRE_EQUAL(atrace[7].except.valid(), false); + + // executed + BOOST_REQUIRE_EQUAL((int)atrace[8].action_ordinal, 9); + BOOST_REQUIRE_EQUAL((int)atrace[8].creator_action_ordinal, 3); + BOOST_REQUIRE_EQUAL((int)atrace[8].parent_action_ordinal, 3); + BOOST_REQUIRE_EQUAL(atrace[8].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[8].receipt->global_sequence, start_gseq + 5); + + // executed + BOOST_REQUIRE_EQUAL((int)atrace[9].action_ordinal, 10); + BOOST_REQUIRE_EQUAL((int)atrace[9].creator_action_ordinal, 3); + BOOST_REQUIRE_EQUAL((int)atrace[9].parent_action_ordinal, 3); + BOOST_REQUIRE_EQUAL(atrace[9].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[9].receipt->global_sequence, start_gseq + 6); + + // executed + BOOST_REQUIRE_EQUAL((int)atrace[10].action_ordinal, 11); + BOOST_REQUIRE_EQUAL((int)atrace[10].creator_action_ordinal, 3); + BOOST_REQUIRE_EQUAL((int)atrace[10].parent_action_ordinal, 3); + BOOST_REQUIRE_EQUAL(atrace[10].receipt.valid(), true); + BOOST_REQUIRE_EQUAL(atrace[10].receipt->global_sequence, start_gseq + 7); + +} FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() diff --git a/unittests/test-contracts/test_api/test_action.cpp b/unittests/test-contracts/test_api/test_action.cpp index bf1985ae3ef..6424d05f513 100644 --- a/unittests/test-contracts/test_api/test_action.cpp +++ b/unittests/test-contracts/test_api/test_action.cpp @@ -259,3 +259,86 @@ void test_action::test_ram_billing_in_notify( uint64_t receiver, uint64_t code, db_store_i64( "notifytest"_n.value, "notifytest"_n.value, payer, "notifytest"_n.value, &to_notify, sizeof(to_notify) ); } } + +void test_action::test_action_ordinal1(uint64_t receiver, uint64_t code, uint64_t action) { + uint64_t _self = receiver; + if (receiver == "testapi"_n.value) { + print("exec 1"); + eosio::require_recipient( "bob"_n ); //-> exec2 + + eosio::action act1({name(_self), "active"_n}, name(_self), + name(WASM_TEST_ACTION("test_action", "test_action_ordinal2")), + std::tuple<>()); + act1.send(); // -> exec 5, 6, 7 + + if (is_account("fail1"_n)) { + eosio_assert(false, "fail at point 1"); + } + + eosio::action act2({name(_self), "active"_n}, name(_self), + name(WASM_TEST_ACTION("test_action", "test_action_ordinal3")), + std::tuple<>()); + act2.send(); // -> exec 9 + + eosio::require_recipient( "charlie"_n ); // -> exec 3 + + } else if (receiver == "bob"_n.value) { + print("exec 2"); + eosio::action act1({name(_self), "active"_n}, name(_self), + name(WASM_TEST_ACTION("test_action", "test_action_ordinal_foo")), + std::tuple<>()); + act1.send(); + + eosio::require_recipient( "david"_n ); // -> exec 4 + } else if (receiver == "charlie"_n.value) { + print("exec 3"); + eosio::action act1({name(_self), "active"_n}, name(_self), + name(WASM_TEST_ACTION("test_action", "test_action_ordinal_bar")), + std::tuple<>()); // exec 11 + act1.send(); + + if (is_account("fail3"_n)) { + eosio_assert(false, "fail at point 3"); + } + + } else if (receiver == "david"_n.value) { + print("exec 4"); + } else { + eosio_assert(false, "assert failed at test_action::test_action_ordinal1"); + } +} +void test_action::test_action_ordinal2(uint64_t receiver, uint64_t code, uint64_t action) { + uint64_t _self = receiver; + if (receiver == "testapi"_n.value) { + print("exec 5"); + eosio::require_recipient( "david"_n ); + eosio::require_recipient( "erin"_n ); + + eosio::action act1({name(_self), "active"_n}, name(_self), + name(WASM_TEST_ACTION("test_action", "test_action_ordinal4")), + std::tuple<>()); + act1.send(); // -> exec 8 + } else if (receiver == "david"_n.value) { + print("exec 6"); + } else if (receiver == "erin"_n.value) { + print("exec 7"); + } else { + eosio_assert(false, "assert failed at test_action::test_action_ordinal2"); + } +} +void test_action::test_action_ordinal4(uint64_t receiver, uint64_t code, uint64_t action) { + print("exec 8"); +} +void test_action::test_action_ordinal3(uint64_t receiver, uint64_t code, uint64_t action) { + print("exec 9"); + + if (is_account("failnine"_n)) { + eosio_assert(false, "fail at point 9"); + } +} +void test_action::test_action_ordinal_foo(uint64_t receiver, uint64_t code, uint64_t action) { + print("exec 10"); +} +void test_action::test_action_ordinal_bar(uint64_t receiver, uint64_t code, uint64_t action) { + print("exec 11"); +} diff --git a/unittests/test-contracts/test_api/test_api.cpp b/unittests/test-contracts/test_api/test_api.cpp index 598990dc1a7..241d4762a00 100644 --- a/unittests/test-contracts/test_api/test_api.cpp +++ b/unittests/test-contracts/test_api/test_api.cpp @@ -64,6 +64,12 @@ extern "C" { WASM_TEST_HANDLER ( test_action, test_publication_time ); WASM_TEST_HANDLER ( test_action, test_assert_code ); WASM_TEST_HANDLER_EX( test_action, test_ram_billing_in_notify ); + WASM_TEST_HANDLER_EX( test_action, test_action_ordinal1 ); + WASM_TEST_HANDLER_EX( test_action, test_action_ordinal2 ); + WASM_TEST_HANDLER_EX( test_action, test_action_ordinal3 ); + WASM_TEST_HANDLER_EX( test_action, test_action_ordinal4 ); + WASM_TEST_HANDLER_EX( test_action, test_action_ordinal_foo ); + WASM_TEST_HANDLER_EX( test_action, test_action_ordinal_bar ); // test named actions // We enforce action name matches action data type name, so name mangling will not work for these tests. diff --git a/unittests/test-contracts/test_api/test_api.hpp b/unittests/test-contracts/test_api/test_api.hpp index 865923fcfb2..bbcf9965352 100644 --- a/unittests/test-contracts/test_api/test_api.hpp +++ b/unittests/test-contracts/test_api/test_api.hpp @@ -69,6 +69,12 @@ struct test_action { static void test_publication_time(); static void test_assert_code(); static void test_ram_billing_in_notify(uint64_t receiver, uint64_t code, uint64_t action); + static void test_action_ordinal1(uint64_t receiver, uint64_t code, uint64_t action); + static void test_action_ordinal2(uint64_t receiver, uint64_t code, uint64_t action); + static void test_action_ordinal3(uint64_t receiver, uint64_t code, uint64_t action); + static void test_action_ordinal4(uint64_t receiver, uint64_t code, uint64_t action); + static void test_action_ordinal_foo(uint64_t receiver, uint64_t code, uint64_t action); + static void test_action_ordinal_bar(uint64_t receiver, uint64_t code, uint64_t action); }; struct test_db { diff --git a/unittests/test-contracts/test_api/test_api.wasm b/unittests/test-contracts/test_api/test_api.wasm index c7a7601ace1eba1bdb1353776620bcfc72ebbbaa..dc9a7125d82e9770c5724b76b05ef779bc39d1ba 100755 GIT binary patch delta 20458 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 From da3d8d18b4099f84494b46282ef6d2d68e255a52 Mon Sep 17 00:00:00 2001 From: Kayan Date: Thu, 4 Apr 2019 16:00:07 +0800 Subject: [PATCH 08/15] remove debug print --- unittests/api_tests.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index 367b2c6bcf5..a83b1a94b9a 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -2377,11 +2377,6 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest3, TESTER) { try { CALL_TEST_FUNCTION_SCOPE_EXPECT_FAIL( *this, "test_action", "test_action_ordinal1", {}, vector{ N(testapi)}); - for (auto &at : txn_trace->action_traces) { - std::cout << "\n\n"; - std::cout << FC_LOG_MESSAGE(info, "${t}", ("t", at)).get_message(); - } - BOOST_REQUIRE_EQUAL( validate(), true ); BOOST_REQUIRE_EQUAL( txn_trace != nullptr, true); From bff645372d7a3250668d7fbfd857a08c02beaeda Mon Sep 17 00:00:00 2001 From: Kayan Date: Thu, 4 Apr 2019 17:58:08 +0800 Subject: [PATCH 09/15] fix test case --- unittests/api_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index a83b1a94b9a..1290b02c33a 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -735,7 +735,7 @@ BOOST_FIXTURE_TEST_CASE(cf_action_tests, TESTER) { try { auto ttrace = CALL_TEST_FUNCTION( *this, "test_transaction", "send_cf_action", {} ); BOOST_REQUIRE_EQUAL(ttrace->action_traces.size(), 2); - BOOST_CHECK_EQUAL((int)(ttrace->action_traces[1].creator_action_ordinal), 0); + BOOST_CHECK_EQUAL((int)(ttrace->action_traces[1].creator_action_ordinal), 1); BOOST_CHECK_EQUAL(ttrace->action_traces[1].receiver, account_name("dummy")); BOOST_CHECK_EQUAL(ttrace->action_traces[1].act.account, account_name("dummy")); BOOST_CHECK_EQUAL(ttrace->action_traces[1].act.name, account_name("event1")); From 3be5baaa031925407806c5903272acc25e7b582e Mon Sep 17 00:00:00 2001 From: Andrianto Lie Date: Thu, 4 Apr 2019 18:19:28 +0800 Subject: [PATCH 10/15] Add additional API for push transaction backward compatibility --- plugins/chain_api_plugin/chain_api_plugin.cpp | 4 +- plugins/chain_plugin/chain_plugin.cpp | 101 +++++++++++++++--- .../eosio/chain_plugin/chain_plugin.hpp | 8 ++ 3 files changed, 98 insertions(+), 15 deletions(-) diff --git a/plugins/chain_api_plugin/chain_api_plugin.cpp b/plugins/chain_api_plugin/chain_api_plugin.cpp index 6433ce02ba0..bab3f5ce266 100644 --- a/plugins/chain_api_plugin/chain_api_plugin.cpp +++ b/plugins/chain_api_plugin/chain_api_plugin.cpp @@ -106,7 +106,9 @@ void chain_api_plugin::plugin_startup() { CHAIN_RO_CALL(get_transaction_id, 200), CHAIN_RW_CALL_ASYNC(push_block, chain_apis::read_write::push_block_results, 202), CHAIN_RW_CALL_ASYNC(push_transaction, chain_apis::read_write::push_transaction_results, 202), - CHAIN_RW_CALL_ASYNC(push_transactions, chain_apis::read_write::push_transactions_results, 202) + CHAIN_RW_CALL_ASYNC(push_transactions, chain_apis::read_write::push_transactions_results, 202), + CHAIN_RW_CALL_ASYNC(send_transaction, chain_apis::read_write::send_transaction_results, 202), + CHAIN_RW_CALL_ASYNC(send_transactions, chain_apis::read_write::send_transactions_results, 202) }); } diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index aca508db776..b586e6c2b6e 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1880,7 +1880,80 @@ void read_write::push_block(read_write::push_block_params&& params, next_functio } CATCH_AND_CALL(next); } +static fc::variant convert_tx_trace_to_tree_struct(const fc::variant& tx_result) { + fc::mutable_variant_object tx_trace_mvo(tx_result); + + std::multimap act_trace_multimap; + for (auto& act_trace: tx_trace_mvo["action_traces"].get_array()) { + act_trace_multimap.emplace(act_trace["parent_action_ordinal"].as(), act_trace); + } + std::function(fc::unsigned_int)> convert_act_trace_to_tree_struct = [&](fc::unsigned_int parent_action_ordinal) { + vector reordered_act_traces; + auto range = act_trace_multimap.equal_range(parent_action_ordinal); + for (auto it = range.first; it != range.second; it++) { + fc::mutable_variant_object act_trace_mvo(it->second); + act_trace_mvo["inline_traces"] = convert_act_trace_to_tree_struct(it->second["action_ordinal"].as()); + act_trace_mvo.erase("action_ordinal"); + act_trace_mvo.erase("creator_action_ordinal"); + act_trace_mvo.erase("parent_action_ordinal"); + act_trace_mvo.erase("receiver"); + reordered_act_traces.push_back(act_trace_mvo); + } + std::sort(reordered_act_traces.begin(), reordered_act_traces.end(), [](auto& a, auto&b) { + return a["receipt"]["global_sequence"] < b["receipt"]["global_sequence"]; + }); + return reordered_act_traces; + }; + tx_trace_mvo["action_traces"] = convert_act_trace_to_tree_struct(0); + + tx_trace_mvo.erase("account_ram_delta"); + + return tx_trace_mvo; +} + void read_write::push_transaction(const read_write::push_transaction_params& params, next_function next) { + try { + auto wrapped_next = [=](const fc::static_variant& result) { + try { + if (result.contains()) { + next(result); + } else { + read_write::send_transaction_results modified_result = std::move(result.get()); + modified_result.processed = convert_tx_trace_to_tree_struct(modified_result.processed); + next(modified_result); + } + } CATCH_AND_CALL(next); + }; + send_transaction(params, wrapped_next); + } catch ( boost::interprocess::bad_alloc& ) { + chain_plugin::handle_db_exhaustion(); + } CATCH_AND_CALL(next); +} + +void read_write::push_transactions(const read_write::push_transactions_params& params, next_function next) { + try { + auto wrapped_next = [=](const fc::static_variant& result) { + try { + if (result.contains()) { + next(result); + } else { + read_write::send_transactions_results modified_results = std::move(result.get()); + for (auto& modified_result: modified_results) { + if (modified_result.transaction_id != transaction_id_type()) { + modified_result.processed = convert_tx_trace_to_tree_struct(modified_result.processed); + } + } + next(modified_results); + } + } CATCH_AND_CALL(next); + }; + send_transactions(params, wrapped_next); + } catch ( boost::interprocess::bad_alloc& ) { + chain_plugin::handle_db_exhaustion(); + } CATCH_AND_CALL(next); +} + +void read_write::send_transaction(const read_write::send_transaction_params& params, next_function next) { try { auto pretty_input = std::make_shared(); @@ -1906,50 +1979,50 @@ void read_write::push_transaction(const read_write::push_transaction_params& par } const chain::transaction_id_type& id = trx_trace_ptr->id; - next(read_write::push_transaction_results{id, output}); + next(read_write::send_transaction_results{id, output}); } CATCH_AND_CALL(next); } }); - - } catch ( boost::interprocess::bad_alloc& ) { chain_plugin::handle_db_exhaustion(); } CATCH_AND_CALL(next); } -static void push_recurse(read_write* rw, int index, const std::shared_ptr& params, const std::shared_ptr& results, const next_function& next) { - auto wrapped_next = [=](const fc::static_variant& result) { +static void send_recurse(read_write* rw, int index, const std::shared_ptr& params, const std::shared_ptr& results, const next_function& next) { + auto wrapped_next = [=](const fc::static_variant& result) { if (result.contains()) { const auto& e = result.get(); - results->emplace_back( read_write::push_transaction_results{ transaction_id_type(), fc::mutable_variant_object( "error", e->to_detail_string() ) } ); + results->emplace_back( read_write::send_transaction_results{ transaction_id_type(), fc::mutable_variant_object( "error", e->to_detail_string() ) } ); } else { - const auto& r = result.get(); + const auto& r = result.get(); results->emplace_back( r ); } size_t next_index = index + 1; if (next_index < params->size()) { - push_recurse(rw, next_index, params, results, next ); + send_recurse(rw, next_index, params, results, next ); } else { next(*results); } }; - rw->push_transaction(params->at(index), wrapped_next); + rw->send_transaction(params->at(index), wrapped_next); } -void read_write::push_transactions(const read_write::push_transactions_params& params, next_function next) { +void read_write::send_transactions(const read_write::send_transactions_params& params, next_function next) { try { EOS_ASSERT( params.size() <= 1000, too_many_tx_at_once, "Attempt to push too many transactions at once" ); - auto params_copy = std::make_shared(params.begin(), params.end()); - auto result = std::make_shared(); + auto params_copy = std::make_shared(params.begin(), params.end()); + auto result = std::make_shared(); result->reserve(params.size()); - push_recurse(this, 0, params_copy, result, next); - + send_recurse(this, 0, params_copy, result, next); + } catch ( boost::interprocess::bad_alloc& ) { + chain_plugin::handle_db_exhaustion(); } CATCH_AND_CALL(next); } + read_only::get_abi_results read_only::get_abi( const get_abi_params& params )const { get_abi_results result; result.account_name = params.account_name; diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 733bc32825f..80353e5be46 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -600,6 +600,14 @@ class read_write { using push_transactions_results = vector; void push_transactions(const push_transactions_params& params, chain::plugin_interface::next_function next); + using send_transaction_params = push_transaction_params; + using send_transaction_results = push_transaction_results; + void send_transaction(const send_transaction_params& params, chain::plugin_interface::next_function next); + + using send_transactions_params = vector; + using send_transactions_results = vector; + void send_transactions(const send_transactions_params& params, chain::plugin_interface::next_function next); + friend resolver_factory; }; From c622c8d0188f3b583cdf542a0fb21b257e55ba69 Mon Sep 17 00:00:00 2001 From: Kayan Date: Mon, 8 Apr 2019 16:14:02 +0800 Subject: [PATCH 11/15] improve test cases --- .../testing/include/eosio/testing/tester.hpp | 2 +- libraries/testing/tester.cpp | 4 +- unittests/api_tests.cpp | 150 +++++++++++++----- .../test-contracts/test_api/test_action.cpp | 12 +- 4 files changed, 118 insertions(+), 50 deletions(-) diff --git a/libraries/testing/include/eosio/testing/tester.hpp b/libraries/testing/include/eosio/testing/tester.hpp index 154ebef7410..0bccbfe8034 100644 --- a/libraries/testing/include/eosio/testing/tester.hpp +++ b/libraries/testing/include/eosio/testing/tester.hpp @@ -126,7 +126,7 @@ namespace eosio { namespace testing { vector get_scheduled_transactions() const; transaction_trace_ptr push_transaction( packed_transaction& trx, fc::time_point deadline = fc::time_point::maximum(), uint32_t billed_cpu_time_us = DEFAULT_BILLED_CPU_TIME_US ); - transaction_trace_ptr push_transaction( signed_transaction& trx, fc::time_point deadline = fc::time_point::maximum(), uint32_t billed_cpu_time_us = DEFAULT_BILLED_CPU_TIME_US ); + transaction_trace_ptr push_transaction( signed_transaction& trx, fc::time_point deadline = fc::time_point::maximum(), uint32_t billed_cpu_time_us = DEFAULT_BILLED_CPU_TIME_US, bool no_throw = false ); action_result push_action(action&& cert_act, uint64_t authorizer); // TODO/QUESTION: Is this needed? transaction_trace_ptr push_action( const account_name& code, diff --git a/libraries/testing/tester.cpp b/libraries/testing/tester.cpp index 93dc4b5f61f..82f91b90576 100644 --- a/libraries/testing/tester.cpp +++ b/libraries/testing/tester.cpp @@ -454,7 +454,8 @@ namespace eosio { namespace testing { transaction_trace_ptr base_tester::push_transaction( signed_transaction& trx, fc::time_point deadline, - uint32_t billed_cpu_time_us + uint32_t billed_cpu_time_us, + bool no_throw ) { try { if( !control->is_building_block() ) @@ -466,6 +467,7 @@ namespace eosio { namespace testing { } auto r = control->push_transaction( std::make_shared(trx,c), deadline, billed_cpu_time_us ); + if (no_throw) return r; if( r->except_ptr ) std::rethrow_exception( r->except_ptr ); if( r->except) throw *r->except; return r; diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index 1290b02c33a..c94c9fdb2b3 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -218,7 +218,7 @@ transaction_trace_ptr CallAction(TESTER& test, T ac, const vector& } template -transaction_trace_ptr CallFunction(TESTER& test, T ac, const vector& data, const vector& scope = {N(testapi)}) { +transaction_trace_ptr CallFunction(TESTER& test, T ac, const vector& data, const vector& scope = {N(testapi)}, bool no_throw = false) { { signed_transaction trx; @@ -238,41 +238,11 @@ transaction_trace_ptr CallFunction(TESTER& test, T ac, const vector& data, flat_set keys; trx.get_signature_keys(test.control->get_chain_id(), fc::time_point::maximum(), keys); - auto res = test.push_transaction(trx); - BOOST_CHECK_EQUAL(res->receipt->status, transaction_receipt::executed); - test.produce_block(); - return res; - } -} - -template -transaction_trace_ptr CallFunctionExpectFail(TESTER& test, T ac, const vector& data, const vector& scope = {N(testapi)}) { - { - signed_transaction trx; - - auto pl = vector{{scope[0], config::active_name}}; - if (scope.size() > 1) - for (unsigned int i=1; i < scope.size(); i++) - pl.push_back({scope[i], config::active_name}); - - action act(pl, ac); - act.data = data; - act.authorization = {{N(testapi), config::active_name}}; - trx.actions.push_back(act); - - test.set_transaction_headers(trx, test.DEFAULT_EXPIRATION_DELTA); - auto sigs = trx.sign(test.get_private_key(scope[0], "active"), test.control->get_chain_id()); - - flat_set keys; - trx.get_signature_keys(test.control->get_chain_id(), fc::time_point::maximum(), keys); - - auto c = packed_transaction::none; - - if( fc::raw::pack_size(trx) > 1000 ) { - c = packed_transaction::zlib; + auto res = test.push_transaction(trx, fc::time_point::maximum(), TESTER::DEFAULT_BILLED_CPU_TIME_US, no_throw); + if (!no_throw) { + BOOST_CHECK_EQUAL(res->receipt->status, transaction_receipt::executed); } - - auto res = test.control->push_transaction(std::make_shared(trx,c), fc::time_point::maximum(), 100); + test.produce_block(); return res; } } @@ -280,7 +250,7 @@ transaction_trace_ptr CallFunctionExpectFail(TESTER& test, T ac, const vector{}, DATA) #define CALL_TEST_FUNCTION_SYSTEM(_TESTER, CLS, MTH, DATA) CallFunction(_TESTER, test_chain_action{}, DATA, {config::system_account_name} ) #define CALL_TEST_FUNCTION_SCOPE(_TESTER, CLS, MTH, DATA, ACCOUNT) CallFunction(_TESTER, test_api_action{}, DATA, ACCOUNT) -#define CALL_TEST_FUNCTION_SCOPE_EXPECT_FAIL(_TESTER, CLS, MTH, DATA, ACCOUNT) CallFunctionExpectFail(_TESTER, test_api_action{}, DATA, ACCOUNT) +#define CALL_TEST_FUNCTION_NO_THROW(_TESTER, CLS, MTH, DATA) CallFunction(_TESTER, test_api_action{}, DATA, {N(testapi)}, true) #define CALL_TEST_FUNCTION_AND_CHECK_EXCEPTION(_TESTER, CLS, MTH, DATA, EXC, EXC_MESSAGE) \ BOOST_CHECK_EXCEPTION( \ CALL_TEST_FUNCTION( _TESTER, CLS, MTH, DATA), \ @@ -2127,66 +2097,99 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_test, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[0].action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[0].creator_action_ordinal, 0); BOOST_REQUIRE_EQUAL((int)atrace[0].parent_action_ordinal, 0); + BOOST_REQUIRE_EQUAL(atrace[0].receiver.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[0].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[0].act.name.value, TEST_METHOD("test_action", "test_action_ordinal1")); BOOST_REQUIRE_EQUAL(atrace[0].receipt.valid(), true); int start_gseq = atrace[0].receipt->global_sequence; BOOST_REQUIRE_EQUAL((int)atrace[1].action_ordinal,2); BOOST_REQUIRE_EQUAL((int)atrace[1].creator_action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[1].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[1].receiver.value, N(bob)); + BOOST_REQUIRE_EQUAL(atrace[1].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[1].act.name.value, TEST_METHOD("test_action", "test_action_ordinal1")); BOOST_REQUIRE_EQUAL(atrace[1].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[1].receipt->global_sequence, start_gseq + 1); BOOST_REQUIRE_EQUAL((int)atrace[2].action_ordinal, 3); BOOST_REQUIRE_EQUAL((int)atrace[2].creator_action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[2].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[2].receiver.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[2].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[2].act.name.value, TEST_METHOD("test_action", "test_action_ordinal2")); BOOST_REQUIRE_EQUAL(atrace[2].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[2].receipt->global_sequence, start_gseq + 4); BOOST_REQUIRE_EQUAL((int)atrace[3].action_ordinal, 4); BOOST_REQUIRE_EQUAL((int)atrace[3].creator_action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[3].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[3].receiver.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[3].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[3].act.name.value, TEST_METHOD("test_action", "test_action_ordinal3")); BOOST_REQUIRE_EQUAL(atrace[3].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[3].receipt->global_sequence, start_gseq + 8); BOOST_REQUIRE_EQUAL((int)atrace[4].action_ordinal, 5); BOOST_REQUIRE_EQUAL((int)atrace[4].creator_action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[4].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[4].receiver.value, N(charlie)); + BOOST_REQUIRE_EQUAL(atrace[4].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[4].act.name.value, TEST_METHOD("test_action", "test_action_ordinal1")); BOOST_REQUIRE_EQUAL(atrace[4].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[4].receipt->global_sequence, start_gseq + 2); BOOST_REQUIRE_EQUAL((int)atrace[5].action_ordinal, 6); BOOST_REQUIRE_EQUAL((int)atrace[5].creator_action_ordinal, 2); BOOST_REQUIRE_EQUAL((int)atrace[5].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[5].receiver.value, N(bob)); + BOOST_REQUIRE_EQUAL(atrace[5].act.account.value, N(bob)); + BOOST_REQUIRE_EQUAL(atrace[5].act.name.value, TEST_METHOD("test_action", "test_action_ordinal_foo")); BOOST_REQUIRE_EQUAL(atrace[5].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[5].receipt->global_sequence, start_gseq + 9); BOOST_REQUIRE_EQUAL((int)atrace[6].action_ordinal, 7); BOOST_REQUIRE_EQUAL((int)atrace[6].creator_action_ordinal,2); BOOST_REQUIRE_EQUAL((int)atrace[6].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[6].receiver.value, N(david)); + BOOST_REQUIRE_EQUAL(atrace[6].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[6].act.name.value, TEST_METHOD("test_action", "test_action_ordinal1")); BOOST_REQUIRE_EQUAL(atrace[6].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[6].receipt->global_sequence, start_gseq + 3); BOOST_REQUIRE_EQUAL((int)atrace[7].action_ordinal, 8); BOOST_REQUIRE_EQUAL((int)atrace[7].creator_action_ordinal, 5); BOOST_REQUIRE_EQUAL((int)atrace[7].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[7].receiver.value, N(charlie)); + BOOST_REQUIRE_EQUAL(atrace[7].act.account.value, N(charlie)); + BOOST_REQUIRE_EQUAL(atrace[7].act.name.value, TEST_METHOD("test_action", "test_action_ordinal_bar")); BOOST_REQUIRE_EQUAL(atrace[7].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[7].receipt->global_sequence, start_gseq + 10); BOOST_REQUIRE_EQUAL((int)atrace[8].action_ordinal, 9); BOOST_REQUIRE_EQUAL((int)atrace[8].creator_action_ordinal, 3); BOOST_REQUIRE_EQUAL((int)atrace[8].parent_action_ordinal, 3); + BOOST_REQUIRE_EQUAL(atrace[8].receiver.value, N(david)); + BOOST_REQUIRE_EQUAL(atrace[8].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[8].act.name.value, TEST_METHOD("test_action", "test_action_ordinal2")); BOOST_REQUIRE_EQUAL(atrace[8].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[8].receipt->global_sequence, start_gseq + 5); BOOST_REQUIRE_EQUAL((int)atrace[9].action_ordinal, 10); BOOST_REQUIRE_EQUAL((int)atrace[9].creator_action_ordinal, 3); BOOST_REQUIRE_EQUAL((int)atrace[9].parent_action_ordinal, 3); + BOOST_REQUIRE_EQUAL(atrace[9].receiver.value, N(erin)); + BOOST_REQUIRE_EQUAL(atrace[9].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[9].act.name.value, TEST_METHOD("test_action", "test_action_ordinal2")); BOOST_REQUIRE_EQUAL(atrace[9].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[9].receipt->global_sequence, start_gseq + 6); BOOST_REQUIRE_EQUAL((int)atrace[10].action_ordinal, 11); BOOST_REQUIRE_EQUAL((int)atrace[10].creator_action_ordinal, 3); BOOST_REQUIRE_EQUAL((int)atrace[10].parent_action_ordinal, 3); + BOOST_REQUIRE_EQUAL(atrace[10].receiver.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[10].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[10].act.name.value, TEST_METHOD("test_action", "test_action_ordinal4")); BOOST_REQUIRE_EQUAL(atrace[10].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[10].receipt->global_sequence, start_gseq + 7); } FC_LOG_AND_RETHROW() } @@ -2218,8 +2221,7 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest1, TESTER) { try { produce_blocks(1); transaction_trace_ptr txn_trace = - CALL_TEST_FUNCTION_SCOPE_EXPECT_FAIL( *this, "test_action", "test_action_ordinal1", - {}, vector{ N(testapi)}); + CALL_TEST_FUNCTION_NO_THROW( *this, "test_action", "test_action_ordinal1", {}); BOOST_REQUIRE_EQUAL( validate(), true ); @@ -2232,6 +2234,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest1, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[0].action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[0].creator_action_ordinal, 0); BOOST_REQUIRE_EQUAL((int)atrace[0].parent_action_ordinal, 0); + BOOST_REQUIRE_EQUAL(atrace[0].receiver.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[0].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[0].act.name.value, TEST_METHOD("test_action", "test_action_ordinal1")); BOOST_REQUIRE_EQUAL(atrace[0].receipt.valid(), false); BOOST_REQUIRE_EQUAL(atrace[0].except.valid(), true); BOOST_REQUIRE_EQUAL(atrace[0].except->code(), 3050003); @@ -2240,6 +2245,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest1, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[1].action_ordinal, 2); BOOST_REQUIRE_EQUAL((int)atrace[1].creator_action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[1].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[1].receiver.value, N(bob)); + BOOST_REQUIRE_EQUAL(atrace[1].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[1].act.name.value, TEST_METHOD("test_action", "test_action_ordinal1")); BOOST_REQUIRE_EQUAL(atrace[1].receipt.valid(), false); BOOST_REQUIRE_EQUAL(atrace[1].except.valid(), false); @@ -2247,6 +2255,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest1, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[2].action_ordinal, 3); BOOST_REQUIRE_EQUAL((int)atrace[2].creator_action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[2].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[2].receiver.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[2].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[2].act.name.value, TEST_METHOD("test_action", "test_action_ordinal2")); BOOST_REQUIRE_EQUAL(atrace[2].receipt.valid(), false); BOOST_REQUIRE_EQUAL(atrace[2].except.valid(), false); @@ -2278,8 +2289,7 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest2, TESTER) { try { produce_blocks(1); transaction_trace_ptr txn_trace = - CALL_TEST_FUNCTION_SCOPE_EXPECT_FAIL( *this, "test_action", "test_action_ordinal1", - {}, vector{ N(testapi)}); + CALL_TEST_FUNCTION_NO_THROW( *this, "test_action", "test_action_ordinal1", {}); BOOST_REQUIRE_EQUAL( validate(), true ); @@ -2292,6 +2302,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest2, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[0].action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[0].creator_action_ordinal, 0); BOOST_REQUIRE_EQUAL((int)atrace[0].parent_action_ordinal, 0); + BOOST_REQUIRE_EQUAL(atrace[0].receiver.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[0].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[0].act.name.value, TEST_METHOD("test_action", "test_action_ordinal1")); BOOST_REQUIRE_EQUAL(atrace[0].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[0].except.valid(), false); int start_gseq = atrace[0].receipt->global_sequence; @@ -2300,6 +2313,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest2, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[1].action_ordinal,2); BOOST_REQUIRE_EQUAL((int)atrace[1].creator_action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[1].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[1].receiver.value, N(bob)); + BOOST_REQUIRE_EQUAL(atrace[1].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[1].act.name.value, TEST_METHOD("test_action", "test_action_ordinal1")); BOOST_REQUIRE_EQUAL(atrace[1].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[1].receipt->global_sequence, start_gseq + 1); @@ -2307,6 +2323,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest2, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[2].action_ordinal, 3); BOOST_REQUIRE_EQUAL((int)atrace[2].creator_action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[2].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[2].receiver.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[2].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[2].act.name.value, TEST_METHOD("test_action", "test_action_ordinal2")); BOOST_REQUIRE_EQUAL(atrace[2].receipt.valid(), false); BOOST_REQUIRE_EQUAL(atrace[2].except.valid(), false); @@ -2314,6 +2333,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest2, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[3].action_ordinal, 4); BOOST_REQUIRE_EQUAL((int)atrace[3].creator_action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[3].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[3].receiver.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[3].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[3].act.name.value, TEST_METHOD("test_action", "test_action_ordinal3")); BOOST_REQUIRE_EQUAL(atrace[3].receipt.valid(), false); BOOST_REQUIRE_EQUAL(atrace[3].except.valid(), false); @@ -2321,6 +2343,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest2, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[4].action_ordinal, 5); BOOST_REQUIRE_EQUAL((int)atrace[4].creator_action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[4].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[4].receiver.value, N(charlie)); + BOOST_REQUIRE_EQUAL(atrace[4].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[4].act.name.value, TEST_METHOD("test_action", "test_action_ordinal1")); BOOST_REQUIRE_EQUAL(atrace[4].receipt.valid(), false); BOOST_REQUIRE_EQUAL(atrace[4].except.valid(), true); BOOST_REQUIRE_EQUAL(atrace[4].except->code(), 3050003); @@ -2329,6 +2354,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest2, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[5].action_ordinal, 6); BOOST_REQUIRE_EQUAL((int)atrace[5].creator_action_ordinal, 2); BOOST_REQUIRE_EQUAL((int)atrace[5].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[5].receiver.value, N(bob)); + BOOST_REQUIRE_EQUAL(atrace[5].act.account.value, N(bob)); + BOOST_REQUIRE_EQUAL(atrace[5].act.name.value, TEST_METHOD("test_action", "test_action_ordinal_foo")); BOOST_REQUIRE_EQUAL(atrace[5].receipt.valid(), false); BOOST_REQUIRE_EQUAL(atrace[5].except.valid(), false); @@ -2336,6 +2364,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest2, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[6].action_ordinal, 7); BOOST_REQUIRE_EQUAL((int)atrace[6].creator_action_ordinal,2); BOOST_REQUIRE_EQUAL((int)atrace[6].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[6].receiver.value, N(david)); + BOOST_REQUIRE_EQUAL(atrace[6].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[6].act.name.value, TEST_METHOD("test_action", "test_action_ordinal1")); BOOST_REQUIRE_EQUAL(atrace[6].receipt.valid(), false); BOOST_REQUIRE_EQUAL(atrace[6].except.valid(), false); @@ -2343,6 +2374,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest2, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[7].action_ordinal, 8); BOOST_REQUIRE_EQUAL((int)atrace[7].creator_action_ordinal, 5); BOOST_REQUIRE_EQUAL((int)atrace[7].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[7].receiver.value, N(charlie)); + BOOST_REQUIRE_EQUAL(atrace[7].act.account.value, N(charlie)); + BOOST_REQUIRE_EQUAL(atrace[7].act.name.value, TEST_METHOD("test_action", "test_action_ordinal_bar")); BOOST_REQUIRE_EQUAL(atrace[7].receipt.valid(), false); BOOST_REQUIRE_EQUAL(atrace[7].except.valid(), false); @@ -2374,8 +2408,7 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest3, TESTER) { try { produce_blocks(1); transaction_trace_ptr txn_trace = - CALL_TEST_FUNCTION_SCOPE_EXPECT_FAIL( *this, "test_action", "test_action_ordinal1", - {}, vector{ N(testapi)}); + CALL_TEST_FUNCTION_NO_THROW( *this, "test_action", "test_action_ordinal1", {}); BOOST_REQUIRE_EQUAL( validate(), true ); @@ -2388,6 +2421,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest3, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[0].action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[0].creator_action_ordinal, 0); BOOST_REQUIRE_EQUAL((int)atrace[0].parent_action_ordinal, 0); + BOOST_REQUIRE_EQUAL(atrace[0].receiver.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[0].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[0].act.name.value, TEST_METHOD("test_action", "test_action_ordinal1")); BOOST_REQUIRE_EQUAL(atrace[0].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[0].except.valid(), false); int start_gseq = atrace[0].receipt->global_sequence; @@ -2396,6 +2432,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest3, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[1].action_ordinal,2); BOOST_REQUIRE_EQUAL((int)atrace[1].creator_action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[1].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[1].receiver.value, N(bob)); + BOOST_REQUIRE_EQUAL(atrace[1].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[1].act.name.value, TEST_METHOD("test_action", "test_action_ordinal1")); BOOST_REQUIRE_EQUAL(atrace[1].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[1].receipt->global_sequence, start_gseq + 1); @@ -2403,6 +2442,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest3, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[2].action_ordinal, 3); BOOST_REQUIRE_EQUAL((int)atrace[2].creator_action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[2].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[2].receiver.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[2].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[2].act.name.value, TEST_METHOD("test_action", "test_action_ordinal2")); BOOST_REQUIRE_EQUAL(atrace[2].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[2].receipt->global_sequence, start_gseq + 4); @@ -2410,6 +2452,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest3, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[3].action_ordinal, 4); BOOST_REQUIRE_EQUAL((int)atrace[3].creator_action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[3].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[3].receiver.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[3].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[3].act.name.value, TEST_METHOD("test_action", "test_action_ordinal3")); BOOST_REQUIRE_EQUAL(atrace[3].receipt.valid(), false); BOOST_REQUIRE_EQUAL(atrace[3].except.valid(), true); BOOST_REQUIRE_EQUAL(atrace[3].except->code(), 3050003); @@ -2418,6 +2463,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest3, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[4].action_ordinal, 5); BOOST_REQUIRE_EQUAL((int)atrace[4].creator_action_ordinal, 1); BOOST_REQUIRE_EQUAL((int)atrace[4].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[4].receiver.value, N(charlie)); + BOOST_REQUIRE_EQUAL(atrace[4].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[4].act.name.value, TEST_METHOD("test_action", "test_action_ordinal1")); BOOST_REQUIRE_EQUAL(atrace[4].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[4].receipt->global_sequence, start_gseq + 2); @@ -2425,6 +2473,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest3, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[5].action_ordinal, 6); BOOST_REQUIRE_EQUAL((int)atrace[5].creator_action_ordinal, 2); BOOST_REQUIRE_EQUAL((int)atrace[5].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[5].receiver.value, N(bob)); + BOOST_REQUIRE_EQUAL(atrace[5].act.account.value, N(bob)); + BOOST_REQUIRE_EQUAL(atrace[5].act.name.value, TEST_METHOD("test_action", "test_action_ordinal_foo")); BOOST_REQUIRE_EQUAL(atrace[5].receipt.valid(), false); BOOST_REQUIRE_EQUAL(atrace[5].except.valid(), false); @@ -2432,6 +2483,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest3, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[6].action_ordinal, 7); BOOST_REQUIRE_EQUAL((int)atrace[6].creator_action_ordinal,2); BOOST_REQUIRE_EQUAL((int)atrace[6].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[6].receiver.value, N(david)); + BOOST_REQUIRE_EQUAL(atrace[6].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[6].act.name.value, TEST_METHOD("test_action", "test_action_ordinal1")); BOOST_REQUIRE_EQUAL(atrace[6].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[6].receipt->global_sequence, start_gseq + 3); @@ -2439,6 +2493,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest3, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[7].action_ordinal, 8); BOOST_REQUIRE_EQUAL((int)atrace[7].creator_action_ordinal, 5); BOOST_REQUIRE_EQUAL((int)atrace[7].parent_action_ordinal, 1); + BOOST_REQUIRE_EQUAL(atrace[7].receiver.value, N(charlie)); + BOOST_REQUIRE_EQUAL(atrace[7].act.account.value, N(charlie)); + BOOST_REQUIRE_EQUAL(atrace[7].act.name.value, TEST_METHOD("test_action", "test_action_ordinal_bar")); BOOST_REQUIRE_EQUAL(atrace[7].receipt.valid(), false); BOOST_REQUIRE_EQUAL(atrace[7].except.valid(), false); @@ -2446,6 +2503,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest3, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[8].action_ordinal, 9); BOOST_REQUIRE_EQUAL((int)atrace[8].creator_action_ordinal, 3); BOOST_REQUIRE_EQUAL((int)atrace[8].parent_action_ordinal, 3); + BOOST_REQUIRE_EQUAL(atrace[8].receiver.value, N(david)); + BOOST_REQUIRE_EQUAL(atrace[8].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[8].act.name.value, TEST_METHOD("test_action", "test_action_ordinal2")); BOOST_REQUIRE_EQUAL(atrace[8].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[8].receipt->global_sequence, start_gseq + 5); @@ -2453,6 +2513,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest3, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[9].action_ordinal, 10); BOOST_REQUIRE_EQUAL((int)atrace[9].creator_action_ordinal, 3); BOOST_REQUIRE_EQUAL((int)atrace[9].parent_action_ordinal, 3); + BOOST_REQUIRE_EQUAL(atrace[9].receiver.value, N(erin)); + BOOST_REQUIRE_EQUAL(atrace[9].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[9].act.name.value, TEST_METHOD("test_action", "test_action_ordinal2")); BOOST_REQUIRE_EQUAL(atrace[9].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[9].receipt->global_sequence, start_gseq + 6); @@ -2460,6 +2523,9 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest3, TESTER) { try { BOOST_REQUIRE_EQUAL((int)atrace[10].action_ordinal, 11); BOOST_REQUIRE_EQUAL((int)atrace[10].creator_action_ordinal, 3); BOOST_REQUIRE_EQUAL((int)atrace[10].parent_action_ordinal, 3); + BOOST_REQUIRE_EQUAL(atrace[10].receiver.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[10].act.account.value, N(testapi)); + BOOST_REQUIRE_EQUAL(atrace[10].act.name.value, TEST_METHOD("test_action", "test_action_ordinal4")); BOOST_REQUIRE_EQUAL(atrace[10].receipt.valid(), true); BOOST_REQUIRE_EQUAL(atrace[10].receipt->global_sequence, start_gseq + 7); diff --git a/unittests/test-contracts/test_api/test_action.cpp b/unittests/test-contracts/test_api/test_action.cpp index 6424d05f513..e371f336cc0 100644 --- a/unittests/test-contracts/test_api/test_action.cpp +++ b/unittests/test-contracts/test_api/test_action.cpp @@ -264,12 +264,12 @@ void test_action::test_action_ordinal1(uint64_t receiver, uint64_t code, uint64_ uint64_t _self = receiver; if (receiver == "testapi"_n.value) { print("exec 1"); - eosio::require_recipient( "bob"_n ); //-> exec2 + eosio::require_recipient( "bob"_n ); //-> exec 2 which would then cause execution of 4, 10 eosio::action act1({name(_self), "active"_n}, name(_self), name(WASM_TEST_ACTION("test_action", "test_action_ordinal2")), std::tuple<>()); - act1.send(); // -> exec 5, 6, 7 + act1.send(); // -> exec 5 which would then cause execution of 6, 7, 8 if (is_account("fail1"_n)) { eosio_assert(false, "fail at point 1"); @@ -280,14 +280,14 @@ void test_action::test_action_ordinal1(uint64_t receiver, uint64_t code, uint64_ std::tuple<>()); act2.send(); // -> exec 9 - eosio::require_recipient( "charlie"_n ); // -> exec 3 + eosio::require_recipient( "charlie"_n ); // -> exec 3 which would then cause execution of 11 } else if (receiver == "bob"_n.value) { print("exec 2"); eosio::action act1({name(_self), "active"_n}, name(_self), name(WASM_TEST_ACTION("test_action", "test_action_ordinal_foo")), std::tuple<>()); - act1.send(); + act1.send(); // -> exec 10 eosio::require_recipient( "david"_n ); // -> exec 4 } else if (receiver == "charlie"_n.value) { @@ -311,8 +311,8 @@ void test_action::test_action_ordinal2(uint64_t receiver, uint64_t code, uint64_ uint64_t _self = receiver; if (receiver == "testapi"_n.value) { print("exec 5"); - eosio::require_recipient( "david"_n ); - eosio::require_recipient( "erin"_n ); + eosio::require_recipient( "david"_n ); // -> exec 6 + eosio::require_recipient( "erin"_n ); // -> exec 7 eosio::action act1({name(_self), "active"_n}, name(_self), name(WASM_TEST_ACTION("test_action", "test_action_ordinal4")), From dcde1978c3f431c112fb2713a9e0a9af0e0c449b Mon Sep 17 00:00:00 2001 From: Andrianto Lie Date: Mon, 8 Apr 2019 17:57:45 +0800 Subject: [PATCH 12/15] Refactor push_transaction API to use direct approach instead of wrapping next --- plugins/chain_api_plugin/chain_api_plugin.cpp | 3 +- plugins/chain_plugin/chain_plugin.cpp | 169 +++++++++--------- .../eosio/chain_plugin/chain_plugin.hpp | 4 - 3 files changed, 85 insertions(+), 91 deletions(-) diff --git a/plugins/chain_api_plugin/chain_api_plugin.cpp b/plugins/chain_api_plugin/chain_api_plugin.cpp index bab3f5ce266..3a591eedbb5 100644 --- a/plugins/chain_api_plugin/chain_api_plugin.cpp +++ b/plugins/chain_api_plugin/chain_api_plugin.cpp @@ -107,8 +107,7 @@ void chain_api_plugin::plugin_startup() { CHAIN_RW_CALL_ASYNC(push_block, chain_apis::read_write::push_block_results, 202), CHAIN_RW_CALL_ASYNC(push_transaction, chain_apis::read_write::push_transaction_results, 202), CHAIN_RW_CALL_ASYNC(push_transactions, chain_apis::read_write::push_transactions_results, 202), - CHAIN_RW_CALL_ASYNC(send_transaction, chain_apis::read_write::send_transaction_results, 202), - CHAIN_RW_CALL_ASYNC(send_transactions, chain_apis::read_write::send_transactions_results, 202) + CHAIN_RW_CALL_ASYNC(send_transaction, chain_apis::read_write::send_transaction_results, 202) }); } diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index b586e6c2b6e..de6a9f77e8f 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1880,81 +1880,7 @@ void read_write::push_block(read_write::push_block_params&& params, next_functio } CATCH_AND_CALL(next); } -static fc::variant convert_tx_trace_to_tree_struct(const fc::variant& tx_result) { - fc::mutable_variant_object tx_trace_mvo(tx_result); - - std::multimap act_trace_multimap; - for (auto& act_trace: tx_trace_mvo["action_traces"].get_array()) { - act_trace_multimap.emplace(act_trace["parent_action_ordinal"].as(), act_trace); - } - std::function(fc::unsigned_int)> convert_act_trace_to_tree_struct = [&](fc::unsigned_int parent_action_ordinal) { - vector reordered_act_traces; - auto range = act_trace_multimap.equal_range(parent_action_ordinal); - for (auto it = range.first; it != range.second; it++) { - fc::mutable_variant_object act_trace_mvo(it->second); - act_trace_mvo["inline_traces"] = convert_act_trace_to_tree_struct(it->second["action_ordinal"].as()); - act_trace_mvo.erase("action_ordinal"); - act_trace_mvo.erase("creator_action_ordinal"); - act_trace_mvo.erase("parent_action_ordinal"); - act_trace_mvo.erase("receiver"); - reordered_act_traces.push_back(act_trace_mvo); - } - std::sort(reordered_act_traces.begin(), reordered_act_traces.end(), [](auto& a, auto&b) { - return a["receipt"]["global_sequence"] < b["receipt"]["global_sequence"]; - }); - return reordered_act_traces; - }; - tx_trace_mvo["action_traces"] = convert_act_trace_to_tree_struct(0); - - tx_trace_mvo.erase("account_ram_delta"); - - return tx_trace_mvo; -} - void read_write::push_transaction(const read_write::push_transaction_params& params, next_function next) { - try { - auto wrapped_next = [=](const fc::static_variant& result) { - try { - if (result.contains()) { - next(result); - } else { - read_write::send_transaction_results modified_result = std::move(result.get()); - modified_result.processed = convert_tx_trace_to_tree_struct(modified_result.processed); - next(modified_result); - } - } CATCH_AND_CALL(next); - }; - send_transaction(params, wrapped_next); - } catch ( boost::interprocess::bad_alloc& ) { - chain_plugin::handle_db_exhaustion(); - } CATCH_AND_CALL(next); -} - -void read_write::push_transactions(const read_write::push_transactions_params& params, next_function next) { - try { - auto wrapped_next = [=](const fc::static_variant& result) { - try { - if (result.contains()) { - next(result); - } else { - read_write::send_transactions_results modified_results = std::move(result.get()); - for (auto& modified_result: modified_results) { - if (modified_result.transaction_id != transaction_id_type()) { - modified_result.processed = convert_tx_trace_to_tree_struct(modified_result.processed); - } - } - next(modified_results); - } - } CATCH_AND_CALL(next); - }; - send_transactions(params, wrapped_next); - } catch ( boost::interprocess::bad_alloc& ) { - chain_plugin::handle_db_exhaustion(); - } CATCH_AND_CALL(next); -} - -void read_write::send_transaction(const read_write::send_transaction_params& params, next_function next) { - try { auto pretty_input = std::make_shared(); auto resolver = make_resolver(this, abi_serializer_max_time); @@ -1974,12 +1900,51 @@ void read_write::send_transaction(const read_write::send_transaction_params& par fc::variant output; try { output = db.to_variant_with_abi( *trx_trace_ptr, abi_serializer_max_time ); + + // Create map of (parent_action_ordinal, global_sequence) with action trace + std::map< std::pair, fc::mutable_variant_object > act_traces_map; + for (auto& act_trace: output["action_traces"].get_array()) { + if (act_trace["receipt"].is_null() && act_trace["except"].is_null()) continue; + auto parent_action_ordinal = act_trace["parent_action_ordinal"].as().value; + auto global_sequence = act_trace["receipt"].is_null() ? + std::numeric_limits::max() : + act_trace["receipt"]["global_sequence"].as(); + act_traces_map.emplace( std::make_pair( parent_action_ordinal, global_sequence ), act_trace ); + } + + std::function(uint32_t)> convert_act_trace_to_tree_struct = [&](uint32_t parent_action_ordinal) { + vector restructured_act_traces; + auto it = act_traces_map.lower_bound( std::make_pair(parent_action_ordinal, 0) ); + for (; it != act_traces_map.end(); it++) { + if (it->first.first != parent_action_ordinal) break; + auto& act_trace_mvo = it->second; + + auto action_ordinal = act_trace_mvo["action_ordinal"].as().value; + act_trace_mvo["inline_traces"] = convert_act_trace_to_tree_struct(action_ordinal); + if (act_trace_mvo["receipt"].is_null()) { + act_trace_mvo["receipt"] = fc::mutable_variant_object()("abi_sequence", 0) + ("act_digest", digest_type::hash(trx_trace_ptr->action_traces[action_ordinal-1].act)) + ("auth_sequence", flat_map()) + ("code_sequence", 0) + ("global_sequence", 0) + ("receiver", act_trace_mvo["receiver"]) + ("recv_sequence", 0); + } + restructured_act_traces.push_back( std::move(act_trace_mvo) ); + } + return restructured_act_traces; + }; + + fc::mutable_variant_object output_mvo(output); + output_mvo["action_traces"] = convert_act_trace_to_tree_struct(0); + + output = output_mvo; } catch( chain::abi_exception& ) { output = *trx_trace_ptr; } const chain::transaction_id_type& id = trx_trace_ptr->id; - next(read_write::send_transaction_results{id, output}); + next(read_write::push_transaction_results{id, output}); } CATCH_AND_CALL(next); } }); @@ -1988,40 +1953,74 @@ void read_write::send_transaction(const read_write::send_transaction_params& par } CATCH_AND_CALL(next); } -static void send_recurse(read_write* rw, int index, const std::shared_ptr& params, const std::shared_ptr& results, const next_function& next) { - auto wrapped_next = [=](const fc::static_variant& result) { +static void push_recurse(read_write* rw, int index, const std::shared_ptr& params, const std::shared_ptr& results, const next_function& next) { + auto wrapped_next = [=](const fc::static_variant& result) { if (result.contains()) { const auto& e = result.get(); - results->emplace_back( read_write::send_transaction_results{ transaction_id_type(), fc::mutable_variant_object( "error", e->to_detail_string() ) } ); + results->emplace_back( read_write::push_transaction_results{ transaction_id_type(), fc::mutable_variant_object( "error", e->to_detail_string() ) } ); } else { - const auto& r = result.get(); + const auto& r = result.get(); results->emplace_back( r ); } size_t next_index = index + 1; if (next_index < params->size()) { - send_recurse(rw, next_index, params, results, next ); + push_recurse(rw, next_index, params, results, next ); } else { next(*results); } }; - rw->send_transaction(params->at(index), wrapped_next); + rw->push_transaction(params->at(index), wrapped_next); } -void read_write::send_transactions(const read_write::send_transactions_params& params, next_function next) { +void read_write::push_transactions(const read_write::push_transactions_params& params, next_function next) { try { EOS_ASSERT( params.size() <= 1000, too_many_tx_at_once, "Attempt to push too many transactions at once" ); - auto params_copy = std::make_shared(params.begin(), params.end()); - auto result = std::make_shared(); + auto params_copy = std::make_shared(params.begin(), params.end()); + auto result = std::make_shared(); result->reserve(params.size()); - send_recurse(this, 0, params_copy, result, next); + push_recurse(this, 0, params_copy, result, next); } catch ( boost::interprocess::bad_alloc& ) { chain_plugin::handle_db_exhaustion(); } CATCH_AND_CALL(next); } +void read_write::send_transaction(const read_write::send_transaction_params& params, next_function next) { + + try { + auto pretty_input = std::make_shared(); + auto resolver = make_resolver(this, abi_serializer_max_time); + transaction_metadata_ptr ptrx; + try { + abi_serializer::from_variant(params, *pretty_input, resolver, abi_serializer_max_time); + ptrx = std::make_shared( pretty_input ); + } EOS_RETHROW_EXCEPTIONS(chain::packed_transaction_type_exception, "Invalid packed transaction") + + app().get_method()(ptrx, true, [this, next](const fc::static_variant& result) -> void{ + if (result.contains()) { + next(result.get()); + } else { + auto trx_trace_ptr = result.get(); + + try { + fc::variant output; + try { + output = db.to_variant_with_abi( *trx_trace_ptr, abi_serializer_max_time ); + } catch( chain::abi_exception& ) { + output = *trx_trace_ptr; + } + + const chain::transaction_id_type& id = trx_trace_ptr->id; + next(read_write::send_transaction_results{id, output}); + } CATCH_AND_CALL(next); + } + }); + } catch ( boost::interprocess::bad_alloc& ) { + chain_plugin::handle_db_exhaustion(); + } CATCH_AND_CALL(next); +} read_only::get_abi_results read_only::get_abi( const get_abi_params& params )const { get_abi_results result; diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 80353e5be46..6c85c354481 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -604,10 +604,6 @@ class read_write { using send_transaction_results = push_transaction_results; void send_transaction(const send_transaction_params& params, chain::plugin_interface::next_function next); - using send_transactions_params = vector; - using send_transactions_results = vector; - void send_transactions(const send_transactions_params& params, chain::plugin_interface::next_function next); - friend resolver_factory; }; From 9a12ae17b6522ded72b373daa600485f8dd053f9 Mon Sep 17 00:00:00 2001 From: arhag Date: Mon, 8 Apr 2019 15:04:12 -0400 Subject: [PATCH 13/15] small changes to implementation of read_write::push_transaction --- plugins/chain_plugin/chain_plugin.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index de6a9f77e8f..e367d0b85d2 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1903,20 +1903,20 @@ void read_write::push_transaction(const read_write::push_transaction_params& par // Create map of (parent_action_ordinal, global_sequence) with action trace std::map< std::pair, fc::mutable_variant_object > act_traces_map; - for (auto& act_trace: output["action_traces"].get_array()) { + for( const auto& act_trace : output["action_traces"].get_array() ) { if (act_trace["receipt"].is_null() && act_trace["except"].is_null()) continue; auto parent_action_ordinal = act_trace["parent_action_ordinal"].as().value; auto global_sequence = act_trace["receipt"].is_null() ? std::numeric_limits::max() : act_trace["receipt"]["global_sequence"].as(); - act_traces_map.emplace( std::make_pair( parent_action_ordinal, global_sequence ), act_trace ); + act_traces_map.emplace( std::make_pair( parent_action_ordinal, global_sequence ), + act_trace.get_object() ); } std::function(uint32_t)> convert_act_trace_to_tree_struct = [&](uint32_t parent_action_ordinal) { vector restructured_act_traces; auto it = act_traces_map.lower_bound( std::make_pair(parent_action_ordinal, 0) ); - for (; it != act_traces_map.end(); it++) { - if (it->first.first != parent_action_ordinal) break; + for( ; it != act_traces_map.end() && it->first.first == parent_action_ordinal; ++it ) { auto& act_trace_mvo = it->second; auto action_ordinal = act_trace_mvo["action_ordinal"].as().value; From 164a8dd6b1d439d9519c674869e8164d262a4234 Mon Sep 17 00:00:00 2001 From: arhag Date: Mon, 8 Apr 2019 19:18:36 -0400 Subject: [PATCH 14/15] remove trailing comma from action_trace_v0 ABI of state_history_plugin --- plugins/state_history_plugin/state_history_plugin_abi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/state_history_plugin/state_history_plugin_abi.cpp b/plugins/state_history_plugin/state_history_plugin_abi.cpp index 95affaf57c2..b35882a7b83 100644 --- a/plugins/state_history_plugin/state_history_plugin_abi.cpp +++ b/plugins/state_history_plugin/state_history_plugin_abi.cpp @@ -103,7 +103,7 @@ extern const char* const state_history_plugin_abi = R"({ { "name": "elapsed", "type": "int64" }, { "name": "console", "type": "string" }, { "name": "account_ram_deltas", "type": "account_delta[]" }, - { "name": "except", "type": "string?" }, + { "name": "except", "type": "string?" } ] }, { From 36dbc01fe8ed49ad1149946b47c1990de3f86407 Mon Sep 17 00:00:00 2001 From: arhag Date: Tue, 9 Apr 2019 18:25:52 -0400 Subject: [PATCH 15/15] address review comments on #7044 --- libraries/chain/controller.cpp | 2 +- .../chain/include/eosio/chain/apply_context.hpp | 4 ++-- libraries/chain/include/eosio/chain/trace.hpp | 1 - .../include/eosio/chain/transaction_context.hpp | 14 +++++++------- libraries/chain/transaction_context.cpp | 14 ++++++++++---- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index a32a4ce1b2c..14fffa061b5 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -966,7 +966,7 @@ struct controller_impl { try { trx_context.init_for_implicit_trx(); trx_context.published = gtrx.published; - trx_context.execute_action( trx_context.schedule_action( etrx.actions.back(), gtrx.sender ) ); + trx_context.execute_action( trx_context.schedule_action( etrx.actions.back(), gtrx.sender, false, 0, 0 ), 0 ); trx_context.finalize(); // Automatically rounds up network and CPU usage in trace and bills payers if successful auto restore = make_block_restore_point(); diff --git a/libraries/chain/include/eosio/chain/apply_context.hpp b/libraries/chain/include/eosio/chain/apply_context.hpp index 805bb74e485..d1eac6495dd 100644 --- a/libraries/chain/include/eosio/chain/apply_context.hpp +++ b/libraries/chain/include/eosio/chain/apply_context.hpp @@ -466,8 +466,8 @@ class apply_context { bool cancel_deferred_transaction( const uint128_t& sender_id ) { return cancel_deferred_transaction(sender_id, receiver); } protected: - uint32_t schedule_action( uint32_t ordinal_of_action_to_schedule, account_name receiver, bool context_free = false ); - uint32_t schedule_action( action&& act_to_schedule, account_name receiver, bool context_free = false ); + uint32_t schedule_action( uint32_t ordinal_of_action_to_schedule, account_name receiver, bool context_free ); + uint32_t schedule_action( action&& act_to_schedule, account_name receiver, bool context_free ); /// Authorization methods: diff --git a/libraries/chain/include/eosio/chain/trace.hpp b/libraries/chain/include/eosio/chain/trace.hpp index 67e7f62a7ee..5331bef1563 100644 --- a/libraries/chain/include/eosio/chain/trace.hpp +++ b/libraries/chain/include/eosio/chain/trace.hpp @@ -28,7 +28,6 @@ namespace eosio { namespace chain { uint32_t action_ordinal, uint32_t creator_action_ordinal, uint32_t parent_action_ordinal ); action_trace( const transaction_trace& trace, action&& act, account_name receiver, bool context_free, uint32_t action_ordinal, uint32_t creator_action_ordinal, uint32_t parent_action_ordinal ); - //action_trace( const action_receipt& r ):receipt(r){} action_trace(){} fc::unsigned_int action_ordinal; diff --git a/libraries/chain/include/eosio/chain/transaction_context.hpp b/libraries/chain/include/eosio/chain/transaction_context.hpp index 636b3a87c82..bbfe53810f6 100644 --- a/libraries/chain/include/eosio/chain/transaction_context.hpp +++ b/libraries/chain/include/eosio/chain/transaction_context.hpp @@ -68,18 +68,18 @@ namespace eosio { namespace chain { const action_trace& get_action_trace( uint32_t action_ordinal )const; /** invalidates any action_trace references returned by get_action_trace */ - uint32_t schedule_action( const action& act, account_name receiver, bool context_free = false, - uint32_t creator_action_ordinal = 0, uint32_t parent_action_ordinal = 0 ); + uint32_t schedule_action( const action& act, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, uint32_t parent_action_ordinal ); /** invalidates any action_trace references returned by get_action_trace */ - uint32_t schedule_action( action&& act, account_name receiver, bool context_free = false, - uint32_t creator_action_ordinal = 0, uint32_t parent_action_ordinal = 0 ); + uint32_t schedule_action( action&& act, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, uint32_t parent_action_ordinal ); /** invalidates any action_trace references returned by get_action_trace */ - uint32_t schedule_action( uint32_t action_ordinal, account_name receiver, bool context_free = false, - uint32_t creator_action_ordinal = 0, uint32_t parent_action_ordinal = 0 ); + uint32_t schedule_action( uint32_t action_ordinal, account_name receiver, bool context_free, + uint32_t creator_action_ordinal, uint32_t parent_action_ordinal ); - void execute_action( uint32_t action_ordinal, uint32_t recurse_depth = 0 ); + void execute_action( uint32_t action_ordinal, uint32_t recurse_depth ); void schedule_transaction(); void record_transaction( const transaction_id_type& id, fc::time_point_sec expire ); diff --git a/libraries/chain/transaction_context.cpp b/libraries/chain/transaction_context.cpp index 730658538e7..0cfd87fef8d 100644 --- a/libraries/chain/transaction_context.cpp +++ b/libraries/chain/transaction_context.cpp @@ -333,13 +333,13 @@ namespace bacc = boost::accumulators; if( apply_context_free ) { for( const auto& act : trx.context_free_actions ) { - schedule_action( act, act.account, true ); + schedule_action( act, act.account, true, 0, 0 ); } } if( delay == fc::microseconds() ) { for( const auto& act : trx.actions ) { - schedule_action( act, act.account ); + schedule_action( act, act.account, false, 0, 0 ); } } @@ -574,13 +574,19 @@ namespace bacc = boost::accumulators; action_trace& transaction_context::get_action_trace( uint32_t action_ordinal ) { EOS_ASSERT( 0 < action_ordinal && action_ordinal <= trace->action_traces.size() , - transaction_exception, "invalid action_ordinal" ); + transaction_exception, + "action_ordinal ${ordinal} is outside allowed range [1,${max}]", + ("ordinal", action_ordinal)("max", trace->action_traces.size()) + ); return trace->action_traces[action_ordinal-1]; } const action_trace& transaction_context::get_action_trace( uint32_t action_ordinal )const { EOS_ASSERT( 0 < action_ordinal && action_ordinal <= trace->action_traces.size() , - transaction_exception, "invalid action_ordinal" ); + transaction_exception, + "action_ordinal ${ordinal} is outside allowed range [1,${max}]", + ("ordinal", action_ordinal)("max", trace->action_traces.size()) + ); return trace->action_traces[action_ordinal-1]; }