From 3095d85e3f57c25908587c15b0cdd54c2d3fbc66 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 11 Dec 2018 22:18:48 -0600 Subject: [PATCH 01/23] Switch interface from packed_transaction_ptr to transaction_metadata_ptr --- plugins/bnet_plugin/bnet_plugin.cpp | 4 ++- .../include/eosio/chain/plugin_interface.hpp | 6 ++-- plugins/chain_plugin/chain_plugin.cpp | 10 +++--- .../eosio/chain_plugin/chain_plugin.hpp | 2 +- plugins/net_plugin/net_plugin.cpp | 30 +++++++++-------- plugins/producer_plugin/producer_plugin.cpp | 32 +++++++++---------- 6 files changed, 46 insertions(+), 38 deletions(-) diff --git a/plugins/bnet_plugin/bnet_plugin.cpp b/plugins/bnet_plugin/bnet_plugin.cpp index ce0a096b531..9cf267b6f0f 100644 --- a/plugins/bnet_plugin/bnet_plugin.cpp +++ b/plugins/bnet_plugin/bnet_plugin.cpp @@ -1558,6 +1558,8 @@ namespace eosio { if( mark_transaction_known_by_peer( id ) ) return; - app().get_channel().publish(p); + auto ptr = std::make_shared(p); + + app().get_channel().publish(ptr); } } /// namespace eosio diff --git a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp index 7303768cab4..5a0c7bc11fd 100644 --- a/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp +++ b/plugins/chain_interface/include/eosio/chain/plugin_interface.hpp @@ -45,19 +45,19 @@ namespace eosio { namespace chain { namespace plugin_interface { namespace incoming { namespace channels { using block = channel_decl; - using transaction = channel_decl; + using transaction = channel_decl; } namespace methods { // synchronously push a block/trx to a single provider using block_sync = method_decl; - using transaction_async = method_decl), first_provider_policy>; + using transaction_async = method_decl), first_provider_policy>; } } namespace compat { namespace channels { - using transaction_ack = channel_decl>; + using transaction_ack = channel_decl>; } } diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index cfe4ea38268..6eeeb5a5082 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -756,10 +756,10 @@ void chain_plugin::accept_block(const signed_block_ptr& block ) { } void chain_plugin::accept_transaction(const chain::packed_transaction& trx, next_function next) { - my->incoming_transaction_async_method(std::make_shared(trx), false, std::forward(next)); + my->incoming_transaction_async_method(std::make_shared(std::make_shared(trx)), false, std::forward(next)); } -void chain_plugin::accept_transaction(const chain::packed_transaction_ptr& trx, next_function next) { +void chain_plugin::accept_transaction(const chain::transaction_metadata_ptr& trx, next_function next) { my->incoming_transaction_async_method(trx, false, std::forward(next)); } @@ -1544,18 +1544,19 @@ void read_write::push_transaction(const read_write::push_transaction_params& par try { auto pretty_input = std::make_shared(); auto resolver = make_resolver(this, abi_serializer_max_time); + transaction_metadata_ptr ptrx; try { abi_serializer::from_variant(params, *pretty_input, resolver, abi_serializer_max_time); + ptrx = std::make_shared( pretty_input ); } EOS_RETHROW_EXCEPTIONS(chain::packed_transaction_type_exception, "Invalid packed transaction") - app().get_method()(pretty_input, true, [this, next](const fc::static_variant& result) -> void{ + app().get_method()(ptrx, true, [this, next](const fc::static_variant& result) -> void{ if (result.contains()) { next(result.get()); } else { auto trx_trace_ptr = result.get(); try { - chain::transaction_id_type id = trx_trace_ptr->id; fc::variant output; try { output = db.to_variant_with_abi( *trx_trace_ptr, abi_serializer_max_time ); @@ -1563,6 +1564,7 @@ void read_write::push_transaction(const read_write::push_transaction_params& par output = *trx_trace_ptr; } + const chain::transaction_id_type& id = trx_trace_ptr->id; next(read_write::push_transaction_results{id, output}); } CATCH_AND_CALL(next); } diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 0f4af5dcd27..cf20781fd44 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -664,7 +664,7 @@ class chain_plugin : public plugin { void accept_block( const chain::signed_block_ptr& block ); void accept_transaction(const chain::packed_transaction& trx, chain::plugin_interface::next_function next); - void accept_transaction(const chain::packed_transaction_ptr& trx, chain::plugin_interface::next_function next); + void accept_transaction(const chain::transaction_metadata_ptr& trx, chain::plugin_interface::next_function next); bool block_is_on_preferred_chain(const chain::block_id_type& block_id); diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 34a4fd61e47..7f7cd607fad 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -168,7 +168,7 @@ namespace eosio { void send_all( const std::shared_ptr>& send_buffer, VerifierFunc verify ); void accepted_block(const block_state_ptr&); - void transaction_ack(const std::pair&); + void transaction_ack(const std::pair&); bool is_valid( const handshake_message &msg); @@ -631,7 +631,7 @@ namespace eosio { std::multimap received_blocks; std::multimap received_transactions; - void bcast_transaction(const packed_transaction_ptr& trx); + void bcast_transaction(const transaction_metadata_ptr& trx); void rejected_transaction(const transaction_id_type& msg); void bcast_block(const block_state_ptr& bs); void rejected_block(const block_id_type& id); @@ -1596,9 +1596,9 @@ namespace eosio { received_blocks.erase(range.first, range.second); } - void dispatch_manager::bcast_transaction(const packed_transaction_ptr& trx) { + void dispatch_manager::bcast_transaction(const transaction_metadata_ptr& ptrx) { std::set skips; - transaction_id_type id = trx->id(); + const auto& id = ptrx->id; auto range = received_transactions.equal_range(id); for (auto org = range.first; org != range.second; ++org) { @@ -1611,13 +1611,14 @@ namespace eosio { return; } - time_point_sec trx_expiration = trx->expiration(); + time_point_sec trx_expiration = ptrx->packed_trx->expiration(); + const packed_transaction& trx = *ptrx->packed_trx; // this implementation is to avoid copy of packed_transaction to net_message int which = 8; // matches which of net_message for packed_transaction uint32_t which_size = fc::raw::pack_size( unsigned_int( which )); - uint32_t payload_size = which_size + fc::raw::pack_size( *trx ); + uint32_t payload_size = which_size + fc::raw::pack_size( trx ); char* header = reinterpret_cast(&payload_size); size_t header_size = sizeof(payload_size); @@ -1627,7 +1628,7 @@ namespace eosio { fc::datastream ds( buff->data(), buffer_size); ds.write( header, header_size ); fc::raw::pack( ds, unsigned_int( which )); - fc::raw::pack( ds, *trx ); + fc::raw::pack( ds, trx ); node_transaction_state nts = {id, trx_expiration, 0, buff}; my_impl->local_txns.insert(std::move(nts)); @@ -2358,28 +2359,31 @@ namespace eosio { fc_dlog(logger, "got a txn during sync - dropping"); return; } - transaction_id_type tid = trx->id(); + + auto ptrx = std::make_shared( trx ); + const auto& tid = ptrx->id; + c->cancel_wait(); if(local_txns.get().find(tid) != local_txns.end()) { fc_dlog(logger, "got a duplicate transaction - dropping"); return; } dispatcher->recv_transaction(c, tid); - chain_plug->accept_transaction(trx, [c, this, trx](const static_variant& result) { + chain_plug->accept_transaction(ptrx, [c, this, ptrx](const static_variant& result) { if (result.contains()) { peer_dlog(c, "bad packed_transaction : ${m}", ("m",result.get()->what())); } else { auto trace = result.get(); if (!trace->except) { fc_dlog(logger, "chain accepted transaction"); - this->dispatcher->bcast_transaction(trx); + this->dispatcher->bcast_transaction(ptrx); return; } peer_elog(c, "bad packed_transaction : ${m}", ("m",trace->except->what())); } - dispatcher->rejected_transaction(trx->id()); + dispatcher->rejected_transaction(ptrx->id); }); } @@ -2572,8 +2576,8 @@ namespace eosio { dispatcher->bcast_block(block); } - void net_plugin_impl::transaction_ack(const std::pair& results) { - transaction_id_type id = results.second->id(); + void net_plugin_impl::transaction_ack(const std::pair& results) { + const auto& id = results.second->id; if (results.first) { fc_ilog(logger,"signaled NACK, trx-id = ${id} : ${why}",("id", id)("why", results.first->to_detail_string())); dispatcher->rejected_transaction(id); diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index ad80df46cee..1a1d7d0d515 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -343,9 +343,9 @@ class producer_plugin_impl : public std::enable_shared_from_this>> _pending_incoming_transactions; + std::deque>> _pending_incoming_transactions; - void on_incoming_transaction_async(const packed_transaction_ptr& trx, bool persist_until_expired, next_function next) { + void on_incoming_transaction_async(const transaction_metadata_ptr& trx, bool persist_until_expired, next_function next) { chain::controller& chain = chain_plug->chain(); if (!chain.pending_block_state()) { _pending_incoming_transactions.emplace_back(trx, persist_until_expired, next); @@ -357,34 +357,34 @@ class producer_plugin_impl : public std::enable_shared_from_this& response) { next(response); if (response.contains()) { - _transaction_ack_channel.publish(std::pair(response.get(), trx)); + _transaction_ack_channel.publish(std::pair(response.get(), trx)); if (_pending_block_mode == pending_block_mode::producing) { fc_dlog(_trx_trace_log, "[TRX_TRACE] Block ${block_num} for producer ${prod} is REJECTING tx: ${txid} : ${why} ", ("block_num", chain.head_block_num() + 1) ("prod", chain.pending_block_state()->header.producer) - ("txid", trx->id()) + ("txid", trx->id) ("why",response.get()->what())); } else { fc_dlog(_trx_trace_log, "[TRX_TRACE] Speculative execution is REJECTING tx: ${txid} : ${why} ", - ("txid", trx->id()) + ("txid", trx->id) ("why",response.get()->what())); } } else { - _transaction_ack_channel.publish(std::pair(nullptr, trx)); + _transaction_ack_channel.publish(std::pair(nullptr, trx)); if (_pending_block_mode == pending_block_mode::producing) { fc_dlog(_trx_trace_log, "[TRX_TRACE] Block ${block_num} for producer ${prod} is ACCEPTING tx: ${txid}", ("block_num", chain.head_block_num() + 1) ("prod", chain.pending_block_state()->header.producer) - ("txid", trx->id())); + ("txid", trx->id)); } else { fc_dlog(_trx_trace_log, "[TRX_TRACE] Speculative execution is ACCEPTING tx: ${txid}", - ("txid", trx->id())); + ("txid", trx->id)); } } }; - auto id = trx->id(); - if( fc::time_point(trx->expiration()) < block_time ) { + const auto& id = trx->id; + if( fc::time_point(trx->packed_trx->expiration()) < block_time ) { send_response(std::static_pointer_cast(std::make_shared(FC_LOG_MESSAGE(error, "expired transaction ${id}", ("id", id)) ))); return; } @@ -402,7 +402,7 @@ class producer_plugin_impl : public std::enable_shared_from_this(trx), deadline); + auto trace = chain.push_transaction(trx, deadline); if (trace->except) { if (failure_is_subjective(*trace->except, deadline_is_subjective)) { _pending_incoming_transactions.emplace_back(trx, persist_until_expired, next); @@ -410,10 +410,10 @@ class producer_plugin_impl : public std::enable_shared_from_thisheader.producer) - ("txid", trx->id())); + ("txid", trx->id)); } else { fc_dlog(_trx_trace_log, "[TRX_TRACE] Speculative execution COULD NOT FIT tx: ${txid} RETRYING", - ("txid", trx->id())); + ("txid", trx->id)); } } else { auto e_ptr = trace->except->dynamic_copy_exception(); @@ -423,7 +423,7 @@ class producer_plugin_impl : public std::enable_shared_from_thisid(), trx->expiration()}); + _persistent_transactions.insert(transaction_id_with_expiry{trx->id, trx->packed_trx->expiration()}); } send_response(trace); } @@ -682,7 +682,7 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ } FC_LOG_AND_DROP(); }); - my->_incoming_transaction_subscription = app().get_channel().subscribe([this](const packed_transaction_ptr& trx){ + my->_incoming_transaction_subscription = app().get_channel().subscribe([this](const transaction_metadata_ptr& trx){ try { my->on_incoming_transaction_async(trx, false, [](const auto&){}); } FC_LOG_AND_DROP(); @@ -692,7 +692,7 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ my->on_incoming_block(block); }); - my->_incoming_transaction_async_provider = app().get_method().register_provider([this](const packed_transaction_ptr& trx, bool persist_until_expired, next_function next) -> void { + my->_incoming_transaction_async_provider = app().get_method().register_provider([this](const transaction_metadata_ptr& trx, bool persist_until_expired, next_function next) -> void { return my->on_incoming_transaction_async(trx, persist_until_expired, next ); }); From 49a9c55ef2a1e5c201f523ca66f1e8ce8ebe4f4e Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 12 Dec 2018 07:38:55 -0600 Subject: [PATCH 02/23] Thread pool does not need to be optional --- libraries/chain/controller.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index c7dda941e01..f18b92524f6 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -135,7 +135,7 @@ struct controller_impl { optional subjective_cpu_leeway; bool trusted_producer_light_validation = false; uint32_t snapshot_head_block = 0; - optional thread_pool; + boost::asio::thread_pool thread_pool; typedef pair handler_key; map< account_name, map > apply_handlers; @@ -151,7 +151,7 @@ struct controller_impl { template auto async_thread_pool( F&& f ) { auto task = std::make_shared>( std::forward( f ) ); - boost::asio::post( *thread_pool, [task]() { (*task)(); } ); + boost::asio::post( thread_pool, [task]() { (*task)(); } ); return task->get_future(); } @@ -194,7 +194,8 @@ struct controller_impl { authorization( s, db ), conf( cfg ), chain_id( cfg.genesis.compute_chain_id() ), - read_mode( cfg.read_mode ) + read_mode( cfg.read_mode ), + thread_pool( cfg.thread_pool_size ) { #define SET_APP_HANDLER( receiver, contract, action) \ @@ -349,8 +350,6 @@ struct controller_impl { void init(std::function shutdown, const snapshot_reader_ptr& snapshot) { - thread_pool.emplace( conf.thread_pool_size ); - bool report_integrity_hash = !!snapshot; if (snapshot) { EOS_ASSERT( !head, fork_database_exception, "" ); @@ -418,10 +417,8 @@ struct controller_impl { ~controller_impl() { pending.reset(); - if( thread_pool ) { - thread_pool->join(); - thread_pool->stop(); - } + thread_pool.join(); + thread_pool.stop(); db.flush(); reversible_blocks.flush(); From 4a4a80a12affeebab1f66712d53c1286fd7b9b5a Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 12 Dec 2018 11:55:39 -0600 Subject: [PATCH 03/23] Add transaction_metadata create_signing_keys_future method --- libraries/chain/CMakeLists.txt | 2 +- libraries/chain/controller.cpp | 26 ++++---------- .../chain/include/eosio/chain/controller.hpp | 8 +++-- .../include/eosio/chain/thread_utils.hpp | 24 +++++++++++++ .../eosio/chain/transaction_metadata.hpp | 25 ++++++-------- libraries/chain/transaction_metadata.cpp | 34 +++++++++++++++++++ 6 files changed, 82 insertions(+), 37 deletions(-) create mode 100644 libraries/chain/include/eosio/chain/thread_utils.hpp create mode 100644 libraries/chain/transaction_metadata.cpp diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index ee8fe1ebab2..2c430fecea0 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -46,7 +46,7 @@ add_library( eosio_chain # contracts/chain_initializer.cpp -# transaction_metadata.cpp + transaction_metadata.cpp ${HEADERS} ) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index f18b92524f6..1f777906722 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -17,15 +17,13 @@ #include #include #include +#include #include #include #include #include -#include -#include - namespace eosio { namespace chain { @@ -147,14 +145,6 @@ struct controller_impl { */ map unapplied_transactions; - // async on thread_pool and return future - template - auto async_thread_pool( F&& f ) { - auto task = std::make_shared>( std::forward( f ) ); - boost::asio::post( thread_pool, [task]() { (*task)(); } ); - return task->get_future(); - } - void pop_block() { auto prev = fork_db.get_block( head->header.previous ); EOS_ASSERT( prev, block_validate_exception, "attempt to pop beyond last irreversible block" ); @@ -1202,13 +1192,7 @@ struct controller_impl { auto& pt = receipt.trx.get(); auto mtrx = std::make_shared( std::make_shared( pt ) ); if( !self.skip_auth_check() ) { - std::weak_ptr mtrx_wp = mtrx; - mtrx->signing_keys_future = async_thread_pool( [chain_id = this->chain_id, mtrx_wp]() { - auto mtrx = mtrx_wp.lock(); - return mtrx ? - std::make_pair( chain_id, mtrx->trx.get_signature_keys( chain_id ) ) : - std::make_pair( chain_id, decltype( mtrx->trx.get_signature_keys( chain_id ) ){} ); - } ); + transaction_metadata::create_signing_keys_future( mtrx, thread_pool, chain_id ); } packed_transactions.emplace_back( std::move( mtrx ) ); } @@ -1286,7 +1270,7 @@ struct controller_impl { auto prev = fork_db.get_block( b->previous ); EOS_ASSERT( prev, unlinkable_block_exception, "unlinkable block ${id}", ("id", id)("previous", b->previous) ); - return async_thread_pool( [b, prev]() { + return async_thread_pool( thread_pool, [b, prev]() { const bool skip_validate_signee = false; return std::make_shared( *prev, move( b ), skip_validate_signee ); } ); @@ -1780,6 +1764,10 @@ void controller::abort_block() { my->abort_block(); } +boost::asio::thread_pool& controller::get_thread_pool() { + return my->thread_pool; +} + std::future controller::create_block_state_future( const signed_block_ptr& b ) { return my->create_block_state_future( b ); } diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 7e963cd1028..bb07d223a8e 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -11,7 +11,9 @@ namespace chainbase { class database; } - +namespace boost { namespace asio { + class thread_pool; +}} namespace eosio { namespace chain { @@ -87,7 +89,7 @@ namespace eosio { namespace chain { incomplete = 3, ///< this is an incomplete block (either being produced by a producer or speculatively produced by a node) }; - controller( const config& cfg ); + explicit controller( const config& cfg ); ~controller(); void add_indices(); @@ -144,6 +146,8 @@ namespace eosio { namespace chain { std::future create_block_state_future( const signed_block_ptr& b ); void push_block( std::future& block_state_future ); + boost::asio::thread_pool& get_thread_pool(); + const chainbase::database& db()const; const fork_database& fork_db()const; diff --git a/libraries/chain/include/eosio/chain/thread_utils.hpp b/libraries/chain/include/eosio/chain/thread_utils.hpp new file mode 100644 index 00000000000..31b32cbd91f --- /dev/null +++ b/libraries/chain/include/eosio/chain/thread_utils.hpp @@ -0,0 +1,24 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ +#pragma once + +#include +#include +#include +#include + +namespace eosio { namespace chain { + + // async on thread_pool and return future + template + auto async_thread_pool( boost::asio::thread_pool& thread_pool, F&& f ) { + auto task = std::make_shared>( std::forward( f ) ); + boost::asio::post( thread_pool, [task]() { (*task)(); } ); + return task->get_future(); + } + +} } // eosio::chain + + diff --git a/libraries/chain/include/eosio/chain/transaction_metadata.hpp b/libraries/chain/include/eosio/chain/transaction_metadata.hpp index ef50c0c6400..5f2be488dc8 100644 --- a/libraries/chain/include/eosio/chain/transaction_metadata.hpp +++ b/libraries/chain/include/eosio/chain/transaction_metadata.hpp @@ -7,8 +7,14 @@ #include #include +namespace boost { namespace asio { + class thread_pool; +}} + namespace eosio { namespace chain { +class transaction_metadata; +using transaction_metadata_ptr = std::shared_ptr; /** * This data structure should store context-free cached data about a transaction such as * packed/unpacked/compressed and recovered keys @@ -43,23 +49,12 @@ class transaction_metadata { signed_id = digest_type::hash(*packed_trx); } - const flat_set& recover_keys( const chain_id_type& chain_id ) { - // Unlikely for more than one chain_id to be used in one nodeos instance - if( !signing_keys || signing_keys->first != chain_id ) { - if( signing_keys_future.valid() ) { - signing_keys = signing_keys_future.get(); - if( signing_keys->first == chain_id ) { - return signing_keys->second; - } - } - signing_keys = std::make_pair( chain_id, trx.get_signature_keys( chain_id )); - } - return signing_keys->second; - } + const flat_set& recover_keys( const chain_id_type& chain_id ); + + static void create_signing_keys_future( transaction_metadata_ptr& mtrx, + boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id ); uint32_t total_actions()const { return trx.context_free_actions.size() + trx.actions.size(); } }; -using transaction_metadata_ptr = std::shared_ptr; - } } // eosio::chain diff --git a/libraries/chain/transaction_metadata.cpp b/libraries/chain/transaction_metadata.cpp new file mode 100644 index 00000000000..9afc1a01fd0 --- /dev/null +++ b/libraries/chain/transaction_metadata.cpp @@ -0,0 +1,34 @@ +#include +#include +#include + +namespace eosio { namespace chain { + + +const flat_set& transaction_metadata::recover_keys( const chain_id_type& chain_id ) { + // Unlikely for more than one chain_id to be used in one nodeos instance + if( !signing_keys || signing_keys->first != chain_id ) { + if( signing_keys_future.valid() ) { + signing_keys = signing_keys_future.get(); + if( signing_keys->first == chain_id ) { + return signing_keys->second; + } + } + signing_keys = std::make_pair( chain_id, trx.get_signature_keys( chain_id )); + } + return signing_keys->second; +} + +void transaction_metadata::create_signing_keys_future( transaction_metadata_ptr& mtrx, + boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id ) { + std::weak_ptr mtrx_wp = mtrx; + mtrx->signing_keys_future = async_thread_pool( thread_pool, [chain_id, mtrx_wp]() { + auto mtrx = mtrx_wp.lock(); + return mtrx ? + std::make_pair( chain_id, mtrx->trx.get_signature_keys( chain_id ) ) : + std::make_pair( chain_id, decltype( mtrx->trx.get_signature_keys( chain_id ) ){} ); + } ); +} + + +} } // eosio::chain From f71d490b47630740f19be9dc769ae04a296b59e3 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 12 Dec 2018 15:07:18 -0600 Subject: [PATCH 04/23] Start transaction signature earily in thread pool --- .../include/eosio/chain/transaction_metadata.hpp | 2 +- libraries/chain/transaction.cpp | 5 +++-- libraries/chain/transaction_metadata.cpp | 8 +++++++- plugins/producer_plugin/producer_plugin.cpp | 16 ++++++++++++++-- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/libraries/chain/include/eosio/chain/transaction_metadata.hpp b/libraries/chain/include/eosio/chain/transaction_metadata.hpp index 5f2be488dc8..60f89e2c4fe 100644 --- a/libraries/chain/include/eosio/chain/transaction_metadata.hpp +++ b/libraries/chain/include/eosio/chain/transaction_metadata.hpp @@ -51,7 +51,7 @@ class transaction_metadata { const flat_set& recover_keys( const chain_id_type& chain_id ); - static void create_signing_keys_future( transaction_metadata_ptr& mtrx, + static void create_signing_keys_future( const transaction_metadata_ptr& mtrx, boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id ); uint32_t total_actions()const { return trx.context_free_actions.size() + trx.actions.size(); } diff --git a/libraries/chain/transaction.cpp b/libraries/chain/transaction.cpp index 6e6639bac52..d2528dc21a3 100644 --- a/libraries/chain/transaction.cpp +++ b/libraries/chain/transaction.cpp @@ -95,9 +95,10 @@ flat_set transaction::get_signature_keys( const vector::type::iterator it = recovery_cache.get().find( sig ); - if( it == recovery_cache.get().end() || it->trx_id != id()) { + const auto& tid = id(); + if( it == recovery_cache.get().end() || it->trx_id != tid) { recov = public_key_type( sig, digest ); - recovery_cache.emplace_back(cached_pub_key{id(), recov, sig} ); //could fail on dup signatures; not a problem + recovery_cache.emplace_back(cached_pub_key{tid, recov, sig} ); //could fail on dup signatures; not a problem } else { recov = it->pub_key; } diff --git a/libraries/chain/transaction_metadata.cpp b/libraries/chain/transaction_metadata.cpp index 9afc1a01fd0..068f711f6b0 100644 --- a/libraries/chain/transaction_metadata.cpp +++ b/libraries/chain/transaction_metadata.cpp @@ -19,8 +19,14 @@ const flat_set& transaction_metadata::recover_keys( const chain return signing_keys->second; } -void transaction_metadata::create_signing_keys_future( transaction_metadata_ptr& mtrx, +void transaction_metadata::create_signing_keys_future( const transaction_metadata_ptr& mtrx, boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id ) { + if( mtrx->signing_keys && mtrx->signing_keys->first == chain_id ) + return; + + if( mtrx->signing_keys.valid() ) // already created + return; + std::weak_ptr mtrx_wp = mtrx; mtrx->signing_keys_future = async_thread_pool( thread_pool, [chain_id, mtrx_wp]() { auto mtrx = mtrx_wp.lock(); diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 1a1d7d0d515..d0bda3edf0a 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -346,6 +346,18 @@ class producer_plugin_impl : public std::enable_shared_from_this>> _pending_incoming_transactions; void on_incoming_transaction_async(const transaction_metadata_ptr& trx, bool persist_until_expired, next_function next) { + chain::controller& chain = chain_plug->chain(); + transaction_metadata::create_signing_keys_future( trx, chain.get_thread_pool(), chain.get_chain_id() ); + boost::asio::post( chain.get_thread_pool(), [self = this, trx, persist_until_expired, next]() { + if( trx->signing_keys_future.valid() ) + trx->signing_keys_future.wait(); + app().get_io_service().post( [self, trx, persist_until_expired, next]() { + self->process_incoming_transaction_async( trx, persist_until_expired, next ); + }); + }); + } + + void process_incoming_transaction_async(const transaction_metadata_ptr& trx, bool persist_until_expired, next_function next) { chain::controller& chain = chain_plug->chain(); if (!chain.pending_block_state()) { _pending_incoming_transactions.emplace_back(trx, persist_until_expired, next); @@ -1245,7 +1257,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool _pending_incoming_transactions.pop_front(); --orig_pending_txn_size; _incoming_trx_weight -= 1.0; - on_incoming_transaction_async(std::get<0>(e), std::get<1>(e), std::get<2>(e)); + process_incoming_transaction_async(std::get<0>(e), std::get<1>(e), std::get<2>(e)); } if (block_time <= fc::time_point::now()) { @@ -1308,7 +1320,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block(bool auto e = _pending_incoming_transactions.front(); _pending_incoming_transactions.pop_front(); --orig_pending_txn_size; - on_incoming_transaction_async(std::get<0>(e), std::get<1>(e), std::get<2>(e)); + process_incoming_transaction_async(std::get<0>(e), std::get<1>(e), std::get<2>(e)); if (block_time <= fc::time_point::now()) return start_block_result::exhausted; } } From 96fb1e5f4691013ee6fc310a1e00a0e2888778b6 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 13 Dec 2018 16:41:54 -0600 Subject: [PATCH 05/23] Refactor packed_transaction for better encapsulation --- .../include/eosio/chain/abi_serializer.hpp | 39 ++++++++--------- .../chain/include/eosio/chain/transaction.hpp | 40 ++++++++++++------ libraries/chain/transaction.cpp | 42 ++++++++++++++----- unittests/misc_tests.cpp | 6 +-- 4 files changed, 81 insertions(+), 46 deletions(-) diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index 221424e041e..8577c1de972 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -418,11 +418,11 @@ namespace impl { mutable_variant_object mvo; auto trx = ptrx.get_transaction(); mvo("id", trx.id()); - mvo("signatures", ptrx.signatures); - mvo("compression", ptrx.compression); - mvo("packed_context_free_data", ptrx.packed_context_free_data); + mvo("signatures", ptrx.get_signatures()); + mvo("compression", ptrx.get_compression()); + mvo("packed_context_free_data", ptrx.get_packed_context_free_data()); mvo("context_free_data", ptrx.get_context_free_data()); - mvo("packed_trx", ptrx.packed_trx); + mvo("packed_trx", ptrx.get_packed_transaction()); add(mvo, "transaction", trx, resolver, ctx); out(name, std::move(mvo)); @@ -577,32 +577,33 @@ namespace impl { const variant_object& vo = v.get_object(); EOS_ASSERT(vo.contains("signatures"), packed_transaction_type_exception, "Missing signatures"); EOS_ASSERT(vo.contains("compression"), packed_transaction_type_exception, "Missing compression"); - from_variant(vo["signatures"], ptrx.signatures); - from_variant(vo["compression"], ptrx.compression); + std::vector signatures; + packed_transaction::compression_type compression; + from_variant(vo["signatures"], signatures); + from_variant(vo["compression"], compression); - // TODO: Make this nicer eventually. But for now, if it works... good enough. + bytes packed_cfd; if( vo.contains("packed_trx") && vo["packed_trx"].is_string() && !vo["packed_trx"].as_string().empty() ) { - from_variant(vo["packed_trx"], ptrx.packed_trx); - auto trx = ptrx.get_transaction(); // Validates transaction data provided. + bytes packed_trx; + std::vector cfd; + from_variant(vo["packed_trx"], packed_trx); if( vo.contains("packed_context_free_data") && vo["packed_context_free_data"].is_string() && !vo["packed_context_free_data"].as_string().empty() ) { - from_variant(vo["packed_context_free_data"], ptrx.packed_context_free_data ); + from_variant(vo["packed_context_free_data"], packed_cfd ); } else if( vo.contains("context_free_data") ) { - vector context_free_data; - from_variant(vo["context_free_data"], context_free_data); - ptrx.set_transaction(trx, context_free_data, ptrx.compression); + from_variant(vo["context_free_data"], cfd); } + ptrx = packed_transaction( std::move(packed_trx), std::move(signatures), std::move(packed_cfd), std::move(cfd), compression ); } else { EOS_ASSERT(vo.contains("transaction"), packed_transaction_type_exception, "Missing transaction"); - transaction trx; - vector context_free_data; + signed_transaction trx; + trx.signatures = std::move(signatures); extract(vo["transaction"], trx, resolver, ctx); if( vo.contains("packed_context_free_data") && vo["packed_context_free_data"].is_string() && !vo["packed_context_free_data"].as_string().empty() ) { - from_variant(vo["packed_context_free_data"], ptrx.packed_context_free_data ); - context_free_data = ptrx.get_context_free_data(); + from_variant(vo["packed_context_free_data"], packed_cfd ); } else if( vo.contains("context_free_data") ) { - from_variant(vo["context_free_data"], context_free_data); + from_variant(vo["context_free_data"], trx.context_free_data ); } - ptrx.set_transaction(trx, context_free_data, ptrx.compression); + ptrx = packed_transaction( std::move(trx), std::move(packed_cfd), compression ); } } }; diff --git a/libraries/chain/include/eosio/chain/transaction.hpp b/libraries/chain/include/eosio/chain/transaction.hpp index b3fb7c5d7e0..c848490800a 100644 --- a/libraries/chain/include/eosio/chain/transaction.hpp +++ b/libraries/chain/include/eosio/chain/transaction.hpp @@ -108,27 +108,29 @@ namespace eosio { namespace chain { packed_transaction& operator=(packed_transaction&&) = default; explicit packed_transaction(const signed_transaction& t, compression_type _compression = none) - :signatures(t.signatures) + :signatures(t.signatures), compression(_compression) { - set_transaction(t, t.context_free_data, _compression); + set_transaction(t); + set_context_free_data(t.context_free_data); } explicit packed_transaction(signed_transaction&& t, compression_type _compression = none) - :signatures(std::move(t.signatures)) + :signatures(std::move(t.signatures)), compression(_compression) { - set_transaction(t, t.context_free_data, _compression); + set_transaction(t); + set_context_free_data(t.context_free_data); } + // used by abi_serializer + explicit packed_transaction( bytes&& packed_txn, vector&& sigs, + bytes&& packed_cfd, vector&& cfd, compression_type _compression ); + explicit packed_transaction( signed_transaction&& t, bytes&& packed_cfd, compression_type _compression ); + uint32_t get_unprunable_size()const; uint32_t get_prunable_size()const; digest_type packed_digest()const; - vector signatures; - fc::enum_type compression; - bytes packed_context_free_data; - bytes packed_trx; - time_point_sec expiration()const; transaction_id_type id()const; transaction_id_type get_uncached_id()const; // thread safe @@ -136,12 +138,26 @@ namespace eosio { namespace chain { vector get_context_free_data()const; transaction get_transaction()const; signed_transaction get_signed_transaction()const; - void set_transaction(const transaction& t, compression_type _compression = none); - void set_transaction(const transaction& t, const vector& cfd, compression_type _compression = none); + + const vector& get_signatures()const { return signatures; } + const fc::enum_type& get_compression()const { return compression; } + const bytes& get_packed_context_free_data()const { return packed_context_free_data; } + const bytes& get_packed_transaction()const { return packed_trx; } private: - mutable optional unpacked_trx; // <-- intermediate buffer used to retrieve values void local_unpack()const; + void set_transaction(const transaction& t); + void set_context_free_data(const vector& cfd); + + friend struct fc::reflector; + private: + vector signatures; + fc::enum_type compression; + bytes packed_context_free_data; + bytes packed_trx; + + private: + mutable optional unpacked_trx; // <-- intermediate buffer used to retrieve values }; using packed_transaction_ptr = std::shared_ptr; diff --git a/libraries/chain/transaction.cpp b/libraries/chain/transaction.cpp index d2528dc21a3..910651031f8 100644 --- a/libraries/chain/transaction.cpp +++ b/libraries/chain/transaction.cpp @@ -344,10 +344,35 @@ signed_transaction packed_transaction::get_signed_transaction() const } -void packed_transaction::set_transaction(const transaction& t, packed_transaction::compression_type _compression) +packed_transaction::packed_transaction( bytes&& packed_txn, vector&& sigs, + bytes&& packed_cfd, vector&& cfd, compression_type _compression ) +:signatures(std::move(sigs)) +,compression(_compression) +,packed_context_free_data(std::move(packed_cfd)) +,packed_trx(std::move(packed_txn)) +{ + EOS_ASSERT(packed_cfd.empty() || cfd.empty(), tx_decompression_error, "Invalid packed_transaction"); + if( !cfd.empty() ) { + set_context_free_data(cfd); + } +} + +packed_transaction::packed_transaction( signed_transaction&& t, bytes&& packed_cfd, compression_type _compression ) +:signatures(std::move(t.signatures)) +,compression(_compression) +,packed_context_free_data(std::move(packed_cfd)) +{ + set_transaction(t); + // allow passed in packed_cfd to overwrite signed_transaction.context_free_data if provided + if( packed_context_free_data.empty() ) { + set_context_free_data(t.context_free_data); + } +} + +void packed_transaction::set_transaction(const transaction& t) { try { - switch(_compression) { + switch(compression) { case none: packed_trx = pack_transaction(t); break; @@ -357,28 +382,23 @@ void packed_transaction::set_transaction(const transaction& t, packed_transactio default: EOS_THROW(unknown_transaction_compression, "Unknown transaction compression algorithm"); } - } FC_CAPTURE_AND_RETHROW((_compression)(t)) - packed_context_free_data.clear(); - compression = _compression; + } FC_CAPTURE_AND_RETHROW((compression)(t)) } -void packed_transaction::set_transaction(const transaction& t, const vector& cfd, packed_transaction::compression_type _compression) +void packed_transaction::set_context_free_data(const vector& cfd) { try { - switch(_compression) { + switch(compression) { case none: - packed_trx = pack_transaction(t); packed_context_free_data = pack_context_free_data(cfd); break; case zlib: - packed_trx = zlib_compress_transaction(t); packed_context_free_data = zlib_compress_context_free_data(cfd); break; default: EOS_THROW(unknown_transaction_compression, "Unknown transaction compression algorithm"); } - } FC_CAPTURE_AND_RETHROW((_compression)(t)) - compression = _compression; + } FC_CAPTURE_AND_RETHROW((compression)) } diff --git a/unittests/misc_tests.cpp b/unittests/misc_tests.cpp index 1a93b66e97a..14918b6a1f5 100644 --- a/unittests/misc_tests.cpp +++ b/unittests/misc_tests.cpp @@ -590,11 +590,9 @@ BOOST_AUTO_TEST_CASE(transaction_test) { try { BOOST_CHECK_EQUAL(1, trx.signatures.size()); trx.validate(); - packed_transaction pkt; - pkt.set_transaction(trx, packed_transaction::none); + packed_transaction pkt(trx, packed_transaction::none); - packed_transaction pkt2; - pkt2.set_transaction(trx, packed_transaction::zlib); + packed_transaction pkt2(trx, packed_transaction::zlib); BOOST_CHECK_EQUAL(true, trx.expiration == pkt.expiration()); BOOST_CHECK_EQUAL(true, trx.expiration == pkt2.expiration()); From 20ffa70f649b0e2abb2f0b9afec6b076946fa3df Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 12 Dec 2018 11:55:39 -0600 Subject: [PATCH 06/23] Add transaction_metadata create_signing_keys_future method --- libraries/chain/include/eosio/chain/transaction_metadata.hpp | 2 +- libraries/chain/transaction_metadata.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/include/eosio/chain/transaction_metadata.hpp b/libraries/chain/include/eosio/chain/transaction_metadata.hpp index 60f89e2c4fe..5f2be488dc8 100644 --- a/libraries/chain/include/eosio/chain/transaction_metadata.hpp +++ b/libraries/chain/include/eosio/chain/transaction_metadata.hpp @@ -51,7 +51,7 @@ class transaction_metadata { const flat_set& recover_keys( const chain_id_type& chain_id ); - static void create_signing_keys_future( const transaction_metadata_ptr& mtrx, + static void create_signing_keys_future( transaction_metadata_ptr& mtrx, boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id ); uint32_t total_actions()const { return trx.context_free_actions.size() + trx.actions.size(); } diff --git a/libraries/chain/transaction_metadata.cpp b/libraries/chain/transaction_metadata.cpp index 068f711f6b0..c16702c837b 100644 --- a/libraries/chain/transaction_metadata.cpp +++ b/libraries/chain/transaction_metadata.cpp @@ -19,7 +19,7 @@ const flat_set& transaction_metadata::recover_keys( const chain return signing_keys->second; } -void transaction_metadata::create_signing_keys_future( const transaction_metadata_ptr& mtrx, +void transaction_metadata::create_signing_keys_future( transaction_metadata_ptr& mtrx, boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id ) { if( mtrx->signing_keys && mtrx->signing_keys->first == chain_id ) return; From f64da40d800ca37815017b89892efdd75d503acb Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 12 Dec 2018 15:07:18 -0600 Subject: [PATCH 07/23] Start transaction signature earily in thread pool --- libraries/chain/include/eosio/chain/transaction_metadata.hpp | 2 +- libraries/chain/transaction_metadata.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/include/eosio/chain/transaction_metadata.hpp b/libraries/chain/include/eosio/chain/transaction_metadata.hpp index 5f2be488dc8..60f89e2c4fe 100644 --- a/libraries/chain/include/eosio/chain/transaction_metadata.hpp +++ b/libraries/chain/include/eosio/chain/transaction_metadata.hpp @@ -51,7 +51,7 @@ class transaction_metadata { const flat_set& recover_keys( const chain_id_type& chain_id ); - static void create_signing_keys_future( transaction_metadata_ptr& mtrx, + static void create_signing_keys_future( const transaction_metadata_ptr& mtrx, boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id ); uint32_t total_actions()const { return trx.context_free_actions.size() + trx.actions.size(); } diff --git a/libraries/chain/transaction_metadata.cpp b/libraries/chain/transaction_metadata.cpp index c16702c837b..068f711f6b0 100644 --- a/libraries/chain/transaction_metadata.cpp +++ b/libraries/chain/transaction_metadata.cpp @@ -19,7 +19,7 @@ const flat_set& transaction_metadata::recover_keys( const chain return signing_keys->second; } -void transaction_metadata::create_signing_keys_future( transaction_metadata_ptr& mtrx, +void transaction_metadata::create_signing_keys_future( const transaction_metadata_ptr& mtrx, boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id ) { if( mtrx->signing_keys && mtrx->signing_keys->first == chain_id ) return; From 22ab63cc1d06b73ce7297a714fbb482962a5ef99 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 14 Dec 2018 15:14:28 -0600 Subject: [PATCH 08/23] Update txn_test_gen_plugin to overlap transaction submit @taokayan --- .../txn_test_gen_plugin.cpp | 50 +++++++++++++------ 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp index 6b4753e9919..fd11b129155 100644 --- a/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp +++ b/plugins/txn_test_gen_plugin/txn_test_gen_plugin.cpp @@ -87,19 +87,38 @@ using namespace eosio::chain; api_handle->call_name(vs.at(0).as(), vs.at(1).as(), result_handler); struct txn_test_gen_plugin_impl { - static void push_next_transaction(const std::shared_ptr>& trxs, size_t index, const std::function& next ) { + + uint64_t _total_us = 0; + uint64_t _txcount = 0; + + int _remain = 0; + + void push_next_transaction(const std::shared_ptr>& trxs, size_t index, const std::function& next ) { chain_plugin& cp = app().get_plugin(); - cp.accept_transaction( packed_transaction(trxs->at(index)), [=](const fc::static_variant& result){ - if (result.contains()) { - next(result.get()); - } else { - if (index + 1 < trxs->size()) { - push_next_transaction(trxs, index + 1, next); + + const int overlap = 20; + int end = std::min(index + overlap, trxs->size()); + _remain = end - index; + for (int i = index; i < end; ++i) { + cp.accept_transaction( packed_transaction(trxs->at(i)), [=](const fc::static_variant& result){ + if (result.contains()) { + next(result.get()); } else { - next(nullptr); + if (result.contains() && result.get()->receipt) { + _total_us += result.get()->receipt->cpu_usage_us; + ++_txcount; + } + --_remain; + if (_remain == 0 ) { + if (end < trxs->size()) { + push_next_transaction(trxs, index + overlap, next); + } else { + next(nullptr); + } + } } - } - }); + }); + } } void push_transactions( std::vector&& trxs, const std::function& next ) { @@ -295,13 +314,11 @@ struct txn_test_gen_plugin_impl { try { controller& cc = app().get_plugin().chain(); auto chainid = app().get_plugin().get_chain_id(); - auto abi_serializer_max_time = app().get_plugin().get_abi_serializer_max_time(); - fc::crypto::private_key a_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'a'))); - fc::crypto::private_key b_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'b'))); + static fc::crypto::private_key a_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'a'))); + static fc::crypto::private_key b_priv_key = fc::crypto::private_key::regenerate(fc::sha256(std::string(64, 'b'))); static uint64_t nonce = static_cast(fc::time_point::now().sec_since_epoch()) << 32; - abi_serializer eosio_serializer(cc.db().find(config::system_account_name)->get_abi(), abi_serializer_max_time); uint32_t reference_block_num = cc.last_irreversible_block_num(); if (txn_reference_block_lag >= 0) { @@ -351,6 +368,11 @@ struct txn_test_gen_plugin_impl { timer.cancel(); running = false; ilog("Stopping transaction generation test"); + + if (_txcount) { + ilog("${d} transactions executed, ${t}us / transaction", ("d", _txcount)("t", _total_us / (double)_txcount)); + _txcount = _total_us = 0; + } } boost::asio::high_resolution_timer timer{app().get_io_service()}; From 64537c562671434f120c1091c1921d5751df55aa Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 17 Dec 2018 12:13:17 -0500 Subject: [PATCH 09/23] Remove redundant signing_keys check --- libraries/chain/transaction_metadata.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/chain/transaction_metadata.cpp b/libraries/chain/transaction_metadata.cpp index 068f711f6b0..95edf0f3f68 100644 --- a/libraries/chain/transaction_metadata.cpp +++ b/libraries/chain/transaction_metadata.cpp @@ -21,9 +21,6 @@ const flat_set& transaction_metadata::recover_keys( const chain void transaction_metadata::create_signing_keys_future( const transaction_metadata_ptr& mtrx, boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id ) { - if( mtrx->signing_keys && mtrx->signing_keys->first == chain_id ) - return; - if( mtrx->signing_keys.valid() ) // already created return; From ca8e5bc30fcfcedfd9cc65e652f2a5a705f7cf37 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 17 Dec 2018 16:23:25 -0500 Subject: [PATCH 10/23] Add deadline to key recovery --- libraries/chain/controller.cpp | 2 +- .../chain/include/eosio/chain/transaction.hpp | 7 ++-- .../eosio/chain/transaction_metadata.hpp | 4 +-- libraries/chain/transaction.cpp | 33 +++++++++---------- libraries/chain/transaction_metadata.cpp | 10 +++--- plugins/mongo_db_plugin/mongo_db_plugin.cpp | 2 +- plugins/producer_plugin/producer_plugin.cpp | 4 ++- tests/wallet_tests.cpp | 2 +- unittests/api_tests.cpp | 8 ++--- 9 files changed, 37 insertions(+), 35 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 1f777906722..461f481a34f 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1192,7 +1192,7 @@ struct controller_impl { auto& pt = receipt.trx.get(); auto mtrx = std::make_shared( std::make_shared( pt ) ); if( !self.skip_auth_check() ) { - transaction_metadata::create_signing_keys_future( mtrx, thread_pool, chain_id ); + transaction_metadata::create_signing_keys_future( mtrx, thread_pool, chain_id, fc::time_point::maximum() ); } packed_transactions.emplace_back( std::move( mtrx ) ); } diff --git a/libraries/chain/include/eosio/chain/transaction.hpp b/libraries/chain/include/eosio/chain/transaction.hpp index c848490800a..65f3c35ff63 100644 --- a/libraries/chain/include/eosio/chain/transaction.hpp +++ b/libraries/chain/include/eosio/chain/transaction.hpp @@ -60,9 +60,9 @@ namespace eosio { namespace chain { digest_type sig_digest( const chain_id_type& chain_id, const vector& cfd = vector() )const; flat_set get_signature_keys( const vector& signatures, const chain_id_type& chain_id, + fc::time_point deadline, const vector& cfd = vector(), - bool allow_duplicate_keys = false, - bool use_cache = true )const; + bool allow_duplicate_keys = false)const; uint32_t total_actions()const { return context_free_actions.size() + actions.size(); } account_name first_authorizor()const { @@ -92,7 +92,8 @@ namespace eosio { namespace chain { const signature_type& sign(const private_key_type& key, const chain_id_type& chain_id); signature_type sign(const private_key_type& key, const chain_id_type& chain_id)const; - flat_set get_signature_keys( const chain_id_type& chain_id, bool allow_duplicate_keys = false, bool use_cache = true )const; + flat_set get_signature_keys( const chain_id_type& chain_id, fc::time_point deadline, + bool allow_duplicate_keys = false )const; }; struct packed_transaction { diff --git a/libraries/chain/include/eosio/chain/transaction_metadata.hpp b/libraries/chain/include/eosio/chain/transaction_metadata.hpp index 60f89e2c4fe..e3742eb0978 100644 --- a/libraries/chain/include/eosio/chain/transaction_metadata.hpp +++ b/libraries/chain/include/eosio/chain/transaction_metadata.hpp @@ -51,8 +51,8 @@ class transaction_metadata { const flat_set& recover_keys( const chain_id_type& chain_id ); - static void create_signing_keys_future( const transaction_metadata_ptr& mtrx, - boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id ); + static void create_signing_keys_future( const transaction_metadata_ptr& mtrx, boost::asio::thread_pool& thread_pool, + const chain_id_type& chain_id, fc::time_point deadline); uint32_t total_actions()const { return trx.context_free_actions.size() + trx.actions.size(); } }; diff --git a/libraries/chain/transaction.cpp b/libraries/chain/transaction.cpp index 910651031f8..9cdac6f4889 100644 --- a/libraries/chain/transaction.cpp +++ b/libraries/chain/transaction.cpp @@ -82,28 +82,28 @@ digest_type transaction::sig_digest( const chain_id_type& chain_id, const vector } flat_set transaction::get_signature_keys( const vector& signatures, - const chain_id_type& chain_id, const vector& cfd, bool allow_duplicate_keys, bool use_cache )const + const chain_id_type& chain_id, fc::time_point deadline, const vector& cfd, bool allow_duplicate_keys)const { try { using boost::adaptors::transformed; constexpr size_t recovery_cache_size = 1000; static thread_local recovery_cache_type recovery_cache; + fc::time_point start = fc::time_point::now(); const digest_type digest = sig_digest(chain_id, cfd); flat_set recovered_pub_keys; for(const signature_type& sig : signatures) { + auto now = fc::time_point::now(); + EOS_ASSERT( start + now <= deadline, tx_cpu_usage_exceeded, "transaction signature verification executed for too long", + ("now", now)("deadline", deadline)("start", start) ); public_key_type recov; - if( use_cache ) { - recovery_cache_type::index::type::iterator it = recovery_cache.get().find( sig ); - const auto& tid = id(); - if( it == recovery_cache.get().end() || it->trx_id != tid) { - recov = public_key_type( sig, digest ); - recovery_cache.emplace_back(cached_pub_key{tid, recov, sig} ); //could fail on dup signatures; not a problem - } else { - recov = it->pub_key; - } - } else { + recovery_cache_type::index::type::iterator it = recovery_cache.get().find( sig ); + const auto& tid = id(); + if( it == recovery_cache.get().end() || it->trx_id != tid ) { recov = public_key_type( sig, digest ); + recovery_cache.emplace_back( cached_pub_key{tid, recov, sig} ); //could fail on dup signatures; not a problem + } else { + recov = it->pub_key; } bool successful_insertion = false; std::tie(std::ignore, successful_insertion) = recovered_pub_keys.insert(recov); @@ -113,10 +113,8 @@ flat_set transaction::get_signature_keys( const vector recovery_cache_size ) - recovery_cache.erase( recovery_cache.begin() ); - } + while ( recovery_cache.size() > recovery_cache_size ) + recovery_cache.erase( recovery_cache.begin()); return recovered_pub_keys; } FC_CAPTURE_AND_RETHROW() } @@ -131,9 +129,10 @@ signature_type signed_transaction::sign(const private_key_type& key, const chain return key.sign(sig_digest(chain_id, context_free_data)); } -flat_set signed_transaction::get_signature_keys( const chain_id_type& chain_id, bool allow_duplicate_keys, bool use_cache )const +flat_set signed_transaction::get_signature_keys( const chain_id_type& chain_id, fc::time_point deadline, + bool allow_duplicate_keys)const { - return transaction::get_signature_keys(signatures, chain_id, context_free_data, allow_duplicate_keys, use_cache); + return transaction::get_signature_keys(signatures, chain_id, deadline, context_free_data, allow_duplicate_keys); } uint32_t packed_transaction::get_unprunable_size()const { diff --git a/libraries/chain/transaction_metadata.cpp b/libraries/chain/transaction_metadata.cpp index 95edf0f3f68..5e049fdf217 100644 --- a/libraries/chain/transaction_metadata.cpp +++ b/libraries/chain/transaction_metadata.cpp @@ -14,22 +14,22 @@ const flat_set& transaction_metadata::recover_keys( const chain return signing_keys->second; } } - signing_keys = std::make_pair( chain_id, trx.get_signature_keys( chain_id )); + signing_keys = std::make_pair( chain_id, trx.get_signature_keys( chain_id, fc::time_point::maximum() )); } return signing_keys->second; } void transaction_metadata::create_signing_keys_future( const transaction_metadata_ptr& mtrx, - boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id ) { + boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id, fc::time_point deadline ) { if( mtrx->signing_keys.valid() ) // already created return; std::weak_ptr mtrx_wp = mtrx; - mtrx->signing_keys_future = async_thread_pool( thread_pool, [chain_id, mtrx_wp]() { + mtrx->signing_keys_future = async_thread_pool( thread_pool, [deadline, chain_id, mtrx_wp]() { auto mtrx = mtrx_wp.lock(); return mtrx ? - std::make_pair( chain_id, mtrx->trx.get_signature_keys( chain_id ) ) : - std::make_pair( chain_id, decltype( mtrx->trx.get_signature_keys( chain_id ) ){} ); + std::make_pair( chain_id, mtrx->trx.get_signature_keys( chain_id, deadline ) ) : + std::make_pair( chain_id, decltype( mtrx->trx.get_signature_keys( chain_id, deadline ) ){} ); } ); } diff --git a/plugins/mongo_db_plugin/mongo_db_plugin.cpp b/plugins/mongo_db_plugin/mongo_db_plugin.cpp index 3ef0ee252ac..6c7ce0959d7 100644 --- a/plugins/mongo_db_plugin/mongo_db_plugin.cpp +++ b/plugins/mongo_db_plugin/mongo_db_plugin.cpp @@ -761,7 +761,7 @@ void mongo_db_plugin_impl::_process_accepted_transaction( const chain::transacti if( t->signing_keys.valid() ) { signing_keys_json = fc::json::to_string( t->signing_keys->second ); } else { - auto signing_keys = trx.get_signature_keys( *chain_id, false, false ); + auto signing_keys = trx.get_signature_keys( *chain_id, fc::time_point::maximum(), false ); if( !signing_keys.empty() ) { signing_keys_json = fc::json::to_string( signing_keys ); } diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index d0bda3edf0a..320d12b9877 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -347,7 +347,9 @@ class producer_plugin_impl : public std::enable_shared_from_this next) { chain::controller& chain = chain_plug->chain(); - transaction_metadata::create_signing_keys_future( trx, chain.get_thread_pool(), chain.get_chain_id() ); + const auto& cfg = chain.get_global_properties().configuration; + fc::time_point deadline = fc::time_point::now() + fc::time_point( fc::microseconds( cfg.max_transaction_cpu_usage )); + transaction_metadata::create_signing_keys_future( trx, chain.get_thread_pool(), chain.get_chain_id(), deadline ); boost::asio::post( chain.get_thread_pool(), [self = this, trx, persist_until_expired, next]() { if( trx->signing_keys_future.valid() ) trx->signing_keys_future.wait(); diff --git a/tests/wallet_tests.cpp b/tests/wallet_tests.cpp index 0891b030906..e52f5d0a483 100644 --- a/tests/wallet_tests.cpp +++ b/tests/wallet_tests.cpp @@ -173,7 +173,7 @@ BOOST_AUTO_TEST_CASE(wallet_manager_test) pubkeys.emplace(pkey1.get_public_key()); pubkeys.emplace(pkey2.get_public_key()); trx = wm.sign_transaction(trx, pubkeys, chain_id ); - const auto& pks = trx.get_signature_keys(chain_id); + const auto& pks = trx.get_signature_keys(chain_id, fc::time_point::maximum()); BOOST_CHECK_EQUAL(2, pks.size()); BOOST_CHECK(find(pks.cbegin(), pks.cend(), pkey1.get_public_key()) != pks.cend()); BOOST_CHECK(find(pks.cbegin(), pks.cend(), pkey2.get_public_key()) != pks.cend()); diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index 79b4555aa91..3f3468885e9 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -149,7 +149,7 @@ transaction_trace_ptr CallAction(TESTER& test, T ac, const vector& test.set_transaction_headers(trx); auto sigs = trx.sign(test.get_private_key(scope[0], "active"), test.control->get_chain_id()); - trx.get_signature_keys(test.control->get_chain_id()); + trx.get_signature_keys(test.control->get_chain_id(), fc::time_point::maximum()); auto res = test.push_transaction(trx); BOOST_CHECK_EQUAL(res->receipt->status, transaction_receipt::executed); test.produce_block(); @@ -173,7 +173,7 @@ transaction_trace_ptr CallFunction(TESTER& test, T ac, const vector& data, test.set_transaction_headers(trx, test.DEFAULT_EXPIRATION_DELTA); auto sigs = trx.sign(test.get_private_key(scope[0], "active"), test.control->get_chain_id()); - trx.get_signature_keys(test.control->get_chain_id() ); + trx.get_signature_keys(test.control->get_chain_id(), fc::time_point::maximum()); auto res = test.push_transaction(trx); BOOST_CHECK_EQUAL(res->receipt->status, transaction_receipt::executed); test.produce_block(); @@ -266,7 +266,7 @@ BOOST_FIXTURE_TEST_CASE(action_receipt_tests, TESTER) { try { trx.actions.push_back(act); this->set_transaction_headers(trx, this->DEFAULT_EXPIRATION_DELTA); trx.sign(this->get_private_key(config::system_account_name, "active"), control->get_chain_id()); - trx.get_signature_keys(control->get_chain_id() ); + trx.get_signature_keys(control->get_chain_id(), fc::time_point::maximum()); auto res = this->push_transaction(trx); BOOST_CHECK_EQUAL(res->receipt->status, transaction_receipt::executed); this->produce_block(); @@ -745,7 +745,7 @@ void call_test(TESTER& test, T ac, uint32_t billed_cpu_time_us , uint32_t max_cp test.set_transaction_headers(trx); //trx.max_cpu_usage_ms = max_cpu_usage_ms; auto sigs = trx.sign(test.get_private_key(N(testapi), "active"), test.control->get_chain_id()); - trx.get_signature_keys(test.control->get_chain_id() ); + trx.get_signature_keys(test.control->get_chain_id(), fc::time_point::maximum()); auto res = test.push_transaction( trx, fc::time_point::now() + fc::milliseconds(max_cpu_usage_ms), billed_cpu_time_us ); BOOST_CHECK_EQUAL(res->receipt->status, transaction_receipt::executed); test.produce_block(); From b8a565952bc426741dea96ce4f3fe84ff384faa9 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 17 Dec 2018 16:38:18 -0500 Subject: [PATCH 11/23] Modify producer_plugin to have its own thead_pool instead of using chain-threads --- plugins/producer_plugin/producer_plugin.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 320d12b9877..2ab341f7114 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -114,6 +114,13 @@ class producer_plugin_impl : public std::enable_shared_from_thisjoin(); + _thread_pool->stop(); + } + } + optional calculate_next_block_time(const account_name& producer_name, const block_timestamp_type& current_block_time) const; void schedule_production_loop(); void produce_block(); @@ -131,6 +138,7 @@ class producer_plugin_impl : public std::enable_shared_from_this _producer_watermarks; pending_block_mode _pending_block_mode; transaction_id_with_expiry_index _persistent_transactions; + fc::optional _thread_pool; int32_t _max_transaction_time_ms; fc::microseconds _max_irreversible_block_age_us; @@ -349,8 +357,8 @@ class producer_plugin_impl : public std::enable_shared_from_thischain(); const auto& cfg = chain.get_global_properties().configuration; fc::time_point deadline = fc::time_point::now() + fc::time_point( fc::microseconds( cfg.max_transaction_cpu_usage )); - transaction_metadata::create_signing_keys_future( trx, chain.get_thread_pool(), chain.get_chain_id(), deadline ); - boost::asio::post( chain.get_thread_pool(), [self = this, trx, persist_until_expired, next]() { + transaction_metadata::create_signing_keys_future( trx, *_thread_pool, chain.get_chain_id(), deadline ); + boost::asio::post( *_thread_pool, [self = this, trx, persist_until_expired, next]() { if( trx->signing_keys_future.valid() ) trx->signing_keys_future.wait(); app().get_io_service().post( [self, trx, persist_until_expired, next]() { @@ -543,6 +551,8 @@ void producer_plugin::set_program_options( "offset of last block producing time in microseconds. Negative number results in blocks to go out sooner, and positive number results in blocks to go out later") ("incoming-defer-ratio", bpo::value()->default_value(1.0), "ratio between incoming transations and deferred transactions when both are exhausted") + ("producer-threads", bpo::value()->default_value(config::default_controller_thread_pool_size), + "Number of worker threads in producer thread pool") ("snapshots-dir", bpo::value()->default_value("snapshots"), "the location of the snapshots directory (absolute path or relative to application data dir)") ; @@ -675,6 +685,11 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ my->_incoming_defer_ratio = options.at("incoming-defer-ratio").as(); + auto thread_pool_size = options.at( "producer-threads" ).as(); + EOS_ASSERT( thread_pool_size > 0, plugin_config_exception, + "producer-threads ${num} must be greater than 0", ("num", thread_pool_size)); + my->_thread_pool.emplace( thread_pool_size ); + if( options.count( "snapshots-dir" )) { auto sd = options.at( "snapshots-dir" ).as(); if( sd.is_relative()) { From 957db7f667349ea816d54b0e11107c9d806cd556 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 17 Dec 2018 17:32:31 -0500 Subject: [PATCH 12/23] Move thread_pool join/stop to plugin shutdown so that they are joined before application quit --- libraries/chain/controller.cpp | 3 --- plugins/chain_plugin/chain_plugin.cpp | 2 ++ plugins/producer_plugin/producer_plugin.cpp | 11 ++++------- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 461f481a34f..e2fbd402f84 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -407,9 +407,6 @@ struct controller_impl { ~controller_impl() { pending.reset(); - thread_pool.join(); - thread_pool.stop(); - db.flush(); reversible_blocks.flush(); } diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 6eeeb5a5082..0f46927b260 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -738,6 +738,8 @@ void chain_plugin::plugin_shutdown() { my->accepted_transaction_connection.reset(); my->applied_transaction_connection.reset(); my->accepted_confirmation_connection.reset(); + my->chain->get_thread_pool().stop(); + my->chain->get_thread_pool().join(); my->chain.reset(); } diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 2ab341f7114..57423dbb804 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -114,13 +114,6 @@ class producer_plugin_impl : public std::enable_shared_from_thisjoin(); - _thread_pool->stop(); - } - } - optional calculate_next_block_time(const account_name& producer_name, const block_timestamp_type& current_block_time) const; void schedule_production_loop(); void produce_block(); @@ -791,6 +784,10 @@ void producer_plugin::plugin_shutdown() { edump((e.to_detail_string())); } + if( my->_thread_pool ) { + my->_thread_pool->join(); + my->_thread_pool->stop(); + } my->_accepted_block_connection.reset(); my->_irreversible_block_connection.reset(); } From 9270c9cb9a611dd3857b6d09c75b9381e72e6167 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 17 Dec 2018 17:35:50 -0500 Subject: [PATCH 13/23] Fix signature future deadline from starting too early --- libraries/chain/controller.cpp | 2 +- libraries/chain/include/eosio/chain/transaction_metadata.hpp | 2 +- libraries/chain/transaction_metadata.cpp | 5 +++-- plugins/producer_plugin/producer_plugin.cpp | 3 +-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index e2fbd402f84..83eb9a472e0 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1189,7 +1189,7 @@ struct controller_impl { auto& pt = receipt.trx.get(); auto mtrx = std::make_shared( std::make_shared( pt ) ); if( !self.skip_auth_check() ) { - transaction_metadata::create_signing_keys_future( mtrx, thread_pool, chain_id, fc::time_point::maximum() ); + transaction_metadata::create_signing_keys_future( mtrx, thread_pool, chain_id, microseconds::maximum() ); } packed_transactions.emplace_back( std::move( mtrx ) ); } diff --git a/libraries/chain/include/eosio/chain/transaction_metadata.hpp b/libraries/chain/include/eosio/chain/transaction_metadata.hpp index e3742eb0978..76c55e88635 100644 --- a/libraries/chain/include/eosio/chain/transaction_metadata.hpp +++ b/libraries/chain/include/eosio/chain/transaction_metadata.hpp @@ -52,7 +52,7 @@ class transaction_metadata { const flat_set& recover_keys( const chain_id_type& chain_id ); static void create_signing_keys_future( const transaction_metadata_ptr& mtrx, boost::asio::thread_pool& thread_pool, - const chain_id_type& chain_id, fc::time_point deadline); + const chain_id_type& chain_id, fc::microseconds timelimit ); uint32_t total_actions()const { return trx.context_free_actions.size() + trx.actions.size(); } }; diff --git a/libraries/chain/transaction_metadata.cpp b/libraries/chain/transaction_metadata.cpp index 5e049fdf217..bd95904a0d0 100644 --- a/libraries/chain/transaction_metadata.cpp +++ b/libraries/chain/transaction_metadata.cpp @@ -20,12 +20,13 @@ const flat_set& transaction_metadata::recover_keys( const chain } void transaction_metadata::create_signing_keys_future( const transaction_metadata_ptr& mtrx, - boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id, fc::time_point deadline ) { + boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id, fc::microseconds timelimit ) { if( mtrx->signing_keys.valid() ) // already created return; std::weak_ptr mtrx_wp = mtrx; - mtrx->signing_keys_future = async_thread_pool( thread_pool, [deadline, chain_id, mtrx_wp]() { + mtrx->signing_keys_future = async_thread_pool( thread_pool, [timelimit, chain_id, mtrx_wp]() { + fc::time_point deadline = fc::time_point::now() + timelimit; auto mtrx = mtrx_wp.lock(); return mtrx ? std::make_pair( chain_id, mtrx->trx.get_signature_keys( chain_id, deadline ) ) : diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 57423dbb804..d4a8e877b01 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -349,8 +349,7 @@ class producer_plugin_impl : public std::enable_shared_from_this next) { chain::controller& chain = chain_plug->chain(); const auto& cfg = chain.get_global_properties().configuration; - fc::time_point deadline = fc::time_point::now() + fc::time_point( fc::microseconds( cfg.max_transaction_cpu_usage )); - transaction_metadata::create_signing_keys_future( trx, *_thread_pool, chain.get_chain_id(), deadline ); + transaction_metadata::create_signing_keys_future( trx, *_thread_pool, chain.get_chain_id(), fc::microseconds( cfg.max_transaction_cpu_usage ) ); boost::asio::post( *_thread_pool, [self = this, trx, persist_until_expired, next]() { if( trx->signing_keys_future.valid() ) trx->signing_keys_future.wait(); From 3e733f5711209df5e65536f03bb202be9d2d0b9c Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 17 Dec 2018 18:22:09 -0500 Subject: [PATCH 14/23] Fix overflow of deadline and deadline check --- libraries/chain/transaction.cpp | 6 ++---- libraries/chain/transaction_metadata.cpp | 3 ++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/libraries/chain/transaction.cpp b/libraries/chain/transaction.cpp index 9cdac6f4889..0f6ad026b94 100644 --- a/libraries/chain/transaction.cpp +++ b/libraries/chain/transaction.cpp @@ -88,14 +88,12 @@ flat_set transaction::get_signature_keys( const vector recovered_pub_keys; for(const signature_type& sig : signatures) { - auto now = fc::time_point::now(); - EOS_ASSERT( start + now <= deadline, tx_cpu_usage_exceeded, "transaction signature verification executed for too long", - ("now", now)("deadline", deadline)("start", start) ); + EOS_ASSERT( fc::time_point::now() < deadline, tx_cpu_usage_exceeded, "transaction signature verification executed for too long", + ("now", fc::time_point::now())("deadline", deadline) ); public_key_type recov; recovery_cache_type::index::type::iterator it = recovery_cache.get().find( sig ); const auto& tid = id(); diff --git a/libraries/chain/transaction_metadata.cpp b/libraries/chain/transaction_metadata.cpp index bd95904a0d0..c493a846cd5 100644 --- a/libraries/chain/transaction_metadata.cpp +++ b/libraries/chain/transaction_metadata.cpp @@ -26,7 +26,8 @@ void transaction_metadata::create_signing_keys_future( const transaction_metadat std::weak_ptr mtrx_wp = mtrx; mtrx->signing_keys_future = async_thread_pool( thread_pool, [timelimit, chain_id, mtrx_wp]() { - fc::time_point deadline = fc::time_point::now() + timelimit; + fc::time_point deadline = timelimit == fc::microseconds::maximum() ? + fc::time_point::maximum() : fc::time_point::now() + timelimit; auto mtrx = mtrx_wp.lock(); return mtrx ? std::make_pair( chain_id, mtrx->trx.get_signature_keys( chain_id, deadline ) ) : From 6e9b4419da691028f3e837904f72b3dbf9cfd2e4 Mon Sep 17 00:00:00 2001 From: arhag Date: Mon, 17 Dec 2018 20:30:47 -0500 Subject: [PATCH 15/23] initial setup of billing CPU for signatures recovered earlier --- libraries/chain/controller.cpp | 16 ++++++++++++++-- .../include/eosio/chain/transaction_context.hpp | 1 - libraries/chain/transaction_context.cpp | 1 - 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 83eb9a472e0..fa3ec68cb6c 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -998,7 +998,20 @@ struct controller_impl { transaction_trace_ptr trace; try { - transaction_context trx_context(self, trx->trx, trx->id); + auto start = fc::time_point::now(); + if( !explicit_billed_cpu_time ) { + int64_t cpu_per_signature_us = 10; // TODO: plumb in producer configuration for this value. + auto already_consumed_time = fc::microseconds( cpu_per_signature_us * trx->trx.signatures.size() ); + // Alternatively store actual time to recover keys in transaction_metadata and use that as already_consumed_time (makes more sense if recovery cache was removed). + + if( start.time_since_epoch() < already_consumed_time ) { + start = fc::time_point(); + } else { + start -= already_consumed_time; + } + } + + transaction_context trx_context(self, trx->trx, trx->id, start); if ((bool)subjective_cpu_leeway && pending->_block_status == controller::block_status::incomplete) { trx_context.leeway = *subjective_cpu_leeway; } @@ -1014,7 +1027,6 @@ struct controller_impl { bool skip_recording = replay_head_time && (time_point(trx->trx.expiration) <= *replay_head_time); trx_context.init_for_input_trx( trx->packed_trx->get_unprunable_size(), trx->packed_trx->get_prunable_size(), - trx->trx.signatures.size(), skip_recording); } diff --git a/libraries/chain/include/eosio/chain/transaction_context.hpp b/libraries/chain/include/eosio/chain/transaction_context.hpp index 2e215f00ec2..b0327dafb18 100644 --- a/libraries/chain/include/eosio/chain/transaction_context.hpp +++ b/libraries/chain/include/eosio/chain/transaction_context.hpp @@ -33,7 +33,6 @@ namespace eosio { namespace chain { void init_for_input_trx( uint64_t packed_trx_unprunable_size, uint64_t packed_trx_prunable_size, - uint32_t num_signatures, bool skip_recording); void init_for_deferred_trx( fc::time_point published ); diff --git a/libraries/chain/transaction_context.cpp b/libraries/chain/transaction_context.cpp index 989905ef9a0..d5da8ca279b 100644 --- a/libraries/chain/transaction_context.cpp +++ b/libraries/chain/transaction_context.cpp @@ -284,7 +284,6 @@ namespace bacc = boost::accumulators; void transaction_context::init_for_input_trx( uint64_t packed_trx_unprunable_size, uint64_t packed_trx_prunable_size, - uint32_t num_signatures, bool skip_recording ) { const auto& cfg = control.get_global_properties().configuration; From 2b6a88a299fa017386e4b2a945c2cf5fa096ff3b Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 18 Dec 2018 11:53:33 -0500 Subject: [PATCH 16/23] Make recovery cache non-thread local and guard by mutex --- libraries/chain/transaction.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/libraries/chain/transaction.cpp b/libraries/chain/transaction.cpp index 0f6ad026b94..5bd5090d114 100644 --- a/libraries/chain/transaction.cpp +++ b/libraries/chain/transaction.cpp @@ -28,6 +28,7 @@ struct cached_pub_key { transaction_id_type trx_id; public_key_type pub_key; signature_type sig; + fc::microseconds cpu_usage; cached_pub_key(const cached_pub_key&) = delete; cached_pub_key() = delete; cached_pub_key& operator=(const cached_pub_key&) = delete; @@ -48,6 +49,8 @@ typedef multi_index_container< > > recovery_cache_type; +static std::mutex cache_mtx; + void transaction_header::set_reference_block( const block_id_type& reference_block ) { ref_block_num = fc::endian_reverse_u32(reference_block._hash[0]); ref_block_prefix = reference_block._hash[1]; @@ -81,38 +84,48 @@ digest_type transaction::sig_digest( const chain_id_type& chain_id, const vector return enc.result(); } + flat_set transaction::get_signature_keys( const vector& signatures, const chain_id_type& chain_id, fc::time_point deadline, const vector& cfd, bool allow_duplicate_keys)const { try { using boost::adaptors::transformed; - constexpr size_t recovery_cache_size = 1000; - static thread_local recovery_cache_type recovery_cache; + constexpr size_t recovery_cache_size = 10000; + static recovery_cache_type recovery_cache; + auto start = fc::time_point::now(); const digest_type digest = sig_digest(chain_id, cfd); + std::unique_lock lock(cache_mtx, std::defer_lock); flat_set recovered_pub_keys; for(const signature_type& sig : signatures) { - EOS_ASSERT( fc::time_point::now() < deadline, tx_cpu_usage_exceeded, "transaction signature verification executed for too long", - ("now", fc::time_point::now())("deadline", deadline) ); + auto now = fc::time_point::now(); + EOS_ASSERT( now < deadline, tx_cpu_usage_exceeded, "transaction signature verification executed for too long", + ("now", now)("deadline", deadline)("start", start) ); public_key_type recov; - recovery_cache_type::index::type::iterator it = recovery_cache.get().find( sig ); const auto& tid = id(); + lock.lock(); + recovery_cache_type::index::type::iterator it = recovery_cache.get().find( sig ); if( it == recovery_cache.get().end() || it->trx_id != tid ) { + lock.unlock(); recov = public_key_type( sig, digest ); - recovery_cache.emplace_back( cached_pub_key{tid, recov, sig} ); //could fail on dup signatures; not a problem + fc::microseconds cpu_usage = fc::time_point::now() - start; + lock.lock(); + recovery_cache.emplace_back( cached_pub_key{tid, recov, sig, cpu_usage} ); //could fail on dup signatures; not a problem } else { recov = it->pub_key; } + lock.unlock(); bool successful_insertion = false; std::tie(std::ignore, successful_insertion) = recovered_pub_keys.insert(recov); EOS_ASSERT( allow_duplicate_keys || successful_insertion, tx_duplicate_sig, "transaction includes more than one signature signed using the same key associated with public key: ${key}", - ("key", recov) - ); + ("key", recov) ); } + lock.lock(); while ( recovery_cache.size() > recovery_cache_size ) recovery_cache.erase( recovery_cache.begin()); + lock.unlock(); return recovered_pub_keys; } FC_CAPTURE_AND_RETHROW() } From 94ad2d1533ed48a5dbfa466504758b24395de7ac Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 18 Dec 2018 14:58:21 -0500 Subject: [PATCH 17/23] Calculate cpu usage of signature recovery --- .../chain/include/eosio/chain/transaction.hpp | 10 ++++--- .../eosio/chain/transaction_metadata.hpp | 4 ++- libraries/chain/transaction.cpp | 20 ++++++++------ libraries/chain/transaction_metadata.cpp | 27 ++++++++++++------- plugins/mongo_db_plugin/mongo_db_plugin.cpp | 7 ++--- tests/wallet_tests.cpp | 3 ++- unittests/api_tests.cpp | 12 ++++++--- 7 files changed, 52 insertions(+), 31 deletions(-) diff --git a/libraries/chain/include/eosio/chain/transaction.hpp b/libraries/chain/include/eosio/chain/transaction.hpp index 65f3c35ff63..0829907c09c 100644 --- a/libraries/chain/include/eosio/chain/transaction.hpp +++ b/libraries/chain/include/eosio/chain/transaction.hpp @@ -58,11 +58,12 @@ namespace eosio { namespace chain { transaction_id_type id()const; digest_type sig_digest( const chain_id_type& chain_id, const vector& cfd = vector() )const; - flat_set get_signature_keys( const vector& signatures, + fc::microseconds get_signature_keys( const vector& signatures, const chain_id_type& chain_id, fc::time_point deadline, - const vector& cfd = vector(), - bool allow_duplicate_keys = false)const; + const vector& cfd, + flat_set& recovered_pub_keys, + bool allow_duplicate_keys = false) const; uint32_t total_actions()const { return context_free_actions.size() + actions.size(); } account_name first_authorizor()const { @@ -92,7 +93,8 @@ namespace eosio { namespace chain { const signature_type& sign(const private_key_type& key, const chain_id_type& chain_id); signature_type sign(const private_key_type& key, const chain_id_type& chain_id)const; - flat_set get_signature_keys( const chain_id_type& chain_id, fc::time_point deadline, + fc::microseconds get_signature_keys( const chain_id_type& chain_id, fc::time_point deadline, + flat_set& recovered_pub_keys, bool allow_duplicate_keys = false )const; }; diff --git a/libraries/chain/include/eosio/chain/transaction_metadata.hpp b/libraries/chain/include/eosio/chain/transaction_metadata.hpp index 76c55e88635..9b9dfd9df77 100644 --- a/libraries/chain/include/eosio/chain/transaction_metadata.hpp +++ b/libraries/chain/include/eosio/chain/transaction_metadata.hpp @@ -25,8 +25,10 @@ class transaction_metadata { transaction_id_type signed_id; signed_transaction trx; packed_transaction_ptr packed_trx; + fc::microseconds sig_cpu_usage; optional>> signing_keys; - std::future>> signing_keys_future; + std::future>> + signing_keys_future; bool accepted = false; bool implicit = false; bool scheduled = false; diff --git a/libraries/chain/transaction.cpp b/libraries/chain/transaction.cpp index 5bd5090d114..f53b140a1ef 100644 --- a/libraries/chain/transaction.cpp +++ b/libraries/chain/transaction.cpp @@ -84,9 +84,9 @@ digest_type transaction::sig_digest( const chain_id_type& chain_id, const vector return enc.result(); } - -flat_set transaction::get_signature_keys( const vector& signatures, - const chain_id_type& chain_id, fc::time_point deadline, const vector& cfd, bool allow_duplicate_keys)const +fc::microseconds transaction::get_signature_keys( const vector& signatures, + const chain_id_type& chain_id, fc::time_point deadline, const vector& cfd, + flat_set& recovered_pub_keys, bool allow_duplicate_keys)const { try { using boost::adaptors::transformed; @@ -96,7 +96,7 @@ flat_set transaction::get_signature_keys( const vector lock(cache_mtx, std::defer_lock); - flat_set recovered_pub_keys; + fc::microseconds sig_cpu_usage; for(const signature_type& sig : signatures) { auto now = fc::time_point::now(); EOS_ASSERT( now < deadline, tx_cpu_usage_exceeded, "transaction signature verification executed for too long", @@ -111,8 +111,10 @@ flat_set transaction::get_signature_keys( const vectorpub_key; + sig_cpu_usage += it->cpu_usage; } lock.unlock(); bool successful_insertion = false; @@ -127,7 +129,7 @@ flat_set transaction::get_signature_keys( const vector signed_transaction::get_signature_keys( const chain_id_type& chain_id, fc::time_point deadline, - bool allow_duplicate_keys)const +fc::microseconds +signed_transaction::get_signature_keys( const chain_id_type& chain_id, fc::time_point deadline, + flat_set& recovered_pub_keys, + bool allow_duplicate_keys)const { - return transaction::get_signature_keys(signatures, chain_id, deadline, context_free_data, allow_duplicate_keys); + return transaction::get_signature_keys(signatures, chain_id, deadline, context_free_data, recovered_pub_keys, allow_duplicate_keys); } uint32_t packed_transaction::get_unprunable_size()const { diff --git a/libraries/chain/transaction_metadata.cpp b/libraries/chain/transaction_metadata.cpp index c493a846cd5..4324612bbdb 100644 --- a/libraries/chain/transaction_metadata.cpp +++ b/libraries/chain/transaction_metadata.cpp @@ -9,29 +9,36 @@ const flat_set& transaction_metadata::recover_keys( const chain // Unlikely for more than one chain_id to be used in one nodeos instance if( !signing_keys || signing_keys->first != chain_id ) { if( signing_keys_future.valid() ) { - signing_keys = signing_keys_future.get(); - if( signing_keys->first == chain_id ) { + std::tuple> sig_keys = signing_keys_future.get(); + if( std::get<0>( sig_keys ) == chain_id ) { + sig_cpu_usage = std::get<1>( sig_keys ); + signing_keys.emplace( std::make_pair( std::get<0>( sig_keys ), std::get<2>( sig_keys ))); return signing_keys->second; } } - signing_keys = std::make_pair( chain_id, trx.get_signature_keys( chain_id, fc::time_point::maximum() )); + flat_set recovered_pub_keys; + sig_cpu_usage = trx.get_signature_keys( chain_id, fc::time_point::maximum(), recovered_pub_keys ); + signing_keys.emplace( chain_id, std::move( recovered_pub_keys )); } return signing_keys->second; } void transaction_metadata::create_signing_keys_future( const transaction_metadata_ptr& mtrx, - boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id, fc::microseconds timelimit ) { + boost::asio::thread_pool& thread_pool, const chain_id_type& chain_id, fc::microseconds time_limit ) { if( mtrx->signing_keys.valid() ) // already created return; std::weak_ptr mtrx_wp = mtrx; - mtrx->signing_keys_future = async_thread_pool( thread_pool, [timelimit, chain_id, mtrx_wp]() { - fc::time_point deadline = timelimit == fc::microseconds::maximum() ? - fc::time_point::maximum() : fc::time_point::now() + timelimit; + mtrx->signing_keys_future = async_thread_pool( thread_pool, [time_limit, chain_id, mtrx_wp]() { + fc::time_point deadline = time_limit == fc::microseconds::maximum() ? + fc::time_point::maximum() : fc::time_point::now() + time_limit; auto mtrx = mtrx_wp.lock(); - return mtrx ? - std::make_pair( chain_id, mtrx->trx.get_signature_keys( chain_id, deadline ) ) : - std::make_pair( chain_id, decltype( mtrx->trx.get_signature_keys( chain_id, deadline ) ){} ); + fc::microseconds cpu_usage; + flat_set recovered_pub_keys; + if( mtrx ) { + mtrx->trx.get_signature_keys( chain_id, deadline, recovered_pub_keys ); + } + return std::make_tuple( chain_id, cpu_usage, recovered_pub_keys); } ); } diff --git a/plugins/mongo_db_plugin/mongo_db_plugin.cpp b/plugins/mongo_db_plugin/mongo_db_plugin.cpp index 6c7ce0959d7..5c70db212c7 100644 --- a/plugins/mongo_db_plugin/mongo_db_plugin.cpp +++ b/plugins/mongo_db_plugin/mongo_db_plugin.cpp @@ -761,9 +761,10 @@ void mongo_db_plugin_impl::_process_accepted_transaction( const chain::transacti if( t->signing_keys.valid() ) { signing_keys_json = fc::json::to_string( t->signing_keys->second ); } else { - auto signing_keys = trx.get_signature_keys( *chain_id, fc::time_point::maximum(), false ); - if( !signing_keys.empty() ) { - signing_keys_json = fc::json::to_string( signing_keys ); + flat_set keys; + trx.get_signature_keys( *chain_id, fc::time_point::maximum(), keys, false ); + if( !keys.empty() ) { + signing_keys_json = fc::json::to_string( keys ); } } diff --git a/tests/wallet_tests.cpp b/tests/wallet_tests.cpp index e52f5d0a483..fd22a95f6da 100644 --- a/tests/wallet_tests.cpp +++ b/tests/wallet_tests.cpp @@ -173,7 +173,8 @@ BOOST_AUTO_TEST_CASE(wallet_manager_test) pubkeys.emplace(pkey1.get_public_key()); pubkeys.emplace(pkey2.get_public_key()); trx = wm.sign_transaction(trx, pubkeys, chain_id ); - const auto& pks = trx.get_signature_keys(chain_id, fc::time_point::maximum()); + flat_set pks; + trx.get_signature_keys(chain_id, fc::time_point::maximum(), pks); BOOST_CHECK_EQUAL(2, pks.size()); BOOST_CHECK(find(pks.cbegin(), pks.cend(), pkey1.get_public_key()) != pks.cend()); BOOST_CHECK(find(pks.cbegin(), pks.cend(), pkey2.get_public_key()) != pks.cend()); diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index 3f3468885e9..e077d2dad08 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -149,7 +149,8 @@ transaction_trace_ptr CallAction(TESTER& test, T ac, const vector& test.set_transaction_headers(trx); auto sigs = trx.sign(test.get_private_key(scope[0], "active"), test.control->get_chain_id()); - trx.get_signature_keys(test.control->get_chain_id(), fc::time_point::maximum()); + flat_set keys; + trx.get_signature_keys(test.control->get_chain_id(), fc::time_point::maximum(), keys); auto res = test.push_transaction(trx); BOOST_CHECK_EQUAL(res->receipt->status, transaction_receipt::executed); test.produce_block(); @@ -173,7 +174,8 @@ transaction_trace_ptr CallFunction(TESTER& test, T ac, const vector& data, test.set_transaction_headers(trx, test.DEFAULT_EXPIRATION_DELTA); auto sigs = trx.sign(test.get_private_key(scope[0], "active"), test.control->get_chain_id()); - trx.get_signature_keys(test.control->get_chain_id(), fc::time_point::maximum()); + flat_set keys; + trx.get_signature_keys(test.control->get_chain_id(), fc::time_point::maximum(), keys); auto res = test.push_transaction(trx); BOOST_CHECK_EQUAL(res->receipt->status, transaction_receipt::executed); test.produce_block(); @@ -266,7 +268,8 @@ BOOST_FIXTURE_TEST_CASE(action_receipt_tests, TESTER) { try { trx.actions.push_back(act); this->set_transaction_headers(trx, this->DEFAULT_EXPIRATION_DELTA); trx.sign(this->get_private_key(config::system_account_name, "active"), control->get_chain_id()); - trx.get_signature_keys(control->get_chain_id(), fc::time_point::maximum()); + flat_set keys; + trx.get_signature_keys(control->get_chain_id(), fc::time_point::maximum(), keys); auto res = this->push_transaction(trx); BOOST_CHECK_EQUAL(res->receipt->status, transaction_receipt::executed); this->produce_block(); @@ -745,7 +748,8 @@ void call_test(TESTER& test, T ac, uint32_t billed_cpu_time_us , uint32_t max_cp test.set_transaction_headers(trx); //trx.max_cpu_usage_ms = max_cpu_usage_ms; auto sigs = trx.sign(test.get_private_key(N(testapi), "active"), test.control->get_chain_id()); - trx.get_signature_keys(test.control->get_chain_id(), fc::time_point::maximum()); + flat_set keys; + trx.get_signature_keys(test.control->get_chain_id(), fc::time_point::maximum(), keys); auto res = test.push_transaction( trx, fc::time_point::now() + fc::milliseconds(max_cpu_usage_ms), billed_cpu_time_us ); BOOST_CHECK_EQUAL(res->receipt->status, transaction_receipt::executed); test.produce_block(); From 48bf2d4c63e95dac06d1a4912722a639aba811a0 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 18 Dec 2018 15:32:36 -0500 Subject: [PATCH 18/23] Add signature-cpu-billable-pct option to chain_plugin --- libraries/chain/controller.cpp | 4 +--- libraries/chain/include/eosio/chain/config.hpp | 1 + libraries/chain/include/eosio/chain/controller.hpp | 1 + plugins/chain_plugin/chain_plugin.cpp | 4 ++++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index fa3ec68cb6c..e46f65bf11f 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1000,9 +1000,7 @@ struct controller_impl { try { auto start = fc::time_point::now(); if( !explicit_billed_cpu_time ) { - int64_t cpu_per_signature_us = 10; // TODO: plumb in producer configuration for this value. - auto already_consumed_time = fc::microseconds( cpu_per_signature_us * trx->trx.signatures.size() ); - // Alternatively store actual time to recover keys in transaction_metadata and use that as already_consumed_time (makes more sense if recovery cache was removed). + fc::microseconds already_consumed_time( EOS_PERCENT(trx->sig_cpu_usage.count(), conf.sig_cpu_bill_pct) ); if( start.time_since_epoch() < already_consumed_time ) { start = fc::time_point(); diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 307b36aab00..2c208ffd6c0 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -79,6 +79,7 @@ const static uint32_t default_max_trx_delay = 45*24*3600; // const static uint32_t default_max_inline_action_size = 4 * 1024; // 4 KB const static uint16_t default_max_inline_action_depth = 4; const static uint16_t default_max_auth_depth = 6; +const static uint32_t default_sig_cpu_bill_pct = 50 * percent_1; // billable percentage of signature recovery const static uint16_t default_controller_thread_pool_size = 2; const static uint32_t min_net_usage_delta_between_base_and_max_for_trx = 10*1024; diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index bb07d223a8e..f0d5a53f52d 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -65,6 +65,7 @@ namespace eosio { namespace chain { uint64_t state_guard_size = chain::config::default_state_guard_size; uint64_t reversible_cache_size = chain::config::default_reversible_cache_size; uint64_t reversible_guard_size = chain::config::default_reversible_guard_size; + uint32_t sig_cpu_bill_pct = chain::config::default_sig_cpu_bill_pct; uint16_t thread_pool_size = chain::config::default_controller_thread_pool_size; bool read_only = false; bool force_all_checks = false; diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 0f46927b260..ffdbdccf7a1 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -218,6 +218,8 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip ("chain-state-db-guard-size-mb", bpo::value()->default_value(config::default_state_guard_size / (1024 * 1024)), "Safely shut down node when free space remaining in the chain state database drops below this size (in MiB).") ("reversible-blocks-db-size-mb", bpo::value()->default_value(config::default_reversible_cache_size / (1024 * 1024)), "Maximum size (in MiB) of the reversible blocks database") ("reversible-blocks-db-guard-size-mb", bpo::value()->default_value(config::default_reversible_guard_size / (1024 * 1024)), "Safely shut down node when free space remaining in the reverseible blocks database drops below this size (in MiB).") + ("signature-cpu-billable-pct", bpo::value()->default_value(config::default_sig_cpu_bill_pct / config::percent_1), + "Percentage of actual signature recovery cpu to bill. Whole number percentages, e.g. 50 for 50%") ("chain-threads", bpo::value()->default_value(config::default_controller_thread_pool_size), "Number of worker threads in controller thread pool") ("contracts-console", bpo::bool_switch()->default_value(false), @@ -426,6 +428,8 @@ void chain_plugin::plugin_initialize(const variables_map& options) { "chain-threads ${num} must be greater than 0", ("num", my->chain_config->thread_pool_size) ); } + my->chain_config->sig_cpu_bill_pct = options.at("signature-cpu-billable-pct").as() * config::percent_1; + if( my->wasm_runtime ) my->chain_config->wasm_runtime = *my->wasm_runtime; From 1ecb7cc59b1d305a6e997f2f5459692523554a35 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 18 Dec 2018 15:39:02 -0500 Subject: [PATCH 19/23] Add missing include of mutex --- libraries/chain/transaction.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/chain/transaction.cpp b/libraries/chain/transaction.cpp index f53b140a1ef..c914aab80fc 100644 --- a/libraries/chain/transaction.cpp +++ b/libraries/chain/transaction.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -49,8 +50,6 @@ typedef multi_index_container< > > recovery_cache_type; -static std::mutex cache_mtx; - void transaction_header::set_reference_block( const block_id_type& reference_block ) { ref_block_num = fc::endian_reverse_u32(reference_block._hash[0]); ref_block_prefix = reference_block._hash[1]; @@ -92,6 +91,8 @@ fc::microseconds transaction::get_signature_keys( const vector& constexpr size_t recovery_cache_size = 10000; static recovery_cache_type recovery_cache; + static std::mutex cache_mtx; + auto start = fc::time_point::now(); const digest_type digest = sig_digest(chain_id, cfd); From 75587d0959a8fadd17f4c8a49b0ac4bab87aa6bf Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 18 Dec 2018 16:10:40 -0500 Subject: [PATCH 20/23] Assert signature-cpu-billable-pct is 0-100 --- plugins/chain_plugin/chain_plugin.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index ffdbdccf7a1..c7863b906d9 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -428,7 +428,10 @@ void chain_plugin::plugin_initialize(const variables_map& options) { "chain-threads ${num} must be greater than 0", ("num", my->chain_config->thread_pool_size) ); } - my->chain_config->sig_cpu_bill_pct = options.at("signature-cpu-billable-pct").as() * config::percent_1; + my->chain_config->sig_cpu_bill_pct = options.at("signature-cpu-billable-pct").as(); + EOS_ASSERT( my->chain_config->sig_cpu_bill_pct >= 0 && my->chain_config->sig_cpu_bill_pct <= 100, plugin_config_exception, + "signature-cpu-billable-pct must be 0 - 100, ${pct}", ("pct", my->chain_config->sig_cpu_bill_pct) ); + my->chain_config->sig_cpu_bill_pct *= config::percent_1; if( my->wasm_runtime ) my->chain_config->wasm_runtime = *my->wasm_runtime; From 21d20a866a52435457c96344832a172f63b6932d Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 18 Dec 2018 16:12:36 -0500 Subject: [PATCH 21/23] Fix capture of cpu_usage. move flat_set into attribute --- libraries/chain/transaction_metadata.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/transaction_metadata.cpp b/libraries/chain/transaction_metadata.cpp index 4324612bbdb..a7ed2935107 100644 --- a/libraries/chain/transaction_metadata.cpp +++ b/libraries/chain/transaction_metadata.cpp @@ -12,7 +12,7 @@ const flat_set& transaction_metadata::recover_keys( const chain std::tuple> sig_keys = signing_keys_future.get(); if( std::get<0>( sig_keys ) == chain_id ) { sig_cpu_usage = std::get<1>( sig_keys ); - signing_keys.emplace( std::make_pair( std::get<0>( sig_keys ), std::get<2>( sig_keys ))); + signing_keys.emplace( std::get<0>( sig_keys ), std::move( std::get<2>( sig_keys ))); return signing_keys->second; } } @@ -36,7 +36,7 @@ void transaction_metadata::create_signing_keys_future( const transaction_metadat fc::microseconds cpu_usage; flat_set recovered_pub_keys; if( mtrx ) { - mtrx->trx.get_signature_keys( chain_id, deadline, recovered_pub_keys ); + cpu_usage = mtrx->trx.get_signature_keys( chain_id, deadline, recovered_pub_keys ); } return std::make_tuple( chain_id, cpu_usage, recovered_pub_keys); } ); From 058d4ac4f8ecc55bb093ed3705a1f79e0bc5b46c Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 18 Dec 2018 16:18:49 -0500 Subject: [PATCH 22/23] clear recovered_pub_keys to preserve previous behaviour --- libraries/chain/transaction.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/chain/transaction.cpp b/libraries/chain/transaction.cpp index c914aab80fc..e53e663ed40 100644 --- a/libraries/chain/transaction.cpp +++ b/libraries/chain/transaction.cpp @@ -94,6 +94,7 @@ fc::microseconds transaction::get_signature_keys( const vector& static std::mutex cache_mtx; auto start = fc::time_point::now(); + recovered_pub_keys.clear(); const digest_type digest = sig_digest(chain_id, cfd); std::unique_lock lock(cache_mtx, std::defer_lock); From 1c8640b1757180fbe9de6df0150cad99fb240a66 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 18 Dec 2018 16:22:03 -0500 Subject: [PATCH 23/23] Add move into tuple creation --- libraries/chain/transaction_metadata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/transaction_metadata.cpp b/libraries/chain/transaction_metadata.cpp index a7ed2935107..5b275baccf9 100644 --- a/libraries/chain/transaction_metadata.cpp +++ b/libraries/chain/transaction_metadata.cpp @@ -38,7 +38,7 @@ void transaction_metadata::create_signing_keys_future( const transaction_metadat if( mtrx ) { cpu_usage = mtrx->trx.get_signature_keys( chain_id, deadline, recovered_pub_keys ); } - return std::make_tuple( chain_id, cpu_usage, recovered_pub_keys); + return std::make_tuple( chain_id, cpu_usage, std::move( recovered_pub_keys )); } ); }