Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

backport 2.1 ACTION_RETURN_VALUE #7

Merged
merged 6 commits into from
Jan 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions libraries/chain/abi_serializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ namespace eosio { namespace chain {
tables.clear();
error_messages.clear();
variants.clear();
action_results.clear();

for( const auto& st : abi.structs )
structs[st.name] = st;
Expand All @@ -163,6 +164,9 @@ namespace eosio { namespace chain {
for( const auto& v : abi.variants.value )
variants[v.name] = v;

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

/**
* The ABI vector may contain duplicates which would make it
* an invalid ABI
Expand All @@ -173,6 +177,7 @@ namespace eosio { namespace chain {
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" );

validate(ctx);
}
Expand Down Expand Up @@ -301,6 +306,11 @@ namespace eosio { namespace chain {
ctx.check_deadline();
EOS_ASSERT(_is_type(t.second, ctx), invalid_type_inside_abi, "${type}", ("type",impl::limit_size(t.second)) );
} FC_CAPTURE_AND_RETHROW( (t) ) }

for( const auto& r : action_results ) { try {
ctx.check_deadline();
EOS_ASSERT(_is_type(r.second, ctx), invalid_type_inside_abi, "${type}", ("type",impl::limit_size(r.second)) );
} FC_CAPTURE_AND_RETHROW( (r) ) }
}

std::string_view abi_serializer::resolve_type(const std::string_view& type)const {
Expand Down Expand Up @@ -590,6 +600,12 @@ namespace eosio { namespace chain {
return type_name();
}

type_name abi_serializer::get_action_result_type(name action_result)const {
auto itr = action_results.find(action_result);
if( itr != action_results.end() ) return itr->second;
return type_name();
}

optional<string> abi_serializer::get_error_message( uint64_t error_code )const {
auto itr = error_messages.find( error_code );
if( itr == error_messages.end() )
Expand Down
29 changes: 22 additions & 7 deletions libraries/chain/apply_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,13 @@ void apply_context::exec_one()
{
auto start = fc::time_point::now();

action_receipt r;
r.receiver = receiver;
r.act_digest = digest_type::hash(*act);
digest_type act_digest;

const auto& cfg = control.get_global_properties().configuration;
const account_metadata_object* receiver_account = nullptr;
try {
try {
action_return_value.clear();
receiver_account = &db.get<account_metadata_object,by_name>( receiver );
privileged = receiver_account->is_privileged();
auto native = control.find_apply_handler( receiver, act->account, act->name );
Expand Down Expand Up @@ -111,6 +110,18 @@ void apply_context::exec_one()
}
}
} FC_RETHROW_EXCEPTIONS( warn, "pending console output: ${console}", ("console", _pending_console_output) )

if( control.is_builtin_activated( builtin_protocol_feature_t::action_return_value ) ) {
act_digest = generate_action_digest(
[this](const char* data, uint32_t datalen) {
return trx_context.hash_with_checktime<digest_type>(data, datalen);
},
*act,
action_return_value
);
} else {
act_digest = digest_type::hash(*act);
}
} catch( const fc::exception& e ) {
action_trace& trace = trx_context.get_action_trace( action_ordinal );
trace.error_code = controller::convert_exception_to_error_code( e );
Expand All @@ -124,6 +135,13 @@ void apply_context::exec_one()
// * a pointer to an object in a chainbase index is not invalidated if the fields of that object are modified;
// * and, the *receiver_account object itself cannot be removed because accounts cannot be deleted in EOSIO.

action_trace& trace = trx_context.get_action_trace( action_ordinal );
trace.return_value = std::move(action_return_value);
trace.receipt.emplace();

action_receipt& r = *trace.receipt;
r.receiver = receiver;
r.act_digest = act_digest;
r.global_sequence = next_global_sequence();
r.recv_sequence = next_recv_sequence( *receiver_account );

Expand All @@ -141,10 +159,7 @@ void apply_context::exec_one()
r.auth_sequence[auth.actor] = next_auth_sequence( auth.actor );
}

action_trace& trace = trx_context.get_action_trace( action_ordinal );
trace.receipt = r;

trx_context.executed.emplace_back( std::move(r) );
trx_context.executed_action_receipt_digests.emplace_back( r.digest() );

finalize_trace( trace, start );

Expand Down
25 changes: 24 additions & 1 deletion libraries/chain/chain_config.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#include <eosio/chain/chain_config.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/controller.hpp>

namespace eosio { namespace chain {

void chain_config::validate()const {
void chain_config_v0::validate() const {
EOS_ASSERT( target_block_net_usage_pct <= config::percent_100, action_validate_exception,
"target block net usage percentage cannot exceed 100%" );
EOS_ASSERT( target_block_net_usage_pct >= config::percent_1/10, action_validate_exception,
Expand Down Expand Up @@ -38,4 +39,26 @@ namespace eosio { namespace chain {
"max authority depth should be at least 1" );
}

void chain_config_v1::validate() const {
chain_config_v0::validate();
EOS_ASSERT( max_action_return_value_size <= MAX_SIZE_OF_BYTE_ARRAYS, action_validate_exception,
"max action return value size should be less than MAX_SIZE_OF_BYTE_ARRAYS" );
}

bool config_entry_validator::operator()(uint32_t id) const {
bool allowed = true;
switch(id){
case chain_config_v1::max_action_return_value_size_id:
{
allowed = control.is_builtin_activated(builtin_protocol_feature_t::action_return_value);
if (!allowed){
wlog("action_return_value protocol feature is not active, max_action_return_value_size config is not allowed");
}
}
break;
}

return allowed;
}

} } // namespace eosio::chain
38 changes: 19 additions & 19 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ struct building_block {
size_t _num_new_protocol_features_that_have_activated = 0;
vector<transaction_metadata_ptr> _pending_trx_metas;
vector<transaction_receipt> _pending_trx_receipts;
vector<action_receipt> _actions;
vector<digest_type> _action_receipt_digests;
optional<checksum256_type> _transaction_mroot;
};

Expand Down Expand Up @@ -328,6 +328,7 @@ struct controller_impl {
set_activation_handler<builtin_protocol_feature_t::get_sender>();
set_activation_handler<builtin_protocol_feature_t::webauthn_key>();
set_activation_handler<builtin_protocol_feature_t::wtmsig_block_signatures>();
set_activation_handler<builtin_protocol_feature_t::action_return_value>();
set_activation_handler<builtin_protocol_feature_t::configurable_wasm_limits>();

self.irreversible_block.connect([this](const block_state_ptr& bsp) {
Expand Down Expand Up @@ -1120,17 +1121,17 @@ struct controller_impl {
auto& bb = pending->_block_stage.get<building_block>();
auto orig_block_transactions_size = bb._pending_trx_receipts.size();
auto orig_state_transactions_size = bb._pending_trx_metas.size();
auto orig_state_actions_size = bb._actions.size();
auto orig_action_receipt_digests_size = bb._action_receipt_digests.size();

std::function<void()> callback = [this,
orig_block_transactions_size,
orig_state_transactions_size,
orig_state_actions_size]()
orig_action_receipt_digests_size]()
{
auto& bb = pending->_block_stage.get<building_block>();
bb._pending_trx_receipts.resize(orig_block_transactions_size);
bb._pending_trx_metas.resize(orig_state_transactions_size);
bb._actions.resize(orig_state_actions_size);
bb._action_receipt_digests.resize(orig_action_receipt_digests_size);
};

return fc::make_scoped_exit( std::move(callback) );
Expand Down Expand Up @@ -1174,7 +1175,8 @@ struct controller_impl {
auto restore = make_block_restore_point();
trace->receipt = push_receipt( gtrx.trx_id, transaction_receipt::soft_fail,
trx_context.billed_cpu_time_us, trace->net_usage );
fc::move_append( pending->_block_stage.get<building_block>()._actions, move(trx_context.executed) );
fc::move_append( pending->_block_stage.get<building_block>()._action_receipt_digests,
std::move(trx_context.executed_action_receipt_digests) );

trx_context.squash();
restore.cancel();
Expand Down Expand Up @@ -1317,7 +1319,8 @@ struct controller_impl {
trx_context.billed_cpu_time_us,
trace->net_usage );

fc::move_append( pending->_block_stage.get<building_block>()._actions, move(trx_context.executed) );
fc::move_append( pending->_block_stage.get<building_block>()._action_receipt_digests,
std::move(trx_context.executed_action_receipt_digests) );

trace->account_ram_delta = account_delta( gtrx.payer, trx_removal_ram_delta );

Expand Down Expand Up @@ -1509,7 +1512,8 @@ struct controller_impl {
trace->receipt = r;
}

fc::move_append(pending->_block_stage.get<building_block>()._actions, move(trx_context.executed));
fc::move_append( pending->_block_stage.get<building_block>()._action_receipt_digests,
std::move(trx_context.executed_action_receipt_digests) );

// call the accept signal but only once for this transaction
if (!trx->accepted) {
Expand Down Expand Up @@ -1724,7 +1728,7 @@ struct controller_impl {
// Create (unsigned) block:
auto block_ptr = std::make_shared<signed_block>( pbhs.make_block_header(
bb._transaction_mroot ? *bb._transaction_mroot : calculate_trx_merkle( bb._pending_trx_receipts ),
calculate_action_merkle(),
merkle( std::move( pending->_block_stage.get<building_block>()._action_receipt_digests ) ),
bb._new_pending_producer_schedule,
std::move( bb._new_protocol_feature_activations ),
protocol_features.get_protocol_feature_set()
Expand Down Expand Up @@ -2196,16 +2200,6 @@ struct controller_impl {
return applied_trxs;
}

checksum256_type calculate_action_merkle() {
vector<digest_type> action_digests;
const auto& actions = pending->_block_stage.get<building_block>()._actions;
action_digests.reserve( actions.size() );
for( const auto& a : actions )
action_digests.emplace_back( a.digest() );

return merkle( move(action_digests) );
}

static checksum256_type calculate_trx_merkle( const vector<transaction_receipt>& trxs ) {
vector<digest_type> trx_digests;
trx_digests.reserve( trxs.size() );
Expand Down Expand Up @@ -3410,6 +3404,13 @@ void controller_impl::on_activation<builtin_protocol_feature_t::wtmsig_block_sig
} );
}

template<>
void controller_impl::on_activation<builtin_protocol_feature_t::action_return_value>() {
db.modify( db.get<protocol_state_object>(), [&]( auto& ps ) {
add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "set_action_return_value" );
} );
}

template<>
void controller_impl::on_activation<builtin_protocol_feature_t::configurable_wasm_limits>() {
db.modify( db.get<protocol_state_object>(), [&]( auto& ps ) {
Expand All @@ -3418,7 +3419,6 @@ void controller_impl::on_activation<builtin_protocol_feature_t::configurable_was
} );
}


/// End of protocol feature activation handlers

} } /// eosio::chain
32 changes: 22 additions & 10 deletions libraries/chain/include/eosio/chain/abi_def.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ struct variant_def {
vector<type_name> types;
};

struct action_result_def {
action_result_def() = default;
action_result_def(const action_name& name, const type_name& result_type)
:name(name), result_type(result_type)
{}

action_name name;
type_name result_type;
};

template<typename T>
struct may_not_exist {
T value{};
Expand All @@ -111,15 +121,16 @@ struct abi_def {
,error_messages(error_msgs)
{}

string version = "";
vector<type_def> types;
vector<struct_def> structs;
vector<action_def> actions;
vector<table_def> tables;
vector<clause_pair> ricardian_clauses;
vector<error_message> error_messages;
extensions_type abi_extensions;
may_not_exist<vector<variant_def>> variants;
string version = "";
vector<type_def> types;
vector<struct_def> structs;
vector<action_def> actions;
vector<table_def> tables;
vector<clause_pair> ricardian_clauses;
vector<error_message> error_messages;
extensions_type abi_extensions;
may_not_exist<vector<variant_def>> variants;
may_not_exist<vector<action_result_def>> action_results;
};

abi_def eosio_contract_abi(const abi_def& eosio_system_abi);
Expand Down Expand Up @@ -164,5 +175,6 @@ FC_REFLECT( eosio::chain::table_def , (name)(index_type)(
FC_REFLECT( eosio::chain::clause_pair , (id)(body) )
FC_REFLECT( eosio::chain::error_message , (error_code)(error_msg) )
FC_REFLECT( eosio::chain::variant_def , (name)(types) )
FC_REFLECT( eosio::chain::action_result_def , (name)(result_type) )
FC_REFLECT( eosio::chain::abi_def , (version)(types)(structs)(actions)(tables)
(ricardian_clauses)(error_messages)(abi_extensions)(variants) )
(ricardian_clauses)(error_messages)(abi_extensions)(variants)(action_results) )
51 changes: 51 additions & 0 deletions libraries/chain/include/eosio/chain/abi_serializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ struct abi_serializer {

type_name get_action_type(name action)const;
type_name get_table_type(name action)const;
type_name get_action_result_type(name action_result)const;

optional<string> get_error_message( uint64_t error_code )const;

Expand Down Expand Up @@ -139,6 +140,7 @@ struct abi_serializer {
map<name,type_name> tables;
map<uint64_t, string> error_messages;
map<type_name, variant_def, std::less<>> variants;
map<name,type_name> action_results;

map<type_name, pair<unpack_function, pack_function>, std::less<>> built_in_types;
void configure_built_in_types();
Expand Down Expand Up @@ -443,6 +445,55 @@ namespace impl {
out(name, std::move(mvo));
}

/**
* overload of to_variant_object for action_trace
*
* This matches the FC_REFLECT for this type, but this is provided to extract the contents of action_trace.return_value
* @tparam Resolver
* @param action_trace
* @param resolver
* @return
*/
template<typename Resolver>
static void add( mutable_variant_object& out, const char* name, const action_trace& act_trace, Resolver resolver, abi_traverse_context& ctx )
{
static_assert(fc::reflector<action_trace>::total_member_count == 17);
auto h = ctx.enter_scope();
mutable_variant_object mvo;

mvo("action_ordinal", act_trace.action_ordinal);
mvo("creator_action_ordinal", act_trace.creator_action_ordinal);
mvo("closest_unnotified_ancestor_action_ordinal", act_trace.closest_unnotified_ancestor_action_ordinal);
mvo("receipt", act_trace.receipt);
mvo("receiver", act_trace.receiver);
add(mvo, "act", act_trace.act, resolver, ctx);
mvo("context_free", act_trace.context_free);
mvo("elapsed", act_trace.elapsed);
mvo("console", act_trace.console);
mvo("trx_id", act_trace.trx_id);
mvo("block_num", act_trace.block_num);
mvo("block_time", act_trace.block_time);
mvo("producer_block_id", act_trace.producer_block_id);
mvo("account_ram_deltas", act_trace.account_ram_deltas);
mvo("except", act_trace.except);
mvo("error_code", act_trace.error_code);

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);
if (!type.empty()) {
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 ));
}
}
} catch(...) {}
out(name, std::move(mvo));
}

/**
* overload of to_variant_object for packed_transaction
*
Expand Down
Loading