From df2422b4a954e6d5c146c09da2ecb990ac0d0f9b Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 21 Nov 2018 16:56:33 +0800 Subject: [PATCH] add actionseed, global action sequence (#5) --- contracts/eosiolib/transaction.h | 22 ++ libraries/chain/apply_context.cpp | 4 + libraries/chain/block_header.cpp | 10 + libraries/chain/block_header_state.cpp | 4 +- libraries/chain/controller.cpp | 56 +++- libraries/chain/fork_database.cpp | 2 - .../include/eosio/chain/apply_context.hpp | 1 + libraries/chain/include/eosio/chain/block.hpp | 3 + .../include/eosio/chain/block_header.hpp | 9 +- .../chain/include/eosio/chain/config_xos.hpp | 9 +- .../chain/include/eosio/chain/controller.hpp | 7 +- .../eosio/chain/global_property_object.hpp | 14 +- .../include/eosio/chain/resource_limits.hpp | 8 +- .../eosio/chain/resource_limits_private.hpp | 2 +- libraries/chain/include/eosio/chain/types.hpp | 1 + libraries/chain/resource_limits.cpp | 6 +- libraries/chain/wasm_interface.cpp | 90 ++++- plugins/kafka_plugin/kafka.hpp | 1 + plugins/producer_plugin/producer_plugin.cpp | 7 +- unittests/actiondemo/actiondemo.abi | 99 ++++++ unittests/actiondemo/actiondemo.cpp | 106 ++++++ unittests/actiondemo/actiondemo.hpp | 50 +++ unittests/actiondemo/test.py | 223 +++++++++++++ unittests/database_gmr_blklst_tests.cpp | 309 ++++++++++++++++++ unittests/gmr_test.cpp | 234 +++++++++++++ 25 files changed, 1236 insertions(+), 41 deletions(-) create mode 100644 unittests/actiondemo/actiondemo.abi create mode 100644 unittests/actiondemo/actiondemo.cpp create mode 100644 unittests/actiondemo/actiondemo.hpp create mode 100644 unittests/actiondemo/test.py create mode 100644 unittests/database_gmr_blklst_tests.cpp create mode 100644 unittests/gmr_test.cpp diff --git a/contracts/eosiolib/transaction.h b/contracts/eosiolib/transaction.h index dd7c05ded17..db115ca27e1 100644 --- a/contracts/eosiolib/transaction.h +++ b/contracts/eosiolib/transaction.h @@ -94,6 +94,28 @@ extern "C" { */ size_t transaction_size(); + /** + * Get transaction id + * + * @param id : return id + */ + void get_transaction_id( transaction_id_type* id ); + + /** + * Get the action globally unique sequence + * + * @param seq : return sequence + */ + void get_action_sequence(uint64_t* seq); + + /** + * Get the producer's signature for the action + * @param sig : Memory buffer + * @param siglen :Memory buffer size + * @return : Return valid data size + */ + int bpsig_action_time_seed( const char* sig, size_t siglen ); + /** * Gets the block number used for TAPOS on the currently executing transaction. * diff --git a/libraries/chain/apply_context.cpp b/libraries/chain/apply_context.cpp index de1450013d8..07ab384eeff 100644 --- a/libraries/chain/apply_context.cpp +++ b/libraries/chain/apply_context.cpp @@ -44,6 +44,9 @@ void apply_context::exec_one( action_trace& trace ) trace.act = act; trace.context_free = context_free; + const auto& p = control.get_dynamic_global_properties(); + global_action_sequence = p.global_action_sequence + 1; + const auto& cfg = control.get_global_properties().configuration; try { try { @@ -79,6 +82,7 @@ void apply_context::exec_one( action_trace& trace ) r.global_sequence = next_global_sequence(); r.recv_sequence = next_recv_sequence( receiver ); + global_action_sequence = 0; const auto& account_sequence = db.get(act.account); r.code_sequence = account_sequence.code_sequence; // could be modified by action execution above diff --git a/libraries/chain/block_header.cpp b/libraries/chain/block_header.cpp index 8ba95b705e2..b73338b3ca2 100644 --- a/libraries/chain/block_header.cpp +++ b/libraries/chain/block_header.cpp @@ -28,5 +28,15 @@ namespace eosio { namespace chain { return result; } + void block_header::set_block_extensions_mroot(digest_type& mroot) + { + if (header_extensions.size() < 1) + header_extensions.emplace_back(); + + header_extensions[0].first = static_cast(block_header_extensions_type::block_extensions_mroot); + header_extensions[0].second.resize(mroot.data_size()); + std::copy(mroot.data(), mroot.data() + mroot.data_size(), header_extensions[0].second.data()); + } + } } diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index 6e7b339c42c..2ae15af7341 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -145,7 +145,7 @@ namespace eosio { namespace chain { */ block_header_state block_header_state::next( const signed_block_header& h, bool trust )const { EOS_ASSERT( h.timestamp != block_timestamp_type(), block_validate_exception, "", ("h",h) ); - EOS_ASSERT( h.header_extensions.size() == 0, block_validate_exception, "no supported extensions" ); + //EOS_ASSERT( h.header_extensions.size() == 0, block_validate_exception, "no supported extensions" ); EOS_ASSERT( h.timestamp > header.timestamp, block_validate_exception, "block must be later in time" ); EOS_ASSERT( h.previous == id, unlinkable_block_exception, "block must link to current state" ); @@ -175,8 +175,10 @@ namespace eosio { namespace chain { result.header.action_mroot = h.action_mroot; result.header.transaction_mroot = h.transaction_mroot; result.header.producer_signature = h.producer_signature; + result.header.header_extensions = h.header_extensions; result.id = result.header.id(); + // ASSUMPTION FROM controller_impl::apply_block = all untrusted blocks will have their signatures pre-validated here if( !trust ) { EOS_ASSERT( result.block_signing_key == result.signee(), wrong_signing_key, "block not signed by expected key", diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index fe52fcabc79..6bea61766be 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -33,7 +33,7 @@ using controller_index_set = index_set< account_index, account_sequence_index, global_property_multi_index, - global_propertyex_multi_index, + global_property2_multi_index, dynamic_global_property_multi_index, block_summary_multi_index, transaction_multi_index, @@ -109,6 +109,8 @@ struct pending_state { optional _producer_block_id; + std::function _signer; + void push() { _db_session.push(); } @@ -640,11 +642,11 @@ struct controller_impl { db.create([](auto&){}); // *bos begin* - - db.create([&](auto &gpo) { - gpo.gmr.cpu_us = config::default_free_cpu_limit; - gpo.gmr.net_byte = config::default_free_net_limit; - gpo.gmr.ram_byte = config::default_free_ram_limit; + //guaranteed minimum resources which is abbreviated gmr + db.create([&](auto &gpo) { + gpo.gmr.cpu_us = config::default_gmr_cpu_limit; + gpo.gmr.net_byte = config::default_gmr_net_limit; + gpo.gmr.ram_byte = config::default_gmr_ram_limit; }); sync_name_list(list_type::actor_blacklist_type,true); @@ -708,7 +710,7 @@ struct controller_impl { sync_name_list(list); } - void sync_list_and_db(list_type list, global_propertyex_object &gprops2,bool isMerge=false) + void sync_list_and_db(list_type list, global_property2_object &gprops2,bool isMerge=false) { int64_t lst = static_cast(list); EOS_ASSERT( list >= list_type::actor_blacklist_type && list < list_type::list_type_count, transaction_exception, "unknown list type : ${l}, ismerge: ${n}", ("l", static_cast(list))("n", isMerge)); @@ -737,7 +739,7 @@ struct controller_impl { void sync_name_list(list_type list,bool isMerge=false) { - const auto &gpo2 = db.get(); + const auto &gpo2 = db.get(); db.modify(gpo2, [&](auto &gprops2) { sync_list_and_db(list, gprops2,isMerge); }); @@ -1155,7 +1157,7 @@ struct controller_impl { void start_block( block_timestamp_type when, uint16_t confirm_block_count, controller::block_status s, - const optional& producer_block_id ) + const optional& producer_block_id , std::function signer = nullptr) { EOS_ASSERT( !pending, block_validate_exception, "pending block already exists" ); @@ -1174,6 +1176,7 @@ struct controller_impl { pending->_block_status = s; pending->_producer_block_id = producer_block_id; + pending->_signer = signer; pending->_pending_block_state = std::make_shared( *head, when ); // promotes pending schedule (if any) to active pending->_pending_block_state->in_current_chain = true; @@ -1241,10 +1244,13 @@ struct controller_impl { void apply_block( const signed_block_ptr& b, controller::block_status s ) { try { try { - EOS_ASSERT( b->block_extensions.size() == 0, block_validate_exception, "no supported extensions" ); + //EOS_ASSERT( b->block_extensions.size() == 0, block_validate_exception, "no supported extensions" ); auto producer_block_id = b->id(); start_block( b->timestamp, b->confirmed, s , producer_block_id); + pending->_pending_block_state->block->header_extensions = b->header_extensions; + pending->_pending_block_state->block->block_extensions = b->block_extensions; + transaction_trace_ptr trace; for( const auto& receipt : b->transactions ) { @@ -1309,7 +1315,6 @@ struct controller_impl { void push_block( const signed_block_ptr& b, controller::block_status s ) { EOS_ASSERT(!pending, block_validate_exception, "it is not valid to push a block when there is a pending block"); - auto reset_prod_light_validation = fc::make_scoped_exit([old_value=trusted_producer_light_validation, this]() { trusted_producer_light_validation = old_value; }); @@ -1442,6 +1447,17 @@ struct controller_impl { pending->_pending_block_state->header.transaction_mroot = merkle( move(trx_digests) ); } + void set_ext_merkle() { + vector ext_digests; + const auto& exts = pending->_pending_block_state->block->block_extensions; + ext_digests.reserve( exts.size()); + for( const auto& a : exts ) + ext_digests.emplace_back( digest_type::hash(a) ); + + auto mroot = merkle( move(ext_digests)); + pending->_pending_block_state->header.set_block_extensions_mroot(mroot); + } + void finalize_block() { @@ -1466,7 +1482,7 @@ struct controller_impl { // Update resource limits: resource_limits.process_account_limit_updates(); const auto& chain_config = self.get_global_properties().configuration; - const auto& gmr = self.get_global_properties2().gmr; + const auto& gmr = self.get_global_properties2().gmr;//guaranteed minimum resources which is abbreviated gmr uint32_t max_virtual_mult = 1000; uint64_t CPU_TARGET = EOS_PERCENT(chain_config.max_block_cpu_usage, chain_config.target_block_cpu_usage_pct); @@ -1475,7 +1491,7 @@ struct controller_impl { {EOS_PERCENT(chain_config.max_block_net_usage, chain_config.target_block_net_usage_pct), chain_config.max_block_net_usage, config::block_size_average_window_ms / config::block_interval_ms, max_virtual_mult, {99, 100}, {1000, 999}} ); - resource_limits.set_block_parameters_ex( + resource_limits.set_gmr_parameters( { gmr.ram_byte, gmr.cpu_us,gmr.net_byte} ); @@ -1483,6 +1499,7 @@ struct controller_impl { set_action_merkle(); set_trx_merkle(); + set_ext_merkle(); auto p = pending->_pending_block_state; p->id = p->header.id(); @@ -1693,9 +1710,9 @@ chainbase::database& controller::mutable_db()const { return my->db; } const fork_database& controller::fork_db()const { return my->fork_db; } -void controller::start_block( block_timestamp_type when, uint16_t confirm_block_count) { +void controller::start_block( block_timestamp_type when, uint16_t confirm_block_count, std::function signer) { validate_db_available_size(); - my->start_block(when, confirm_block_count, block_status::incomplete, optional() ); + my->start_block(when, confirm_block_count, block_status::incomplete, optional() , signer); } void controller::finalize_block() { @@ -1841,6 +1858,11 @@ optional controller::pending_producer_block_id()const { return my->pending->_producer_block_id; } +std::function controller::pending_producer_signer()const { + EOS_ASSERT( my->pending, block_validate_exception, "no pending block" ); + return my->pending->_signer; +} + uint32_t controller::last_irreversible_block_num() const { return std::max(std::max(my->head->bft_irreversible_blocknum, my->head->dpos_irreversible_blocknum), my->snapshot_head_block); } @@ -2213,8 +2235,8 @@ const flat_set &controller::get_resource_greylist() const { } // *bos begin* -const global_propertyex_object& controller::get_global_properties2()const { - return my->db.get(); +const global_property2_object& controller::get_global_properties2()const { + return my->db.get(); } void controller::set_name_list(int64_t list, int64_t action, std::vector name_list) diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index c56ed0add05..317453f19b8 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -142,7 +142,6 @@ namespace eosio { namespace chain { block_state_ptr fork_database::add( signed_block_ptr b, bool trust ) { EOS_ASSERT( b, fork_database_exception, "attempt to add null block" ); EOS_ASSERT( my->head, fork_db_block_not_found, "no head block set" ); - const auto& by_id_idx = my->index.get(); auto existing = by_id_idx.find( b->id() ); EOS_ASSERT( existing == by_id_idx.end(), fork_database_exception, "we already know about this block" ); @@ -203,7 +202,6 @@ namespace eosio { namespace chain { /// remove all of the invalid forks built of this id including this id void fork_database::remove( const block_id_type& id ) { vector remove_queue{id}; - for( uint32_t i = 0; i < remove_queue.size(); ++i ) { auto itr = my->index.find( remove_queue[i] ); if( itr != my->index.end() ) diff --git a/libraries/chain/include/eosio/chain/apply_context.hpp b/libraries/chain/include/eosio/chain/apply_context.hpp index a253d950358..2b68d015442 100644 --- a/libraries/chain/include/eosio/chain/apply_context.hpp +++ b/libraries/chain/include/eosio/chain/apply_context.hpp @@ -594,6 +594,7 @@ class apply_context { bool privileged = false; bool context_free = false; bool used_context_free_api = false; + uint64_t global_action_sequence = 0; generic_index idx64; generic_index idx128; diff --git a/libraries/chain/include/eosio/chain/block.hpp b/libraries/chain/include/eosio/chain/block.hpp index 0e85b167df8..28c49f9772e 100644 --- a/libraries/chain/include/eosio/chain/block.hpp +++ b/libraries/chain/include/eosio/chain/block.hpp @@ -51,6 +51,9 @@ namespace eosio { namespace chain { } }; + enum class block_extension_type : uint16_t { + bpsig_action_time_seed + }; /** */ diff --git a/libraries/chain/include/eosio/chain/block_header.hpp b/libraries/chain/include/eosio/chain/block_header.hpp index bf9cf0bedb8..723824b5310 100644 --- a/libraries/chain/include/eosio/chain/block_header.hpp +++ b/libraries/chain/include/eosio/chain/block_header.hpp @@ -4,6 +4,12 @@ namespace eosio { namespace chain { + /* Extended spatial data category + */ + enum block_header_extensions_type : uint16_t { + block_extensions_mroot = 0 // mroot of block extensions + }; + struct block_header { block_timestamp_type timestamp; @@ -32,13 +38,14 @@ namespace eosio { namespace chain { */ uint32_t schedule_version = 0; optional new_producers; - extensions_type header_extensions; + extensions_type header_extensions; // [0] : mroot of block extensions digest_type digest()const; block_id_type id() const; uint32_t block_num() const { return num_from_id(previous) + 1; } static uint32_t num_from_id(const block_id_type& id); + void set_block_extensions_mroot(digest_type& mroot); }; diff --git a/libraries/chain/include/eosio/chain/config_xos.hpp b/libraries/chain/include/eosio/chain/config_xos.hpp index 23cbee7efb9..02adf0d54d0 100644 --- a/libraries/chain/include/eosio/chain/config_xos.hpp +++ b/libraries/chain/include/eosio/chain/config_xos.hpp @@ -10,10 +10,11 @@ namespace eosio { namespace chain { namespace config { -const static uint32_t default_free_cpu_limit = 200'000; /// free cpu usage in microseconds -const static uint32_t default_free_net_limit = 10 * 1024; // 10 KB -const static uint32_t default_free_ram_limit = 0; // 0 KB -const static uint16_t default_free_resource_limit_per_day = 1000; +//guaranteed minimum resources which is abbreviated gmr +const static uint32_t default_gmr_cpu_limit = 200'000; /// free cpu usage in microseconds +const static uint32_t default_gmr_net_limit = 10 * 1024; // 10 KB +const static uint32_t default_gmr_ram_limit = 0; // 0 KB +const static uint16_t default_gmr_resource_limit_per_day = 1000; diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index ddbecd4fe86..17ca27b3235 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -27,7 +27,7 @@ namespace eosio { namespace chain { class dynamic_global_property_object; class global_property_object; - class global_propertyex_object; // *bos* + class global_property2_object; // *bos* class permission_object; class account_object; using resource_limits::resource_limits_manager; @@ -111,7 +111,7 @@ namespace eosio { namespace chain { * Starts a new pending block session upon which new transactions can * be pushed. */ - void start_block( block_timestamp_type time = block_timestamp_type(), uint16_t confirm_block_count = 0 ); + void start_block( block_timestamp_type time = block_timestamp_type(), uint16_t confirm_block_count = 0, std::function signer = nullptr ); void abort_block(); @@ -206,6 +206,7 @@ namespace eosio { namespace chain { optional pending_producer_block_id()const; const producer_schedule_type& active_producers()const; + std::function pending_producer_signer()const; const producer_schedule_type& pending_producers()const; optional proposed_producers()const; @@ -234,7 +235,7 @@ namespace eosio { namespace chain { void remove_resource_greylist(const account_name &name); // *bos begin* - const global_propertyex_object& get_global_properties2()const; // *bos* + const global_property2_object& get_global_properties2()const; // *bos* void set_name_list(int64_t list, int64_t action, std::vector name_list); // void list_add_name(const int list, const account_name &name); diff --git a/libraries/chain/include/eosio/chain/global_property_object.hpp b/libraries/chain/include/eosio/chain/global_property_object.hpp index 039f9c779dd..6f4f35ffd80 100644 --- a/libraries/chain/include/eosio/chain/global_property_object.hpp +++ b/libraries/chain/include/eosio/chain/global_property_object.hpp @@ -35,9 +35,9 @@ namespace eosio { namespace chain { }; // *bos* - class global_propertyex_object : public chainbase::object + class global_property2_object : public chainbase::object { - OBJECT_CTOR(global_propertyex_object, (cfg)) + OBJECT_CTOR(global_property2_object, (cfg)) id_type id; chain_config2 cfg; @@ -81,11 +81,11 @@ namespace eosio { namespace chain { >; // *bos* - using global_propertyex_multi_index = chainbase::shared_multi_index_container< - global_propertyex_object, + using global_property2_multi_index = chainbase::shared_multi_index_container< + global_property2_object, indexed_by< ordered_unique, - BOOST_MULTI_INDEX_MEMBER(global_propertyex_object, global_propertyex_object::id_type, id) + BOOST_MULTI_INDEX_MEMBER(global_property2_object, global_property2_object::id_type, id) > > >; @@ -95,7 +95,7 @@ CHAINBASE_SET_INDEX_TYPE(eosio::chain::global_property_object, eosio::chain::glo CHAINBASE_SET_INDEX_TYPE(eosio::chain::dynamic_global_property_object, eosio::chain::dynamic_global_property_multi_index) // *bos* -CHAINBASE_SET_INDEX_TYPE(eosio::chain::global_propertyex_object, eosio::chain::global_propertyex_multi_index) +CHAINBASE_SET_INDEX_TYPE(eosio::chain::global_property2_object, eosio::chain::global_property2_multi_index) FC_REFLECT(eosio::chain::dynamic_global_property_object, (global_action_sequence) @@ -105,6 +105,6 @@ FC_REFLECT(eosio::chain::global_property_object, (proposed_schedule_block_num)(proposed_schedule)(configuration) ) // *bos* -FC_REFLECT(eosio::chain::global_propertyex_object, +FC_REFLECT(eosio::chain::global_property2_object, (cfg)(gmr) ) \ No newline at end of file diff --git a/libraries/chain/include/eosio/chain/resource_limits.hpp b/libraries/chain/include/eosio/chain/resource_limits.hpp index 5458db608e7..616deb3f2a0 100644 --- a/libraries/chain/include/eosio/chain/resource_limits.hpp +++ b/libraries/chain/include/eosio/chain/resource_limits.hpp @@ -60,7 +60,13 @@ namespace eosio { namespace chain { namespace resource_limits { void initialize_account( const account_name& account ); void set_block_parameters( const elastic_limit_parameters& cpu_limit_parameters, const elastic_limit_parameters& net_limit_parameters ); - void set_block_parameters_ex( const gmr_parameters& res_parameters ); // *bos* + + /** + * @brief Set the guaranteed minimum resources parameters object + * + * @param res_parameters guaranteed minimum resources parameters object include ram net cpu + */ + void set_gmr_parameters( const gmr_parameters& res_parameters ); // *bos* //guaranteed minimum resources which is abbreviated gmr void update_account_usage( const flat_set& accounts, uint32_t ordinal ); void add_transaction_usage( const flat_set& accounts, uint64_t cpu_usage, uint64_t net_usage, uint32_t ordinal ); diff --git a/libraries/chain/include/eosio/chain/resource_limits_private.hpp b/libraries/chain/include/eosio/chain/resource_limits_private.hpp index 124c0673fc8..877c77e5acb 100644 --- a/libraries/chain/include/eosio/chain/resource_limits_private.hpp +++ b/libraries/chain/include/eosio/chain/resource_limits_private.hpp @@ -208,7 +208,7 @@ namespace eosio { namespace chain { namespace resource_limits { id_type id; - gmr_parameters res_parameters = { config::default_free_ram_limit,config::default_free_cpu_limit, config::default_free_net_limit}; + gmr_parameters res_parameters = { config::default_gmr_ram_limit,config::default_gmr_cpu_limit, config::default_gmr_net_limit}; }; diff --git a/libraries/chain/include/eosio/chain/types.hpp b/libraries/chain/include/eosio/chain/types.hpp index c244a97b08c..028b050a595 100644 --- a/libraries/chain/include/eosio/chain/types.hpp +++ b/libraries/chain/include/eosio/chain/types.hpp @@ -148,6 +148,7 @@ namespace eosio { namespace chain { index_double_object_type, index_long_double_object_type, global_property_object_type, + global_property2_object_type, dynamic_global_property_object_type, block_summary_object_type, transaction_object_type, diff --git a/libraries/chain/resource_limits.cpp b/libraries/chain/resource_limits.cpp index 2cb530597f8..21865ac8676 100644 --- a/libraries/chain/resource_limits.cpp +++ b/libraries/chain/resource_limits.cpp @@ -121,7 +121,8 @@ void resource_limits_manager::set_block_parameters(const elastic_limit_parameter }); } -void resource_limits_manager::set_block_parameters_ex(const gmr_parameters& res_parameters) { +//guaranteed minimum resources which is abbreviated gmr +void resource_limits_manager::set_gmr_parameters(const gmr_parameters& res_parameters) { res_parameters.validate(); const auto& config = _db.get(); _db.modify(config, [&](gmr_config_object& c){ @@ -143,6 +144,9 @@ void resource_limits_manager::update_account_usage(const flat_set& void resource_limits_manager::add_transaction_usage(const flat_set& accounts, uint64_t cpu_usage, uint64_t net_usage, uint32_t time_slot ) { const auto& state = _db.get(); const auto& config = _db.get(); + + + //guaranteed minimum resources which is abbreviated gmr const auto& gmr = _db.get().res_parameters; // *bos* for( const auto& a : accounts ) { diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index e2fe59153d7..f63d836d377 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -211,12 +211,13 @@ class privileged_api : public context_aware_api { } - void set_guaranteed_minmum_resources(int64_t ram_byte, int64_t cpu_us, int64_t net_byte) + void set_guaranteed_minimum_resources(int64_t ram_byte, int64_t cpu_us, int64_t net_byte) { EOS_ASSERT(ram_byte >= 0 && ram_byte <= 100 * 1024, wasm_execution_error, "resouces minimum guarantee for ram limit expected [0, 102400]"); EOS_ASSERT(cpu_us >= 0 && cpu_us <= 100 * 1000, wasm_execution_error, "resouces minimum guarantee for cpu limit expected [0, 100000]"); EOS_ASSERT(net_byte >= 0 && net_byte <= 100 * 1024, wasm_execution_error, "resouces minimum guarantee for net limit expected [0, 102400]"); + //guaranteed minimum resources which is abbreviated gmr context.db.modify(context.control.get_global_properties2(), [&](auto &gprops2) { gprops2.gmr.ram_byte = ram_byte; @@ -1397,6 +1398,14 @@ class context_free_transaction_api : public context_aware_api { return context.get_packed_transaction().size(); } + void get_transaction_id( fc::sha256& id ) { + id = context.trx_context.id; + } + + void get_action_sequence(uint64_t& seq){ + seq = context.global_action_sequence; + } + int expiration() { return context.trx_context.trx.expiration.sec_since_epoch(); } @@ -1679,6 +1688,81 @@ class call_depth_api : public context_aware_api { } }; + +class action_seed_api : public context_aware_api { +public: + action_seed_api(apply_context& ctx) + : context_aware_api(ctx) {} + + int bpsig_action_time_seed(array_ptr sig, size_t siglen) { + auto data = action_timestamp(); + fc::sha256::encoder encoder; + encoder.write(reinterpret_cast(data.data()), data.size()* sizeof(uint32_t)); + auto digest = encoder.result(); + optional signature; + auto block_state = context.control.pending_block_state(); + for (auto& extension: block_state->block->block_extensions) { + if (extension.first != static_cast(block_extension_type::bpsig_action_time_seed)) continue; + EOS_ASSERT(extension.second.size() > 8, transaction_exception, "invalid producer signature in block extensions"); + uint64_t* act_parts = reinterpret_cast(extension.second.data()); + if ( act_parts[0] != context.global_action_sequence) continue; + + auto sig_data = extension.second.data() + 8; + auto sig_size = extension.second.size() - 8; + signature.emplace(); + datastream ds(sig_data, sig_size); + fc::raw::unpack(ds, *signature); + auto check = fc::crypto::public_key(*signature, digest, false); + EOS_ASSERT( check == block_state->block_signing_key, transaction_exception, "wrong expected key different than recovered key" ); + break; + } + bool sign = false; + if (context.control.is_producing_block() && !signature) { + auto signer = context.control.pending_producer_signer(); + if (signer) { + // Producer is producing this block + signature = signer(digest); + sign = true; + } else { + // Non-producer is speculating this block, so skips the signing + // TODO: speculating result will be different from producing result + signature.emplace(); + } + } + EOS_ASSERT(!!signature, transaction_exception, "empty sig action seed"); + auto& s = *signature; + auto sig_size = fc::raw::pack_size(s); + if (siglen == 0) return sig_size; + if (sig_size <= siglen) { + datastream ds(sig, sig_size); + fc::raw::pack(ds, s); + if (sign) { + block_state->block->block_extensions.emplace_back(); + char* act_parts = reinterpret_cast(&context.global_action_sequence); + auto &extension = block_state->block->block_extensions.back(); + extension.first = static_cast(block_extension_type::bpsig_action_time_seed); + extension.second.resize(8 + sig_size); + std::copy(act_parts, act_parts + 8, extension.second.data()); + std::copy((char*)sig, (char*)sig + sig_size, extension.second.data() + 8); + } + return sig_size; + } + return 0; + } +private: + vector action_timestamp() { + auto current = context.control.pending_block_time().time_since_epoch().count(); + current -= current % (config::block_interval_us); + + uint32_t* current_halves = reinterpret_cast(¤t); + uint32_t* act_parts = reinterpret_cast(&context.global_action_sequence); + return vector{act_parts[0],act_parts[1], current_halves[0], current_halves[1]}; + } +}; +REGISTER_INTRINSICS(action_seed_api, +(bpsig_action_time_seed, int(int, int) ) +); + REGISTER_INJECTED_INTRINSICS(call_depth_api, (call_depth_assert, void() ) ); @@ -1738,7 +1822,7 @@ REGISTER_INTRINSICS(privileged_api, (get_blockchain_parameters_packed, int(int, int) ) (set_blockchain_parameters_packed, void(int,int) ) (set_name_list_packed, void(int64_t,int64_t,int,int) ) - (set_guaranteed_minmum_resources, void(int64_t,int64_t,int64_t) ) + (set_guaranteed_minimum_resources, void(int64_t,int64_t,int64_t) ) (is_privileged, int(int64_t) ) (set_privileged, void(int64_t, int) ) ); @@ -1860,6 +1944,8 @@ REGISTER_INTRINSICS(console_api, REGISTER_INTRINSICS(context_free_transaction_api, (read_transaction, int(int, int) ) (transaction_size, int() ) + (get_transaction_id, void(int) ) + (get_action_sequence, void(int) ) (expiration, int() ) (tapos_block_prefix, int() ) (tapos_block_num, int() ) diff --git a/plugins/kafka_plugin/kafka.hpp b/plugins/kafka_plugin/kafka.hpp index fee4c4e8db4..5242ee872e7 100644 --- a/plugins/kafka_plugin/kafka.hpp +++ b/plugins/kafka_plugin/kafka.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index c46452b5fb4..2d60e92a006 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -1071,8 +1071,13 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool } } + signature_provider_type signature_provider; + if (signature_provider_itr != _signature_providers.end()) { + signature_provider = signature_provider_itr->second; + } + chain.abort_block(); - chain.start_block(block_time, blocks_to_confirm); + chain.start_block(block_time, blocks_to_confirm, signature_provider); } FC_LOG_AND_DROP(); const auto& pbs = chain.pending_block_state(); diff --git a/unittests/actiondemo/actiondemo.abi b/unittests/actiondemo/actiondemo.abi new file mode 100644 index 00000000000..172d180bfef --- /dev/null +++ b/unittests/actiondemo/actiondemo.abi @@ -0,0 +1,99 @@ +{ + "____comment": "This file was generated by eosio-abigen. DO NOT EDIT - 2018-11-17T13:26:02", + "version": "eosio::abi/1.0", + "types": [], + "structs": [{ + "name": "seedobj", + "base": "", + "fields": [{ + "name": "id", + "type": "uint64" + },{ + "name": "create", + "type": "time_point" + },{ + "name": "seedstr", + "type": "string" + },{ + "name": "txid", + "type": "string" + },{ + "name": "action", + "type": "uint64" + } + ] + },{ + "name": "args", + "base": "", + "fields": [{ + "name": "loop", + "type": "uint64" + },{ + "name": "num", + "type": "uint64" + } + ] + },{ + "name": "generate", + "base": "", + "fields": [{ + "name": "t", + "type": "args" + } + ] + },{ + "name": "clear", + "base": "", + "fields": [] + },{ + "name": "args_inline", + "base": "", + "fields": [{ + "name": "payer", + "type": "name" + },{ + "name": "in", + "type": "name" + } + ] + },{ + "name": "inlineact", + "base": "", + "fields": [{ + "name": "t", + "type": "args_inline" + } + ] + } + ], + "actions": [{ + "name": "generate", + "type": "generate", + "ricardian_contract": "" + },{ + "name": "clear", + "type": "clear", + "ricardian_contract": "" + },{ + "name": "inlineact", + "type": "inlineact", + "ricardian_contract": "" + } + ], + "tables": [{ + "name": "seedobjs", + "index_type": "i64", + "key_names": [ + "id" + ], + "key_types": [ + "uint64" + ], + "type": "seedobj" + } + ], + "ricardian_clauses": [], + "error_messages": [], + "abi_extensions": [], + "variants": [] +} \ No newline at end of file diff --git a/unittests/actiondemo/actiondemo.cpp b/unittests/actiondemo/actiondemo.cpp new file mode 100644 index 00000000000..3f8a3fcb6e0 --- /dev/null +++ b/unittests/actiondemo/actiondemo.cpp @@ -0,0 +1,106 @@ +#include "actiondemo.hpp" +#include "../../contracts/eosiolib/print.hpp" +#include "../../contracts/eosiolib/types.hpp" +#include "../../contracts/eosiolib/transaction.hpp" + +namespace spaceaction { + + void actiondemo::apply( account_name code, account_name act ) { + + if( code != _self ) + return; + + switch( act ) { + case N(generate): + generate(unpack_action_data()); + return; + case N(inlineact): + inlineact(unpack_action_data()); + case N(clear): + clear(); + return; + } + } + + void actiondemo::clear(){ + //require_auth(_self); + seedobjs table(_self, _self); + auto iter = table.begin(); + while (iter != table.end()) + { + table.erase(iter); + iter = table.begin(); + } + } + + std::string to_hex( const char* d, uint32_t s ) + { + std::string r; + const char* to_hex="0123456789abcdef"; + uint8_t* c = (uint8_t*)d; + for( uint32_t i = 0; i < s; ++i ) + (r += to_hex[(c[i]>>4)]) += to_hex[(c[i] &0x0f)]; + return r; + } + + void actiondemo::generate(const args& t){ + for (int i = 0; i < t.loop; ++i) { + transaction_id_type txid; + get_transaction_id(&txid); + std::string tx = to_hex((char*)&txid.hash, 32); + + uint64_t seq = 0; + get_action_sequence(&seq); + + + size_t szBuff = sizeof(signature); + char buf[szBuff]; + memset(buf,0,szBuff); + size_t size = bpsig_action_time_seed(buf, sizeof(buf)); + eosio_assert(size > 0 && size <= sizeof(buf), "buffer is too small"); + std::string seedstr = to_hex(buf,size); + + + seedobjs table(_self, _self); + uint64_t count = 0; + for (auto itr = table.begin(); itr != table.end(); ++itr) { + ++count; + } + + auto r = table.emplace(_self, [&](auto &a) { + a.id = count + 1; + a.create = eosio::time_point_sec(now()); + a.seedstr = seedstr; + a.txid = tx; + a.action = seq; + }); + print_f("self:%, loop:%, count:%, seedstr:%", name{_self}.to_string(), t.loop, count, r->seedstr); + } + } + + void actiondemo::inlineact(const args_inline& t){ + auto& payer = t.payer; + args gen; + gen.loop = 1; + gen.num = 1; + + generate(gen); + + if(t.in != 0) + { + INLINE_ACTION_SENDER(spaceaction::actiondemo, generate)( t.in, {payer,N(active)}, + { gen}); + INLINE_ACTION_SENDER(spaceaction::actiondemo, generate)( t.in, {payer,N(active)}, + { gen}); + } + + } +} + +extern "C" { +[[noreturn]] void apply(uint64_t receiver, uint64_t code, uint64_t action) { + spaceaction::actiondemo obj(receiver); + obj.apply(code, action); + eosio_exit(0); +} +} \ No newline at end of file diff --git a/unittests/actiondemo/actiondemo.hpp b/unittests/actiondemo/actiondemo.hpp new file mode 100644 index 00000000000..e1d5031bfa5 --- /dev/null +++ b/unittests/actiondemo/actiondemo.hpp @@ -0,0 +1,50 @@ +#pragma once +#include +#include + +namespace spaceaction { + + using namespace eosio; + class actiondemo : public contract { + typedef std::chrono::milliseconds duration; + public: + actiondemo( account_name self ):contract(self){} + + void apply( account_name contract, account_name act ); + + struct args{ + uint64_t loop; + uint64_t num; + }; + //@abi action + void generate(const args& t); + + //@abi action + void clear(); + + + struct args_inline{ + account_name payer; + account_name in; + }; + //@abi action + void inlineact(const args_inline& t); + + public: + // @abi table seedobjs i64 + struct seedobj { + uint64_t id; + time_point create; + std::string seedstr; + std::string txid; + uint64_t action; + + uint64_t primary_key()const { return id; } + EOSLIB_SERIALIZE(seedobj,(id)(create)(seedstr)(txid)(action)) + }; + typedef eosio::multi_index< N(seedobjs), seedobj> seedobjs; + + + }; + +} /// namespace eosio diff --git a/unittests/actiondemo/test.py b/unittests/actiondemo/test.py new file mode 100644 index 00000000000..5ced2b4276c --- /dev/null +++ b/unittests/actiondemo/test.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python3 + +import argparse +import json + +import os + +import subprocess + +import time + +args = None +logFile = None + +unlockTimeout = 999999 + +systemAccounts = [ + 'eosio.bpay', + 'eosio.msig', + 'eosio.names', + 'eosio.ram', + 'eosio.ramfee', + 'eosio.saving', + 'eosio.stake', + 'eosio.token', + 'eosio.vpay', +] + + +def jsonArg(a): + return " '" + json.dumps(a) + "' " + +def run(args): + print('testtool.py:', args) + logFile.write(args + '\n') + if subprocess.call(args, shell=True): + print('testtool.py: exiting because of error') + #sys.exit(1) + +def retry(args): + while True: + print('testtool.py:', args) + logFile.write(args + '\n') + if subprocess.call(args, shell=True): + print('*** Retry') + else: + break + +def background(args): + print('testtool.py:', args) + logFile.write(args + '\n') + return subprocess.Popen(args, shell=True) + +def getOutput(args): + print('testtool.py:', args) + logFile.write(args + '\n') + proc = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE) + return proc.communicate()[0].decode('utf-8') + +def getJsonOutput(args): + print('testtool.py:', args) + logFile.write(args + '\n') + proc = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE) + return json.loads(proc.communicate()[0].decode('utf-8')) + +def sleep(t): + print('sleep', t, '...') + time.sleep(t) + print('resume') + +def startWallet(): + run('rm -rf ' + os.path.abspath(args.wallet_dir)) + run('mkdir -p ' + os.path.abspath(args.wallet_dir)) + background(args.keosd + ' --unlock-timeout %d --http-server-address 127.0.0.1:6666 --wallet-dir %s' % (unlockTimeout, os.path.abspath(args.wallet_dir))) + sleep(4) + run(args.cleos + 'wallet create --file ./unlock.key ' ) + +def importKeys(): + run(args.cleos + 'wallet import --private-key ' + args.private_key) + +# def createStakedAccounts(b, e): +# for i in range(b, e): +# a = accounts[i] +# stake = 100 +# run(args.cleos + 'system newaccount eosio --transfer ' + a['name'] + ' ' + a['pub'] + ' --stake-net "' + stake + '" --stake-cpu "' + stake + '"') + + +def stepStartWallet(): + startWallet() + importKeys() + # run('rm -rf ~/.local/share/eosio/nodeos/data ') + run("rm -rf ./data/*") + background(args.nodeos + ' -e -p eosio --blocks-dir ./data/block/ --genesis-json %s --config-dir ./ --data-dir ./data/ --plugin eosio::http_plugin --plugin eosio::chain_api_plugin --plugin eosio::producer_plugin --plugin eosio::history_api_plugin> eos.log 2>&1 &' % args.genesis) + run("rm -rf ./data2/*") + background(args.nodeos + ' --blocks-dir ./data2/block/ --genesis-json %s --data-dir ./data2/ --config-dir ./ --p2p-peer-address 127.0.0.1:9876 --http-server-address 0.0.0.0:8001 --p2p-listen-endpoint 0.0.0.0:9001 --plugin eosio::http_plugin --plugin eosio::chain_api_plugin --plugin eosio::producer_plugin --plugin eosio::history_api_plugin > eos2.log 2>&1 &' % args.genesis) + sleep(30) + + +def createAccounts(): + for a in systemAccounts: + run(args.cleos + 'create account eosio ' + a + ' ' + args.public_key) + run(args.cleos + 'set contract eosio.token ' + args.contracts_dir + 'eosio.token/') + run(args.cleos + 'set contract eosio.msig ' + args.contracts_dir + 'eosio.msig/') + run(args.cleos + 'push action eosio.token create \'["eosio", "10000000000.0000 %s"]\' -p eosio.token' % (args.symbol)) + run(args.cleos + 'push action eosio.token issue \'["eosio", "%s %s", "memo"]\' -p eosio' % ("1000000.0000", args.symbol)) + retry(args.cleos + 'set contract eosio ' + args.contracts_dir + 'eosio.system/ -p eosio') + sleep(1) + run(args.cleos + 'push action eosio setpriv' + jsonArg(['eosio.msig', 1]) + '-p eosio@active') + + for a in accounts: + run(args.cleos + 'system newaccount --stake-net "10.0000 %s" --stake-cpu "10.0000 %s" --buy-ram-kbytes 80 eosio ' %(args.symbol,args.symbol) + a + ' ' + args.public_key) + + run(args.cleos + 'system newaccount --stake-net "10.0000 %s" --stake-cpu "10.0000 %s" --buy-ram-kbytes 80 eosio '%(args.symbol,args.symbol) + 'cochaintoken' + ' ' + args.public_key) + + run(args.cleos + 'system buyram eosio %s -k 80000 -p eosio ' % args.contract ) + run(args.cleos + 'system delegatebw eosio %s "1000.0000 SYS" "1000.0000 SYS"'% args.contract ) + + run(args.cleos + 'system buyram eosio %s -k 80000 -p eosio ' % args.contract2 ) + run(args.cleos + 'system delegatebw eosio %s "1000.0000 SYS" "1000.0000 SYS"'% args.contract2 ) + +# stepIssueToken() +# +# +# def stepIssueToken(): +# run(args.cleos + 'push action eosio.token issue \'["eosio", "%s %s", "memo"]\' -p eosio' % ("1000000.0000", args.symbol)) +# for i in accounts: +# run(args.cleos + 'push action eosio.token issue \'["%s", "%s %s", "memo"]\' -p eosio' % (i, "1000000.0000", args.symbol)) +# +# sleep(1) + + +def stepKillAll(): + run('killall keosd nodeos || true') + sleep(1.5) +# Command Line Arguments + +def stepInitCaee(): + print ("=========================== set contract caee ===========================" ) + run(args.cleos + 'set contract %s ../actiondemo' %args.contract ) + run(args.cleos + 'set contract %s ../actiondemo' %args.contract2 ) + run(args.cleos + 'set account permission %s active \'{"threshold": 1,"keys": [{"key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV","weight": 1}],"accounts": [{"permission":{"actor":"%s","permission":"eosio.code"},"weight":1}]}\' ' % (args.contract,args.contract)) + print ("sleep 5") + + +def stepClear(): + print ("=========================== set contract clear ===========================" ) + run(args.cleos + 'push action %s clear "[]" -p %s ' %(args.contract, args.contract)) + run(args.cleos + 'get table %s %s seedobjs' %(args.contract, args.contract) ) + run(args.cleos + 'push action %s clear "[]" -p %s ' %(args.contract2, args.contract2)) + run(args.cleos + 'get table %s %s seedobjs' %(args.contract2, args.contract2) ) + print ("sleep 5") + + +def stepGenerate(): + print ("=========================== set contract stepGenerate ===========================" ) + # run(args.cleos + 'push action %s generate \'[{"loop":1, "num":1}]\' -p %s ' %(args.contract, args.contract)) + run(args.cleos + 'push action %s inlineact \'[{"payer":"%s", "in":"%s"}]\' -p %s ' %(args.contract,args.contract,args.contract2, args.contract)) + run(args.cleos + 'get table %s %s seedobjs' %(args.contract, args.contract) ) + run(args.cleos + 'get table %s %s seedobjs' %(args.contract2, args.contract2) ) + print ("sleep 5") + + +parser = argparse.ArgumentParser() + +commands = [ + ('k', 'kill', stepKillAll, True, ""), + ('w', 'wallet', stepStartWallet, True, "Start keosd, create wallet"), + ('s', 'sys', createAccounts, True, "Create all accounts"), + ('i', 'init', stepInitCaee, True, "stepInitCaee"), + ('c', 'clear', stepClear, True, "stepInitCaee"), + ('g', 'generate', stepGenerate, True, "stepInitCaee"), +] + +parser.add_argument('--public-key', metavar='', help="EOSIO Public Key", default='EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV', dest="public_key") +parser.add_argument('--private-Key', metavar='', help="EOSIO Private Key", default='5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3', dest="private_key") +parser.add_argument('--cleos', metavar='', help="Cleos command", default='../../build/programs/cleos/cleos --wallet-url http://127.0.0.1:6666 ') +parser.add_argument('--nodeos', metavar='', help="Path to nodeos binary", default='../../build/programs/nodeos/nodeos ') +parser.add_argument('--keosd', metavar='', help="Path to keosd binary", default='../../build/programs/keosd/keosd ') +parser.add_argument('--contracts-dir', metavar='', help="Path to contracts directory", default='../../build/contracts/') +parser.add_argument('--nodes-dir', metavar='', help="Path to nodes diretodctory", default='./') +parser.add_argument('--genesis', metavar='', help="Path to genesis.json", default="./genesis.json") +parser.add_argument('--wallet-dir', metavar='', help="Path to wallet directory", default='./wallet/') +parser.add_argument('--log-path', metavar='', help="Path to log file", default='./output.log') +# parser.add_argument('--symbol', metavar='', help="The eosio.system symbol", default='SYS') +parser.add_argument('-a', '--all', action='store_true', help="Do everything marked with (*)") +#parser.add_argument('-H', '--http-port', type=int, default=8888, metavar='', help='HTTP port for cleos') + +for (flag, command, function, inAll, help) in commands: + prefix = '' + if inAll: prefix += '*' + if prefix: help = '(' + prefix + ') ' + help + if flag: + parser.add_argument('-' + flag, '--' + command, action='store_true', help=help, dest=command) + else: + parser.add_argument('--' + command, action='store_true', help=help, dest=command) + +args = parser.parse_args() + +args.cleos += '--url http://127.0.0.1:8888 ' +args.symbol = 'SYS' +args.contract = 'caee' +args.contract2 = 'caee2' + + +accnum = 26 +accounts = [] +# for i in range(97,97+accnum): +# accounts.append("user%c"% chr(i)) +# accounts.append("payman") +accounts.append(args.contract) +accounts.append(args.contract2) + +logFile = open(args.log_path, 'a') +logFile.write('\n\n' + '*' * 80 + '\n\n\n') + +haveCommand = False +for (flag, command, function, inAll, help) in commands: + if getattr(args, command) or inAll and args.all: + if function: + haveCommand = True + function() +if not haveCommand: + print('testtool.py: Tell me what to do. -a does almost everything. -h shows options.') \ No newline at end of file diff --git a/unittests/database_gmr_blklst_tests.cpp b/unittests/database_gmr_blklst_tests.cpp new file mode 100644 index 00000000000..f448ba5a172 --- /dev/null +++ b/unittests/database_gmr_blklst_tests.cpp @@ -0,0 +1,309 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef NON_VALIDATING_TEST +#define TESTER tester +#else +#define TESTER validating_tester +#endif + +using namespace eosio::chain; +using namespace eosio::testing; +namespace bfs = boost::filesystem; + +BOOST_AUTO_TEST_SUITE(database_gmr_blklst_tests) + +vector parse_list_string(string items) +{ + vector item_list; + vector itemlist; + boost::split(itemlist, items, boost::is_any_of(",")); + for (string item : itemlist) + { + item_list.push_back(string_to_name(item.c_str())); + } + + return item_list; +} + +// Simple tests of undo infrastructure +BOOST_AUTO_TEST_CASE(list_config_parse_test) +{ + try + { + TESTER test; + + string str = "alice,bob,tom"; + vector list = parse_list_string(str); + BOOST_TEST(list.size() > 0); + account_name n = N(a); + if (list.size() > 0) + { + n = *(list.begin()); + } + + BOOST_TEST(n != N(a)); + BOOST_TEST(n == N(alice)); + } + FC_LOG_AND_RETHROW() +} + +// Simple tests of undo infrastructure +BOOST_AUTO_TEST_CASE(set_name_list_test) +{ + try + { + TESTER test; + // Bypass read-only restriction on state DB access for this unit test which really needs to mutate the DB to properly conduct its test. + chainbase::database &db = const_cast(test.control->db()); + + auto ses = db.start_undo_session(true); + + string str = "alice,bob,tom"; + vector list = parse_list_string(str); + + flat_set nameset(list.begin(), list.end()); + + test.control->set_actor_blacklist(nameset); + + // Make sure we can retrieve that account by name + const global_property2_object &ptr = db.get(); + + // Create an account + db.modify(ptr, [&](global_property2_object &a) { + a.cfg.actor_blacklist = {N(a)}; + a.cfg.contract_blacklist = {N(a)}; + a.cfg.resource_greylist = {N(a)}; + }); + + int64_t lt = static_cast(list_type::actor_blacklist_type); + int64_t lat = static_cast(list_action_type::insert_type); + test.control->set_name_list(lt, lat, list); + + + + + const flat_set& ab = test.control->get_actor_blacklist(); + const flat_set& cb = test.control->get_contract_blacklist(); + const flat_set& rg = test.control->get_resource_greylist(); + + + + + auto convert_names = [&](const shared_vector& namevec, flat_set& nameset) -> void { + for(const auto& a :namevec) + { + nameset.insert(uint64_t(a)); + } + }; + + flat_set aab; + flat_set acb; + flat_set arg; + + const global_property2_object &ptr1 = db.get(); + chain_config2 c = ptr1.cfg; + + BOOST_TEST(c.actor_blacklist.size() == 4); + BOOST_TEST(ab.size() == 4); + + convert_names(c.actor_blacklist, aab); + convert_names(c.contract_blacklist, acb); + convert_names(c.resource_greylist, arg); + + + if (c.actor_blacklist.size() == 4) + { + + bool b = (aab.find(N(a)) != aab.end()); + BOOST_TEST(b); + } + + bool d = ab.find(N(a)) != ab.end(); + BOOST_TEST(d); + bool m = aab.find(N(alice)) != aab.end(); + BOOST_TEST(m); + + // Undo creation of the account + ses.undo(); + + + } + FC_LOG_AND_RETHROW() +} + +// Simple tests of undo infrastructure +BOOST_AUTO_TEST_CASE(actor_blacklist_config_test) +{ + try + { + TESTER test; + // Bypass read-only restriction on state DB access for this unit test which really needs to mutate the DB to properly conduct its test. + chainbase::database &db = const_cast(test.control->db()); + + auto ses = db.start_undo_session(true); + + // string str= "alice,bob,tom"; + // vector list = parse_list_string(str); + + // Make sure we can retrieve that account by name + const global_property2_object &ptr = db.get(); + + // Create an account + db.modify(ptr, [&](global_property2_object &a) { + a.cfg.actor_blacklist = {N(a)}; + }); + + chain_config2 a = ptr.cfg; + + account_name v; + if (a.actor_blacklist.size() > 0) + { + v = *(a.actor_blacklist.begin()); + } + + std::size_t s = a.actor_blacklist.size(); + + BOOST_TEST(1 == s); + + BOOST_TEST(v == N(a)); + + // Undo creation of the account + ses.undo(); + + + } + FC_LOG_AND_RETHROW() +} + +// Simple tests of undo infrastructure +BOOST_AUTO_TEST_CASE(contract_blacklist_config_test) +{ + try + { + TESTER test; + // Bypass read-only restriction on state DB access for this unit test which really needs to mutate the DB to properly conduct its test. + chainbase::database &db = const_cast(test.control->db()); + + auto ses = db.start_undo_session(true); + + // string str= "alice,bob,tom"; + // vector list = parse_list_string(str); + + // Make sure we can retrieve that account by name + const global_property2_object &ptr = db.get(); + + // Create an account + db.modify(ptr, [&](global_property2_object &a) { + a.cfg.contract_blacklist = {N(a)}; + }); + + chain_config2 a = ptr.cfg; + + account_name v ; + if (a.contract_blacklist.size() > 0) + { + v = *(a.contract_blacklist.begin()); + } + + std::size_t s = a.contract_blacklist.size(); + + BOOST_TEST(1 == s); + + BOOST_TEST(v == N(a)); + + // Undo creation of the account + ses.undo(); + + + } + FC_LOG_AND_RETHROW() +} + +// Simple tests of undo infrastructure +BOOST_AUTO_TEST_CASE(resource_greylist_config_test) +{ + try + { + TESTER test; + // Bypass read-only restriction on state DB access for this unit test which really needs to mutate the DB to properly conduct its test. + chainbase::database &db = const_cast(test.control->db()); + + auto ses = db.start_undo_session(true); + + // string str= "alice,bob,tom"; + // vector list = parse_list_string(str); + + // Make sure we can retrieve that account by name + const global_property2_object &ptr = db.get(); + + // Create an account + db.modify(ptr, [&](global_property2_object &a) { + a.cfg.resource_greylist = {N(a)}; + }); + + chain_config2 a = ptr.cfg; + + account_name v ; + if (a.resource_greylist.size() > 0) + { + v = *(a.resource_greylist.begin()); + } + + std::size_t s = a.resource_greylist.size(); + + BOOST_TEST(1 == s); + + BOOST_TEST(v == N(a)); + + // Undo creation of the account + ses.undo(); + + } + FC_LOG_AND_RETHROW() +} + +// Simple tests of undo infrastructure +BOOST_AUTO_TEST_CASE(gmrource_limit_config_test) +{ + try + { + TESTER test; + // Bypass read-only restriction on state DB access for this unit test which really needs to mutate the DB to properly conduct its test. + chainbase::database &db = const_cast(test.control->db()); + + auto ses = db.start_undo_session(true); + + // Make sure we can retrieve that account by name + const global_property2_object &ptr = db.get(); + + // Create an account + db.modify(ptr, [&](global_property2_object &a) { + a.gmr.cpu_us = 100; + a.gmr.net_byte = 1024; + a.gmr.ram_byte = 1; + }); + + BOOST_TEST(ptr.gmr.cpu_us == 100); + BOOST_TEST(ptr.gmr.net_byte == 1024); + BOOST_TEST(ptr.gmr.ram_byte == 1); + + // Undo creation of the account + ses.undo(); + + + } + FC_LOG_AND_RETHROW() +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/unittests/gmr_test.cpp b/unittests/gmr_test.cpp new file mode 100644 index 00000000000..3874552d0e5 --- /dev/null +++ b/unittests/gmr_test.cpp @@ -0,0 +1,234 @@ +#include +#include +#include +#include +#include +#include + +#include +#ifdef NON_VALIDATING_TEST +#define TESTER tester +#else +#define TESTER validating_tester +#endif + +using namespace eosio::chain::resource_limits; +using namespace eosio::testing; +using namespace eosio::chain; + +class gmr_fixture : private chainbase_fixture<512 * 1024>, public resource_limits_manager +{ + public: + gmr_fixture() + : chainbase_fixture(), resource_limits_manager(*chainbase_fixture::_db) + { + add_indices(); + initialize_database(); + } + + ~gmr_fixture() {} + + chainbase::database::session start_session() + { + return chainbase_fixture::_db->start_undo_session(true); + } +}; + +BOOST_AUTO_TEST_SUITE(gmr_test) + +BOOST_FIXTURE_TEST_CASE(check_block_limits_cpu, gmr_fixture) +try +{ + const account_name account(1); + const uint64_t increment = 10000; + initialize_account(account); + set_account_limits(account, 1000, 0, 0); + initialize_account(N(dan)); + initialize_account(N(everyone)); + set_account_limits(N(dan), 0, 0, 10000); + set_account_limits(N(everyone), 0, 0, 10000000000000ll); + + + process_account_limit_updates(); + + // uint16_t gmrource_limit_per_day = 100; + + // Bypass read-only restriction on state DB access for this unit test which really needs to mutate the DB to properly conduct its test. + + // test.control->startup(); + + // // Make sure we can no longer find + + const uint64_t expected_iterations = config::default_gmr_cpu_limit / increment; + + for (int idx = 0; idx < expected_iterations-1; idx++) + { + add_transaction_usage({account}, increment, 0, 0); + process_block_usage(idx); + } + + auto arl = get_account_cpu_limit_ex(account, true); + + BOOST_TEST(arl.available >= 9997); + BOOST_REQUIRE_THROW(add_transaction_usage({account}, increment, 0, 0), block_resource_exhausted); +} +FC_LOG_AND_RETHROW(); + +BOOST_FIXTURE_TEST_CASE(check_block_limits_cpu_lowerthan, gmr_fixture) +try +{ + const account_name account(1); + const uint64_t increment = 10000; + initialize_account(account); + set_account_limits(account, increment, 0, 0); + initialize_account(N(dan)); + initialize_account(N(everyone)); + set_account_limits(N(dan), 0, 0, 10000); + set_account_limits(N(everyone), 0, 0, 10000000000000ll); + process_account_limit_updates(); + + const uint64_t expected_iterations = config::default_gmr_cpu_limit / increment; + + for (int idx = 0; idx < expected_iterations-1; idx++) + { + add_transaction_usage({account}, increment, 0, 0); + process_block_usage(idx); + } + + auto arl = get_account_cpu_limit_ex(account, true); + BOOST_TEST(arl.available >= 9997); + + // BOOST_REQUIRE_THROW(add_transaction_usage({account}, increment, 0, 0), block_resource_exhausted); +} +FC_LOG_AND_RETHROW(); + +BOOST_FIXTURE_TEST_CASE(check_block_limits_net_lowerthan, gmr_fixture) +try +{ + const account_name account(1); + const uint64_t increment = 1000; + initialize_account(account); + set_account_limits(account, increment, 0, 0); + initialize_account(N(dan)); + initialize_account(N(everyone)); + set_account_limits(N(dan), 0, 10000, 0); + set_account_limits(N(everyone), 0, 10000000000000ll, 0); + process_account_limit_updates(); + + const uint64_t expected_iterations = config::default_gmr_net_limit / increment; + + for (int idx = 0; idx < expected_iterations-1; idx++) + { + add_transaction_usage({account}, 0, increment, 0); + process_block_usage(idx); + } + + auto arl = get_account_net_limit_ex(account, true); + BOOST_TEST(arl.available >= 1238); + + // BOOST_REQUIRE_THROW(add_transaction_usage({account}, 0,increment, 0), block_resource_exhausted); +} +FC_LOG_AND_RETHROW(); + +BOOST_FIXTURE_TEST_CASE(check_block_limits_ram, gmr_fixture) +try +{ + set_gmr_parameters( + { 1024, 200000,10240} + ); + + const account_name account(1); + const uint64_t increment = 1000; + initialize_account(account); + set_account_limits(account, increment, 10, 10); + initialize_account(N(dan)); + initialize_account(N(everyone)); + set_account_limits(N(dan), 0, 10000, 0); + set_account_limits(N(everyone), 0, 10000000000000ll, 0); + process_account_limit_updates(); + + const uint64_t expected_iterations = config::default_gmr_net_limit / increment; + + //for ( + int idx = 0;// idx < expected_iterations-1; idx++) + { + add_transaction_usage({account}, 0, increment, 0); + process_block_usage(idx); + } + + auto arl = get_account_net_limit_ex(account, true); + BOOST_TEST(arl.available >= 0); + + int64_t ram_bytes; + int64_t net_weight; + int64_t cpu_weight; + bool raw = false; + get_account_limits(account, ram_bytes, net_weight, cpu_weight, raw); + + BOOST_TEST(1024*2 == ram_bytes); + BOOST_TEST(10 == net_weight); + BOOST_TEST(10 == cpu_weight); + + + raw = true; + get_account_limits(account, ram_bytes, net_weight, cpu_weight, raw); + + BOOST_TEST(1024 == ram_bytes); + BOOST_TEST(10 == net_weight); + BOOST_TEST(10 == cpu_weight); + + // BOOST_REQUIRE_THROW(add_transaction_usage({account}, 0,increment, 0), block_resource_exhausted); +} +FC_LOG_AND_RETHROW(); + + + +BOOST_FIXTURE_TEST_CASE(get_account_limits_res, gmr_fixture) +try +{ + const account_name account(1); + const uint64_t increment = 1000; + initialize_account(account); + set_account_limits(account, increment+24, 0, 0); + initialize_account(N(dan)); + initialize_account(N(everyone)); + set_account_limits(N(dan), 0, 10000, 0); + set_account_limits(N(everyone), 0, 10000000000000ll, 0); + process_account_limit_updates(); + + const uint64_t expected_iterations = config::default_gmr_net_limit / increment; + + for (int idx = 0; idx < expected_iterations-1; idx++) + { + add_transaction_usage({account}, 0, increment, 0); + process_block_usage(idx); + } + + auto arl = get_account_net_limit_ex(account, true); + BOOST_TEST(arl.available > 0); + + int64_t ram_bytes; + int64_t net_weight; + int64_t cpu_weight; + bool raw = false; + get_account_limits(account, ram_bytes, net_weight, cpu_weight, raw); + + BOOST_TEST(1024 == ram_bytes); + BOOST_TEST(0 == net_weight); + BOOST_TEST(0 == cpu_weight); + + + raw = true; + get_account_limits(account, ram_bytes, net_weight, cpu_weight, raw); + + BOOST_TEST(1024 == ram_bytes); + BOOST_TEST(0 == net_weight); + BOOST_TEST(0 == cpu_weight); + + + // BOOST_REQUIRE_THROW(add_transaction_usage({account}, 0,increment, 0), block_resource_exhausted); +} +FC_LOG_AND_RETHROW(); + + +BOOST_AUTO_TEST_SUITE_END()