Skip to content

Commit

Permalink
Merge pull request #696 from AntelopeIO/GH-677-get-block
Browse files Browse the repository at this point in the history
Move get_block abi serialization off the main thread
  • Loading branch information
heifner authored Feb 15, 2023
2 parents 0dee765 + 34baed9 commit dd59a99
Show file tree
Hide file tree
Showing 22 changed files with 232 additions and 146 deletions.
64 changes: 36 additions & 28 deletions libraries/chain/abi_serializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,14 @@ namespace eosio { namespace chain {
);
}

abi_serializer::abi_serializer( const abi_def& abi, const yield_function_t& yield ) {
abi_serializer::abi_serializer( abi_def&& abi, const yield_function_t& yield ) {
configure_built_in_types();
set_abi(abi, yield);
set_abi(std::move(abi), yield);
}

abi_serializer::abi_serializer( const abi_def& abi, const fc::microseconds& max_serialization_time) {
abi_serializer::abi_serializer( abi_def&& abi, const fc::microseconds& max_serialization_time) {
configure_built_in_types();
set_abi(abi, create_yield_function(max_serialization_time));
set_abi(std::move(abi), create_yield_function(max_serialization_time));
}

void abi_serializer::add_specialized_unpack_pack( const string& name,
Expand Down Expand Up @@ -128,11 +128,19 @@ namespace eosio { namespace chain {
built_in_types.emplace("extended_asset", pack_unpack<extended_asset>());
}

void abi_serializer::set_abi(const abi_def& abi, const yield_function_t& yield) {
void abi_serializer::set_abi(abi_def&& abi, const yield_function_t& yield) {
impl::abi_traverse_context ctx(yield);

EOS_ASSERT(starts_with(abi.version, "eosio::abi/1."), unsupported_abi_version_exception, "ABI has an unsupported version");

size_t types_size = abi.types.size();
size_t structs_size = abi.structs.size();
size_t actions_size = abi.actions.size();
size_t tables_size = abi.tables.size();
size_t error_messages_size = abi.error_messages.size();
size_t variants_size = abi.variants.value.size();
size_t action_results_size = abi.action_results.value.size();

typedefs.clear();
structs.clear();
actions.clear();
Expand All @@ -141,47 +149,47 @@ namespace eosio { namespace chain {
variants.clear();
action_results.clear();

for( const auto& st : abi.structs )
structs[st.name] = st;
for( auto& st : abi.structs )
structs[st.name] = std::move(st);

for( const auto& td : abi.types ) {
for( auto& td : abi.types ) {
EOS_ASSERT(!_is_type(td.new_type_name, ctx), duplicate_abi_type_def_exception,
"type already exists", ("new_type_name",impl::limit_size(td.new_type_name)));
typedefs[td.new_type_name] = td.type;
typedefs[std::move(td.new_type_name)] = std::move(td.type);
}

for( const auto& a : abi.actions )
actions[a.name] = a.type;
for( auto& a : abi.actions )
actions[std::move(a.name)] = std::move(a.type);

for( const auto& t : abi.tables )
tables[t.name] = t.type;
for( auto& t : abi.tables )
tables[std::move(t.name)] = std::move(t.type);

for( const auto& e : abi.error_messages )
error_messages[e.error_code] = e.error_msg;
for( auto& e : abi.error_messages )
error_messages[std::move(e.error_code)] = std::move(e.error_msg);

for( const auto& v : abi.variants.value )
variants[v.name] = v;
for( auto& v : abi.variants.value )
variants[v.name] = std::move(v);

for( const auto& r : abi.action_results.value )
action_results[r.name] = r.result_type;
for( auto& r : abi.action_results.value )
action_results[std::move(r.name)] = std::move(r.result_type);

/**
* The ABI vector may contain duplicates which would make it
* an invalid ABI
*/
EOS_ASSERT( typedefs.size() == abi.types.size(), duplicate_abi_type_def_exception, "duplicate type definition detected" );
EOS_ASSERT( structs.size() == abi.structs.size(), duplicate_abi_struct_def_exception, "duplicate struct definition detected" );
EOS_ASSERT( actions.size() == abi.actions.size(), duplicate_abi_action_def_exception, "duplicate action definition detected" );
EOS_ASSERT( tables.size() == abi.tables.size(), duplicate_abi_table_def_exception, "duplicate table definition detected" );
EOS_ASSERT( error_messages.size() == abi.error_messages.size(), duplicate_abi_err_msg_def_exception, "duplicate error message definition detected" );
EOS_ASSERT( variants.size() == abi.variants.value.size(), duplicate_abi_variant_def_exception, "duplicate variant definition detected" );
EOS_ASSERT( action_results.size() == abi.action_results.value.size(), duplicate_abi_action_results_def_exception, "duplicate action results definition detected" );
EOS_ASSERT( typedefs.size() == types_size, duplicate_abi_type_def_exception, "duplicate type definition detected" );
EOS_ASSERT( structs.size() == structs_size, duplicate_abi_struct_def_exception, "duplicate struct definition detected" );
EOS_ASSERT( actions.size() == actions_size, duplicate_abi_action_def_exception, "duplicate action definition detected" );
EOS_ASSERT( tables.size() == tables_size, duplicate_abi_table_def_exception, "duplicate table definition detected" );
EOS_ASSERT( error_messages.size() == error_messages_size, duplicate_abi_err_msg_def_exception, "duplicate error message definition detected" );
EOS_ASSERT( variants.size() == variants_size, duplicate_abi_variant_def_exception, "duplicate variant definition detected" );
EOS_ASSERT( action_results.size() == action_results_size, duplicate_abi_action_results_def_exception, "duplicate action results definition detected" );

validate(ctx);
}

void abi_serializer::set_abi(const abi_def& abi, const fc::microseconds& max_serialization_time) {
return set_abi(abi, create_yield_function(max_serialization_time));
void abi_serializer::set_abi(abi_def&& abi, const fc::microseconds& max_serialization_time) {
return set_abi(std::move(abi), create_yield_function(max_serialization_time));
}

bool abi_serializer::is_builtin_type(const std::string_view& type)const {
Expand Down
8 changes: 4 additions & 4 deletions libraries/chain/include/eosio/chain/abi_serializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ struct abi_serializer {
using yield_function_t = fc::optional_delegate<void(size_t)>;

abi_serializer(){ configure_built_in_types(); }
abi_serializer( const abi_def& abi, const yield_function_t& yield );
abi_serializer( abi_def&& abi, const yield_function_t& yield );
[[deprecated("use the overload with yield_function_t[=create_yield_function(max_serialization_time)]")]]
abi_serializer( const abi_def& abi, const fc::microseconds& max_serialization_time );
void set_abi( const abi_def& abi, const yield_function_t& yield );
abi_serializer( abi_def&& abi, const fc::microseconds& max_serialization_time );
void set_abi( abi_def&& abi, const yield_function_t& yield );
[[deprecated("use the overload with yield_function_t[=create_yield_function(max_serialization_time)]")]]
void set_abi(const abi_def& abi, const fc::microseconds& max_serialization_time);
void set_abi( abi_def&& abi, const fc::microseconds& max_serialization_time);

/// @return string_view of `t` or internal string type
std::string_view resolve_type(const std::string_view& t)const;
Expand Down
5 changes: 2 additions & 3 deletions libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,9 +348,8 @@ namespace eosio { namespace chain {
if( n.good() ) {
try {
const auto& a = get_account( n );
abi_def abi;
if( abi_serializer::to_abi( a.abi, abi ))
return abi_serializer( abi, yield );
if( abi_def abi; abi_serializer::to_abi( a.abi, abi ))
return abi_serializer( std::move(abi), yield );
} FC_CAPTURE_AND_LOG((n))
}
return std::optional<abi_serializer>();
Expand Down
5 changes: 2 additions & 3 deletions libraries/testing/include/eosio/testing/tester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,9 +341,8 @@ namespace eosio { namespace testing {
return [this]( const account_name& name ) -> std::optional<abi_serializer> {
try {
const auto& accnt = control->db().get<account_object, by_name>( name );
abi_def abi;
if( abi_serializer::to_abi( accnt.abi, abi )) {
return abi_serializer( abi, abi_serializer::create_yield_function( abi_serializer_max_time ) );
if( abi_def abi; abi_serializer::to_abi( accnt.abi, abi )) {
return abi_serializer( std::move(abi), abi_serializer::create_yield_function( abi_serializer_max_time ) );
}
return std::optional<abi_serializer>();
} FC_RETHROW_EXCEPTIONS( error, "Failed to find or parse ABI for ${name}", ("name", name))
Expand Down
2 changes: 1 addition & 1 deletion libraries/testing/tester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ namespace eosio { namespace testing {
const variant_object& data )const { try {
const auto& acnt = control->get_account(code);
auto abi = acnt.get_abi();
chain::abi_serializer abis(abi, abi_serializer::create_yield_function( abi_serializer_max_time ));
chain::abi_serializer abis(std::move(abi), abi_serializer::create_yield_function( abi_serializer_max_time ));

string action_type_name = abis.get_action_type(acttype);
FC_ASSERT( action_type_name != string(), "unknown action type ${a}", ("a",acttype) );
Expand Down
41 changes: 37 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,41 @@ 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, &_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 abi_cache = ro_api.get_block_serializers( block, max_time );
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(
[ro_api, 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);

fc::variant result = ro_api.convert_block( block, abi_cache, remaining_time );

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
Loading

0 comments on commit dd59a99

Please sign in to comment.