Skip to content

Commit

Permalink
GH-677 Move abi serialization off the main thread for get_block
Browse files Browse the repository at this point in the history
  • Loading branch information
heifner committed Feb 7, 2023
1 parent 7b01097 commit 38f3988
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 19 deletions.
74 changes: 70 additions & 4 deletions plugins/chain_api_plugin/chain_api_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,20 +98,18 @@ void chain_api_plugin::plugin_startup() {
ilog( "starting chain_api_plugin" );
my.reset(new chain_api_plugin_impl(app().get_plugin<chain_plugin>().chain()));
auto& chain = app().get_plugin<chain_plugin>();
auto& http = app().get_plugin<http_plugin>();
fc::microseconds max_response_time = http.get_max_response_time();
auto& _http_plugin = app().get_plugin<http_plugin>();
fc::microseconds max_response_time = _http_plugin.get_max_response_time();

auto ro_api = chain.get_read_only_api(max_response_time);
auto rw_api = chain.get_read_write_api(max_response_time);

auto& _http_plugin = app().get_plugin<http_plugin>();
ro_api.set_shorten_abi_errors( !http_plugin::verbose_errors() );

_http_plugin.add_api( {
CHAIN_RO_CALL(get_info, 200, http_params_types::no_params)}, 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(get_block, 200, http_params_types::params_required),
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),
Expand Down Expand Up @@ -151,6 +149,74 @@ void chain_api_plugin::plugin_startup() {
CHAIN_RO_CALL_WITH_400(get_transaction_status, 200, http_params_types::params_required),
});
}

_http_plugin.add_api({
{ std::string("/v1/chain/get_block"),
[ro_api, &chain, &_http_plugin, max_time=std::min(chain.get_abi_serializer_max_time(),max_response_time)]
( string, string body, url_response_callback cb ) mutable {
auto deadline = ro_api.start();
try {
auto start = fc::time_point::now();
auto params = parse_params<chain_apis::read_only::get_block_params, http_params_types::params_required>(body);
FC_CHECK_DEADLINE( deadline );
chain::signed_block_ptr block = ro_api.get_block( params, deadline );

auto yield = abi_serializer::create_yield_function( max_time );
std::unordered_map<account_name, std::optional<abi_serializer> > abi_cache;
auto add_to_cache = [&]( const chain::action& a ) {
auto it = abi_cache.find( a.account );
if( it == abi_cache.end() )
abi_cache.emplace_hint( it, a.account, chain.chain().get_abi_serializer( a.account, yield ) );
};
for( const auto& receipt: block->transactions ) {
if( std::holds_alternative<chain::packed_transaction>( receipt.trx ) ) {
const auto& pt = std::get<chain::packed_transaction>( 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 );
}
}
FC_CHECK_DEADLINE( deadline );

auto post_time = fc::time_point::now();
auto remaining_time = max_time - (post_time - start);
_http_plugin.post_http_thread_pool(
[cb, deadline, post_time, remaining_time, abi_cache{std::move(abi_cache)}, block{std::move( block )}]() {
try {
auto new_deadline = deadline + (fc::time_point::now() - post_time);

auto abi_serializer_resolver = [&abi_cache](const account_name& account) -> std::optional<abi_serializer> {
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( remaining_time ) );

const auto block_id = block->calculate_id();
uint32_t ref_block_prefix = block_id._hash[1];

fc::variant result = fc::mutable_variant_object( pretty_output.get_object() )
( "id", block_id )
( "block_num", block->block_num() )
( "ref_block_prefix", ref_block_prefix );

cb( 200, new_deadline, std::move( result ) );
} catch( ... ) {
http_plugin::handle_exception( "chain", "get_block", "", cb );
}
} );
} catch( ... ) {
http_plugin::handle_exception("chain", "get_block", body, cb);
}
}
}
} );
}

void chain_api_plugin::plugin_shutdown() {}
Expand Down
17 changes: 3 additions & 14 deletions plugins/chain_plugin/chain_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include <eosio/chain_plugin/trx_finality_status_processing.hpp>
#include <eosio/chain/permission_link_object.hpp>
#include <eosio/chain/global_property_object.hpp>
#include <eosio/chain/eosio_contract.hpp>

#include <eosio/resource_monitor_plugin/resource_monitor_plugin.hpp>

Expand All @@ -30,7 +29,6 @@

#include <fc/io/json.hpp>
#include <fc/variant.hpp>
#include <signal.h>
#include <cstdlib>

// reflect chainbase::environment for --print-build-info option
Expand Down Expand Up @@ -1881,7 +1879,7 @@ read_only::get_scheduled_transactions( const read_only::get_scheduled_transactio
return result;
}

fc::variant read_only::get_block(const read_only::get_block_params& params, const fc::time_point& deadline) const {
chain::signed_block_ptr read_only::get_block(const read_only::get_block_params& params, const fc::time_point& deadline) const {
signed_block_ptr block;
std::optional<uint64_t> block_num;

Expand All @@ -1903,18 +1901,9 @@ fc::variant read_only::get_block(const read_only::get_block_params& params, cons
}

EOS_ASSERT( block, unknown_block_exception, "Could not find block: ${block}", ("block", params.block_num_or_id));
FC_CHECK_DEADLINE(deadline);

fc::variant pretty_output;
abi_serializer::to_variant(*block, pretty_output, make_resolver(db, abi_serializer::create_yield_function( abi_serializer_max_time )),
abi_serializer::create_yield_function( abi_serializer_max_time ));

const auto block_id = block->calculate_id();
uint32_t ref_block_prefix = block_id._hash[1];

return fc::mutable_variant_object(pretty_output.get_object())
("id", block_id)
("block_num",block->block_num())
("ref_block_prefix", ref_block_prefix);
return block;
}

fc::variant read_only::get_block_info(const read_only::get_block_info_params& params, const fc::time_point& deadline) const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ class read_only {
string block_num_or_id;
};

fc::variant get_block(const get_block_params& params, const fc::time_point& deadline) const;
chain::signed_block_ptr get_block(const get_block_params& params, const fc::time_point& deadline) const;

struct get_block_info_params {
uint32_t block_num = 0;
Expand Down
5 changes: 5 additions & 0 deletions plugins/http_plugin/http_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,11 @@ class http_plugin_impl : public std::enable_shared_from_this<http_plugin_impl> {
my->plugin_state->url_handlers[url] = my->make_http_thread_url_handler(handler);
}

void http_plugin::post_http_thread_pool(std::function<void()> f) {
if( f )
boost::asio::post( my->plugin_state->thread_pool.get_executor(), f );
}

void http_plugin::handle_exception( const char *api_name, const char *call_name, const string& body, const url_response_callback& cb) {
try {
try {
Expand Down
2 changes: 2 additions & 0 deletions plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ namespace eosio {
// standard exception handling for api handlers
static void handle_exception( const char *api_name, const char *call_name, const string& body, const url_response_callback& cb );

void post_http_thread_pool(std::function<void()> f);

bool is_on_loopback() const;
bool is_secure() const;

Expand Down

0 comments on commit 38f3988

Please sign in to comment.