diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 3825d839d4..a528960790 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1014,8 +1014,8 @@ struct controller_impl { ); } - sha256 calculate_integrity_hash() { - sha256::encoder enc; + fc::sha256 calculate_integrity_hash() { + fc::sha256::encoder enc; auto hash_writer = std::make_shared(enc); add_to_snapshot(hash_writer); hash_writer->finalize(); @@ -2091,7 +2091,7 @@ struct controller_impl { } else { packed_transaction_ptr ptrx( b, &pt ); // alias signed_block_ptr auto fut = transaction_metadata::start_recover_keys( - std::move( ptrx ), thread_pool.get_executor(), chain_id, microseconds::maximum(), transaction_metadata::trx_type::input ); + std::move( ptrx ), thread_pool.get_executor(), chain_id, fc::microseconds::maximum(), transaction_metadata::trx_type::input ); trx_metas.emplace_back( transaction_metadata_ptr{}, std::move( fut ) ); } } @@ -3218,7 +3218,7 @@ block_id_type controller::get_block_id_for_num( uint32_t block_num )const { try return id; } FC_CAPTURE_AND_RETHROW( (block_num) ) } -sha256 controller::calculate_integrity_hash() { try { +fc::sha256 controller::calculate_integrity_hash() { try { return my->calculate_integrity_hash(); } FC_LOG_AND_RETHROW() } diff --git a/libraries/chain/include/eosio/chain/apply_context.hpp b/libraries/chain/include/eosio/chain/apply_context.hpp index 090531bfcb..da6e17cfa6 100644 --- a/libraries/chain/include/eosio/chain/apply_context.hpp +++ b/libraries/chain/include/eosio/chain/apply_context.hpp @@ -14,6 +14,7 @@ namespace chainbase { class database; } namespace eosio { namespace chain { class controller; +class account_metadata_object; class apply_context { private: diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index e0d40bf21c..5960853786 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -6,8 +6,6 @@ #include #include -#include -#include #include #include #include @@ -259,7 +257,7 @@ namespace eosio { namespace chain { // thread-safe block_id_type get_block_id_for_num( uint32_t block_num )const; - sha256 calculate_integrity_hash(); + fc::sha256 calculate_integrity_hash(); void write_snapshot( const snapshot_writer_ptr& snapshot ); bool sender_avoids_whitelist_blacklist_enforcement( account_name sender )const; diff --git a/libraries/chain/transaction_context.cpp b/libraries/chain/transaction_context.cpp index 3ee699c496..8c9e434d8f 100644 --- a/libraries/chain/transaction_context.cpp +++ b/libraries/chain/transaction_context.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -8,16 +9,6 @@ #include #include -#pragma push_macro("N") -#undef N -#include -#include -#include -#include -#include -#include -#pragma pop_macro("N") - #include namespace eosio { namespace chain { @@ -828,7 +819,7 @@ namespace eosio { namespace chain { actors.insert( auth.actor ); } } - EOS_ASSERT( one_auth || is_transient(), tx_no_auths, "transaction must have at least one authorization" ); + EOS_ASSERT( one_auth || is_read_only(), tx_no_auths, "transaction must have at least one authorization" ); if( enforce_actor_whitelist_blacklist ) { control.check_actor_list( actors ); diff --git a/libraries/chain/webassembly/authorization.cpp b/libraries/chain/webassembly/authorization.cpp index 43af5cdce6..8f446591ba 100644 --- a/libraries/chain/webassembly/authorization.cpp +++ b/libraries/chain/webassembly/authorization.cpp @@ -1,6 +1,8 @@ #include #include +#include + namespace eosio { namespace chain { namespace webassembly { void interface::require_auth( account_name account ) const { context.require_authorization( account ); @@ -42,7 +44,7 @@ namespace eosio { namespace chain { namespace webassembly { auto s = fc::raw::pack_size(result); if (s <= packed_result.size()) { - datastream ds(packed_result.data(), s); + fc::datastream ds(packed_result.data(), s); fc::raw::pack(ds, result); } return s; diff --git a/libraries/chain/webassembly/crypto.cpp b/libraries/chain/webassembly/crypto.cpp index 095ee4c1d9..d169123d7a 100644 --- a/libraries/chain/webassembly/crypto.cpp +++ b/libraries/chain/webassembly/crypto.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -25,8 +26,8 @@ namespace eosio { namespace chain { namespace webassembly { legacy_span pub ) const { fc::crypto::signature s; fc::crypto::public_key p; - datastream ds( sig.data(), sig.size() ); - datastream pubds ( pub.data(), pub.size() ); + fc::datastream ds( sig.data(), sig.size() ); + fc::datastream pubds ( pub.data(), pub.size() ); fc::raw::unpack( ds, s ); fc::raw::unpack( pubds, p ); @@ -48,7 +49,7 @@ namespace eosio { namespace chain { namespace webassembly { legacy_span sig, legacy_span pub ) const { fc::crypto::signature s; - datastream ds( sig.data(), sig.size() ); + fc::datastream ds( sig.data(), sig.size() ); fc::raw::unpack(ds, s); EOS_ASSERT(s.which() < context.db.get().num_supported_key_types, unactivated_signature_type, @@ -74,7 +75,7 @@ namespace eosio { namespace chain { namespace webassembly { // this will do one less copy for those keys while maintaining the rules of // [0..33) dest sizes: assert (asserts in fc::raw::pack) // [33..inf) dest sizes: return packed size (always 33) - datastream out_ds( pub.data(), pub.size() ); + fc::datastream out_ds( pub.data(), pub.size() ); fc::raw::pack(out_ds, recovered); return out_ds.tellp(); } diff --git a/libraries/chain/webassembly/permission.cpp b/libraries/chain/webassembly/permission.cpp index c5b521b851..a65ad82fcd 100644 --- a/libraries/chain/webassembly/permission.cpp +++ b/libraries/chain/webassembly/permission.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index 1e8ce2382c..f9a8456745 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -5,6 +6,8 @@ #include #include +#include + #include #include @@ -94,7 +97,7 @@ namespace eosio { namespace chain { namespace webassembly { return s; if ( s <= packed_parameters.size() ) { - datastream ds( packed_parameters.data(), s ); + fc::datastream ds( packed_parameters.data(), s ); fc::raw::pack(ds, version); fc::raw::pack(ds, params); } @@ -102,7 +105,7 @@ namespace eosio { namespace chain { namespace webassembly { } void interface::set_wasm_parameters_packed( span packed_parameters ) { EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "set_wasm_parameters_packed not allowed in a readonly transaction"); - datastream ds( packed_parameters.data(), packed_parameters.size() ); + fc::datastream ds( packed_parameters.data(), packed_parameters.size() ); uint32_t version; chain::wasm_config cfg; fc::raw::unpack(ds, version); @@ -117,7 +120,7 @@ namespace eosio { namespace chain { namespace webassembly { } int64_t interface::set_proposed_producers( legacy_span packed_producer_schedule) { EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "set_proposed_producers not allowed in a readonly transaction"); - datastream ds( packed_producer_schedule.data(), packed_producer_schedule.size() ); + fc::datastream ds( packed_producer_schedule.data(), packed_producer_schedule.size() ); std::vector producers; std::vector old_version; fc::raw::unpack(ds, old_version); @@ -137,7 +140,7 @@ namespace eosio { namespace chain { namespace webassembly { if (packed_producer_format == 0) { return set_proposed_producers(std::move(packed_producer_schedule)); } else if (packed_producer_format == 1) { - datastream ds( packed_producer_schedule.data(), packed_producer_schedule.size() ); + fc::datastream ds( packed_producer_schedule.data(), packed_producer_schedule.size() ); vector producers; fc::raw::unpack(ds, producers); @@ -154,7 +157,7 @@ namespace eosio { namespace chain { namespace webassembly { if( packed_blockchain_parameters.size() == 0 ) return s; if ( s <= packed_blockchain_parameters.size() ) { - datastream ds( packed_blockchain_parameters.data(), s ); + fc::datastream ds( packed_blockchain_parameters.data(), s ); fc::raw::pack(ds, gpo.configuration.v0()); return s; } @@ -163,7 +166,7 @@ namespace eosio { namespace chain { namespace webassembly { void interface::set_blockchain_parameters_packed( legacy_span packed_blockchain_parameters ) { EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "set_blockchain_parameters_packed not allowed in a readonly transaction"); - datastream ds( packed_blockchain_parameters.data(), packed_blockchain_parameters.size() ); + fc::datastream ds( packed_blockchain_parameters.data(), packed_blockchain_parameters.size() ); chain::chain_config_v0 cfg; fc::raw::unpack(ds, cfg); cfg.validate(); @@ -174,7 +177,7 @@ namespace eosio { namespace chain { namespace webassembly { } uint32_t interface::get_parameters_packed( span packed_parameter_ids, span packed_parameters) const{ - datastream ds_ids( packed_parameter_ids.data(), packed_parameter_ids.size() ); + fc::datastream ds_ids( packed_parameter_ids.data(), packed_parameter_ids.size() ); chain::chain_config cfg = context.control.get_global_properties().configuration; std::vector ids; @@ -188,14 +191,14 @@ namespace eosio { namespace chain { namespace webassembly { chain::config_parse_error, "get_parameters_packed: buffer size is smaller than ${size}", ("size", size)); - datastream ds( packed_parameters.data(), size ); + fc::datastream ds( packed_parameters.data(), size ); fc::raw::pack( ds, config_range ); return size; } void interface::set_parameters_packed( span packed_parameters ){ EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "set_parameters_packed not allowed in a readonly transaction"); - datastream ds( packed_parameters.data(), packed_parameters.size() ); + fc::datastream ds( packed_parameters.data(), packed_parameters.size() ); chain::chain_config cfg = context.control.get_global_properties().configuration; config_range config_range(cfg, {context.control}); diff --git a/libraries/chain/webassembly/runtimes/eos-vm.cpp b/libraries/chain/webassembly/runtimes/eos-vm.cpp index b0c81c3c6a..033cf978a3 100644 --- a/libraries/chain/webassembly/runtimes/eos-vm.cpp +++ b/libraries/chain/webassembly/runtimes/eos-vm.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include diff --git a/unittests/delay_tests.cpp b/unittests/delay_tests.cpp index 52a22451e8..5b229e48d2 100644 --- a/unittests/delay_tests.cpp +++ b/unittests/delay_tests.cpp @@ -1901,8 +1901,11 @@ BOOST_AUTO_TEST_CASE( canceldelay_test ) { try { chain.set_transaction_headers(trx); trx.sign(chain.get_private_key("tester"_n, "active"), chain.control->get_chain_id()); + // first push as a dry_run trx + trace = chain.push_transaction(trx, fc::time_point::maximum(), base_tester::DEFAULT_BILLED_CPU_TIME_US, false, transaction_metadata::trx_type::dry_run); + BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); + // now push for real trace = chain.push_transaction(trx); - //wdump((fc::json::to_pretty_string(trace))); BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace->receipt->status); gen_size = chain.control->db().get_index().size(); BOOST_CHECK_EQUAL(2u, gen_size); diff --git a/unittests/dry_run_trx_tests.cpp b/unittests/dry_run_trx_tests.cpp new file mode 100644 index 0000000000..6da0f4e75e --- /dev/null +++ b/unittests/dry_run_trx_tests.cpp @@ -0,0 +1,332 @@ +#include +#include +#include +#include +#include +#include + +using namespace eosio; +using namespace eosio::chain; +using namespace eosio::testing; +using namespace fc; + +using mvo = fc::mutable_variant_object; + +struct dry_run_trx_tester : validating_tester { + dry_run_trx_tester() { + produce_block(); + }; + + void set_up_test_contract() { + create_accounts( {"noauthtable"_n, "alice"_n} ); + set_code( "noauthtable"_n, test_contracts::no_auth_table_wasm() ); + set_abi( "noauthtable"_n, test_contracts::no_auth_table_abi() ); + produce_block(); + + insert_data = abi_ser.variant_to_binary( "insert", mutable_variant_object() + ("user", "alice") ("id", 1) ("age", 10), + abi_serializer::create_yield_function( abi_serializer_max_time ) ); + getage_data = abi_ser.variant_to_binary("getage", mutable_variant_object() + ("user", "alice"), + abi_serializer::create_yield_function( abi_serializer_max_time )); + } + + void send_action(const action& act, bool sign = false) { + signed_transaction trx; + trx.actions.push_back( act ); + set_transaction_headers( trx ); + if (sign) // dry-run can contain signature, but not required + trx.sign(get_private_key(act.authorization.at(0).actor, act.authorization.at(0).permission.to_string()), control->get_chain_id()); + + push_transaction( trx, fc::time_point::maximum(), DEFAULT_BILLED_CPU_TIME_US, false, transaction_metadata::trx_type::dry_run ); + } + + auto send_db_api_transaction(action_name name, bytes data, const vector& auth={{"alice"_n, config::active_name}}, + transaction_metadata::trx_type type=transaction_metadata::trx_type::input, uint32_t delay_sec=0) { + action act; + signed_transaction trx; + + act.account = "noauthtable"_n; + act.name = name; + act.authorization = auth; + act.data = data; + + trx.actions.push_back( act ); + set_transaction_headers( trx ); + trx.delay_sec = delay_sec; + if ( type == transaction_metadata::trx_type::input ) { + trx.sign(get_private_key("alice"_n, "active"), control->get_chain_id()); + } + + return push_transaction( trx, fc::time_point::maximum(), DEFAULT_BILLED_CPU_TIME_US, false, type ); + } + + void insert_a_record() { + auto res = send_db_api_transaction("insert"_n, insert_data); + BOOST_CHECK_EQUAL(res->receipt->status, transaction_receipt::executed); + produce_block(); + } + + abi_serializer abi_ser{ json::from_string(test_contracts::no_auth_table_abi()).as(), abi_serializer::create_yield_function(abi_serializer_max_time )}; + bytes insert_data; + bytes getage_data; +}; + +BOOST_AUTO_TEST_SUITE(dry_run_trx_tests) + +BOOST_FIXTURE_TEST_CASE(require_authorization, dry_run_trx_tester) { try { + produce_blocks( 1 ); + + action act = { + {}, // no authorization provided: vector{{config::system_account_name,config::active_name}}, + newaccount{ + .creator = config::system_account_name, + .name = "alice"_n, + .owner = authority( get_public_key( "alice"_n, "owner" ) ), + .active = authority( get_public_key( "alice"_n, "active" ) ) + } + }; + + // dry-run requires authorization + BOOST_REQUIRE_THROW(send_action(act, false), tx_no_auths); + + // sign trx with no authorization + signed_transaction trx; + trx.actions.push_back( act ); + set_transaction_headers( trx ); + trx.sign(get_private_key("alice"_n, "active"), control->get_chain_id()); + BOOST_REQUIRE_THROW(push_transaction( trx, fc::time_point::maximum(), DEFAULT_BILLED_CPU_TIME_US, false, transaction_metadata::trx_type::dry_run ), tx_no_auths); +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(newaccount_test, dry_run_trx_tester) { try { + produce_blocks( 1 ); + + action act = { + vector{{config::system_account_name,config::active_name}}, + newaccount{ + .creator = config::system_account_name, + .name = "alice"_n, + .owner = authority( get_public_key( "alice"_n, "owner" ) ), + .active = authority( get_public_key( "alice"_n, "active" ) ) + } + }; + + send_action(act, false); // should not throw + send_action(act, false); // should not throw + send_action(act, true); // should not throw + BOOST_CHECK_THROW(control->get_account("alice"_n), fc::exception); // not actually created + produce_blocks( 1 ); + BOOST_CHECK_THROW(control->get_account("alice"_n), fc::exception); // not actually created +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(setcode_test, dry_run_trx_tester) { try { + produce_blocks( 1 ); + + create_accounts( {"setcodetest"_n} ); + + auto wasm = test_contracts::no_auth_table_wasm(); + action act = { + vector{{"setcodetest"_n,config::active_name}}, + setcode{ + .account = "setcodetest"_n, + .vmtype = 0, + .vmversion = 0, + .code = bytes(wasm.begin(), wasm.end()) + } + }; + + send_action(act, false); // should not throw + send_action(act, true); // should not throw + BOOST_TEST(!is_code_cached("setcodetest"_n)); +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(setabi_test, dry_run_trx_tester) { try { + produce_blocks( 1 ); + + create_accounts( {"setabitest"_n} ); + + auto abi = test_contracts::no_auth_table_abi(); + action act = { + vector{{"setabitest"_n,config::active_name}}, + setabi { + .account = "setabitest"_n, .abi = bytes(abi.begin(), abi.end()) + } + }; + + send_action(act, false); // should not throw + send_action(act, true); // should not throw + const auto* accnt = control->db().template find( "setabitest"_n ); + BOOST_REQUIRE(accnt); + BOOST_TEST(accnt->abi.size() == 0); // no abi actually set +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(updateauth_test, dry_run_trx_tester) { try { + produce_blocks( 1 ); + + create_accounts( {"alice"_n} ); + + auto auth = authority( get_public_key( "alice"_n, "test" ) ); + action act = { + vector{{"alice"_n, config::active_name}}, + updateauth { + .account = "alice"_n, .permission = "active"_n, .parent = "owner"_n, .auth = auth + } + }; + + send_action(act, false); // should not throw + send_action(act, true); // should not throw +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(deleteauth_test, dry_run_trx_tester) { try { + produce_blocks( 1 ); + + create_accounts( {"alice"_n} ); + + // update auth + push_action(config::system_account_name, updateauth::get_name(), "alice"_n, fc::mutable_variant_object() + ("account", "alice") + ("permission", "first") + ("parent", "active") + ("auth", authority(get_public_key("alice"_n, "first"))) + ); + + name account = "alice"_n; + name permission = "first"_n; + action act = { + vector{{"alice"_n, config::active_name}}, + deleteauth { account, permission } + }; + + send_action(act, false); // should not throw + send_action(act, true); // should not throw +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(linkauth_test, dry_run_trx_tester) { try { + produce_blocks( 1 ); + + create_account("eosio.token"_n); + set_code("eosio.token"_n, test_contracts::eosio_token_wasm()); + set_abi("eosio.token"_n, test_contracts::eosio_token_abi()); + + create_accounts( {"alice"_n} ); + + // update auth + push_action(config::system_account_name, updateauth::get_name(), "alice"_n, fc::mutable_variant_object() + ("account", "alice") + ("permission", "first") + ("parent", "active") + ("auth", authority(get_public_key("alice"_n, "first"))) + ); + + name account = "alice"_n; + name code = "eosio_token"_n; + name type = "transfer"_n; + name requirement = "first"_n; + action act = { + vector{{"alice"_n, config::active_name}}, + linkauth { account, code, type, requirement } + }; + + send_action(act, false); // should not throw + send_action(act, true); // should not throw +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(unlinkauth_test, dry_run_trx_tester) { try { + produce_blocks( 1 ); + + create_account("eosio.token"_n); + set_code("eosio.token"_n, test_contracts::eosio_token_wasm()); + set_abi("eosio.token"_n, test_contracts::eosio_token_abi()); + + create_accounts( {"alice"_n} ); + + // update auth + push_action(config::system_account_name, updateauth::get_name(), "alice"_n, fc::mutable_variant_object() + ("account", "alice") + ("permission", "first") + ("parent", "active") + ("auth", authority(get_public_key("alice"_n, "first"))) + ); + + // link auth + push_action(config::system_account_name, linkauth::get_name(), "alice"_n, fc::mutable_variant_object() + ("account", "alice") + ("code", "eosio.token") + ("type", "transfer") + ("requirement", "first")); + + name account = "alice"_n; + name code = "eosio_token"_n; + name type = "transfer"_n; + action act = { + vector{{"alice"_n, config::active_name}}, + unlinkauth { account, code, type } + }; + + send_action(act, false); // should not throw + send_action(act, true); // should not throw +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(delay_sec_test, dry_run_trx_tester) { try { + set_up_test_contract(); + + // verify dry-run transaction does not allow non-zero delay_sec. + BOOST_CHECK_THROW(send_db_api_transaction("getage"_n, getage_data, {}, transaction_metadata::trx_type::dry_run, 3), transaction_exception); +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(db_insert_test, dry_run_trx_tester) { try { + set_up_test_contract(); + + // verify DB operation is allowed by dry-run transaction + send_db_api_transaction("insert"_n, insert_data, vector{{"alice"_n, config::active_name}}, transaction_metadata::trx_type::dry_run); + + // verify the dry-run insert was rolled back, use a read-only trx to query + BOOST_CHECK_EXCEPTION(send_db_api_transaction("getage"_n, getage_data, {}, transaction_metadata::trx_type::read_only), fc::exception, + [](const fc::exception& e) { + return expect_assert_message(e, "Record does not exist"); + }); + + insert_a_record(); + + // do a dry-run transaction and verify the return value (age) is the same as inserted + auto res = send_db_api_transaction("getage"_n, getage_data, vector{{"alice"_n, config::active_name}}, transaction_metadata::trx_type::dry_run); + BOOST_CHECK_EQUAL(res->receipt->status, transaction_receipt::executed); + BOOST_CHECK_EQUAL(res->action_traces[0].return_value[0], 10); + BOOST_CHECK_GT(res->net_usage, 0u); + BOOST_CHECK_GT(res->elapsed.count(), 0u); +} FC_LOG_AND_RETHROW() } + +BOOST_FIXTURE_TEST_CASE(sequence_numbers_test, dry_run_trx_tester) { try { + set_up_test_contract(); + + const auto& p = control->get_dynamic_global_properties(); + auto receiver_account = control->db().find("noauthtable"_n); + auto amo = control->db().find("alice"_n); + + // verify sequence numbers in state increment for non-read-only transactions + auto prev_global_action_sequence = p.global_action_sequence; + auto prev_recv_sequence = receiver_account->recv_sequence; + auto prev_auth_sequence = amo->auth_sequence; + + auto res = send_db_api_transaction("insert"_n, insert_data); + BOOST_CHECK_EQUAL(res->receipt->status, transaction_receipt::executed); + + BOOST_CHECK_EQUAL( prev_global_action_sequence + 1, p.global_action_sequence ); + BOOST_CHECK_EQUAL( prev_recv_sequence + 1, receiver_account->recv_sequence ); + BOOST_CHECK_EQUAL( prev_auth_sequence + 1, amo->auth_sequence ); + + produce_block(); + + // verify sequence numbers in state do not change for dry-run transactions + prev_global_action_sequence = p.global_action_sequence; + prev_recv_sequence = receiver_account->recv_sequence; + prev_auth_sequence = amo->auth_sequence; + + send_db_api_transaction("getage"_n, getage_data, vector{{"alice"_n, config::active_name}}, transaction_metadata::trx_type::dry_run); + + BOOST_CHECK_EQUAL( prev_global_action_sequence, p.global_action_sequence ); + BOOST_CHECK_EQUAL( prev_recv_sequence, receiver_account->recv_sequence ); + BOOST_CHECK_EQUAL( prev_auth_sequence, amo->auth_sequence ); +} FC_LOG_AND_RETHROW() } + +BOOST_AUTO_TEST_SUITE_END()