From 51d2b5bab77a19ee8be2ac110a6f7f2f7834c158 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Thu, 6 Apr 2023 13:47:52 -0400 Subject: [PATCH 01/17] Move abi serialization of transaction trace off main thread for send_transaction. --- .../chain/include/eosio/chain/exceptions.hpp | 20 ++++++ libraries/chain/include/eosio/chain/types.hpp | 5 +- plugins/chain_plugin/chain_plugin.cpp | 22 +++--- .../include/eosio/http_plugin/macros.hpp | 67 ++++++++++++------- 4 files changed, 79 insertions(+), 35 deletions(-) diff --git a/libraries/chain/include/eosio/chain/exceptions.hpp b/libraries/chain/include/eosio/chain/exceptions.hpp index 2ea1da6acb..b960f3c424 100644 --- a/libraries/chain/include/eosio/chain/exceptions.hpp +++ b/libraries/chain/include/eosio/chain/exceptions.hpp @@ -87,6 +87,26 @@ NEXT(e.dynamic_copy_exception());\ } +/** + * Capture all exceptions and return a fc::exception_ptr + */ +#define CATCH_AND_RETURN(return_type)\ + catch ( const fc::exception& err ) {\ + return return_type(err.dynamic_copy_exception());\ + } catch ( const std::exception& e ) {\ + fc::exception fce( \ + FC_LOG_MESSAGE( warn, "rethrow ${what}: ", ("what",e.what())),\ + fc::std_exception_code,\ + BOOST_CORE_TYPEID(e).name(),\ + e.what() ) ;\ + return return_type(fce.dynamic_copy_exception());\ + } catch( ... ) {\ + fc::unhandled_exception e(\ + FC_LOG_MESSAGE(warn, "rethrow"),\ + std::current_exception());\ + return return_type(e.dynamic_copy_exception());\ + } + #define EOS_RECODE_EXC( cause_type, effect_type ) \ catch( const cause_type& e ) \ { throw( effect_type( e.what(), e.get_log() ) ); } diff --git a/libraries/chain/include/eosio/chain/types.hpp b/libraries/chain/include/eosio/chain/types.hpp index 65d6080099..13f28825a8 100644 --- a/libraries/chain/include/eosio/chain/types.hpp +++ b/libraries/chain/include/eosio/chain/types.hpp @@ -405,7 +405,10 @@ namespace eosio::chain { // http_plugin thread pool) and which completes the API processing and returns the result T. // ------------------------------------------------------------------------------------------------------- template - using next_function_variant = std::variant>; + using t_or_exception = std::variant; + + template + using next_function_variant = std::variant()>>; template using next_function = std::function&)>; diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 3baa801ea4..0643dbeef8 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -2221,17 +2221,21 @@ void read_write::send_transaction(const read_write::send_transaction_params& par next(std::get(result)); } else { auto trx_trace_ptr = std::get(result); - try { - fc::variant output; + using return_type = t_or_exception; + next([this, next, trx_trace_ptr, + resolver = make_resolver(db, abi_serializer::create_yield_function(fc::microseconds::maximum()))]() { try { - output = db.to_variant_with_abi( *trx_trace_ptr, abi_serializer::create_yield_function( abi_serializer_max_time ) ); - } catch( chain::abi_exception& ) { - output = *trx_trace_ptr; - } + fc::variant output; + try { + abi_serializer::to_variant(*trx_trace_ptr, output, resolver, abi_serializer::create_yield_function(abi_serializer_max_time)); + } catch( chain::abi_exception& ) { + output = *trx_trace_ptr; + } - const chain::transaction_id_type& id = trx_trace_ptr->id; - next(read_write::send_transaction_results{id, output}); - } CATCH_AND_CALL(next); + const chain::transaction_id_type& id = trx_trace_ptr->id; + return return_type(read_write::send_transaction_results{id, output}); + } CATCH_AND_RETURN(return_type); + }); } }); } catch ( boost::interprocess::bad_alloc& ) { diff --git a/plugins/http_plugin/include/eosio/http_plugin/macros.hpp b/plugins/http_plugin/include/eosio/http_plugin/macros.hpp index 0e8fb7d694..2acb9a4c72 100644 --- a/plugins/http_plugin/include/eosio/http_plugin/macros.hpp +++ b/plugins/http_plugin/include/eosio/http_plugin/macros.hpp @@ -7,29 +7,46 @@ struct async_result_visitor : public fc::visitor { } }; -#define CALL_ASYNC_WITH_400(api_name, api_handle, api_namespace, call_name, call_result, http_response_code, params_type) \ -{std::string("/v1/" #api_name "/" #call_name), \ - [api_handle](string&&, string&& body, url_response_callback&& cb) mutable { \ - auto deadline = api_handle.start(); \ - try { \ - auto params = parse_params(body); \ - FC_CHECK_DEADLINE(deadline); \ - api_handle.call_name( std::move(params), \ - [cb=std::move(cb), body=std::move(body)](const eosio::chain::next_function_variant& result){ \ - if (std::holds_alternative(result)) { \ - try { \ - std::get(result)->dynamic_rethrow_exception(); \ - } catch (...) { \ - http_plugin::handle_exception(#api_name, #call_name, body, cb); \ - } \ - } else if (std::holds_alternative(result)) { \ - cb(http_response_code, fc::time_point::maximum(), fc::variant(std::get(result))); \ - } else { \ - assert(0); \ - } \ - }); \ - } catch (...) { \ - http_plugin::handle_exception(#api_name, #call_name, body, cb); \ - } \ - } \ +#define CALL_ASYNC_WITH_400(api_name, api_handle, api_namespace, call_name, call_result, http_resp_code, params_type) \ +{ std::string("/v1/" #api_name "/" #call_name), \ + [api_handle, &_http_plugin](string&&, string&& body, url_response_callback&& cb) mutable { \ + auto deadline = api_handle.start(); \ + try { \ + auto params = parse_params(body); \ + FC_CHECK_DEADLINE(deadline); \ + using http_fwd_t = std::function()>; \ + api_handle.call_name( std::move(params), \ + [&_http_plugin, cb=std::move(cb), body=std::move(body)] \ + (const chain::next_function_variant& result){ \ + if (std::holds_alternative(result)) { \ + try { \ + std::get(result)->dynamic_rethrow_exception(); \ + } catch (...) { \ + http_plugin::handle_exception(#api_name, #call_name, body, cb); \ + } \ + } else if (std::holds_alternative(result)) { \ + cb(http_resp_code, fc::time_point::maximum(), fc::variant(std::get(result))); \ + } else { \ + /* api returned a function to be processed on the http_plugin thread pool */ \ + assert(std::holds_alternative(result)); \ + _http_plugin.post_http_thread_pool([resp_code=http_resp_code, cb=std::move(cb), \ + body=std::move(body), \ + http_fwd = std::get(result)]() { \ + auto result = http_fwd(); /* this returns a t_or_exception variant */ \ + if (std::holds_alternative(result)) { \ + try { \ + std::get(result)->dynamic_rethrow_exception(); \ + } catch (...) { \ + http_plugin::handle_exception(#api_name, #call_name, body, cb); \ + } \ + } else { \ + cb(resp_code, fc::time_point::maximum(), fc::variant(std::get(result))) ; \ + } \ + }); \ + } \ + }); \ + } catch (...) { \ + http_plugin::handle_exception(#api_name, #call_name, body, cb); \ + } \ + } \ } From 66c1731f3f0ea5d836435a0d5c6696b852f02ce0 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Fri, 7 Apr 2023 08:27:50 -0400 Subject: [PATCH 02/17] Move serialization off main thread for compute_transaction --- plugins/chain_plugin/chain_plugin.cpp | 30 ++++++++++++++------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 998ac2a959..412c5a6068 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -2222,8 +2222,7 @@ void read_write::send_transaction(const read_write::send_transaction_params& par } else { auto trx_trace_ptr = std::get(result); using return_type = t_or_exception; - next([this, next, trx_trace_ptr, - resolver = make_resolver(db, abi_serializer::create_yield_function(fc::microseconds::maximum()))]() { + next([this, trx_trace_ptr, resolver = make_resolver(db, abi_serializer::create_yield_function(fc::microseconds::maximum()))]() { try { fc::variant output; try { @@ -2588,20 +2587,23 @@ void read_only::send_transient_transaction(const Params& params, next_function(result)); } else { auto trx_trace_ptr = std::get(result); - - try { - fc::variant output; + using return_type = t_or_exception; + next([this, trx_trace_ptr, resolver = make_resolver(db, abi_serializer::create_yield_function(fc::microseconds::maximum()))]() { try { - output = db.to_variant_with_abi( *trx_trace_ptr, abi_serializer::create_yield_function( abi_serializer_max_time ) ); - } catch( chain::abi_exception& ) { - output = *trx_trace_ptr; - } - - const chain::transaction_id_type& id = trx_trace_ptr->id; - next(Results{id, output}); - } CATCH_AND_CALL(next); + fc::variant output; + try { + abi_serializer::to_variant(*trx_trace_ptr, output, resolver, + abi_serializer::create_yield_function(abi_serializer_max_time)); + } catch( chain::abi_exception& ) { + output = *trx_trace_ptr; + } + + const chain::transaction_id_type& id = trx_trace_ptr->id; + return return_type(Results{id, output}); + } CATCH_AND_RETURN(return_type); + }); } - }); + }); } catch ( boost::interprocess::bad_alloc& ) { chain_plugin::handle_db_exhaustion(); } catch ( const std::bad_alloc& ) { From c2aab35c607617361a2fadbe09c105f04e8f87c8 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Mon, 10 Apr 2023 12:04:22 -0400 Subject: [PATCH 03/17] correct abi caching, avoid unnecessary serializer copies --- .../include/eosio/chain/abi_serializer.hpp | 32 +++-- plugins/chain_api_plugin/chain_api_plugin.cpp | 2 +- plugins/chain_plugin/chain_plugin.cpp | 131 ++++++++++++------ .../eosio/chain_plugin/chain_plugin.hpp | 8 +- 4 files changed, 115 insertions(+), 58 deletions(-) diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index c630940139..cbdec28481 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -485,14 +485,15 @@ namespace impl { }; try { - auto abi = resolver(act.account); - if (abi) { - auto type = abi->get_action_type(act.name); + auto abi_optional = resolver(act.account); + if (abi_optional) { + auto& abi = (abi_serializer&)*abi_optional; + auto type = abi.get_action_type(act.name); if (!type.empty()) { try { - binary_to_variant_context _ctx(*abi, ctx, type); + binary_to_variant_context _ctx(abi, ctx, type); _ctx.short_path = true; // Just to be safe while avoiding the complexity of threading an override boolean all over the place - mvo( "data", abi->_binary_to_variant( type, act.data, _ctx )); + mvo( "data", abi._binary_to_variant( type, act.data, _ctx )); } catch(...) { // any failure to serialize data, then leave as not serailzed set_hex_data(mvo, "data", act.data); @@ -546,13 +547,14 @@ namespace impl { mvo("return_value_hex_data", act_trace.return_value); auto act = act_trace.act; try { - auto abi = resolver(act.account); - if (abi) { - auto type = abi->get_action_result_type(act.name); + auto abi_optional = resolver(act.account); + if (abi_optional) { + auto& abi = (abi_serializer&)*abi_optional; + auto type = abi.get_action_result_type(act.name); if (!type.empty()) { - binary_to_variant_context _ctx(*abi, ctx, type); + binary_to_variant_context _ctx(abi, ctx, type); _ctx.short_path = true; // Just to be safe while avoiding the complexity of threading an override boolean all over the place - mvo( "return_value_data", abi->_binary_to_variant( type, act_trace.return_value, _ctx )); + mvo( "return_value_data", abi._binary_to_variant( type, act_trace.return_value, _ctx )); } } } catch(...) {} @@ -678,13 +680,13 @@ namespace impl { * this will degrade to the common fc::to_variant as soon as the type no longer contains * ABI related info * - * @tparam Reslover - callable with the signature (const name& code_account) -> std::optional + * @tparam Resolver - callable with the signature (const name& code_account) -> std::optional */ template class abi_to_variant_visitor { public: - abi_to_variant_visitor( mutable_variant_object& _mvo, const T& _val, Resolver _resolver, abi_traverse_context& _ctx ) + abi_to_variant_visitor( mutable_variant_object& _mvo, const T& _val, Resolver& _resolver, abi_traverse_context& _ctx ) :_vo(_mvo) ,_val(_val) ,_resolver(_resolver) @@ -707,7 +709,7 @@ namespace impl { private: mutable_variant_object& _vo; const T& _val; - Resolver _resolver; + Resolver& _resolver; abi_traverse_context& _ctx; }; @@ -890,7 +892,7 @@ namespace impl { class abi_from_variant_visitor : public reflector_init_visitor { public: - abi_from_variant_visitor( const variant_object& _vo, T& v, Resolver _resolver, abi_traverse_context& _ctx ) + abi_from_variant_visitor( const variant_object& _vo, T& v, Resolver& _resolver, abi_traverse_context& _ctx ) : reflector_init_visitor(v) ,_vo(_vo) ,_resolver(_resolver) @@ -914,7 +916,7 @@ namespace impl { private: const variant_object& _vo; - Resolver _resolver; + Resolver& _resolver; abi_traverse_context& _ctx; }; diff --git a/plugins/chain_api_plugin/chain_api_plugin.cpp b/plugins/chain_api_plugin/chain_api_plugin.cpp index 7f011804f1..629fd87710 100644 --- a/plugins/chain_api_plugin/chain_api_plugin.cpp +++ b/plugins/chain_api_plugin/chain_api_plugin.cpp @@ -170,7 +170,7 @@ void chain_api_plugin::plugin_startup() { return [api, cb, deadline, post_time, remaining_time, abi_cache=std::move(abi_cache), block=std::move(block)]() mutable { try { auto new_deadline = deadline + (fc::time_point::now() - post_time); - fc::variant result = api.convert_block(block, std::move(abi_cache), remaining_time); + fc::variant result = api.convert_block(block, abi_cache, remaining_time); cb(200, new_deadline, std::move(result)); } catch( ... ) { http_plugin::handle_exception("chain", "get_block", "", cb); diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 412c5a6068..21b8d59c24 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1826,6 +1826,74 @@ auto make_resolver(const controller& control, abi_serializer::yield_function_t y }; } +class abi_serializer_cache_builder { +public: + abi_serializer_cache_builder(const controller& db, const fc::microseconds& max_time) : + resolver(make_resolver(db, abi_serializer::create_yield_function(max_time))) + { + } + + abi_serializer_cache_builder(const abi_serializer_cache_builder&) = delete; + + abi_serializer_cache_builder&& add_serializers(const chain::signed_block_ptr& block) && { + for( const auto& receipt: block->transactions ) { + if( std::holds_alternative( receipt.trx ) ) { + const auto& pt = std::get( receipt.trx ); + const auto& t = pt.get_transaction(); + for( const auto& a: t.actions ) + add_to_cache( a ); + for( const auto& a: t.context_free_actions ) + add_to_cache( a ); + } + } + return std::move(*this); + } + + abi_serializer_cache_builder&& add_serializers(const transaction_trace_ptr& trace_ptr) && { + for( const auto& trace: trace_ptr->action_traces ) { + add_to_cache(trace.act); + } + return std::move(*this); + } + + chain_apis::abi_serializer_cache&& get() && { + return std::move(abi_cache); + } + +private: + void add_to_cache(const chain::action& a) { + auto it = abi_cache.find( a.account ); + if( it == abi_cache.end() ) { + try { + abi_cache.emplace_hint( it, a.account, resolver( a.account ) ); + } catch( ... ) { + // keep behavior of not throwing on invalid abi, will result in hex data + } + } + } + + std::function (const account_name &name)> resolver; + chain_apis::abi_serializer_cache abi_cache; +}; + +class abi_resolver { +public: + abi_resolver(chain_apis::abi_serializer_cache &&abi_cache) : + abi_cache(std::move(abi_cache)) + {} + + std::optional> operator()(const account_name& account) { + auto it = abi_cache.find(account); + if (it != abi_cache.end() && it->second) + return std::reference_wrapper(*it->second); + return {}; + }; + +private: + chain_apis::abi_serializer_cache abi_cache; +}; + + read_only::get_scheduled_transactions_result read_only::get_scheduled_transactions( const read_only::get_scheduled_transactions_params& p, const fc::time_point& deadline ) const { @@ -1971,36 +2039,13 @@ read_only::get_block_header_result read_only::get_block_header(const read_only:: } -std::unordered_map> +abi_serializer_cache read_only::get_block_serializers( const chain::signed_block_ptr& block, const fc::microseconds& max_time ) const { - auto yield = abi_serializer::create_yield_function( max_time ); - auto resolver = make_resolver(db, yield ); - std::unordered_map > abi_cache; - auto add_to_cache = [&]( const chain::action& a ) { - auto it = abi_cache.find( a.account ); - if( it == abi_cache.end() ) { - try { - abi_cache.emplace_hint( it, a.account, resolver( a.account ) ); - } catch( ... ) { - // keep behavior of not throwing on invalid abi, will result in hex data - } - } - }; - for( const auto& receipt: block->transactions ) { - if( std::holds_alternative( receipt.trx ) ) { - const auto& pt = std::get( receipt.trx ); - const auto& t = pt.get_transaction(); - for( const auto& a: t.actions ) - add_to_cache( a ); - for( const auto& a: t.context_free_actions ) - add_to_cache( a ); - } - } - return abi_cache; + return abi_serializer_cache_builder(db, max_time).add_serializers(block).get(); } fc::variant read_only::convert_block( const chain::signed_block_ptr& block, - std::unordered_map> abi_cache, + const abi_serializer_cache& abi_cache, const fc::microseconds& max_time ) const { auto abi_serializer_resolver = [&abi_cache](const account_name& account) -> std::optional { @@ -2207,7 +2252,6 @@ void read_write::push_transactions(const read_write::push_transactions_params& p } void read_write::send_transaction(const read_write::send_transaction_params& params, next_function next) { - try { auto pretty_input = std::make_shared(); auto resolver = make_resolver(db, abi_serializer::create_yield_function( abi_serializer_max_time )); @@ -2216,13 +2260,14 @@ void read_write::send_transaction(const read_write::send_transaction_params& par } EOS_RETHROW_EXCEPTIONS(chain::packed_transaction_type_exception, "Invalid packed transaction") app().get_method()(pretty_input, true, transaction_metadata::trx_type::input, false, - [this, next](const next_function_variant& result) -> void { + [this, next](const next_function_variant& result) -> void { if (std::holds_alternative(result)) { next(std::get(result)); } else { auto trx_trace_ptr = std::get(result); - using return_type = t_or_exception; - next([this, trx_trace_ptr, resolver = make_resolver(db, abi_serializer::create_yield_function(fc::microseconds::maximum()))]() { + auto abi_cache = abi_serializer_cache_builder(db, fc::microseconds::maximum()).add_serializers(trx_trace_ptr).get(); + using return_type = t_or_exception; + next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() { try { fc::variant output; try { @@ -2279,14 +2324,21 @@ void read_write::send_transaction2(const read_write::send_transaction2_params& p } } ); } else { - fc::variant output; - try { - output = db.to_variant_with_abi( *trx_trace_ptr, abi_serializer::create_yield_function( abi_serializer_max_time ) ); - } catch( chain::abi_exception& ) { - output = *trx_trace_ptr; - } - const chain::transaction_id_type& id = trx_trace_ptr->id; - next( read_write::send_transaction_results{id, std::move( output )} ); + auto abi_cache = abi_serializer_cache_builder(db, fc::microseconds::maximum()).add_serializers(trx_trace_ptr).get(); + using return_type = t_or_exception; + next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() { + try { + fc::variant output; + try { + abi_serializer::to_variant(*trx_trace_ptr, output, resolver, + abi_serializer::create_yield_function(abi_serializer_max_time)); + } catch( chain::abi_exception& ) { + output = *trx_trace_ptr; + } + const chain::transaction_id_type& id = trx_trace_ptr->id; + return return_type(read_write::send_transaction_results{id, std::move( output )}); + } CATCH_AND_RETURN(return_type); + }); } } CATCH_AND_CALL( next ); } @@ -2587,8 +2639,9 @@ void read_only::send_transient_transaction(const Params& params, next_function(result)); } else { auto trx_trace_ptr = std::get(result); + auto abi_cache = abi_serializer_cache_builder(db, fc::microseconds::maximum()).add_serializers(trx_trace_ptr).get(); using return_type = t_or_exception; - next([this, trx_trace_ptr, resolver = make_resolver(db, abi_serializer::create_yield_function(fc::microseconds::maximum()))]() { + next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() { try { fc::variant output; try { 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 b09fe05496..2ba5370b5b 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -86,6 +86,7 @@ string convert_to_string(const chain::key256_t& source, const string& key_type, template<> string convert_to_string(const float128_t& source, const string& key_type, const string& encode_type, const string& desc); +using abi_serializer_cache = std::unordered_map>; class read_only { const controller& db; @@ -330,12 +331,13 @@ class read_only { }; chain::signed_block_ptr get_raw_block(const get_raw_block_params& params, const fc::time_point& deadline) const; + // call from app() thread - std::unordered_map> - get_block_serializers( const chain::signed_block_ptr& block, const fc::microseconds& max_time ) const; + abi_serializer_cache get_block_serializers( const chain::signed_block_ptr& block, const fc::microseconds& max_time ) const; + // call from any thread fc::variant convert_block( const chain::signed_block_ptr& block, - std::unordered_map> abi_cache, + const abi_serializer_cache& abi_cache, const fc::microseconds& max_time ) const; struct get_block_header_params { From 9fd4dfff7126999e6ad2ed482e973e1bd7154864 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Mon, 10 Apr 2023 15:50:19 -0400 Subject: [PATCH 04/17] Update get_block() API to use new architecture. --- plugins/chain_api_plugin/chain_api_plugin.cpp | 85 ++++++++----------- plugins/chain_plugin/chain_plugin.cpp | 52 +++++------- .../eosio/chain_plugin/chain_plugin.hpp | 24 +++++- 3 files changed, 77 insertions(+), 84 deletions(-) diff --git a/plugins/chain_api_plugin/chain_api_plugin.cpp b/plugins/chain_api_plugin/chain_api_plugin.cpp index 629fd87710..0a2216944c 100644 --- a/plugins/chain_api_plugin/chain_api_plugin.cpp +++ b/plugins/chain_api_plugin/chain_api_plugin.cpp @@ -55,39 +55,46 @@ parse_params(body); \ + FC_CHECK_DEADLINE(deadline); \ + using http_fwd_t = std::function()>; \ + http_fwd_t http_fwd( api_handle.call_name( std::move(params), deadline ) ); \ + FC_CHECK_DEADLINE(deadline); \ + _http_plugin.post_http_thread_pool([resp_code=http_resp_code, cb=std::move(cb), \ + body=std::move(body), \ + http_fwd = std::move(http_fwd)]() { \ + auto result = http_fwd(); /* this returns a t_or_exception variant */ \ + if (std::holds_alternative(result)) { \ + try { \ + std::get(result)->dynamic_rethrow_exception(); \ + } catch (...) { \ + http_plugin::handle_exception(#api_name, #call_name, body, cb); \ + } \ + } else { \ + cb(resp_code, fc::time_point::maximum(), std::get(result)) ; \ + } \ + }); \ + } catch (...) { \ + http_plugin::handle_exception(#api_name, #call_name, body, cb); \ + } \ + }} + #define CHAIN_RO_CALL(call_name, http_response_code, params_type) CALL_WITH_400(chain, ro_api, chain_apis::read_only, call_name, http_response_code, params_type) #define CHAIN_RW_CALL(call_name, http_response_code, params_type) CALL_WITH_400(chain, rw_api, chain_apis::read_write, call_name, http_response_code, params_type) +#define CHAIN_RO_CALL_POST(call_name, http_response_code, params_type) CALL_WITH_400_POST(chain, ro_api, chain_apis::read_only, call_name, http_response_code, params_type) #define CHAIN_RO_CALL_ASYNC(call_name, call_result, http_response_code, params_type) CALL_ASYNC_WITH_400(chain, ro_api, chain_apis::read_only, call_name, call_result, http_response_code, params_type) #define CHAIN_RW_CALL_ASYNC(call_name, call_result, http_response_code, params_type) CALL_ASYNC_WITH_400(chain, rw_api, chain_apis::read_write, call_name, call_result, http_response_code, params_type) #define CHAIN_RO_CALL_WITH_400(call_name, http_response_code, params_type) CALL_WITH_400(chain, ro_api, chain_apis::read_only, call_name, http_response_code, params_type) -template -static api_entry make_api_entry(http_plugin& _http_plugin, API& api, const char* api_name, - const char* call_name, PARAMS_PARSER params_parser, HANDLER handler) { - return api_entry( - std::string("/v1/") + api_name + "/" + call_name, - [&_http_plugin, api, api_name, call_name, - params_parser = std::move(params_parser), handler = std::move(handler)](string&&, string&& body, url_response_callback&& cb) { - auto deadline = api.start(); - try { - auto start = fc::time_point::now(); - auto params = params_parser(body); - FC_CHECK_DEADLINE(deadline); - - // call first handler on main thread (likely because it accesses non thread-safe data) - // returns a thread-safe lambda that can be enqueued on the http thread pool to complete the request - auto completion_handler = handler(api, start, deadline, params, cb); - FC_CHECK_DEADLINE(deadline); // make sure remaining time is > 0 - - // execute thread-safe http_handler on _http_plugin's thread pool - _http_plugin.post_http_thread_pool(std::move(completion_handler)); - } catch (...) { - http_plugin::handle_exception(api_name, call_name, body, cb); - } - }); -} - void chain_api_plugin::plugin_startup() { ilog( "starting chain_api_plugin" ); my.reset(new chain_api_plugin_impl(app().get_plugin().chain())); @@ -104,6 +111,7 @@ void chain_api_plugin::plugin_startup() { CHAIN_RO_CALL(get_info, 200, http_params_types::no_params)}, appbase::exec_queue::read_only, appbase::priority::medium_high); _http_plugin.add_api({ CHAIN_RO_CALL(get_activated_protocol_features, 200, http_params_types::possible_no_params), + CHAIN_RO_CALL_POST(get_block, 200, http_params_types::params_required), // _POST because get_block() returns a lambda to be executed on the http thread pool CHAIN_RO_CALL(get_block_info, 200, http_params_types::params_required), CHAIN_RO_CALL(get_block_header_state, 200, http_params_types::params_required), CHAIN_RO_CALL(get_account, 200, http_params_types::params_required), @@ -153,31 +161,6 @@ void chain_api_plugin::plugin_startup() { }, appbase::exec_queue::read_only); } - _http_plugin.add_api({ - make_api_entry( - _http_plugin, ro_api, "chain", "get_block", - [](const string& body) { - return parse_params(body); - }, - [max_response_time, &chain](auto& api, fc::time_point start, fc::time_point deadline, auto ¶ms, const url_response_callback &cb) { - - chain::signed_block_ptr block = api.get_raw_block(params, deadline); - auto max_time = std::min(chain.get_abi_serializer_max_time(), max_response_time); - auto abi_cache = api.get_block_serializers(block, max_time); - auto post_time = fc::time_point::now(); - auto remaining_time = max_time - (post_time - start); - - return [api, cb, deadline, post_time, remaining_time, abi_cache=std::move(abi_cache), block=std::move(block)]() mutable { - try { - auto new_deadline = deadline + (fc::time_point::now() - post_time); - fc::variant result = api.convert_block(block, abi_cache, remaining_time); - cb(200, new_deadline, std::move(result)); - } catch( ... ) { - http_plugin::handle_exception("chain", "get_block", "", cb); - } - }; - })}, - appbase::exec_queue::read_only); } void chain_api_plugin::plugin_shutdown() {} diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 21b8d59c24..9767d14b78 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1876,24 +1876,6 @@ class abi_serializer_cache_builder { chain_apis::abi_serializer_cache abi_cache; }; -class abi_resolver { -public: - abi_resolver(chain_apis::abi_serializer_cache &&abi_cache) : - abi_cache(std::move(abi_cache)) - {} - - std::optional> operator()(const account_name& account) { - auto it = abi_cache.find(account); - if (it != abi_cache.end() && it->second) - return std::reference_wrapper(*it->second); - return {}; - }; - -private: - chain_apis::abi_serializer_cache abi_cache; -}; - - read_only::get_scheduled_transactions_result read_only::get_scheduled_transactions( const read_only::get_scheduled_transactions_params& p, const fc::time_point& deadline ) const { @@ -1998,6 +1980,23 @@ chain::signed_block_ptr read_only::get_raw_block(const read_only::get_raw_block_ return block; } +std::function()> read_only::get_block(const get_raw_block_params& params, const fc::time_point& deadline) const { + chain::signed_block_ptr block = get_raw_block(params, deadline); + + auto abi_cache = abi_serializer_cache_builder(db, deadline - fc::time_point::now()).add_serializers(block).get(); + FC_CHECK_DEADLINE(deadline); + + using return_type = t_or_exception; + return [this, + remaining_time = deadline - fc::time_point::now(), + resolver = abi_resolver(std::move(abi_cache)), + block = std::move(block)]() mutable -> return_type { + try { + return convert_block(block, resolver, remaining_time); + } CATCH_AND_RETURN(return_type); + }; +} + read_only::get_block_header_result read_only::get_block_header(const read_only::get_block_header_params& params, const fc::time_point& deadline) const{ std::optional block_num; @@ -2039,25 +2038,16 @@ read_only::get_block_header_result read_only::get_block_header(const read_only:: } -abi_serializer_cache +abi_resolver read_only::get_block_serializers( const chain::signed_block_ptr& block, const fc::microseconds& max_time ) const { - return abi_serializer_cache_builder(db, max_time).add_serializers(block).get(); + return abi_resolver(abi_serializer_cache_builder(db, max_time).add_serializers(block).get()); } fc::variant read_only::convert_block( const chain::signed_block_ptr& block, - const abi_serializer_cache& abi_cache, + abi_resolver& resolver, const fc::microseconds& max_time ) const { - - auto abi_serializer_resolver = [&abi_cache](const account_name& account) -> std::optional { - auto it = abi_cache.find( account ); - if( it != abi_cache.end() ) - return it->second; - return {}; - }; - fc::variant pretty_output; - abi_serializer::to_variant( *block, pretty_output, abi_serializer_resolver, - abi_serializer::create_yield_function( max_time ) ); + abi_serializer::to_variant( *block, pretty_output, resolver, abi_serializer::create_yield_function( max_time ) ); const auto block_id = block->calculate_id(); uint32_t ref_block_prefix = block_id._hash[1]; 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 2ba5370b5b..4d71553a7a 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -87,6 +87,23 @@ template<> string convert_to_string(const float128_t& source, const string& key_type, const string& encode_type, const string& desc); using abi_serializer_cache = std::unordered_map>; + +class abi_resolver { +public: + abi_resolver(chain_apis::abi_serializer_cache &&abi_cache) : + abi_cache(std::move(abi_cache)) + {} + + std::optional> operator()(const account_name& account) { + auto it = abi_cache.find(account); + if (it != abi_cache.end() && it->second) + return std::reference_wrapper(*it->second); + return {}; + }; + +private: + chain_apis::abi_serializer_cache abi_cache; +}; class read_only { const controller& db; @@ -332,12 +349,15 @@ class read_only { chain::signed_block_ptr get_raw_block(const get_raw_block_params& params, const fc::time_point& deadline) const; + using get_block_params = get_raw_block_params; + std::function()> get_block(const get_block_params& params, const fc::time_point& deadline) const; + // call from app() thread - abi_serializer_cache get_block_serializers( const chain::signed_block_ptr& block, const fc::microseconds& max_time ) const; + abi_resolver get_block_serializers( const chain::signed_block_ptr& block, const fc::microseconds& max_time ) const; // call from any thread fc::variant convert_block( const chain::signed_block_ptr& block, - const abi_serializer_cache& abi_cache, + abi_resolver& resolver, const fc::microseconds& max_time ) const; struct get_block_header_params { From 28b03d214553dacf8fa31086e69386fa265ab3bc Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Mon, 10 Apr 2023 16:29:57 -0400 Subject: [PATCH 05/17] Make a few lambdas `mutable` to avoid copying abi_serializers --- plugins/chain_plugin/chain_plugin.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 9767d14b78..f9c46f3f1a 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -2250,18 +2250,18 @@ void read_write::send_transaction(const read_write::send_transaction_params& par } EOS_RETHROW_EXCEPTIONS(chain::packed_transaction_type_exception, "Invalid packed transaction") app().get_method()(pretty_input, true, transaction_metadata::trx_type::input, false, - [this, next](const next_function_variant& result) -> void { + [this, next](const next_function_variant& result) mutable -> void { if (std::holds_alternative(result)) { next(std::get(result)); } else { auto trx_trace_ptr = std::get(result); auto abi_cache = abi_serializer_cache_builder(db, fc::microseconds::maximum()).add_serializers(trx_trace_ptr).get(); using return_type = t_or_exception; - next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() { + next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { try { fc::variant output; try { - abi_serializer::to_variant(*trx_trace_ptr, output, resolver, abi_serializer::create_yield_function(abi_serializer_max_time)); + abi_serializer::to_variant(*trx_trace_ptr, output, std::move(resolver), abi_serializer::create_yield_function(abi_serializer_max_time)); } catch( chain::abi_exception& ) { output = *trx_trace_ptr; } @@ -2316,11 +2316,11 @@ void read_write::send_transaction2(const read_write::send_transaction2_params& p } else { auto abi_cache = abi_serializer_cache_builder(db, fc::microseconds::maximum()).add_serializers(trx_trace_ptr).get(); using return_type = t_or_exception; - next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() { + next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { try { fc::variant output; try { - abi_serializer::to_variant(*trx_trace_ptr, output, resolver, + abi_serializer::to_variant(*trx_trace_ptr, output, std::move(resolver), abi_serializer::create_yield_function(abi_serializer_max_time)); } catch( chain::abi_exception& ) { output = *trx_trace_ptr; @@ -2631,7 +2631,7 @@ void read_only::send_transient_transaction(const Params& params, next_function(result); auto abi_cache = abi_serializer_cache_builder(db, fc::microseconds::maximum()).add_serializers(trx_trace_ptr).get(); using return_type = t_or_exception; - next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() { + next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { try { fc::variant output; try { From ac8c37c6d575ce135cfdeb6082643e62182ed838 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Tue, 11 Apr 2023 11:45:54 -0400 Subject: [PATCH 06/17] First batch of changes from PR review comments --- .../include/eosio/chain/abi_serializer.hpp | 76 ++++++++++++++++++- .../chain/include/eosio/chain/exceptions.hpp | 2 +- plugins/chain_plugin/chain_plugin.cpp | 67 +++------------- .../eosio/chain_plugin/chain_plugin.hpp | 22 +----- 4 files changed, 87 insertions(+), 80 deletions(-) diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index cbdec28481..ac75806e18 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -7,7 +7,7 @@ #include #include -namespace eosio { namespace chain { +namespace eosio::chain { using std::map; using std::string; @@ -487,7 +487,7 @@ namespace impl { try { auto abi_optional = resolver(act.account); if (abi_optional) { - auto& abi = (abi_serializer&)*abi_optional; + abi_serializer& abi = *abi_optional; auto type = abi.get_action_type(act.name); if (!type.empty()) { try { @@ -549,7 +549,7 @@ namespace impl { try { auto abi_optional = resolver(act.account); if (abi_optional) { - auto& abi = (abi_serializer&)*abi_optional; + abi_serializer& abi = *abi_optional; auto type = abi.get_action_result_type(act.name); if (!type.empty()) { binary_to_variant_context _ctx(abi, ctx, type); @@ -972,5 +972,73 @@ void abi_serializer::from_variant( const fc::variant& v, T& o, Resolver resolver from_variant( v, o, resolver, create_yield_function(max_serialization_time) ); } +using abi_serializer_cache = std::unordered_map>; + +class abi_resolver { +public: + abi_resolver(abi_serializer_cache &&abi_cache) : + abi_cache(std::move(abi_cache)) + {} + + std::optional> operator()(const account_name& account) { + auto it = abi_cache.find(account); + if (it != abi_cache.end() && it->second) + return std::reference_wrapper(*it->second); + return {}; + }; + +private: + abi_serializer_cache abi_cache; +}; + +class abi_serializer_cache_builder { +public: + abi_serializer_cache_builder(std::function(const account_name& name)> resolver) : + resolver_(std::move(resolver)) + { + } + + abi_serializer_cache_builder(const abi_serializer_cache_builder&) = delete; + + abi_serializer_cache_builder&& add_serializers(const chain::signed_block_ptr& block) && { + for( const auto& receipt: block->transactions ) { + if( std::holds_alternative( receipt.trx ) ) { + const auto& pt = std::get( receipt.trx ); + const auto& t = pt.get_transaction(); + for( const auto& a: t.actions ) + add_to_cache( a ); + for( const auto& a: t.context_free_actions ) + add_to_cache( a ); + } + } + return std::move(*this); + } + + abi_serializer_cache_builder&& add_serializers(const transaction_trace_ptr& trace_ptr) && { + for( const auto& trace: trace_ptr->action_traces ) { + add_to_cache(trace.act); + } + return std::move(*this); + } + + abi_serializer_cache&& get() && { + return std::move(abi_cache); + } + +private: + void add_to_cache(const chain::action& a) { + auto it = abi_cache.find( a.account ); + if( it == abi_cache.end() ) { + try { + abi_cache.emplace_hint( it, a.account, resolver_( a.account ) ); + } catch( ... ) { + // keep behavior of not throwing on invalid abi, will result in hex data + } + } + } + + std::function(const account_name& name)> resolver_; + abi_serializer_cache abi_cache; +}; -} } // eosio::chain +} // eosio::chain diff --git a/libraries/chain/include/eosio/chain/exceptions.hpp b/libraries/chain/include/eosio/chain/exceptions.hpp index 9dd47d879a..d1d50edd8a 100644 --- a/libraries/chain/include/eosio/chain/exceptions.hpp +++ b/libraries/chain/include/eosio/chain/exceptions.hpp @@ -88,7 +88,7 @@ } /** - * Capture all exceptions and return a fc::exception_ptr + * Capture all exceptions and return return_type which is constructible from a fc::exception_ptr */ #define CATCH_AND_RETURN(return_type)\ catch ( const fc::exception& err ) {\ diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index ca586c2133..80a3996dbb 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1832,56 +1832,6 @@ auto make_resolver(const controller& control, abi_serializer::yield_function_t y }; } -class abi_serializer_cache_builder { -public: - abi_serializer_cache_builder(const controller& db, const fc::microseconds& max_time) : - resolver(make_resolver(db, abi_serializer::create_yield_function(max_time))) - { - } - - abi_serializer_cache_builder(const abi_serializer_cache_builder&) = delete; - - abi_serializer_cache_builder&& add_serializers(const chain::signed_block_ptr& block) && { - for( const auto& receipt: block->transactions ) { - if( std::holds_alternative( receipt.trx ) ) { - const auto& pt = std::get( receipt.trx ); - const auto& t = pt.get_transaction(); - for( const auto& a: t.actions ) - add_to_cache( a ); - for( const auto& a: t.context_free_actions ) - add_to_cache( a ); - } - } - return std::move(*this); - } - - abi_serializer_cache_builder&& add_serializers(const transaction_trace_ptr& trace_ptr) && { - for( const auto& trace: trace_ptr->action_traces ) { - add_to_cache(trace.act); - } - return std::move(*this); - } - - chain_apis::abi_serializer_cache&& get() && { - return std::move(abi_cache); - } - -private: - void add_to_cache(const chain::action& a) { - auto it = abi_cache.find( a.account ); - if( it == abi_cache.end() ) { - try { - abi_cache.emplace_hint( it, a.account, resolver( a.account ) ); - } catch( ... ) { - // keep behavior of not throwing on invalid abi, will result in hex data - } - } - } - - std::function (const account_name &name)> resolver; - chain_apis::abi_serializer_cache abi_cache; -}; - read_only::get_scheduled_transactions_result read_only::get_scheduled_transactions( const read_only::get_scheduled_transactions_params& p, const fc::time_point& deadline ) const { @@ -1988,8 +1938,9 @@ chain::signed_block_ptr read_only::get_raw_block(const read_only::get_raw_block_ std::function()> read_only::get_block(const get_raw_block_params& params, const fc::time_point& deadline) const { chain::signed_block_ptr block = get_raw_block(params, deadline); - - auto abi_cache = abi_serializer_cache_builder(db, deadline - fc::time_point::now()).add_serializers(block).get(); + + auto yield = abi_serializer::create_yield_function(deadline - fc::time_point::now()); + auto abi_cache = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(block).get(); FC_CHECK_DEADLINE(deadline); using return_type = t_or_exception; @@ -2046,7 +1997,8 @@ read_only::get_block_header_result read_only::get_block_header(const read_only:: abi_resolver read_only::get_block_serializers( const chain::signed_block_ptr& block, const fc::microseconds& max_time ) const { - return abi_resolver(abi_serializer_cache_builder(db, max_time).add_serializers(block).get()); + auto yield = abi_serializer::create_yield_function(max_time); + return abi_resolver(abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(block).get()); } fc::variant read_only::convert_block( const chain::signed_block_ptr& block, @@ -2261,7 +2213,8 @@ void read_write::send_transaction(const read_write::send_transaction_params& par next(std::get(result)); } else { auto trx_trace_ptr = std::get(result); - auto abi_cache = abi_serializer_cache_builder(db, fc::microseconds::maximum()).add_serializers(trx_trace_ptr).get(); + auto yield = abi_serializer::create_yield_function(fc::microseconds::maximum()); + auto abi_cache = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(trx_trace_ptr).get(); using return_type = t_or_exception; next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { try { @@ -2320,7 +2273,8 @@ void read_write::send_transaction2(const read_write::send_transaction2_params& p } } ); } else { - auto abi_cache = abi_serializer_cache_builder(db, fc::microseconds::maximum()).add_serializers(trx_trace_ptr).get(); + auto yield = abi_serializer::create_yield_function(fc::microseconds::maximum()); + auto abi_cache = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(trx_trace_ptr).get(); using return_type = t_or_exception; next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { try { @@ -2635,7 +2589,8 @@ void read_only::send_transient_transaction(const Params& params, next_function(result)); } else { auto trx_trace_ptr = std::get(result); - auto abi_cache = abi_serializer_cache_builder(db, fc::microseconds::maximum()).add_serializers(trx_trace_ptr).get(); + auto yield = abi_serializer::create_yield_function(fc::microseconds::maximum()); + auto abi_cache = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(trx_trace_ptr).get(); using return_type = t_or_exception; next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { try { 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 4d71553a7a..2278956c0c 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -25,6 +25,8 @@ namespace fc { class variant; } namespace eosio { + namespace chain { class abi_resolver; } + using chain::controller; using std::unique_ptr; using std::pair; @@ -42,6 +44,7 @@ namespace eosio { using chain::action_name; using chain::abi_def; using chain::abi_serializer; + using chain::abi_resolver; class producer_plugin; @@ -86,25 +89,6 @@ string convert_to_string(const chain::key256_t& source, const string& key_type, template<> string convert_to_string(const float128_t& source, const string& key_type, const string& encode_type, const string& desc); -using abi_serializer_cache = std::unordered_map>; - -class abi_resolver { -public: - abi_resolver(chain_apis::abi_serializer_cache &&abi_cache) : - abi_cache(std::move(abi_cache)) - {} - - std::optional> operator()(const account_name& account) { - auto it = abi_cache.find(account); - if (it != abi_cache.end() && it->second) - return std::reference_wrapper(*it->second); - return {}; - }; - -private: - chain_apis::abi_serializer_cache abi_cache; -}; - class read_only { const controller& db; const std::optional& aqdb; From eb49677485d1f751e2aa925e53fa637fac047303 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Tue, 11 Apr 2023 12:21:17 -0400 Subject: [PATCH 07/17] 2nd batch of changes from PR review comments --- .../include/eosio/chain/abi_serializer.hpp | 2 +- libraries/chain/include/eosio/chain/types.hpp | 2 +- plugins/chain_api_plugin/chain_api_plugin.cpp | 32 ----------------- .../include/eosio/http_plugin/macros.hpp | 35 ++++++++++++++++++- 4 files changed, 36 insertions(+), 35 deletions(-) diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index ac75806e18..c7a4f49c5c 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -976,7 +976,7 @@ using abi_serializer_cache = std::unordered_map - using t_or_exception = std::variant; + using t_or_exception = std::variant; template using next_function_variant = std::variant()>>; diff --git a/plugins/chain_api_plugin/chain_api_plugin.cpp b/plugins/chain_api_plugin/chain_api_plugin.cpp index 0a2216944c..b6d7726944 100644 --- a/plugins/chain_api_plugin/chain_api_plugin.cpp +++ b/plugins/chain_api_plugin/chain_api_plugin.cpp @@ -55,38 +55,6 @@ parse_params(body); \ - FC_CHECK_DEADLINE(deadline); \ - using http_fwd_t = std::function()>; \ - http_fwd_t http_fwd( api_handle.call_name( std::move(params), deadline ) ); \ - FC_CHECK_DEADLINE(deadline); \ - _http_plugin.post_http_thread_pool([resp_code=http_resp_code, cb=std::move(cb), \ - body=std::move(body), \ - http_fwd = std::move(http_fwd)]() { \ - auto result = http_fwd(); /* this returns a t_or_exception variant */ \ - if (std::holds_alternative(result)) { \ - try { \ - std::get(result)->dynamic_rethrow_exception(); \ - } catch (...) { \ - http_plugin::handle_exception(#api_name, #call_name, body, cb); \ - } \ - } else { \ - cb(resp_code, fc::time_point::maximum(), std::get(result)) ; \ - } \ - }); \ - } catch (...) { \ - http_plugin::handle_exception(#api_name, #call_name, body, cb); \ - } \ - }} - #define CHAIN_RO_CALL(call_name, http_response_code, params_type) CALL_WITH_400(chain, ro_api, chain_apis::read_only, call_name, http_response_code, params_type) #define CHAIN_RW_CALL(call_name, http_response_code, params_type) CALL_WITH_400(chain, rw_api, chain_apis::read_write, call_name, http_response_code, params_type) #define CHAIN_RO_CALL_POST(call_name, http_response_code, params_type) CALL_WITH_400_POST(chain, ro_api, chain_apis::read_only, call_name, http_response_code, params_type) diff --git a/plugins/http_plugin/include/eosio/http_plugin/macros.hpp b/plugins/http_plugin/include/eosio/http_plugin/macros.hpp index 2acb9a4c72..9009d34fbe 100644 --- a/plugins/http_plugin/include/eosio/http_plugin/macros.hpp +++ b/plugins/http_plugin/include/eosio/http_plugin/macros.hpp @@ -32,7 +32,7 @@ struct async_result_visitor : public fc::visitor { _http_plugin.post_http_thread_pool([resp_code=http_resp_code, cb=std::move(cb), \ body=std::move(body), \ http_fwd = std::get(result)]() { \ - auto result = http_fwd(); /* this returns a t_or_exception variant */ \ + chain::t_or_exception result = http_fwd(); \ if (std::holds_alternative(result)) { \ try { \ std::get(result)->dynamic_rethrow_exception(); \ @@ -50,3 +50,36 @@ struct async_result_visitor : public fc::visitor { } \ } \ } + + +// call an API which returns either fc::exception_ptr, or a function to be posted on the http thread pool +// for execution (typically doing the final serialization) +// ------------------------------------------------------------------------------------------------------ +#define CALL_WITH_400_POST(api_name, api_handle, api_namespace, call_name, http_resp_code, params_type) \ +{std::string("/v1/" #api_name "/" #call_name), \ + [api_handle, &_http_plugin](string&&, string&& body, url_response_callback&& cb) { \ + auto deadline = api_handle.start(); \ + try { \ + auto params = parse_params(body); \ + FC_CHECK_DEADLINE(deadline); \ + using http_fwd_t = std::function()>; \ + http_fwd_t http_fwd( api_handle.call_name( std::move(params), deadline ) ); \ + FC_CHECK_DEADLINE(deadline); \ + _http_plugin.post_http_thread_pool([resp_code=http_resp_code, cb=std::move(cb), \ + body=std::move(body), \ + http_fwd = std::move(http_fwd)]() { \ + chain::t_or_exception result = http_fwd(); \ + if (std::holds_alternative(result)) { \ + try { \ + std::get(result)->dynamic_rethrow_exception(); \ + } catch (...) { \ + http_plugin::handle_exception(#api_name, #call_name, body, cb); \ + } \ + } else { \ + cb(resp_code, fc::time_point::maximum(), std::get(result)) ; \ + } \ + }); \ + } catch (...) { \ + http_plugin::handle_exception(#api_name, #call_name, body, cb); \ + } \ + }} From 841a59eb3289cc0e0e1804401dafda8fa705b34f Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Tue, 11 Apr 2023 12:31:55 -0400 Subject: [PATCH 08/17] remove unnecesary `mutable` qualifiers. --- plugins/chain_plugin/chain_plugin.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 80a3996dbb..7c5fb4bf6f 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -2208,7 +2208,7 @@ void read_write::send_transaction(const read_write::send_transaction_params& par } EOS_RETHROW_EXCEPTIONS(chain::packed_transaction_type_exception, "Invalid packed transaction") app().get_method()(pretty_input, true, transaction_metadata::trx_type::input, false, - [this, next](const next_function_variant& result) mutable -> void { + [this, next](const next_function_variant& result) -> void { if (std::holds_alternative(result)) { next(std::get(result)); } else { @@ -2216,7 +2216,7 @@ void read_write::send_transaction(const read_write::send_transaction_params& par auto yield = abi_serializer::create_yield_function(fc::microseconds::maximum()); auto abi_cache = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(trx_trace_ptr).get(); using return_type = t_or_exception; - next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { + next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() { try { fc::variant output; try { @@ -2276,7 +2276,7 @@ void read_write::send_transaction2(const read_write::send_transaction2_params& p auto yield = abi_serializer::create_yield_function(fc::microseconds::maximum()); auto abi_cache = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(trx_trace_ptr).get(); using return_type = t_or_exception; - next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { + next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() { try { fc::variant output; try { @@ -2592,7 +2592,7 @@ void read_only::send_transient_transaction(const Params& params, next_function; - next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { + next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() { try { fc::variant output; try { From 52e25cdfe33eef0d9dcd33dcd6ccfb23654a0561 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Tue, 11 Apr 2023 13:46:15 -0400 Subject: [PATCH 09/17] Avoid unnecessary copies, restore `mutable` on lambdas capturing the abi cache --- plugins/chain_plugin/chain_plugin.cpp | 6 +++--- .../http_plugin/include/eosio/http_plugin/macros.hpp | 12 +++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 7c5fb4bf6f..edd0f019bb 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -2216,7 +2216,7 @@ void read_write::send_transaction(const read_write::send_transaction_params& par auto yield = abi_serializer::create_yield_function(fc::microseconds::maximum()); auto abi_cache = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(trx_trace_ptr).get(); using return_type = t_or_exception; - next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() { + next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { try { fc::variant output; try { @@ -2276,7 +2276,7 @@ void read_write::send_transaction2(const read_write::send_transaction2_params& p auto yield = abi_serializer::create_yield_function(fc::microseconds::maximum()); auto abi_cache = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(trx_trace_ptr).get(); using return_type = t_or_exception; - next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() { + next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { try { fc::variant output; try { @@ -2592,7 +2592,7 @@ void read_only::send_transient_transaction(const Params& params, next_function; - next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() { + next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { try { fc::variant output; try { diff --git a/plugins/http_plugin/include/eosio/http_plugin/macros.hpp b/plugins/http_plugin/include/eosio/http_plugin/macros.hpp index 9009d34fbe..ffbc73de6e 100644 --- a/plugins/http_plugin/include/eosio/http_plugin/macros.hpp +++ b/plugins/http_plugin/include/eosio/http_plugin/macros.hpp @@ -25,13 +25,14 @@ struct async_result_visitor : public fc::visitor { http_plugin::handle_exception(#api_name, #call_name, body, cb); \ } \ } else if (std::holds_alternative(result)) { \ - cb(http_resp_code, fc::time_point::maximum(), fc::variant(std::get(result))); \ + cb(http_resp_code, fc::time_point::maximum(), \ + fc::variant(std::get(std::move(result)))); \ } else { \ /* api returned a function to be processed on the http_plugin thread pool */ \ assert(std::holds_alternative(result)); \ _http_plugin.post_http_thread_pool([resp_code=http_resp_code, cb=std::move(cb), \ body=std::move(body), \ - http_fwd = std::get(result)]() { \ + http_fwd = std::get(std::move(result))]() { \ chain::t_or_exception result = http_fwd(); \ if (std::holds_alternative(result)) { \ try { \ @@ -40,7 +41,8 @@ struct async_result_visitor : public fc::visitor { http_plugin::handle_exception(#api_name, #call_name, body, cb); \ } \ } else { \ - cb(resp_code, fc::time_point::maximum(), fc::variant(std::get(result))) ; \ + cb(resp_code, fc::time_point::maximum(), \ + fc::variant(std::get(std::move(result)))) ; \ } \ }); \ } \ @@ -63,7 +65,7 @@ struct async_result_visitor : public fc::visitor { auto params = parse_params(body); \ FC_CHECK_DEADLINE(deadline); \ using http_fwd_t = std::function()>; \ - http_fwd_t http_fwd( api_handle.call_name( std::move(params), deadline ) ); \ + http_fwd_t http_fwd(api_handle.call_name(std::move(params), deadline)); \ FC_CHECK_DEADLINE(deadline); \ _http_plugin.post_http_thread_pool([resp_code=http_resp_code, cb=std::move(cb), \ body=std::move(body), \ @@ -76,7 +78,7 @@ struct async_result_visitor : public fc::visitor { http_plugin::handle_exception(#api_name, #call_name, body, cb); \ } \ } else { \ - cb(resp_code, fc::time_point::maximum(), std::get(result)) ; \ + cb(resp_code, fc::time_point::maximum(), std::get(std::move(result))) ; \ } \ }); \ } catch (...) { \ From 9aa412b1079358f62d0a49f093b7d57a6c1ad3e9 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Tue, 11 Apr 2023 17:15:40 -0400 Subject: [PATCH 10/17] Whitespace cleanup --- plugins/chain_plugin/chain_plugin.cpp | 2 +- plugins/http_plugin/include/eosio/http_plugin/macros.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index edd0f019bb..25fc4eff7a 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -2214,7 +2214,7 @@ void read_write::send_transaction(const read_write::send_transaction_params& par } else { auto trx_trace_ptr = std::get(result); auto yield = abi_serializer::create_yield_function(fc::microseconds::maximum()); - auto abi_cache = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(trx_trace_ptr).get(); + auto abi_cache = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(trx_trace_ptr).get(); using return_type = t_or_exception; next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { try { diff --git a/plugins/http_plugin/include/eosio/http_plugin/macros.hpp b/plugins/http_plugin/include/eosio/http_plugin/macros.hpp index ffbc73de6e..e5e5831397 100644 --- a/plugins/http_plugin/include/eosio/http_plugin/macros.hpp +++ b/plugins/http_plugin/include/eosio/http_plugin/macros.hpp @@ -17,7 +17,7 @@ struct async_result_visitor : public fc::visitor { using http_fwd_t = std::function()>; \ api_handle.call_name( std::move(params), \ [&_http_plugin, cb=std::move(cb), body=std::move(body)] \ - (const chain::next_function_variant& result){ \ + (const chain::next_function_variant& result) { \ if (std::holds_alternative(result)) { \ try { \ std::get(result)->dynamic_rethrow_exception(); \ From 52f0a2a9546ca1194108ac4a805b95566f83f9c3 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Wed, 12 Apr 2023 10:51:24 -0400 Subject: [PATCH 11/17] have `send_transaction` call `send_transaction2` --- plugins/chain_plugin/chain_plugin.cpp | 45 +++++---------------------- 1 file changed, 7 insertions(+), 38 deletions(-) diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 25fc4eff7a..ff2686385f 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -2200,42 +2200,11 @@ void read_write::push_transactions(const read_write::push_transactions_params& p } void read_write::send_transaction(const read_write::send_transaction_params& params, next_function next) { - try { - auto pretty_input = std::make_shared(); - auto resolver = make_resolver(db, abi_serializer::create_yield_function( abi_serializer_max_time )); - try { - abi_serializer::from_variant(params, *pretty_input, resolver, abi_serializer::create_yield_function( abi_serializer_max_time )); - } EOS_RETHROW_EXCEPTIONS(chain::packed_transaction_type_exception, "Invalid packed transaction") - - app().get_method()(pretty_input, true, transaction_metadata::trx_type::input, false, - [this, next](const next_function_variant& result) -> void { - if (std::holds_alternative(result)) { - next(std::get(result)); - } else { - auto trx_trace_ptr = std::get(result); - auto yield = abi_serializer::create_yield_function(fc::microseconds::maximum()); - auto abi_cache = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(trx_trace_ptr).get(); - using return_type = t_or_exception; - next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { - try { - fc::variant output; - try { - abi_serializer::to_variant(*trx_trace_ptr, output, std::move(resolver), abi_serializer::create_yield_function(abi_serializer_max_time)); - } catch( chain::abi_exception& ) { - output = *trx_trace_ptr; - } - - const chain::transaction_id_type& id = trx_trace_ptr->id; - return return_type(read_write::send_transaction_results{id, output}); - } CATCH_AND_RETURN(return_type); - }); - } - }); - } catch ( boost::interprocess::bad_alloc& ) { - chain_plugin::handle_db_exhaustion(); - } catch ( const std::bad_alloc& ) { - chain_plugin::handle_bad_alloc(); - } CATCH_AND_CALL(next); + send_transaction2_params params2 { .return_failure_trace = false, + .retry_trx = false, + .retry_trx_num_blocks = std::nullopt, + .transaction = std::move(params) }; + return send_transaction2(params2, std::move(next)); } void read_write::send_transaction2(const read_write::send_transaction2_params& params, next_function next) { @@ -2254,7 +2223,7 @@ void read_write::send_transaction2(const read_write::send_transaction2_params& p "retry transaction expiration ${e} larger than allowed ${m}", ("e", ptrx->expiration())("m", trx_retry->get_max_expiration_time()) ); - app().get_method()(ptrx, true, transaction_metadata::trx_type::input, static_cast(params.return_failure_trace), + app().get_method()(ptrx, true, transaction_metadata::trx_type::input, params.return_failure_trace, [this, ptrx, next, retry, retry_num_blocks](const next_function_variant& result) -> void { if( std::holds_alternative( result ) ) { next( std::get( result ) ); @@ -2274,7 +2243,7 @@ void read_write::send_transaction2(const read_write::send_transaction2_params& p } ); } else { auto yield = abi_serializer::create_yield_function(fc::microseconds::maximum()); - auto abi_cache = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(trx_trace_ptr).get(); + auto abi_cache = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(trx_trace_ptr).get(); using return_type = t_or_exception; next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { try { From 8fabe5d1b8e04e17bd12ceae150d212b0ffbcfd3 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Wed, 12 Apr 2023 16:08:21 -0400 Subject: [PATCH 12/17] Commonize to a single send_transaction function. --- plugins/chain_plugin/chain_plugin.cpp | 206 ++++++++---------- .../eosio/chain_plugin/chain_plugin.hpp | 55 +++-- plugins/producer_plugin/producer_plugin.cpp | 28 +-- 3 files changed, 148 insertions(+), 141 deletions(-) diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index ff2686385f..7e1aaffbaf 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -116,7 +116,7 @@ void validate(boost::any& v, } } -} +} // namespace chain using namespace eosio; using namespace eosio::chain; @@ -1235,13 +1235,13 @@ void chain_plugin::handle_guard_exception(const chain::guard_exception& e) { app().quit(); } -void chain_plugin::handle_db_exhaustion() { +void chain_apis::api_base::handle_db_exhaustion() { elog("database memory exhausted: increase chain-state-db-size-mb"); //return 1 -- it's what programs/nodeos/main.cpp considers "BAD_ALLOC" std::_Exit(1); } -void chain_plugin::handle_bad_alloc() { +void chain_apis::api_base::handle_bad_alloc() { elog("std::bad_alloc - memory exhausted"); //return -2 -- it's what programs/nodeos/main.cpp reports for std::exception std::_Exit(-2); @@ -1819,19 +1819,6 @@ read_only::get_producer_schedule_result read_only::get_producer_schedule( const return result; } - -auto make_resolver(const controller& control, abi_serializer::yield_function_t yield) { - return [&control, yield{std::move(yield)}](const account_name &name) -> std::optional { - const auto* accnt = control.db().template find(name); - if (accnt != nullptr) { - if (abi_def abi; abi_serializer::to_abi(accnt->abi, abi)) { - return abi_serializer(std::move(abi), yield); - } - } - return {}; - }; -} - read_only::get_scheduled_transactions_result read_only::get_scheduled_transactions( const read_only::get_scheduled_transactions_params& p, const fc::time_point& deadline ) const { @@ -2072,9 +2059,9 @@ void read_write::push_block(read_write::push_block_params&& params, next_functio try { app().get_method()(std::make_shared( std::move(params) ), std::optional{}, block_state_ptr{}); } catch ( boost::interprocess::bad_alloc& ) { - chain_plugin::handle_db_exhaustion(); + handle_db_exhaustion(); } catch ( const std::bad_alloc& ) { - chain_plugin::handle_bad_alloc(); + handle_bad_alloc(); } FC_LOG_AND_DROP() next(read_write::push_block_results{}); } @@ -2155,9 +2142,9 @@ void read_write::push_transaction(const read_write::push_transaction_params& par } }); } catch ( boost::interprocess::bad_alloc& ) { - chain_plugin::handle_db_exhaustion(); + handle_db_exhaustion(); } catch ( const std::bad_alloc& ) { - chain_plugin::handle_bad_alloc(); + handle_bad_alloc(); } CATCH_AND_CALL(next); } @@ -2193,69 +2180,73 @@ void read_write::push_transactions(const read_write::push_transactions_params& p push_recurse(this, 0, params_copy, result, next); } catch ( boost::interprocess::bad_alloc& ) { - chain_plugin::handle_db_exhaustion(); + handle_db_exhaustion(); } catch ( const std::bad_alloc& ) { - chain_plugin::handle_bad_alloc(); + handle_bad_alloc(); } CATCH_AND_CALL(next); } -void read_write::send_transaction(const read_write::send_transaction_params& params, next_function next) { - send_transaction2_params params2 { .return_failure_trace = false, - .retry_trx = false, - .retry_trx_num_blocks = std::nullopt, - .transaction = std::move(params) }; - return send_transaction2(params2, std::move(next)); -} - -void read_write::send_transaction2(const read_write::send_transaction2_params& params, next_function next) { +template +void api_base::send_transaction_gen(API &api, const send_transaction_params_t& params, next_function next) { try { auto ptrx = std::make_shared(); - auto resolver = make_resolver(db, abi_serializer::create_yield_function( abi_serializer_max_time )); + auto resolver = make_resolver(api.db, abi_serializer::create_yield_function( api.abi_serializer_max_time )); try { - abi_serializer::from_variant(params.transaction, *ptrx, resolver, abi_serializer::create_yield_function( abi_serializer_max_time )); - } EOS_RETHROW_EXCEPTIONS(chain::packed_transaction_type_exception, "Invalid packed transaction") - - bool retry = params.retry_trx; - std::optional retry_num_blocks = params.retry_trx_num_blocks; - - EOS_ASSERT( !retry || trx_retry.has_value(), unsupported_feature, "Transaction retry not enabled on node" ); - EOS_ASSERT( !retry || (ptrx->expiration() <= trx_retry->get_max_expiration_time()), tx_exp_too_far_exception, - "retry transaction expiration ${e} larger than allowed ${m}", - ("e", ptrx->expiration())("m", trx_retry->get_max_expiration_time()) ); - - app().get_method()(ptrx, true, transaction_metadata::trx_type::input, params.return_failure_trace, - [this, ptrx, next, retry, retry_num_blocks](const next_function_variant& result) -> void { + abi_serializer::from_variant(params.transaction, *ptrx, resolver, abi_serializer::create_yield_function( api.abi_serializer_max_time )); + } EOS_RETHROW_EXCEPTIONS(packed_transaction_type_exception, "Invalid packed transaction") + + bool retry = false; + std::optional retry_num_blocks; + + if constexpr (std::is_same_v) { + retry = params.retry_trx; + retry_num_blocks = params.retry_trx_num_blocks; + + EOS_ASSERT( !retry || api.trx_retry.has_value(), unsupported_feature, "Transaction retry not enabled on node" ); + EOS_ASSERT( !retry || (ptrx->expiration() <= api.trx_retry->get_max_expiration_time()), tx_exp_too_far_exception, + "retry transaction expiration ${e} larger than allowed ${m}", + ("e", ptrx->expiration())("m", api.trx_retry->get_max_expiration_time()) ); + } + + app().get_method()(ptrx, true, params.trx_type, params.return_failure_trace, + [&api, ptrx, next, retry, retry_num_blocks](const next_function_variant& result) -> void { if( std::holds_alternative( result ) ) { next( std::get( result ) ); } else { try { auto trx_trace_ptr = std::get( result ); - if( retry && trx_retry.has_value() && !trx_trace_ptr->except) { - // will be ack'ed via next later - trx_retry->track_transaction( ptrx, retry_num_blocks, - [ptrx, next](const next_function_variant>& result ) { - if( std::holds_alternative( result ) ) { - next( std::get( result ) ); - } else { - fc::variant& output = *std::get>( result ); - next( read_write::send_transaction_results{ptrx->id(), std::move( output )} ); - } - } ); - } else { + bool retried = false; + if constexpr (std::is_same_v) { + if( retry && api.trx_retry.has_value() && !trx_trace_ptr->except) { + // will be ack'ed via next later + api.trx_retry->track_transaction( ptrx, retry_num_blocks, + [ptrx, next](const next_function_variant>& result ) { + if( std::holds_alternative( result ) ) { + next( std::get( result ) ); + } else { + fc::variant& output = *std::get>( result ); + next( Result{ptrx->id(), std::move( output )} ); + } + } ); + retried = true; + } + } + + if (!retried) { auto yield = abi_serializer::create_yield_function(fc::microseconds::maximum()); - auto abi_cache = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(trx_trace_ptr).get(); - using return_type = t_or_exception; - next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { + auto abi_cache = abi_serializer_cache_builder(api_base::make_resolver(api.db, std::move(yield))).add_serializers(trx_trace_ptr).get(); + using return_type = t_or_exception; + next([&api, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { try { fc::variant output; try { abi_serializer::to_variant(*trx_trace_ptr, output, std::move(resolver), - abi_serializer::create_yield_function(abi_serializer_max_time)); - } catch( chain::abi_exception& ) { + abi_serializer::create_yield_function(api.abi_serializer_max_time)); + } catch( abi_exception& ) { output = *trx_trace_ptr; } - const chain::transaction_id_type& id = trx_trace_ptr->id; - return return_type(read_write::send_transaction_results{id, std::move( output )}); + const transaction_id_type& id = trx_trace_ptr->id; + return return_type(Result{id, std::move( output )}); } CATCH_AND_RETURN(return_type); }); } @@ -2263,12 +2254,30 @@ void read_write::send_transaction2(const read_write::send_transaction2_params& p } }); } catch ( boost::interprocess::bad_alloc& ) { - chain_plugin::handle_db_exhaustion(); + handle_db_exhaustion(); } catch ( const std::bad_alloc& ) { - chain_plugin::handle_bad_alloc(); + handle_bad_alloc(); } CATCH_AND_CALL(next); } + +void read_write::send_transaction(const read_write::send_transaction_params& params, next_function next) { + send_transaction_params_t gen_params { .return_failure_trace = false, + .retry_trx = false, + .retry_trx_num_blocks = std::nullopt, + .trx_type = transaction_metadata::trx_type::input, + .transaction = std::move(params) }; + return send_transaction_gen(*this, gen_params, std::move(next)); +} +void read_write::send_transaction2(const read_write::send_transaction2_params& params, next_function next) { + send_transaction_params_t gen_params { .return_failure_trace = params.return_failure_trace, + .retry_trx = params.retry_trx, + .retry_trx_num_blocks = std::move(params.retry_trx_num_blocks), + .trx_type = transaction_metadata::trx_type::input, + .transaction = std::move(params.transaction) }; + return send_transaction_gen(*this, gen_params, std::move(next)); +} + read_only::get_abi_results read_only::get_abi( const get_abi_params& params, const fc::time_point& deadline )const { try { get_abi_results result; @@ -2543,56 +2552,25 @@ read_only::get_required_keys_result read_only::get_required_keys( const get_requ return result; } -template -void read_only::send_transient_transaction(const Params& params, next_function next, chain::transaction_metadata::trx_type trx_type) const { - try { - auto pretty_input = std::make_shared(); - auto resolver = make_resolver(db, abi_serializer::create_yield_function( abi_serializer_max_time )); - try { - abi_serializer::from_variant(params.transaction, *pretty_input, resolver, abi_serializer::create_yield_function( abi_serializer_max_time )); - } EOS_RETHROW_EXCEPTIONS(chain::packed_transaction_type_exception, "Invalid packed transaction") - - app().get_method()(pretty_input, true /* api_trx */, trx_type, true /* return_failure_trace */, - [this, next](const next_function_variant& result) -> void { - if (std::holds_alternative(result)) { - next(std::get(result)); - } else { - auto trx_trace_ptr = std::get(result); - auto yield = abi_serializer::create_yield_function(fc::microseconds::maximum()); - auto abi_cache = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(trx_trace_ptr).get(); - using return_type = t_or_exception; - next([this, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { - try { - fc::variant output; - try { - abi_serializer::to_variant(*trx_trace_ptr, output, resolver, - abi_serializer::create_yield_function(abi_serializer_max_time)); - } catch( chain::abi_exception& ) { - output = *trx_trace_ptr; - } - - const chain::transaction_id_type& id = trx_trace_ptr->id; - return return_type(Results{id, output}); - } CATCH_AND_RETURN(return_type); - }); - } - }); - } catch ( boost::interprocess::bad_alloc& ) { - chain_plugin::handle_db_exhaustion(); - } catch ( const std::bad_alloc& ) { - chain_plugin::handle_bad_alloc(); - } CATCH_AND_CALL(next); -} - -void read_only::compute_transaction(const compute_transaction_params& params, next_function next) const { - return send_transient_transaction(params, next, transaction_metadata::trx_type::dry_run); +void read_only::compute_transaction(const compute_transaction_params& params, next_function next) { + send_transaction_params_t gen_params { .return_failure_trace = false, + .retry_trx = false, + .retry_trx_num_blocks = std::nullopt, + .trx_type = transaction_metadata::trx_type::dry_run, + .transaction = std::move(params.transaction) }; + return send_transaction_gen(*this, gen_params, std::move(next)); } -void read_only::send_read_only_transaction(const send_read_only_transaction_params& params, next_function next) const { - return send_transient_transaction(params, next, transaction_metadata::trx_type::read_only); +void read_only::send_read_only_transaction(const send_read_only_transaction_params& params, next_function next) { + send_transaction_params_t gen_params { .return_failure_trace = false, + .retry_trx = false, + .retry_trx_num_blocks = std::nullopt, + .trx_type = transaction_metadata::trx_type::read_only, + .transaction = std::move(params.transaction) }; + return send_transaction_gen(*this, gen_params, std::move(next)); } -read_only::get_transaction_id_result read_only::get_transaction_id( const read_only::get_transaction_id_params& params, const fc::time_point& deadline)const { +read_only::get_transaction_id_result read_only::get_transaction_id( const read_only::get_transaction_id_params& params, const fc::time_point& deadline) const { return params.id(); } @@ -2659,7 +2637,7 @@ fc::variant chain_plugin::get_log_trx_trace(const transaction_trace_ptr& trx_tra fc::variant pretty_output; try { abi_serializer::to_log_variant(trx_trace, pretty_output, - chain_apis::make_resolver(chain(), abi_serializer::create_yield_function(get_abi_serializer_max_time())), + chain_apis::api_base::make_resolver(chain(), abi_serializer::create_yield_function(get_abi_serializer_max_time())), abi_serializer::create_yield_function(get_abi_serializer_max_time())); } catch (...) { pretty_output = trx_trace; @@ -2671,7 +2649,7 @@ fc::variant chain_plugin::get_log_trx(const transaction& trx) const { fc::variant pretty_output; try { abi_serializer::to_log_variant(trx, pretty_output, - chain_apis::make_resolver(chain(), abi_serializer::create_yield_function(get_abi_serializer_max_time())), + chain_apis::api_base::make_resolver(chain(), abi_serializer::create_yield_function(get_abi_serializer_max_time())), abi_serializer::create_yield_function(get_abi_serializer_max_time())); } catch (...) { pretty_output = trx; 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 2278956c0c..0a7e770573 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -45,6 +45,7 @@ namespace eosio { using chain::abi_def; using chain::abi_serializer; using chain::abi_resolver; + using chain::packed_transaction; class producer_plugin; @@ -89,7 +90,39 @@ string convert_to_string(const chain::key256_t& source, const string& key_type, template<> string convert_to_string(const float128_t& source, const string& key_type, const string& encode_type, const string& desc); -class read_only { +class read_write; + +class api_base { +public: + static void handle_db_exhaustion(); + static void handle_bad_alloc(); + + static auto make_resolver(const controller& control, abi_serializer::yield_function_t yield) { + return [&control, yield{std::move(yield)}](const account_name &name) -> std::optional { + const auto* accnt = control.db().template find(name); + if (accnt != nullptr) { + if (abi_def abi; abi_serializer::to_abi(accnt->abi, abi)) { + return abi_serializer(std::move(abi), yield); + } + } + return {}; + }; + } + +protected: + struct send_transaction_params_t { + bool return_failure_trace = true; + bool retry_trx = false; ///< request transaction retry on validated transaction + std::optional retry_trx_num_blocks{}; ///< if retry_trx, report trace at specified blocks from executed or lib if not specified + chain::transaction_metadata::trx_type trx_type; + fc::variant transaction; + }; + + template + static void send_transaction_gen(API &api, const send_transaction_params_t& params, chain::plugin_interface::next_function next); +}; + +class read_only : public api_base { const controller& db; const std::optional& aqdb; const fc::microseconds abi_serializer_max_time; @@ -97,7 +130,8 @@ class read_only { bool shorten_abi_errors = true; const producer_plugin* producer_plug; const trx_finality_status_processing* trx_finality_status_proc; - + friend class api_base; + public: static const string KEYi64; @@ -487,7 +521,7 @@ class read_only { fc::variant transaction; }; - void compute_transaction(const compute_transaction_params& params, chain::plugin_interface::next_function next ) const; + void compute_transaction(const compute_transaction_params& params, chain::plugin_interface::next_function next ); struct send_read_only_transaction_results { chain::transaction_id_type transaction_id; @@ -496,7 +530,7 @@ class read_only { struct send_read_only_transaction_params { fc::variant transaction; }; - void send_read_only_transaction(const send_read_only_transaction_params& params, chain::plugin_interface::next_function next ) const; + void send_read_only_transaction(const send_read_only_transaction_params& params, chain::plugin_interface::next_function next ); static void copy_inline_row(const chain::key_value_object& obj, vector& data) { data.resize( obj.value.size() ); @@ -721,18 +755,16 @@ class read_only { chain::wasm_config wasm_config; }; get_consensus_parameters_results get_consensus_parameters(const get_consensus_parameters_params&, const fc::time_point& deadline) const; - -private: - template - void send_transient_transaction(const Params& params, eosio::chain::next_function next, chain::transaction_metadata::trx_type trx_type) const; }; -class read_write { +class read_write : public api_base { controller& db; std::optional& trx_retry; const fc::microseconds abi_serializer_max_time; const fc::microseconds http_max_response_time; const bool api_accept_transactions; + friend class api_base; + public: read_write(controller& db, std::optional& trx_retry, const fc::microseconds& abi_serializer_max_time, const fc::microseconds& http_max_response_time, @@ -881,9 +913,6 @@ class chain_plugin : public plugin { static void handle_guard_exception(const chain::guard_exception& e); void do_hard_replay(const variables_map& options); - static void handle_db_exhaustion(); - static void handle_bad_alloc(); - bool account_queries_enabled() const; bool transaction_finality_status_enabled() const; @@ -898,7 +927,7 @@ class chain_plugin : public plugin { unique_ptr my; }; -} +} // namespace eosio FC_REFLECT( eosio::chain_apis::linked_action, (account)(action) ) FC_REFLECT( eosio::chain_apis::permission, (perm_name)(parent)(required_auth)(linked_actions) ) diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 3ccf28527d..b3d791a432 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -48,9 +48,9 @@ using boost::signals2::scoped_connection; catch ( const guard_exception& e ) { \ chain_plugin::handle_guard_exception(e); \ } catch ( const std::bad_alloc& ) { \ - chain_plugin::handle_bad_alloc(); \ + chain_apis::api_base::handle_bad_alloc(); \ } catch ( boost::interprocess::bad_alloc& ) { \ - chain_plugin::handle_db_exhaustion(); \ + chain_apis::api_base::handle_db_exhaustion(); \ } catch( fc::exception& er ) { \ wlog( "${details}", ("details",er.to_detail_string()) ); \ } catch( const std::exception& e ) { \ @@ -622,9 +622,9 @@ class producer_plugin_impl : public std::enable_shared_from_this_timer.cancel(); } catch ( const std::bad_alloc& ) { - chain_plugin::handle_bad_alloc(); + chain_apis::api_base::handle_bad_alloc(); } catch ( const boost::interprocess::bad_alloc& ) { - chain_plugin::handle_bad_alloc(); + chain_apis::api_base::handle_bad_alloc(); } catch(const fc::exception& e) { edump((e.to_detail_string())); } catch(const std::exception& e) { @@ -1977,9 +1977,9 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { try { chain.validate_protocol_features( _protocol_features_to_activate ); } catch ( const std::bad_alloc& ) { - chain_plugin::handle_bad_alloc(); + chain_apis::api_base::handle_bad_alloc(); } catch ( const boost::interprocess::bad_alloc& ) { - chain_plugin::handle_bad_alloc(); + chain_apis::api_base::handle_bad_alloc(); } catch( const fc::exception& e ) { wlog( "protocol features to activate are no longer all valid: ${details}", ("details",e.to_detail_string()) ); @@ -2076,9 +2076,9 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { chain_plugin::handle_guard_exception(e); return start_block_result::failed; } catch ( std::bad_alloc& ) { - chain_plugin::handle_bad_alloc(); + chain_apis::api_base::handle_bad_alloc(); } catch ( boost::interprocess::bad_alloc& ) { - chain_plugin::handle_db_exhaustion(); + chain_apis::api_base::handle_db_exhaustion(); } } @@ -3039,9 +3039,9 @@ bool producer_plugin_impl::push_read_only_transaction(transaction_metadata_ptr t } catch ( const guard_exception& e ) { chain_plugin::handle_guard_exception(e); } catch ( boost::interprocess::bad_alloc& ) { - chain_plugin::handle_db_exhaustion(); + chain_apis::api_base::handle_db_exhaustion(); } catch ( std::bad_alloc& ) { - chain_plugin::handle_bad_alloc(); + chain_apis::api_base::handle_bad_alloc(); } CATCH_AND_CALL(next); return retry; From 0c041509e61a651b6f842b58f680a4154a86f12b Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Wed, 12 Apr 2023 16:54:58 -0400 Subject: [PATCH 13/17] Change `abi_cache` name as per PR review comment. --- .../include/eosio/chain/abi_serializer.hpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index c7a4f49c5c..1a72f73ea2 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -972,23 +972,23 @@ void abi_serializer::from_variant( const fc::variant& v, T& o, Resolver resolver from_variant( v, o, resolver, create_yield_function(max_serialization_time) ); } -using abi_serializer_cache = std::unordered_map>; +using abi_serializer_cache_t = std::unordered_map>; class abi_resolver { public: - abi_resolver(abi_serializer_cache&& abi_cache) : - abi_cache(std::move(abi_cache)) + abi_resolver(abi_serializer_cache_t&& abi_serializers) : + abi_serializers(std::move(abi_serializers)) {} std::optional> operator()(const account_name& account) { - auto it = abi_cache.find(account); - if (it != abi_cache.end() && it->second) + auto it = abi_serializers.find(account); + if (it != abi_serializers.end() && it->second) return std::reference_wrapper(*it->second); return {}; }; private: - abi_serializer_cache abi_cache; + abi_serializer_cache_t abi_serializers; }; class abi_serializer_cache_builder { @@ -1021,16 +1021,16 @@ class abi_serializer_cache_builder { return std::move(*this); } - abi_serializer_cache&& get() && { - return std::move(abi_cache); + abi_serializer_cache_t&& get() && { + return std::move(abi_serializers); } private: void add_to_cache(const chain::action& a) { - auto it = abi_cache.find( a.account ); - if( it == abi_cache.end() ) { + auto it = abi_serializers.find( a.account ); + if( it == abi_serializers.end() ) { try { - abi_cache.emplace_hint( it, a.account, resolver_( a.account ) ); + abi_serializers.emplace_hint( it, a.account, resolver_( a.account ) ); } catch( ... ) { // keep behavior of not throwing on invalid abi, will result in hex data } @@ -1038,7 +1038,7 @@ class abi_serializer_cache_builder { } std::function(const account_name& name)> resolver_; - abi_serializer_cache abi_cache; + abi_serializer_cache_t abi_serializers; }; } // eosio::chain From 6e47c7142a785c90ded3c1f6be2a785d882edd6a Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Wed, 12 Apr 2023 16:58:44 -0400 Subject: [PATCH 14/17] Add comment as suggested in PR review. --- plugins/chain_plugin/chain_plugin.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 7e1aaffbaf..0bf3b78557 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -2233,6 +2233,7 @@ void api_base::send_transaction_gen(API &api, const send_transaction_params_t& p } if (!retried) { + // we are still on main thread here. The lambda passed to `next()` below will be executed on the http thread pool auto yield = abi_serializer::create_yield_function(fc::microseconds::maximum()); auto abi_cache = abi_serializer_cache_builder(api_base::make_resolver(api.db, std::move(yield))).add_serializers(trx_trace_ptr).get(); using return_type = t_or_exception; From 380373b6cd2ae1ce4090b2fc2cfc9fa3d38ba2ac Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Wed, 12 Apr 2023 21:11:21 -0400 Subject: [PATCH 15/17] Address PR comments (mostly allow parameters to be moved by accepting values) --- plugins/chain_plugin/chain_plugin.cpp | 18 +++++++++--------- .../eosio/chain_plugin/chain_plugin.hpp | 10 +++++----- .../include/eosio/http_plugin/macros.hpp | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 0bf3b78557..76284ae33b 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -2187,7 +2187,7 @@ void read_write::push_transactions(const read_write::push_transactions_params& p } template -void api_base::send_transaction_gen(API &api, const send_transaction_params_t& params, next_function next) { +void api_base::send_transaction_gen(API &api, send_transaction_params_t params, next_function next) { try { auto ptrx = std::make_shared(); auto resolver = make_resolver(api.db, abi_serializer::create_yield_function( api.abi_serializer_max_time )); @@ -2261,22 +2261,22 @@ void api_base::send_transaction_gen(API &api, const send_transaction_params_t& p } CATCH_AND_CALL(next); } -void read_write::send_transaction(const read_write::send_transaction_params& params, next_function next) { +void read_write::send_transaction(read_write::send_transaction_params params, next_function next) { send_transaction_params_t gen_params { .return_failure_trace = false, .retry_trx = false, .retry_trx_num_blocks = std::nullopt, .trx_type = transaction_metadata::trx_type::input, .transaction = std::move(params) }; - return send_transaction_gen(*this, gen_params, std::move(next)); + return send_transaction_gen(*this, std::move(gen_params), std::move(next)); } -void read_write::send_transaction2(const read_write::send_transaction2_params& params, next_function next) { +void read_write::send_transaction2(read_write::send_transaction2_params params, next_function next) { send_transaction_params_t gen_params { .return_failure_trace = params.return_failure_trace, .retry_trx = params.retry_trx, .retry_trx_num_blocks = std::move(params.retry_trx_num_blocks), .trx_type = transaction_metadata::trx_type::input, .transaction = std::move(params.transaction) }; - return send_transaction_gen(*this, gen_params, std::move(next)); + return send_transaction_gen(*this, std::move(gen_params), std::move(next)); } read_only::get_abi_results read_only::get_abi( const get_abi_params& params, const fc::time_point& deadline )const { @@ -2553,22 +2553,22 @@ read_only::get_required_keys_result read_only::get_required_keys( const get_requ return result; } -void read_only::compute_transaction(const compute_transaction_params& params, next_function next) { +void read_only::compute_transaction(compute_transaction_params params, next_function next) { send_transaction_params_t gen_params { .return_failure_trace = false, .retry_trx = false, .retry_trx_num_blocks = std::nullopt, .trx_type = transaction_metadata::trx_type::dry_run, .transaction = std::move(params.transaction) }; - return send_transaction_gen(*this, gen_params, std::move(next)); + return send_transaction_gen(*this, std::move(gen_params), std::move(next)); } -void read_only::send_read_only_transaction(const send_read_only_transaction_params& params, next_function next) { +void read_only::send_read_only_transaction(send_read_only_transaction_params params, next_function next) { send_transaction_params_t gen_params { .return_failure_trace = false, .retry_trx = false, .retry_trx_num_blocks = std::nullopt, .trx_type = transaction_metadata::trx_type::read_only, .transaction = std::move(params.transaction) }; - return send_transaction_gen(*this, gen_params, std::move(next)); + return send_transaction_gen(*this, std::move(gen_params), std::move(next)); } read_only::get_transaction_id_result read_only::get_transaction_id( const read_only::get_transaction_id_params& params, const fc::time_point& deadline) const { 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 0a7e770573..0f2a1aa80d 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -119,7 +119,7 @@ class api_base { }; template - static void send_transaction_gen(API &api, const send_transaction_params_t& params, chain::plugin_interface::next_function next); + static void send_transaction_gen(API& api, send_transaction_params_t params, chain::plugin_interface::next_function next); }; class read_only : public api_base { @@ -521,7 +521,7 @@ class read_only : public api_base { fc::variant transaction; }; - void compute_transaction(const compute_transaction_params& params, chain::plugin_interface::next_function next ); + void compute_transaction(compute_transaction_params params, chain::plugin_interface::next_function next ); struct send_read_only_transaction_results { chain::transaction_id_type transaction_id; @@ -530,7 +530,7 @@ class read_only : public api_base { struct send_read_only_transaction_params { fc::variant transaction; }; - void send_read_only_transaction(const send_read_only_transaction_params& params, chain::plugin_interface::next_function next ); + void send_read_only_transaction(send_read_only_transaction_params params, chain::plugin_interface::next_function next ); static void copy_inline_row(const chain::key_value_object& obj, vector& data) { data.resize( obj.value.size() ); @@ -795,7 +795,7 @@ class read_write : public api_base { using send_transaction_params = push_transaction_params; using send_transaction_results = push_transaction_results; - void send_transaction(const send_transaction_params& params, chain::plugin_interface::next_function next); + void send_transaction(send_transaction_params params, chain::plugin_interface::next_function next); struct send_transaction2_params { bool return_failure_trace = true; @@ -803,7 +803,7 @@ class read_write : public api_base { std::optional retry_trx_num_blocks{}; ///< if retry_trx, report trace at specified blocks from executed or lib if not specified fc::variant transaction; }; - void send_transaction2(const send_transaction2_params& params, chain::plugin_interface::next_function next); + void send_transaction2(send_transaction2_params params, chain::plugin_interface::next_function next); }; diff --git a/plugins/http_plugin/include/eosio/http_plugin/macros.hpp b/plugins/http_plugin/include/eosio/http_plugin/macros.hpp index e5e5831397..188252a20d 100644 --- a/plugins/http_plugin/include/eosio/http_plugin/macros.hpp +++ b/plugins/http_plugin/include/eosio/http_plugin/macros.hpp @@ -17,7 +17,7 @@ struct async_result_visitor : public fc::visitor { using http_fwd_t = std::function()>; \ api_handle.call_name( std::move(params), \ [&_http_plugin, cb=std::move(cb), body=std::move(body)] \ - (const chain::next_function_variant& result) { \ + (const chain::next_function_variant& result) mutable { \ if (std::holds_alternative(result)) { \ try { \ std::get(result)->dynamic_rethrow_exception(); \ From 8d830dcef027dfb3b67ecf1eb6e945e3f60438d1 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Wed, 12 Apr 2023 21:49:09 -0400 Subject: [PATCH 16/17] Keep track of whether the serializer cache contains a setabi action. --- .../chain/include/eosio/chain/abi_serializer.hpp | 8 ++++++-- plugins/chain_plugin/chain_plugin.cpp | 15 ++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index 1a72f73ea2..7f427ad104 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -1021,12 +1021,14 @@ class abi_serializer_cache_builder { return std::move(*this); } - abi_serializer_cache_t&& get() && { - return std::move(abi_serializers); + std::pair get() && { + return {std::move(abi_serializers), has_setabi_action}; } private: void add_to_cache(const chain::action& a) { + if (a.name == setabi) + has_setabi_action = true; auto it = abi_serializers.find( a.account ); if( it == abi_serializers.end() ) { try { @@ -1039,6 +1041,8 @@ class abi_serializer_cache_builder { std::function(const account_name& name)> resolver_; abi_serializer_cache_t abi_serializers; + bool has_setabi_action {false}; + inline static const action_name setabi = chain::setabi::get_name(); }; } // eosio::chain diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 76284ae33b..db572d8f13 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1927,7 +1927,7 @@ std::function()> read_only::get_block(const g chain::signed_block_ptr block = get_raw_block(params, deadline); auto yield = abi_serializer::create_yield_function(deadline - fc::time_point::now()); - auto abi_cache = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(block).get(); + auto [abi_cache, has_setabi_action] = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(block).get(); FC_CHECK_DEADLINE(deadline); using return_type = t_or_exception; @@ -1985,7 +1985,7 @@ read_only::get_block_header_result read_only::get_block_header(const read_only:: abi_resolver read_only::get_block_serializers( const chain::signed_block_ptr& block, const fc::microseconds& max_time ) const { auto yield = abi_serializer::create_yield_function(max_time); - return abi_resolver(abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(block).get()); + return abi_resolver(std::get<0>(abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(block).get())); } fc::variant read_only::convert_block( const chain::signed_block_ptr& block, @@ -2186,13 +2186,14 @@ void read_write::push_transactions(const read_write::push_transactions_params& p } CATCH_AND_CALL(next); } + template void api_base::send_transaction_gen(API &api, send_transaction_params_t params, next_function next) { try { auto ptrx = std::make_shared(); - auto resolver = make_resolver(api.db, abi_serializer::create_yield_function( api.abi_serializer_max_time )); + auto resolver = make_resolver(api.db, abi_serializer::create_yield_function(api.abi_serializer_max_time)); try { - abi_serializer::from_variant(params.transaction, *ptrx, resolver, abi_serializer::create_yield_function( api.abi_serializer_max_time )); + abi_serializer::from_variant(params.transaction, *ptrx, resolver, api.abi_serializer_max_time); } EOS_RETHROW_EXCEPTIONS(packed_transaction_type_exception, "Invalid packed transaction") bool retry = false; @@ -2234,9 +2235,9 @@ void api_base::send_transaction_gen(API &api, send_transaction_params_t params, if (!retried) { // we are still on main thread here. The lambda passed to `next()` below will be executed on the http thread pool - auto yield = abi_serializer::create_yield_function(fc::microseconds::maximum()); - auto abi_cache = abi_serializer_cache_builder(api_base::make_resolver(api.db, std::move(yield))).add_serializers(trx_trace_ptr).get(); - using return_type = t_or_exception; + auto yield = abi_serializer::create_yield_function(fc::microseconds::maximum()); + auto [abi_cache, b] = abi_serializer_cache_builder(api_base::make_resolver(api.db, std::move(yield))).add_serializers(trx_trace_ptr).get(); + using return_type = t_or_exception; next([&api, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { try { fc::variant output; From e0edbcdc308a5628acde888aab147481a1010b7a Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Thu, 13 Apr 2023 08:05:58 -0400 Subject: [PATCH 17/17] Revert "Keep track of whether the serializer cache contains a setabi action." This reverts commit 8d830dcef027dfb3b67ecf1eb6e945e3f60438d1. --- .../chain/include/eosio/chain/abi_serializer.hpp | 8 ++------ plugins/chain_plugin/chain_plugin.cpp | 15 +++++++-------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index 7f427ad104..1a72f73ea2 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -1021,14 +1021,12 @@ class abi_serializer_cache_builder { return std::move(*this); } - std::pair get() && { - return {std::move(abi_serializers), has_setabi_action}; + abi_serializer_cache_t&& get() && { + return std::move(abi_serializers); } private: void add_to_cache(const chain::action& a) { - if (a.name == setabi) - has_setabi_action = true; auto it = abi_serializers.find( a.account ); if( it == abi_serializers.end() ) { try { @@ -1041,8 +1039,6 @@ class abi_serializer_cache_builder { std::function(const account_name& name)> resolver_; abi_serializer_cache_t abi_serializers; - bool has_setabi_action {false}; - inline static const action_name setabi = chain::setabi::get_name(); }; } // eosio::chain diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index db572d8f13..76284ae33b 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1927,7 +1927,7 @@ std::function()> read_only::get_block(const g chain::signed_block_ptr block = get_raw_block(params, deadline); auto yield = abi_serializer::create_yield_function(deadline - fc::time_point::now()); - auto [abi_cache, has_setabi_action] = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(block).get(); + auto abi_cache = abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(block).get(); FC_CHECK_DEADLINE(deadline); using return_type = t_or_exception; @@ -1985,7 +1985,7 @@ read_only::get_block_header_result read_only::get_block_header(const read_only:: abi_resolver read_only::get_block_serializers( const chain::signed_block_ptr& block, const fc::microseconds& max_time ) const { auto yield = abi_serializer::create_yield_function(max_time); - return abi_resolver(std::get<0>(abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(block).get())); + return abi_resolver(abi_serializer_cache_builder(make_resolver(db, std::move(yield))).add_serializers(block).get()); } fc::variant read_only::convert_block( const chain::signed_block_ptr& block, @@ -2186,14 +2186,13 @@ void read_write::push_transactions(const read_write::push_transactions_params& p } CATCH_AND_CALL(next); } - template void api_base::send_transaction_gen(API &api, send_transaction_params_t params, next_function next) { try { auto ptrx = std::make_shared(); - auto resolver = make_resolver(api.db, abi_serializer::create_yield_function(api.abi_serializer_max_time)); + auto resolver = make_resolver(api.db, abi_serializer::create_yield_function( api.abi_serializer_max_time )); try { - abi_serializer::from_variant(params.transaction, *ptrx, resolver, api.abi_serializer_max_time); + abi_serializer::from_variant(params.transaction, *ptrx, resolver, abi_serializer::create_yield_function( api.abi_serializer_max_time )); } EOS_RETHROW_EXCEPTIONS(packed_transaction_type_exception, "Invalid packed transaction") bool retry = false; @@ -2235,9 +2234,9 @@ void api_base::send_transaction_gen(API &api, send_transaction_params_t params, if (!retried) { // we are still on main thread here. The lambda passed to `next()` below will be executed on the http thread pool - auto yield = abi_serializer::create_yield_function(fc::microseconds::maximum()); - auto [abi_cache, b] = abi_serializer_cache_builder(api_base::make_resolver(api.db, std::move(yield))).add_serializers(trx_trace_ptr).get(); - using return_type = t_or_exception; + auto yield = abi_serializer::create_yield_function(fc::microseconds::maximum()); + auto abi_cache = abi_serializer_cache_builder(api_base::make_resolver(api.db, std::move(yield))).add_serializers(trx_trace_ptr).get(); + using return_type = t_or_exception; next([&api, trx_trace_ptr, resolver = abi_resolver(std::move(abi_cache))]() mutable { try { fc::variant output;