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

Trace API plugin - Add support for action return values #9547

Merged
merged 3 commits into from
Oct 29, 2020
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
21 changes: 16 additions & 5 deletions plugins/trace_api_plugin/abi_data_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ namespace eosio::trace_api {
std::make_shared<chain::abi_serializer>(abi, chain::abi_serializer::create_yield_function(fc::microseconds::maximum())));
}

fc::variant abi_data_handler::process_data(const action_trace_v0& action, const yield_function& yield ) {
if (abi_serializer_by_account.count(action.account) > 0) {
const auto& serializer_p = abi_serializer_by_account.at(action.account);
auto type_name = serializer_p->get_action_type(action.action);
std::tuple<fc::variant, std::optional<fc::variant>> abi_data_handler::serialize_to_variant(const std::variant<action_trace_v0, action_trace_v1> & action, const yield_function& yield ) {
auto account = std::visit([](auto &&action) -> auto { return action.account; }, action);

if (abi_serializer_by_account.count(account) > 0) {
const auto &serializer_p = abi_serializer_by_account.at(account);
auto action_name = std::visit([](auto &&action) -> auto { return action.action; }, action);
auto type_name = serializer_p->get_action_type(action_name);

if (!type_name.empty()) {
try {
Expand All @@ -22,7 +25,15 @@ namespace eosio::trace_api {
EOS_ASSERT( recursion_depth < chain::abi_serializer::max_recursion_depth, chain::abi_recursion_depth_exception,
"exceeded max_recursion_depth ${r} ", ("r", chain::abi_serializer::max_recursion_depth) );
};
return serializer_p->binary_to_variant(type_name, action.data, abi_yield);
return std::visit([&](auto &&action) -> std::tuple<fc::variant, std::optional<fc::variant>> {
using T = std::decay_t<decltype(action)>;
if constexpr (std::is_same_v<T, action_trace_v0>) {
return {serializer_p->binary_to_variant(type_name, action.data, abi_yield), {}};
} else {
return {serializer_p->binary_to_variant(type_name, action.data, abi_yield),
{serializer_p->binary_to_variant(type_name, action.return_value, abi_yield)}};
}
}, action);
} catch (...) {
except_handler(MAKE_EXCEPTION_WITH_CONTEXT(std::current_exception()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ namespace eosio {
void add_abi( const chain::name& name, const chain::abi_def& abi );

/**
* Given an action trace, produce a variant that represents the `data` field in the trace
* Given an action trace, produce a tuple representing the `data` and `return_value` fields in the trace
*
* @param action - trace of the action including metadata necessary for finding the ABI
* @param yield - a yield function to allow cooperation during long running tasks
* @return variant representing the `data` field of the action interpreted by known ABIs OR an empty variant
* @return tuple with the first element is a variant representing the `data` field of the action interpreted by known ABIs OR an empty variant, the second element representing the `return_value` field of the trace.
*/
fc::variant process_data( const action_trace_v0& action, const yield_function& yield );
std::tuple<fc::variant, std::optional<fc::variant>> serialize_to_variant(const std::variant<action_trace_v0, action_trace_v1> & action, const yield_function& yield );

/**
* Utility class that allows mulitple request_handlers to share the same abi_data_handler
Expand All @@ -48,8 +48,8 @@ namespace eosio {
:handler(handler)
{}

fc::variant process_data( const action_trace_v0& action, const yield_function& yield ) {
return handler->process_data(action, yield);
std::tuple<fc::variant, std::optional<fc::variant>> serialize_to_variant( const std::variant<action_trace_v0, action_trace_v1> & action, const yield_function& yield ) {
return handler->serialize_to_variant(action, yield);
}

std::shared_ptr<abi_data_handler> handler;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,14 @@ class chain_extraction_impl_type {

void store_block_trace( const chain::block_state_ptr& block_state ) {
try {
block_trace_v1 bt = create_block_trace_v1( block_state );
using transaction_trace_t = transaction_trace_v2;

std::vector<transaction_trace_v1>& traces = bt.transactions_v1;
auto bt = create_block_trace( block_state );

std::vector<transaction_trace_t>& traces = std::get<std::vector<transaction_trace_t>>(bt.transactions);
traces.reserve( block_state->block->transactions.size() + 1 );
if( onblock_trace )
traces.emplace_back( to_transaction_trace_v1( *onblock_trace ));
traces.emplace_back( to_transaction_trace<transaction_trace_t>( *onblock_trace ));
for( const auto& r : block_state->block->transactions ) {
transaction_id_type id;
if( std::holds_alternative<transaction_id_type>(r.trx)) {
Expand All @@ -96,7 +98,7 @@ class chain_extraction_impl_type {
}
const auto it = cached_traces.find( id );
if( it != cached_traces.end() ) {
traces.emplace_back( to_transaction_trace_v1( it->second ));
traces.emplace_back( to_transaction_trace<transaction_trace_t>( it->second ));
}
}
clear_caches();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ namespace eosio { namespace trace_api {

using data_log_entry = std::variant<
block_trace_v0,
block_trace_v1
block_trace_v1,
block_trace_v2
>;

}}
90 changes: 37 additions & 53 deletions plugins/trace_api_plugin/include/eosio/trace_api/extract_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@

namespace eosio { namespace trace_api {

/// Used by to_transaction_trace_v0 for creation of action_trace_v0
inline action_trace_v0 to_action_trace_v0( const chain::action_trace& at ) {
action_trace_v0 r;
/// Used by to_transaction_trace for creation of action_trace_v0 or action_trace_v1
template<typename ActionTrace>
inline ActionTrace to_action_trace( const chain::action_trace& at ) {
ActionTrace r;
r.receiver = at.receiver;
r.account = at.act.account;
r.action = at.act.name;
r.data = at.act.data;
if constexpr(std::is_same_v<ActionTrace, action_trace_v1>){
r.return_value = at.return_value;
}
if( at.receipt ) {
r.global_sequence = at.receipt->global_sequence;
}
Expand All @@ -22,70 +26,50 @@ inline action_trace_v0 to_action_trace_v0( const chain::action_trace& at ) {
return r;
}

/// @return transaction_trace_v0 with populated action_trace_v0
inline transaction_trace_v0 to_transaction_trace_v0( const chain::transaction_trace_ptr& t ) {
transaction_trace_v0 r;
if( !t->failed_dtrx_trace ) {
r.id = t->id;
template<typename TransactionTrace>
inline TransactionTrace to_transaction_trace( const cache_trace& t ) {
TransactionTrace r;
if( !t.trace->failed_dtrx_trace ) {
r.id = t.trace->id;
} else {
r.id = t->failed_dtrx_trace->id; // report the failed trx id since that is the id known to user
r.id = t.trace->failed_dtrx_trace->id; // report the failed trx id since that is the id known to user
}

if constexpr(std::is_same_v<TransactionTrace, transaction_trace_v1> || std::is_same_v<TransactionTrace, transaction_trace_v2>){
if (t.trace->receipt) {
r.status = t.trace->receipt->status;
r.cpu_usage_us = t.trace->receipt->cpu_usage_us;
r.net_usage_words = t.trace->receipt->net_usage_words;
}
auto sigs = t.trx->get_signatures();
if( sigs ) r.signatures = *sigs;
r.trx_header = static_cast<const chain::transaction_header&>( t.trx->get_transaction() );
}
r.actions.reserve( t->action_traces.size());
for( const auto& at : t->action_traces ) {

using action_trace_t = std::conditional_t<std::is_same_v<TransactionTrace, transaction_trace_v2>, action_trace_v1, action_trace_v0>;

r.actions = std::vector<action_trace_t>();
std::get<std::vector<action_trace_t>>(r.actions).reserve( t.trace->action_traces.size());
for( const auto& at : t.trace->action_traces ) {
if( !at.context_free ) { // not including CFA at this time
r.actions.emplace_back( to_action_trace_v0( at ));
std::get<std::vector<action_trace_t>>(r.actions).emplace_back( to_action_trace<action_trace_t>(at) );
}
}
return r;
}

inline transaction_trace_v1 to_transaction_trace_v1( const cache_trace& t ) {
transaction_trace_v1 r;
if( !t.trace->failed_dtrx_trace ) {
r.id = t.trace->id;
} else {
r.id = t.trace->failed_dtrx_trace->id; // report the failed trx id since that is the id known to user
}
if (t.trace->receipt) {
r.status = t.trace->receipt->status;
r.cpu_usage_us = t.trace->receipt->cpu_usage_us;
r.net_usage_words = t.trace->receipt->net_usage_words;
}
auto sigs = t.trx->get_signatures();
if( sigs ) r.signatures = *sigs;
r.trx_header = static_cast<const chain::transaction_header&>( t.trx->get_transaction() );
r.actions.reserve( t.trace->action_traces.size());
for( const auto& at : t.trace->action_traces ) {
if( !at.context_free ) { // not including CFA at this time
r.actions.emplace_back( to_action_trace_v0( at ));
}
}
return r;
return r;
}

/// @return block_trace_v0 without any transaction_trace_v0
inline block_trace_v0 create_block_trace_v0( const chain::block_state_ptr& bsp ) {
block_trace_v0 r;
inline block_trace_v2 create_block_trace( const chain::block_state_ptr& bsp ) {
block_trace_v2 r;
r.id = bsp->id;
r.number = bsp->block_num;
r.previous_id = bsp->block->previous;
r.timestamp = bsp->block->timestamp;
r.producer = bsp->block->producer;
r.schedule_version = bsp->block->schedule_version;
r.transaction_mroot = bsp->block->transaction_mroot;
r.action_mroot = bsp->block->action_mroot;
return r;
}

/// @return block_trace_v1 without any transaction_trace_v1
inline block_trace_v1 create_block_trace_v1( const chain::block_state_ptr& bsp ) {
block_trace_v1 r;
r.id = bsp->id;
r.number = bsp->block_num;
r.previous_id = bsp->block->previous;
r.timestamp = bsp->block->timestamp;
r.producer = bsp->block->producer;
r.schedule_version = bsp->block->schedule_version;
r.transaction_mroot = bsp->block->transaction_mroot;
r.action_mroot = bsp->block->action_mroot;
return r;
}

} }
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include <eosio/trace_api/common.hpp>

namespace eosio::trace_api {
using data_handler_function = std::function<fc::variant(const action_trace_v0&, const yield_function&)>;
using data_handler_function = std::function<std::tuple<fc::variant, std::optional<fc::variant>>( const std::variant<action_trace_v0, action_trace_v1> & action_trace_t, const yield_function&)>;

namespace detail {
class response_formatter {
Expand Down Expand Up @@ -43,8 +43,10 @@ namespace eosio::trace_api {

yield();

auto data_handler = [this](const action_trace_v0& action, const yield_function& yield) -> fc::variant {
return data_handler_provider.process_data(action, yield);
auto data_handler = [this](const auto& action, const yield_function& yield) -> std::tuple<fc::variant, std::optional<fc::variant>> {
return std::visit([&](const auto& action_trace_t) {
return data_handler_provider.serialize_to_variant(action_trace_t, yield);
}, action);
};

return detail::response_formatter::process_block(std::get<0>(*data), std::get<1>(*data), data_handler, yield);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,8 @@ namespace eosio::trace_api {
store_provider(const boost::filesystem::path& slice_dir, uint32_t stride_width, std::optional<uint32_t> minimum_irreversible_history_blocks,
std::optional<uint32_t> minimum_uncompressed_irreversible_history_blocks, size_t compression_seek_point_stride);

void append(const block_trace_v1& bt);
template<typename BlockTrace>
void append(const BlockTrace& bt);
void append_lib(uint32_t lib);

/**
Expand Down
31 changes: 31 additions & 0 deletions plugins/trace_api_plugin/include/eosio/trace_api/trace.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ namespace eosio { namespace trace_api {
chain::bytes data = {};
};

struct action_trace_v1 : public action_trace_v0 {
chain::bytes return_value = {};
};

struct transaction_trace_v0 {
using status_type = chain::transaction_receipt_header::status_enum;

Expand All @@ -36,6 +40,18 @@ namespace eosio { namespace trace_api {
chain::transaction_header trx_header = {};
};

struct transaction_trace_v2 {
using status_type = chain::transaction_receipt_header::status_enum;

chain::transaction_id_type id = {};
std::variant<std::vector<action_trace_v1>> actions = {};
fc::enum_type<uint8_t,status_type> status = {};
uint32_t cpu_usage_us = 0;
fc::unsigned_int net_usage_words;
std::vector<chain::signature_type> signatures = {};
chain::transaction_header trx_header = {};
};

struct block_trace_v0 {
chain::block_id_type id = {};
uint32_t number = {};
Expand All @@ -52,6 +68,18 @@ namespace eosio { namespace trace_api {
std::vector<transaction_trace_v1> transactions_v1 = {};
};

struct block_trace_v2 {
chain::block_id_type id = {};
uint32_t number = {};
chain::block_id_type previous_id = {};
chain::block_timestamp_type timestamp = chain::block_timestamp_type(0);
chain::name producer = {};
chain::checksum256_type transaction_mroot = {};
chain::checksum256_type action_mroot = {};
uint32_t schedule_version = {};
std::variant<std::vector<transaction_trace_v2>> transactions = {};
};

struct cache_trace {
chain::transaction_trace_ptr trace;
chain::packed_transaction_ptr trx;
Expand All @@ -61,7 +89,10 @@ namespace eosio { namespace trace_api {

FC_REFLECT(eosio::trace_api::authorization_trace_v0, (account)(permission))
FC_REFLECT(eosio::trace_api::action_trace_v0, (global_sequence)(receiver)(account)(action)(authorization)(data))
FC_REFLECT_DERIVED(eosio::trace_api::action_trace_v1, (eosio::trace_api::action_trace_v0),(return_value))
FC_REFLECT(eosio::trace_api::transaction_trace_v0, (id)(actions))
FC_REFLECT_DERIVED(eosio::trace_api::transaction_trace_v1, (eosio::trace_api::transaction_trace_v0), (status)(cpu_usage_us)(net_usage_words)(signatures)(trx_header))
FC_REFLECT(eosio::trace_api::transaction_trace_v2, (id)(actions)(status)(cpu_usage_us)(net_usage_words)(signatures)(trx_header))
FC_REFLECT(eosio::trace_api::block_trace_v0, (id)(number)(previous_id)(timestamp)(producer)(transactions))
FC_REFLECT_DERIVED(eosio::trace_api::block_trace_v1, (eosio::trace_api::block_trace_v0), (transaction_mroot)(action_mroot)(schedule_version)(transactions_v1))
FC_REFLECT(eosio::trace_api::block_trace_v2, (id)(number)(previous_id)(timestamp)(producer)(transaction_mroot)(action_mroot)(schedule_version)(transactions))
Loading