Skip to content

Commit

Permalink
GH-677 Use std::move for abi into abi_serializer to avoid string copies.
Browse files Browse the repository at this point in the history
  • Loading branch information
heifner committed Feb 7, 2023
1 parent b7fdd1c commit 62903c0
Show file tree
Hide file tree
Showing 19 changed files with 112 additions and 97 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[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[a.name] = std::move(a.type);

for( const auto& t : abi.tables )
tables[t.name] = t.type;
for( auto&& t : abi.tables )
tables[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[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[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
2 changes: 1 addition & 1 deletion libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ namespace eosio { namespace chain {
const auto& a = get_account( n );
abi_def abi;
if( abi_serializer::to_abi( a.abi, abi ))
return abi_serializer( abi, yield );
return abi_serializer( std::move(abi), yield );
} FC_CAPTURE_AND_LOG((n))
}
return std::optional<abi_serializer>();
Expand Down
2 changes: 1 addition & 1 deletion libraries/testing/include/eosio/testing/tester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ namespace eosio { namespace testing {
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 ) );
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
47 changes: 25 additions & 22 deletions plugins/chain_plugin/chain_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1507,53 +1507,53 @@ string get_table_type( const abi_def& abi, const name& table_name ) {
}

read_only::get_table_rows_result read_only::get_table_rows( const read_only::get_table_rows_params& p, const fc::time_point& deadline )const {
const abi_def abi = eosio::chain_apis::get_abi( db, p.code );
abi_def abi = eosio::chain_apis::get_abi( db, p.code );
bool primary = false;
auto table_with_index = get_table_index_name( p, primary );
if( primary ) {
EOS_ASSERT( p.table == table_with_index, chain::contract_table_query_exception, "Invalid table name ${t}", ( "t", p.table ));
auto table_type = get_table_type( abi, p.table );
if( table_type == KEYi64 || p.key_type == "i64" || p.key_type == "name" ) {
return get_table_rows_ex<key_value_index>(p,abi,deadline);
return get_table_rows_ex<key_value_index>(p,std::move(abi),deadline);
}
EOS_ASSERT( false, chain::contract_table_query_exception, "Invalid table type ${type}", ("type",table_type)("abi",abi));
} else {
EOS_ASSERT( !p.key_type.empty(), chain::contract_table_query_exception, "key type required for non-primary index" );

if (p.key_type == chain_apis::i64 || p.key_type == "name") {
return get_table_rows_by_seckey<index64_index, uint64_t>(p, abi, deadline, [](uint64_t v)->uint64_t {
return get_table_rows_by_seckey<index64_index, uint64_t>(p, std::move(abi), deadline, [](uint64_t v)->uint64_t {
return v;
});
}
else if (p.key_type == chain_apis::i128) {
return get_table_rows_by_seckey<index128_index, uint128_t>(p, abi, deadline, [](uint128_t v)->uint128_t {
return get_table_rows_by_seckey<index128_index, uint128_t>(p, std::move(abi), deadline, [](uint128_t v)->uint128_t {
return v;
});
}
else if (p.key_type == chain_apis::i256) {
if ( p.encode_type == chain_apis::hex) {
using conv = keytype_converter<chain_apis::sha256,chain_apis::hex>;
return get_table_rows_by_seckey<conv::index_type, conv::input_type>(p, abi, deadline, conv::function());
return get_table_rows_by_seckey<conv::index_type, conv::input_type>(p, std::move(abi), deadline, conv::function());
}
using conv = keytype_converter<chain_apis::i256>;
return get_table_rows_by_seckey<conv::index_type, conv::input_type>(p, abi, deadline, conv::function());
return get_table_rows_by_seckey<conv::index_type, conv::input_type>(p, std::move(abi), deadline, conv::function());
}
else if (p.key_type == chain_apis::float64) {
return get_table_rows_by_seckey<index_double_index, double>(p, abi, deadline, [](double v)->float64_t {
return get_table_rows_by_seckey<index_double_index, double>(p, std::move(abi), deadline, [](double v)->float64_t {
float64_t f;
double_to_float64(v, f);
return f;
});
}
else if (p.key_type == chain_apis::float128) {
if ( p.encode_type == chain_apis::hex) {
return get_table_rows_by_seckey<index_long_double_index, uint128_t>(p, abi, deadline, [](uint128_t v)->float128_t{
return get_table_rows_by_seckey<index_long_double_index, uint128_t>(p, std::move(abi), deadline, [](uint128_t v)->float128_t{
float128_t f;
uint128_to_float128(v, f);
return f;
});
}
return get_table_rows_by_seckey<index_long_double_index, double>(p, abi, deadline, [](double v)->float128_t{
return get_table_rows_by_seckey<index_long_double_index, double>(p, std::move(abi), deadline, [](double v)->float128_t{
float64_t f;
double_to_float64(v, f);
float128_t f128;
Expand All @@ -1563,11 +1563,11 @@ read_only::get_table_rows_result read_only::get_table_rows( const read_only::get
}
else if (p.key_type == chain_apis::sha256) {
using conv = keytype_converter<chain_apis::sha256,chain_apis::hex>;
return get_table_rows_by_seckey<conv::index_type, conv::input_type>(p, abi, deadline, conv::function());
return get_table_rows_by_seckey<conv::index_type, conv::input_type>(p, std::move(abi), deadline, conv::function());
}
else if(p.key_type == chain_apis::ripemd160) {
using conv = keytype_converter<chain_apis::ripemd160,chain_apis::hex>;
return get_table_rows_by_seckey<conv::index_type, conv::input_type>(p, abi, deadline, conv::function());
return get_table_rows_by_seckey<conv::index_type, conv::input_type>(p, std::move(abi), deadline, conv::function());
}
EOS_ASSERT(false, chain::contract_table_query_exception, "Unsupported secondary index type: ${t}", ("t", p.key_type));
}
Expand Down Expand Up @@ -1695,9 +1695,9 @@ fc::variant get_global_row( const database& db, const abi_def& abi, const abi_se

read_only::get_producers_result
read_only::get_producers( const read_only::get_producers_params& params, const fc::time_point& deadline ) const try {
const abi_def abi = eosio::chain_apis::get_abi(db, config::system_account_name);
abi_def abi = eosio::chain_apis::get_abi(db, config::system_account_name);
const auto table_type = get_table_type(abi, "producers"_n);
const abi_serializer abis{ abi, abi_serializer::create_yield_function( abi_serializer_max_time ) };
const abi_serializer abis{ std::move(abi), abi_serializer::create_yield_function( abi_serializer_max_time ) };
EOS_ASSERT(table_type == KEYi64, chain::contract_table_query_exception, "Invalid table type ${type} for table producers", ("type",table_type));

const auto& d = db.db();
Expand Down Expand Up @@ -1790,7 +1790,7 @@ struct resolver_factory {
if (accnt != nullptr) {
abi_def abi;
if (abi_serializer::to_abi(accnt->abi, abi)) {
return abi_serializer(abi, yield);
return abi_serializer(std::move(abi), yield);
}
}
return std::optional<abi_serializer>();
Expand Down Expand Up @@ -2399,7 +2399,7 @@ read_only::get_account_results read_only::get_account( const get_account_params&

abi_def abi;
if( abi_serializer::to_abi(code_account.abi, abi) ) {
abi_serializer abis( abi, abi_serializer::create_yield_function( abi_serializer_max_time ) );
abi_serializer abis( std::move(abi), abi_serializer::create_yield_function( abi_serializer_max_time ) );

const auto token_code = "eosio.token"_n;

Expand Down Expand Up @@ -2481,11 +2481,14 @@ read_only::get_account_results read_only::get_account( const get_account_params&
return result;
}

static fc::variant action_abi_to_variant( const abi_def& abi, type_name action_type ) {
static fc::variant action_abi_to_variant( const account_object* code_account, type_name action_type ) {
fc::variant v;
auto it = std::find_if(abi.structs.begin(), abi.structs.end(), [&](auto& x){return x.name == action_type;});
if( it != abi.structs.end() )
to_variant( it->fields, v );
abi_def abi;
if( abi_serializer::to_abi(code_account->abi, abi) ) {
auto it = std::find_if(abi.structs.begin(), abi.structs.end(), [&](auto& x){return x.name == action_type;});
if( it != abi.structs.end() )
to_variant( it->fields, v );
}
return v;
};

Expand All @@ -2496,14 +2499,14 @@ read_only::abi_json_to_bin_result read_only::abi_json_to_bin( const read_only::a

abi_def abi;
if( abi_serializer::to_abi(code_account->abi, abi) ) {
abi_serializer abis( abi, abi_serializer::create_yield_function( abi_serializer_max_time ) );
abi_serializer abis( std::move(abi), abi_serializer::create_yield_function( abi_serializer_max_time ) );
auto action_type = abis.get_action_type(params.action);
EOS_ASSERT(!action_type.empty(), action_validate_exception, "Unknown action ${action} in contract ${contract}", ("action", params.action)("contract", params.code));
try {
result.binargs = abis.variant_to_binary( action_type, params.args, abi_serializer::create_yield_function( abi_serializer_max_time ), shorten_abi_errors );
} EOS_RETHROW_EXCEPTIONS(chain::invalid_action_args_exception,
"'${args}' is invalid args for action '${action}' code '${code}'. expected '${proto}'",
("args", params.args)("action", params.action)("code", params.code)("proto", action_abi_to_variant(abi, action_type)))
("args", params.args)("action", params.action)("code", params.code)("proto", action_abi_to_variant(code_account, action_type)))
} else {
EOS_ASSERT(false, abi_not_found_exception, "No ABI found for ${contract}", ("contract", params.code));
}
Expand All @@ -2516,7 +2519,7 @@ read_only::abi_bin_to_json_result read_only::abi_bin_to_json( const read_only::a
const auto& code_account = db.db().get<account_object,by_name>( params.code );
abi_def abi;
if( abi_serializer::to_abi(code_account.abi, abi) ) {
abi_serializer abis( abi, abi_serializer::create_yield_function( abi_serializer_max_time ) );
abi_serializer abis( std::move(abi), abi_serializer::create_yield_function( abi_serializer_max_time ) );
result.args = abis.binary_to_variant( abis.get_action_type( params.action ), params.binargs, abi_serializer::create_yield_function( abi_serializer_max_time ), shorten_abi_errors );
} else {
EOS_ASSERT(false, abi_not_found_exception, "No ABI found for ${contract}", ("contract", params.code));
Expand Down
Loading

0 comments on commit 62903c0

Please sign in to comment.