Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
Merge pull request #7 from eosnetworkfoundation/backport-retval
Browse files Browse the repository at this point in the history
backport 2.1 ACTION_RETURN_VALUE
  • Loading branch information
tbfleming authored Jan 17, 2022
2 parents 3e102d5 + 768d61f commit 8748f59
Show file tree
Hide file tree
Showing 37 changed files with 769 additions and 67 deletions.
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

0 comments on commit 8748f59

Please sign in to comment.