From 94672f59d98fa7aac5e383f0624c684b49a3e2c5 Mon Sep 17 00:00:00 2001 From: arhag Date: Fri, 3 May 2019 21:22:53 -0400 Subject: [PATCH] Change how replace existing deferred transaction is implemented to not violate the new (and now explicitly stated) requirements imposed on chainbase objects that should be respected in this code base. Following those new requirements will automatically satisfy the critical preconditions on the chainbase modify function. Add new unit test, api_tests/more_deferred_transaction_tests, to check that certain deferred transaction replacement schemes do not cause chainbase failure any more. Modified the deferred_test test contract to support the new unit test. --- libraries/chain/apply_context.cpp | 15 +- libraries/chain/eosio_contract.cpp | 1 - .../include/eosio/chain/account_object.hpp | 6 +- .../chain/include/eosio/chain/code_object.hpp | 6 +- .../eosio/chain/contract_table_objects.hpp | 16 +- .../chain/generated_transaction_object.hpp | 6 +- .../eosio/chain/permission_link_object.hpp | 4 +- .../include/eosio/chain/permission_object.hpp | 4 +- .../include/eosio/chain/producer_object.hpp | 49 ----- .../eosio/chain/resource_limits_private.hpp | 6 +- .../eosio/chain/reversible_block_object.hpp | 2 +- .../eosio/chain/transaction_object.hpp | 2 +- libraries/chain/include/eosio/chain/types.hpp | 50 ++++- libraries/chainbase | 2 +- plugins/chain_plugin/chain_plugin.cpp | 1 - plugins/producer_plugin/producer_plugin.cpp | 1 - unittests/api_tests.cpp | 185 +++++++++++++++++- unittests/auth_tests.cpp | 1 - unittests/delay_tests.cpp | 3 +- .../deferred_test/deferred_test.abi | 45 +++++ .../deferred_test/deferred_test.cpp | 20 ++ .../deferred_test/deferred_test.hpp | 7 + .../deferred_test/deferred_test.wasm | Bin 10152 -> 11274 bytes 23 files changed, 342 insertions(+), 90 deletions(-) delete mode 100644 libraries/chain/include/eosio/chain/producer_object.hpp diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index 37ad5a3762f..dc7687cf05c 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -480,10 +480,17 @@ void apply_context::schedule_deferred_transaction( const uint128_t& sender_id, a control.add_to_ram_correction( ptr->payer, orig_trx_ram_bytes ); } - db.modify( *ptr, [&]( auto& gtx ) { - if( replace_deferred_activated ) { - gtx.trx_id = trx.id(); - } + transaction_id_type trx_id_for_new_obj; + if( replace_deferred_activated ) { + trx_id_for_new_obj = trx.id(); + } else { + trx_id_for_new_obj = ptr->trx_id; + } + + // Use remove and create rather than modify because mutating the trx_id field in a modifier is unsafe. + db.remove( *ptr ); + db.create( [&]( auto& gtx ) { + gtx.trx_id = trx_id_for_new_obj; gtx.sender = receiver; gtx.sender_id = sender_id; gtx.payer = payer; diff --git a/libraries/chain/eosio_contract.cpp b/libraries/chain/eosio_contract.cpp index 4a18406ee02..9bd9a022f22 100644 --- a/libraries/chain/eosio_contract.cpp +++ b/libraries/chain/eosio_contract.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include diff --git a/libraries/chain/include/eosio/chain/account_object.hpp b/libraries/chain/include/eosio/chain/account_object.hpp index 28b899ba238..235c3b91284 100644 --- a/libraries/chain/include/eosio/chain/account_object.hpp +++ b/libraries/chain/include/eosio/chain/account_object.hpp @@ -17,7 +17,7 @@ namespace eosio { namespace chain { OBJECT_CTOR(account_object,(abi)) id_type id; - account_name name; + account_name name; //< name should not be changed within a chainbase modifier lambda block_timestamp_type creation_date; shared_blob abi; @@ -56,7 +56,7 @@ namespace eosio { namespace chain { }; id_type id; - account_name name; + account_name name; //< name should not be changed within a chainbase modifier lambda uint64_t recv_sequence = 0; uint64_t auth_sequence = 0; uint64_t code_sequence = 0; @@ -88,7 +88,7 @@ namespace eosio { namespace chain { OBJECT_CTOR(account_ram_correction_object); id_type id; - account_name name; + account_name name; //< name should not be changed within a chainbase modifier lambda uint64_t ram_correction = 0; }; diff --git a/libraries/chain/include/eosio/chain/code_object.hpp b/libraries/chain/include/eosio/chain/code_object.hpp index e8789c1612b..3309704a335 100644 --- a/libraries/chain/include/eosio/chain/code_object.hpp +++ b/libraries/chain/include/eosio/chain/code_object.hpp @@ -14,12 +14,12 @@ namespace eosio { namespace chain { OBJECT_CTOR(code_object, (code)) id_type id; - digest_type code_hash; + digest_type code_hash; //< code_hash should not be changed within a chainbase modifier lambda shared_blob code; uint64_t code_ref_count; uint32_t first_block_used; - uint8_t vm_type = 0; - uint8_t vm_version = 0; + uint8_t vm_type = 0; //< vm_type should not be changed within a chainbase modifier lambda + uint8_t vm_version = 0; //< vm_version should not be changed within a chainbase modifier lambda }; struct by_code_hash; diff --git a/libraries/chain/include/eosio/chain/contract_table_objects.hpp b/libraries/chain/include/eosio/chain/contract_table_objects.hpp index dc6b25b0501..bc58cb3e6d9 100644 --- a/libraries/chain/include/eosio/chain/contract_table_objects.hpp +++ b/libraries/chain/include/eosio/chain/contract_table_objects.hpp @@ -20,9 +20,9 @@ namespace eosio { namespace chain { OBJECT_CTOR(table_id_object) id_type id; - account_name code; - scope_name scope; - table_name table; + account_name code; //< code should not be changed within a chainbase modifier lambda + scope_name scope; //< scope should not be changed within a chainbase modifier lambda + table_name table; //< table should not be changed within a chainbase modifier lambda account_name payer; uint32_t count = 0; /// the number of elements in the table }; @@ -59,8 +59,8 @@ namespace eosio { namespace chain { static const int number_of_keys = 1; id_type id; - table_id t_id; - uint64_t primary_key; + table_id t_id; //< t_id should not be changed within a chainbase modifier lambda + uint64_t primary_key; //< primary_key should not be changed within a chainbase modifier lambda account_name payer = 0; shared_blob value; }; @@ -90,10 +90,10 @@ namespace eosio { namespace chain { typedef SecondaryKey secondary_key_type; typename chainbase::object::id_type id; - table_id t_id; - uint64_t primary_key; + table_id t_id; //< t_id should not be changed within a chainbase modifier lambda + uint64_t primary_key; //< primary_key should not be changed within a chainbase modifier lambda account_name payer = 0; - SecondaryKey secondary_key; + SecondaryKey secondary_key; //< secondary_key should not be changed within a chainbase modifier lambda }; diff --git a/libraries/chain/include/eosio/chain/generated_transaction_object.hpp b/libraries/chain/include/eosio/chain/generated_transaction_object.hpp index 7c3da995e65..74e07a4d9e9 100644 --- a/libraries/chain/include/eosio/chain/generated_transaction_object.hpp +++ b/libraries/chain/include/eosio/chain/generated_transaction_object.hpp @@ -28,9 +28,9 @@ namespace eosio { namespace chain { OBJECT_CTOR(generated_transaction_object, (packed_trx) ) id_type id; - transaction_id_type trx_id; - account_name sender; - uint128_t sender_id = 0; /// ID given this transaction by the sender + transaction_id_type trx_id; //< trx_id should not be changed within a chainbase modifier lambda + account_name sender; //< sender should not be changed within a chainbase modifier lambda + uint128_t sender_id = 0; /// ID given this transaction by the sender (should not be changed within a chainbase modifier lambda) account_name payer; time_point delay_until; /// this generated transaction will not be applied until the specified time time_point expiration; /// this generated transaction will not be applied after this time diff --git a/libraries/chain/include/eosio/chain/permission_link_object.hpp b/libraries/chain/include/eosio/chain/permission_link_object.hpp index b7b4ea76f57..ee5b1287b18 100644 --- a/libraries/chain/include/eosio/chain/permission_link_object.hpp +++ b/libraries/chain/include/eosio/chain/permission_link_object.hpp @@ -39,6 +39,7 @@ namespace eosio { namespace chain { /// May be empty; if so, it sets a default @ref required_permission for all messages to @ref code action_name message_type; /// The permission level which @ref account requires for the specified message types + /// all of the above fields should not be changed within a chainbase modifier lambda permission_name required_permission; }; @@ -61,8 +62,7 @@ namespace eosio { namespace chain { composite_key > > diff --git a/libraries/chain/include/eosio/chain/permission_object.hpp b/libraries/chain/include/eosio/chain/permission_object.hpp index 7db580b74d8..335ce754907 100644 --- a/libraries/chain/include/eosio/chain/permission_object.hpp +++ b/libraries/chain/include/eosio/chain/permission_object.hpp @@ -32,8 +32,8 @@ namespace eosio { namespace chain { id_type id; permission_usage_object::id_type usage_id; id_type parent; ///< parent permission - account_name owner; ///< the account this permission belongs to - permission_name name; ///< human-readable name for the permission + account_name owner; ///< the account this permission belongs to (should not be changed within a chainbase modifier lambda) + permission_name name; ///< human-readable name for the permission (should not be changed within a chainbase modifier lambda) time_point last_updated; ///< the last time this authority was updated shared_authority auth; ///< authority required to execute this permission diff --git a/libraries/chain/include/eosio/chain/producer_object.hpp b/libraries/chain/include/eosio/chain/producer_object.hpp deleted file mode 100644 index 61d23870280..00000000000 --- a/libraries/chain/include/eosio/chain/producer_object.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @file - * @copyright defined in eos/LICENSE - */ -#pragma once -#include -#include - -#include "multi_index_includes.hpp" - -namespace eosio { namespace chain { -class producer_object : public chainbase::object { - OBJECT_CTOR(producer_object) - - id_type id; - account_name owner; - uint64_t last_aslot = 0; - public_key_type signing_key; - int64_t total_missed = 0; - uint32_t last_confirmed_block_num = 0; - - - /// The blockchain configuration values this producer recommends - chain_config configuration; -}; - -struct by_key; -struct by_owner; -using producer_multi_index = chainbase::shared_multi_index_container< - producer_object, - indexed_by< - ordered_unique, member>, - ordered_unique, member>, - ordered_unique, - composite_key, - member - > - > - > ->; - -} } // eosio::chain - -CHAINBASE_SET_INDEX_TYPE(eosio::chain::producer_object, eosio::chain::producer_multi_index) - -FC_REFLECT(eosio::chain::producer_object::id_type, (_id)) -FC_REFLECT(eosio::chain::producer_object, (id)(owner)(last_aslot)(signing_key)(total_missed)(last_confirmed_block_num) - (configuration)) diff --git a/libraries/chain/include/eosio/chain/resource_limits_private.hpp b/libraries/chain/include/eosio/chain/resource_limits_private.hpp index dc5b26008bd..e3ac7346263 100644 --- a/libraries/chain/include/eosio/chain/resource_limits_private.hpp +++ b/libraries/chain/include/eosio/chain/resource_limits_private.hpp @@ -133,8 +133,8 @@ namespace eosio { namespace chain { namespace resource_limits { OBJECT_CTOR(resource_limits_object) id_type id; - account_name owner; - bool pending = false; + account_name owner; //< owner should not be changed within a chainbase modifier lambda + bool pending = false; //< pending should not be changed within a chainbase modifier lambda int64_t net_weight = -1; int64_t cpu_weight = -1; @@ -162,7 +162,7 @@ namespace eosio { namespace chain { namespace resource_limits { OBJECT_CTOR(resource_usage_object) id_type id; - account_name owner; + account_name owner; //< owner should not be changed within a chainbase modifier lambda usage_accumulator net_usage; usage_accumulator cpu_usage; diff --git a/libraries/chain/include/eosio/chain/reversible_block_object.hpp b/libraries/chain/include/eosio/chain/reversible_block_object.hpp index daaac00a71b..c493a4915e2 100644 --- a/libraries/chain/include/eosio/chain/reversible_block_object.hpp +++ b/libraries/chain/include/eosio/chain/reversible_block_object.hpp @@ -17,7 +17,7 @@ namespace eosio { namespace chain { OBJECT_CTOR(reversible_block_object,(packedblock) ) id_type id; - uint32_t blocknum = 0; + uint32_t blocknum = 0; //< blocknum should not be changed within a chainbase modifier lambda shared_string packedblock; void set_block( const signed_block_ptr& b ) { diff --git a/libraries/chain/include/eosio/chain/transaction_object.hpp b/libraries/chain/include/eosio/chain/transaction_object.hpp index 50a7eb62cdd..cf87e11b5e9 100644 --- a/libraries/chain/include/eosio/chain/transaction_object.hpp +++ b/libraries/chain/include/eosio/chain/transaction_object.hpp @@ -27,7 +27,7 @@ namespace eosio { namespace chain { id_type id; time_point_sec expiration; - transaction_id_type trx_id; + transaction_id_type trx_id; //< trx_id should not be changed within a chainbase modifier lambda }; struct by_expiration; diff --git a/libraries/chain/include/eosio/chain/types.hpp b/libraries/chain/include/eosio/chain/types.hpp index e701e92c4fb..d6323fbd23d 100644 --- a/libraries/chain/include/eosio/chain/types.hpp +++ b/libraries/chain/include/eosio/chain/types.hpp @@ -169,7 +169,7 @@ namespace eosio { namespace chain { block_summary_object_type, transaction_object_type, generated_transaction_object_type, - producer_object_type, + UNUSED_producer_object_type, UNUSED_chain_property_object_type, account_control_history_object_type, ///< Defined by history_plugin UNUSED_account_transaction_history_object_type, @@ -195,8 +195,54 @@ namespace eosio { namespace chain { OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types }; + /** + * Important notes on using chainbase objects in EOSIO code: + * + * There are several constraints that need to be followed when using chainbase objects. + * Some of these constraints are due to the requirements imposed by the chainbase library, + * others are due to requirements to ensure determinism in the EOSIO chain library. + * + * Before listing the constraints, the "restricted field set" must be defined. + * + * Every chainbase object includes a field called id which has the type id_type. + * The id field is always included in the restricted field set. + * + * A field of a chainbase object is considered to be in the restricted field set if it is involved in the + * derivation of the key used for one of the indices in the chainbase multi-index unless its only involvement + * is through being included in composite_keys that end with the id field. + * + * So if the multi-index includes an index like the following + * ``` + * ordered_unique< tag, + * composite_key< generated_transaction_object, + * BOOST_MULTI_INDEX_MEMBER( generated_transaction_object, account_name, sender), + * BOOST_MULTI_INDEX_MEMBER( generated_transaction_object, uint128_t, sender_id) + * > + * > + * ``` + * both `sender` and `sender_id` fields are part of the restricted field set. + * + * On the other hand, an index like the following + * ``` + * ordered_unique< tag, + * composite_key< generated_transaction_object, + * BOOST_MULTI_INDEX_MEMBER( generated_transaction_object, time_point, expiration), + * BOOST_MULTI_INDEX_MEMBER( generated_transaction_object, generated_transaction_object::id_type, id) + * > + * > + * ``` + * would not by itself require the `expiration` field to be part of the restricted field set. + * + * The restrictions on usage of the chainbase objects within this code base are: + * + The chainbase object includes the id field discussed above. + * + The multi-index must include an ordered_unique index tagged with by_id that is based on the id field as the sole key. + * + No other types of indices other than ordered_unique are allowed. + * If an index is desired that does not enforce uniqueness, then use a composite key that ends with the id field. + * + When creating a chainbase object, the constructor lambda should never mutate the id field. + * + When modifying a chainbase object, the modifier lambda should never mutate any fields in the restricted field set. + */ + class account_object; - class producer_object; using block_id_type = fc::sha256; using checksum_type = fc::sha256; diff --git a/libraries/chainbase b/libraries/chainbase index 118c513436e..b769749d533 160000 --- a/libraries/chainbase +++ b/libraries/chainbase @@ -1 +1 @@ -Subproject commit 118c513436e1310d8e1395303c964430f26b0bb4 +Subproject commit b769749d53303ec1a037d483c631d02268cbf012 diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 4c0ef6acdb0..6b0247afd0d 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index e2586db8fb7..044caa2757e 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -3,7 +3,6 @@ * @copyright defined in eos/LICENSE */ #include -#include #include #include #include diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index 206d3878ff2..e3b45d07718 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -1090,7 +1091,7 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, TESTER) { try { transaction_trace_ptr trace; auto c = control->applied_transaction.connect([&](std::tuple x) { auto& t = std::get<0>(x); - if (t && t->receipt && t->receipt->status != transaction_receipt::executed) { trace = t; } + if (t && t->receipt && t->receipt->status != transaction_receipt::executed) { trace = t; } } ); // test error handling on deferred transaction failure @@ -1139,7 +1140,7 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try { transaction_trace_ptr trace; auto c = control->applied_transaction.connect([&](std::tuple x) { auto& t = std::get<0>(x); - if (t->scheduled) { trace = t; } + if (t->scheduled) { trace = t; } } ); CALL_TEST_FUNCTION(*this, "test_transaction", "send_deferred_transaction", {} ); BOOST_CHECK(!trace); @@ -1317,6 +1318,186 @@ BOOST_FIXTURE_TEST_CASE(deferred_transaction_tests, TESTER) { try { BOOST_REQUIRE_EQUAL( validate(), true ); } FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE(more_deferred_transaction_tests) { try { + auto cfg = validating_tester::default_config(); + cfg.contracts_console = true; + validating_tester chain( cfg ); + chain.execute_setup_policy( setup_policy::preactivate_feature_and_new_bios ); + + const auto& pfm = chain.control->get_protocol_feature_manager(); + auto d = pfm.get_builtin_digest( builtin_protocol_feature_t::replace_deferred ); + BOOST_REQUIRE( d ); + + chain.preactivate_protocol_features( {*d} ); + chain.produce_block(); + + const auto& index = chain.control->db().get_index(); + + auto print_deferred = [&index]() { + for( const auto& gto : index ) { + wlog("id = ${id}, trx_id = ${trx_id}", ("id", gto.id)("trx_id", gto.trx_id)); + } + }; + + const auto& contract_account = account_name("tester"); + const auto& test_account = account_name("alice"); + + chain.create_accounts( {contract_account, test_account} ); + chain.set_code( contract_account, contracts::deferred_test_wasm() ); + chain.set_abi( contract_account, contracts::deferred_test_abi().data() ); + chain.produce_block(); + + BOOST_REQUIRE_EQUAL(0, index.size()); + + chain.push_action( contract_account, N(delayedcall), test_account, fc::mutable_variant_object() + ("payer", test_account) + ("sender_id", 0) + ("contract", contract_account) + ("payload", 42) + ("delay_sec", 1000) + ("replace_existing", false) + ); + + BOOST_REQUIRE_EQUAL(1, index.size()); + print_deferred(); + + signed_transaction trx; + trx.actions.emplace_back( + chain.get_action( contract_account, N(delayedcall), + vector{{test_account, config::active_name}}, + fc::mutable_variant_object() + ("payer", test_account) + ("sender_id", 0) + ("contract", contract_account) + ("payload", 13) + ("delay_sec", 1000) + ("replace_existing", true) + ) + ); + trx.actions.emplace_back( + chain.get_action( contract_account, N(delayedcall), + vector{{test_account, config::active_name}}, + fc::mutable_variant_object() + ("payer", test_account) + ("sender_id", 1) + ("contract", contract_account) + ("payload", 42) + ("delay_sec", 1000) + ("replace_existing", false) + ) + ); + trx.actions.emplace_back( + chain.get_action( contract_account, N(fail), + vector{}, + fc::mutable_variant_object() + ) + ); + chain.set_transaction_headers(trx); + trx.sign( chain.get_private_key( test_account, "active" ), chain.control->get_chain_id() ); + BOOST_REQUIRE_EXCEPTION( + chain.push_transaction( trx ), + eosio_assert_message_exception, + eosio_assert_message_is("fail") + ); + + BOOST_REQUIRE_EQUAL(1, index.size()); + print_deferred(); + + chain.produce_blocks(2); + + chain.push_action( contract_account, N(delayedcall), test_account, fc::mutable_variant_object() + ("payer", test_account) + ("sender_id", 1) + ("contract", contract_account) + ("payload", 101) + ("delay_sec", 1000) + ("replace_existing", false) + ); + + chain.push_action( contract_account, N(delayedcall), test_account, fc::mutable_variant_object() + ("payer", test_account) + ("sender_id", 2) + ("contract", contract_account) + ("payload", 102) + ("delay_sec", 1000) + ("replace_existing", false) + ); + + BOOST_REQUIRE_EQUAL(3, index.size()); + print_deferred(); + + BOOST_REQUIRE_THROW( + chain.push_action( contract_account, N(delayedcall), test_account, fc::mutable_variant_object() + ("payer", test_account) + ("sender_id", 2) + ("contract", contract_account) + ("payload", 101) + ("delay_sec", 1000) + ("replace_existing", true) + ), + fc::exception + ); + + BOOST_REQUIRE_EQUAL(3, index.size()); + print_deferred(); + + signed_transaction trx2; + trx2.actions.emplace_back( + chain.get_action( contract_account, N(delayedcall), + vector{{test_account, config::active_name}}, + fc::mutable_variant_object() + ("payer", test_account) + ("sender_id", 1) + ("contract", contract_account) + ("payload", 100) + ("delay_sec", 1000) + ("replace_existing", true) + ) + ); + trx2.actions.emplace_back( + chain.get_action( contract_account, N(delayedcall), + vector{{test_account, config::active_name}}, + fc::mutable_variant_object() + ("payer", test_account) + ("sender_id", 2) + ("contract", contract_account) + ("payload", 101) + ("delay_sec", 1000) + ("replace_existing", true) + ) + ); + trx2.actions.emplace_back( + chain.get_action( contract_account, N(delayedcall), + vector{{test_account, config::active_name}}, + fc::mutable_variant_object() + ("payer", test_account) + ("sender_id", 1) + ("contract", contract_account) + ("payload", 102) + ("delay_sec", 1000) + ("replace_existing", true) + ) + ); + trx2.actions.emplace_back( + chain.get_action( contract_account, N(fail), + vector{}, + fc::mutable_variant_object() + ) + ); + chain.set_transaction_headers(trx2); + trx2.sign( chain.get_private_key( test_account, "active" ), chain.control->get_chain_id() ); + BOOST_REQUIRE_EXCEPTION( + chain.push_transaction( trx2 ), + eosio_assert_message_exception, + eosio_assert_message_is("fail") + ); + + BOOST_REQUIRE_EQUAL(3, index.size()); + print_deferred(); + + BOOST_REQUIRE_EQUAL( chain.validate(), true ); +} FC_LOG_AND_RETHROW() } + template struct setprod_act { static account_name get_account() { diff --git a/unittests/auth_tests.cpp b/unittests/auth_tests.cpp index 0422487aae8..b944b532423 100644 --- a/unittests/auth_tests.cpp +++ b/unittests/auth_tests.cpp @@ -8,7 +8,6 @@ #include #include -#include #ifdef NON_VALIDATING_TEST #define TESTER tester diff --git a/unittests/delay_tests.cpp b/unittests/delay_tests.cpp index 913f3395e8e..2d6f77c7ee9 100644 --- a/unittests/delay_tests.cpp +++ b/unittests/delay_tests.cpp @@ -4,7 +4,6 @@ */ #include #include -#include #include #include @@ -261,7 +260,7 @@ BOOST_AUTO_TEST_CASE(delete_auth_test) { try { expect_assert_message(e, "permission_query_exception: Permission Query Exception\nFailed to retrieve permission"); return true; }); - + // update auth chain.push_action(config::system_account_name, updateauth::get_name(), tester_account, fc::mutable_variant_object() ("account", "tester") diff --git a/unittests/test-contracts/deferred_test/deferred_test.abi b/unittests/test-contracts/deferred_test/deferred_test.abi index 37c9eff9492..857e725efec 100644 --- a/unittests/test-contracts/deferred_test/deferred_test.abi +++ b/unittests/test-contracts/deferred_test/deferred_test.abi @@ -35,6 +35,41 @@ } ] }, + { + "name": "delayedcall", + "base": "", + "fields": [ + { + "name": "payer", + "type": "name" + }, + { + "name": "sender_id", + "type": "uint64" + }, + { + "name": "contract", + "type": "name" + }, + { + "name": "payload", + "type": "uint64" + }, + { + "name": "delay_sec", + "type": "uint32" + }, + { + "name": "replace_existing", + "type": "bool" + } + ] + }, + { + "name": "fail", + "base": "", + "fields": [] + }, { "name": "inlinecall", "base": "", @@ -65,6 +100,16 @@ "type": "deferfunc", "ricardian_contract": "" }, + { + "name": "delayedcall", + "type": "delayedcall", + "ricardian_contract": "" + }, + { + "name": "fail", + "type": "fail", + "ricardian_contract": "" + }, { "name": "inlinecall", "type": "inlinecall", diff --git a/unittests/test-contracts/deferred_test/deferred_test.cpp b/unittests/test-contracts/deferred_test/deferred_test.cpp index b24096de146..1ff307d8426 100644 --- a/unittests/test-contracts/deferred_test/deferred_test.cpp +++ b/unittests/test-contracts/deferred_test/deferred_test.cpp @@ -40,6 +40,22 @@ void deferred_test::defercall( name payer, uint64_t sender_id, name contract, ui trx.send( (static_cast(payer.value) << 64) | sender_id, payer, replace_existing ); } +void deferred_test::delayedcall( name payer, uint64_t sender_id, name contract, + uint64_t payload, uint32_t delay_sec, bool replace_existing ) +{ + print( "delayedcall called on ", get_self(), "\n" ); + require_auth( payer ); + + print( "deferred send of deferfunc action (with delay of ", delay_sec, " sec) to ", contract, " by ", payer, + " with sender id ", sender_id, " and payload ", payload ); + transaction trx; + trx.delay_sec = delay_sec; + deferfunc_action a( contract, {get_self(), "active"_n} ); + trx.actions.emplace_back( a.to_action( payload ) ); + + trx.send( sender_id, payer, replace_existing ); +} + void deferred_test::deferfunc( uint64_t payload ) { print( "deferfunc called on ", get_self(), " with payload = ", payload, "\n" ); check( payload != 13, "value 13 not allowed in payload" ); @@ -50,6 +66,10 @@ void deferred_test::inlinecall( name contract, name authorizer, uint64_t payload a.send( payload ); } +void deferred_test::fail() { + check( false, "fail" ); +} + void deferred_test::on_error( uint128_t sender_id, ignore> sent_trx ) { print( "onerror called on ", get_self(), "\n" ); } diff --git a/unittests/test-contracts/deferred_test/deferred_test.hpp b/unittests/test-contracts/deferred_test/deferred_test.hpp index 1e5aa22681b..ba7b5c26730 100644 --- a/unittests/test-contracts/deferred_test/deferred_test.hpp +++ b/unittests/test-contracts/deferred_test/deferred_test.hpp @@ -14,6 +14,10 @@ class [[eosio::contract]] deferred_test : public eosio::contract { [[eosio::action]] void defercall( eosio::name payer, uint64_t sender_id, eosio::name contract, uint64_t payload ); + [[eosio::action]] + void delayedcall( eosio::name payer, uint64_t sender_id, eosio::name contract, + uint64_t payload, uint32_t delay_sec, bool replace_existing ); + [[eosio::action]] void deferfunc( uint64_t payload ); using deferfunc_action = eosio::action_wrapper<"deferfunc"_n, &deferred_test::deferfunc>; @@ -21,6 +25,9 @@ class [[eosio::contract]] deferred_test : public eosio::contract { [[eosio::action]] void inlinecall( eosio::name contract, eosio::name authorizer, uint64_t payload ); + [[eosio::action]] + void fail(); + [[eosio::on_notify("eosio::onerror")]] void on_error( uint128_t sender_id, eosio::ignore> sent_trx ); }; diff --git a/unittests/test-contracts/deferred_test/deferred_test.wasm b/unittests/test-contracts/deferred_test/deferred_test.wasm index 588e38fadf2ed8f3d8a7952114113f3bc43ebd61..416dad9fd5f79c5fea5d29361ffa0eceaffc40d2 100755 GIT binary patch delta 1488 zcmY*YUuc_E6u*DIKUu$a-m$JWX|kU0OWG#2vN$w}(ssF>TU+fcf{Z<=7@KtKXKeaU zwxTRSR_OL1)eFiP3}nK5nK0*km_GC$Oax_p7$OYcRK$u3`drUV+Sq*$zjN-n=imLE z^L;vc=~N@h&Av$qA+$mdyzflgcKJMh<(u`nw%19 zweT{Pm1W|TiM+H{7xo@%=BB2K^8_01pXfG-h&mf;ltb$gbD*-mvGT#sS2n&Sz+N=6 zK!A#@n&K^oBwki-ezA1>&fov+x*X7E{jGoh<1X`2b(P1|GLO?|Z~ewQ19a<_XxyS& z>=h0@rrhAGbW2r&BeY+A7c8OP7aBR;9|8*u8TUP7u!%U1t}m0mIPMz2r0`<|4CfkW zv`o)OiCm&@csAN>Fw%UH0!eV<2ITSz5flP~$#<(761-5p5ttQT44`zzJtXmmazR*{` zE_?kH8^SYB^JJ|vE`{jwOl=`h-X`w$SCt3peS9I92;O$JULR_j&Yi(r+6iHi z`r=8Hn*>kdDV7C0&cdE~tV#C>m_&DLiiA_U5<6GT|6dI|wa&3Ju-cQ606b8zM5Y#( z*@?qO>M5}TI*O-5s4P(&iMkQ`7pHiwZ2_m42oE97gu4SnIJ&Se2Gu9wakj9g8Y6Kn zQju;gUayJwBCqVZ&Z$|(Y2H(xg-2V5u(ToV=bMNma$$`K%K?rRRdWQ=_46{eYRZ7H zL%{VIGS&5PO$@fAz}?v$oKe$}wsJidDclZa$dzkV3%)Zg;h``FhVSC6WRH(24PA-J z*p7SbAzv;7+KE=%d7K1rop^l=99W9A!cmTFV2Tc03j!QynhO-zdjOp=o+tQ_hOCB+ zh9vMf>p?cipy)-Xd+L|SOmzDlCg!TWKfwd8B|oliGr^_*a#g*3Fv#w%st*q?YObNZ zM~fHQqgu?i&(l8jN4wiKLOJs8F_*Kf2zv&u56f2Bs2IbzN``P<)=1S);a~&u`72hi zfGY>i?Az6Zz*oynbpejx;Md_f#7Epd#1rl$;@7UW*xqTxl6OU8M@q@)In?e%lXOu1 z9{mXQzR)4{dCWuYe(ZA9tBClZBZauXGs_?Fed=WAO8cYvLNPaA$dBcUMbJ>lLunES z(Z9HJSl#XPPR7qp%$0i=|v%8<9ij zK)x_um>GX-a_r&k$m$baEt=Kgu8t<;!ZF8l6Ge>LRHd#UY@x+EJ2Np?KoipAm@|c3 M9(CdvOD-Y*0o;*UGXMYp delta 586 zcmYk3KWGzC9LL|gd$~q0kymsuN0Yw0TymF0NEbVqHWynhB1#3pp|J#7wIQ)dEygT1 z2&R&$`a>j&1i?Xy2&Hy$5EGnq5^?F|Bo2ZI&EisjFD`w<=lkXN-tQl;b>-DXofK}B zDItX3KK3wB-CD0IitE5%C9E;+C>{`MSiI~JeT{fhh7M6*p;9T;i8$Ok<1oUb`U}Xb zB0b^DH5!el{r=|XPedrQEGvkhd{TzD-frx?`?Gf-oP}N0e#GL`+jdyoPutrU0{c|T z5w6o5%!jVhHoOm=ry0U5Sc+{x8+hJk-qcM5jl%rVAey z_46S^s0r0?YTkz~;ZzW=c;5z2*38tMIKG2I}FRuxCdlH9!Zl6Q`v@^(f>?ZPYOh&%Pt|MpS&md{hT|CeB-tUFG|Rr#5nR-BCCE?0+3F2p`1Ey;1c?GTjVF5kSnQIdA4;_Z6*#H0l