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

Implement support for read-only contract queries in nodeos #10189

Merged
merged 30 commits into from
May 25, 2021
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2795e6d
Implement support for read-only contract queries in nodeos
jgiszczak Mar 26, 2021
1942d92
Add resulting URL for read-only queries into cleos
nickjjzhao Mar 2, 2021
ac252a7
Add a transaction in cleos for contract query
nickjjzhao Mar 22, 2021
3ea0af1
Print contract query output as JSON
nickjjzhao Mar 24, 2021
1fdde7b
Make new cleos command contract_query as a subcommand of get
nickjjzhao Mar 24, 2021
008b2a3
Merge pull request #10221 from EOSIO/read_only_query_EPE-747
nickjjzhao Apr 1, 2021
08f3d71
Follow through on new read_only flag in producer plugin
jgiszczak Apr 1, 2021
a18ec6c
Merge branch 'read_only_query_EPE-746' of github.com:/EOSIO/eos into …
jgiszczak Apr 1, 2021
a9b6faf
Fix a bug that fails to invoke new RPC API get_contract_query
nickjjzhao Apr 2, 2021
1623b47
Merge pull request #10223 from EOSIO/read_only_query_EPE-747
nickjjzhao Apr 2, 2021
1aa6b10
Use updated structure of get_contract_query_params in cleos
nickjjzhao Apr 2, 2021
7cf0077
Merge pull request #10225 from EOSIO/read_only_query_EPE-747
nickjjzhao Apr 2, 2021
aafaec5
Use read_only flag in producer plugin initialize
jgiszczak Apr 9, 2021
9bd1d7f
Add read-only query integration test
jgiszczak May 7, 2021
836a641
Merge develop
jgiszczak May 10, 2021
2054d61
Add read-only query integration test contracts
jgiszczak May 12, 2021
00cb72e
Merge branch 'develop' into read_only_query_EPE-746
jgiszczak May 13, 2021
d556965
Remove unused code.
jgiszczak May 18, 2021
91ff0c4
Remove unused code.
jgiszczak May 18, 2021
14e2f49
Minor optimizations.
jgiszczak May 19, 2021
630b0c7
Repair bad merge, restoring subjective billing and failure tracking.
jgiszczak May 19, 2021
fb19e7e
Eliminate useless assert on rarely used method.
jgiszczak May 20, 2021
d02a7ea
Rename get_contract_query to push_ro_transaction.
jgiszczak May 20, 2021
cf34342
Add option to return failure traces.
jgiszczak May 20, 2021
f4d1714
Add read-only query integration test to test suite.
jgiszczak May 20, 2021
8feac98
Change cleos command get contract_query to push ro_transaction
nickjjzhao May 21, 2021
4994b2f
Add two flags for cleos command push ro_transaction
nickjjzhao May 22, 2021
2627125
Remove cleos command push ro_transaction and add two new flags for co…
nickjjzhao May 23, 2021
df09841
Don't return failure traces by default.
jgiszczak May 24, 2021
822d90f
Update integration test to push transaction API.
jgiszczak May 24, 2021
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
10 changes: 5 additions & 5 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1275,8 +1275,8 @@ struct controller_impl {
emit(self.applied_transaction, std::tie(trace, trx->packed_trx()));


if ( read_mode != db_read_mode::SPECULATIVE && pending->_block_status == controller::block_status::incomplete ) {
//this may happen automatically in destructor, but I prefere make it more explicit
if ( (read_mode != db_read_mode::SPECULATIVE && pending->_block_status == controller::block_status::incomplete) || trx->read_only ) {
//this may happen automatically in destructor, but I prefer to make it more explicit
trx_context.undo();
} else {
restore.cancel();
Expand Down Expand Up @@ -1696,7 +1696,7 @@ struct controller_impl {
} else {
packed_transaction_ptr ptrx( b, &pt ); // alias signed_block_ptr
auto fut = transaction_metadata::start_recover_keys(
std::move( ptrx ), thread_pool.get_executor(), chain_id, microseconds::maximum() );
std::move( ptrx ), thread_pool.get_executor(), chain_id, microseconds::maximum(), transaction_metadata::trx_type::input );
trx_metas.emplace_back( transaction_metadata_ptr{}, std::move( fut ) );
}
}
Expand Down Expand Up @@ -2735,8 +2735,8 @@ std::optional<block_id_type> controller::pending_producer_block_id()const {
}

const deque<transaction_receipt>& controller::get_pending_trx_receipts()const {
EOS_ASSERT( my->pending, block_validate_exception, "no pending block" );
return my->pending->get_trx_receipts();
static deque<transaction_receipt> empty;
return my->pending ? my->pending->get_trx_receipts() : empty;
}

uint32_t controller::last_irreversible_block_num() 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 @@ -373,7 +373,7 @@ namespace eosio { namespace chain {
}

template<typename T>
fc::variant to_variant_with_abi( const T& obj, const abi_serializer::yield_function_t& yield ) {
fc::variant to_variant_with_abi( const T& obj, const abi_serializer::yield_function_t& yield ) const {
fc::variant pretty_output;
abi_serializer::to_variant( obj, pretty_output,
[&]( account_name n ){ return get_abi_serializer( n, yield ); }, yield );
Expand Down
13 changes: 8 additions & 5 deletions libraries/chain/include/eosio/chain/transaction_metadata.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ class transaction_metadata {
enum class trx_type {
input,
implicit,
scheduled
scheduled,
read_only
};

private:
Expand All @@ -34,6 +35,7 @@ class transaction_metadata {
public:
const bool implicit;
const bool scheduled;
const bool read_only;
bool accepted = false; // not thread safe
uint32_t billed_cpu_time_us = 0; // not thread safe

Expand All @@ -53,12 +55,13 @@ class transaction_metadata {
// creation of tranaction_metadata restricted to start_recover_keys and create_no_recover_keys below, public for make_shared
explicit transaction_metadata( const private_type& pt, packed_transaction_ptr ptrx,
fc::microseconds sig_cpu_usage, flat_set<public_key_type> recovered_pub_keys,
bool _implicit = false, bool _scheduled = false)
bool _implicit = false, bool _scheduled = false, bool _read_only = false)
: _packed_trx( std::move( ptrx ) )
, _sig_cpu_usage( sig_cpu_usage )
, _recovered_pub_keys( std::move( recovered_pub_keys ) )
, implicit( _implicit )
, scheduled( _scheduled ) {
, scheduled( _scheduled )
, read_only( _read_only ) {
}

transaction_metadata() = delete;
Expand All @@ -79,13 +82,13 @@ class transaction_metadata {
static recover_keys_future
start_recover_keys( packed_transaction_ptr trx, boost::asio::io_context& thread_pool,
const chain_id_type& chain_id, fc::microseconds time_limit,
uint32_t max_variable_sig_size = UINT32_MAX );
trx_type t, uint32_t max_variable_sig_size = UINT32_MAX );

/// @returns constructed transaction_metadata with no key recovery (sig_cpu_usage=0, recovered_pub_keys=empty)
static transaction_metadata_ptr
create_no_recover_keys( packed_transaction_ptr trx, trx_type t ) {
return std::make_shared<transaction_metadata>( private_type(), std::move(trx),
fc::microseconds(), flat_set<public_key_type>(), t == trx_type::implicit, t == trx_type::scheduled );
fc::microseconds(), flat_set<public_key_type>(), t == trx_type::implicit, t == trx_type::scheduled, t == trx_type::read_only );
}

};
Expand Down
6 changes: 4 additions & 2 deletions libraries/chain/transaction_metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ recover_keys_future transaction_metadata::start_recover_keys( packed_transaction
boost::asio::io_context& thread_pool,
const chain_id_type& chain_id,
fc::microseconds time_limit,
trx_type t,
uint32_t max_variable_sig_size )
{
return async_thread_pool( thread_pool, [trx{std::move(trx)}, chain_id, time_limit, max_variable_sig_size]() mutable {
return async_thread_pool( thread_pool, [trx{std::move(trx)}, chain_id, time_limit, t, max_variable_sig_size]() mutable {
fc::time_point deadline = time_limit == fc::microseconds::maximum() ?
fc::time_point::maximum() : fc::time_point::now() + time_limit;
const vector<signature_type>& sigs = check_variable_sig_size( trx, max_variable_sig_size );
Expand All @@ -20,7 +21,8 @@ recover_keys_future transaction_metadata::start_recover_keys( packed_transaction
const bool allow_duplicate_keys = false;
fc::microseconds cpu_usage =
trx->get_transaction().get_signature_keys(sigs, chain_id, deadline, *context_free_data, recovered_pub_keys, allow_duplicate_keys);
return std::make_shared<transaction_metadata>( private_type(), std::move( trx ), cpu_usage, std::move( recovered_pub_keys ) );
return std::make_shared<transaction_metadata>( private_type(), std::move( trx ), cpu_usage, std::move( recovered_pub_keys ),
t == trx_type::implicit, t == trx_type::scheduled, t == trx_type::read_only);
}
);
}
Expand Down
4 changes: 2 additions & 2 deletions libraries/testing/tester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ namespace eosio { namespace testing {
auto time_limit = deadline == fc::time_point::maximum() ?
fc::microseconds::maximum() :
fc::microseconds( deadline - fc::time_point::now() );
auto fut = transaction_metadata::start_recover_keys( ptrx, control->get_thread_pool(), control->get_chain_id(), time_limit );
auto fut = transaction_metadata::start_recover_keys( ptrx, control->get_thread_pool(), control->get_chain_id(), time_limit, transaction_metadata::trx_type::input );
auto r = control->push_transaction( fut.get(), deadline, billed_cpu_time_us, billed_cpu_time_us > 0, 0 );
if( r->except_ptr ) std::rethrow_exception( r->except_ptr );
if( r->except ) throw *r->except;
Expand All @@ -600,7 +600,7 @@ namespace eosio { namespace testing {
fc::microseconds::maximum() :
fc::microseconds( deadline - fc::time_point::now() );
auto ptrx = std::make_shared<packed_transaction>( signed_transaction(trx), true, c );
auto fut = transaction_metadata::start_recover_keys( std::move( ptrx ), control->get_thread_pool(), control->get_chain_id(), time_limit );
auto fut = transaction_metadata::start_recover_keys( std::move( ptrx ), control->get_thread_pool(), control->get_chain_id(), time_limit, transaction_metadata::trx_type::input );
auto r = control->push_transaction( fut.get(), deadline, billed_cpu_time_us, billed_cpu_time_us > 0, 0 );
if (no_throw) return r;
if( r->except_ptr ) std::rethrow_exception( r->except_ptr );
Expand Down
1 change: 1 addition & 0 deletions plugins/chain_api_plugin/chain_api_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ void chain_api_plugin::plugin_startup() {
CHAIN_RO_CALL(abi_bin_to_json, 200, http_params_types::params_required),
CHAIN_RO_CALL(get_required_keys, 200, http_params_types::params_required),
CHAIN_RO_CALL(get_transaction_id, 200, http_params_types::params_required),
CHAIN_RO_CALL_ASYNC(push_ro_transaction, chain_apis::read_only::push_ro_transaction_results, 200, http_params_types::params_required),
CHAIN_RW_CALL_ASYNC(push_block, chain_apis::read_write::push_block_results, 202, http_params_types::params_required),
CHAIN_RW_CALL_ASYNC(push_transaction, chain_apis::read_write::push_transaction_results, 202, http_params_types::params_required),
CHAIN_RW_CALL_ASYNC(push_transactions, chain_apis::read_write::push_transactions_results, 202, http_params_types::params_required),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ namespace eosio { namespace chain { namespace plugin_interface {
}

namespace methods {
// synchronously push a block/trx to a single provider
// push a block/trx to a single provider
using block_sync = method_decl<chain_plugin_interface, bool(const signed_block_ptr&, const std::optional<block_id_type>&), first_provider_policy>;
using blockvault_sync = method_decl<chain_plugin_interface, bool(const signed_block_ptr&, bool), first_provider_policy>;
using transaction_async = method_decl<chain_plugin_interface, void(const packed_transaction_ptr&, bool, next_function<transaction_trace_ptr>), first_provider_policy>;
using transaction_async = method_decl<chain_plugin_interface, void(const packed_transaction_ptr&, bool, bool, bool, next_function<transaction_trace_ptr>), first_provider_policy>;
}
}

Expand Down
75 changes: 72 additions & 3 deletions plugins/chain_plugin/chain_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1380,7 +1380,7 @@ bool chain_plugin::accept_block(const signed_block_ptr& block, const block_id_ty
}

void chain_plugin::accept_transaction(const chain::packed_transaction_ptr& trx, next_function<chain::transaction_trace_ptr> next) {
my->incoming_transaction_async_method(trx, false, std::move(next));
my->incoming_transaction_async_method(trx, false, false, false, std::move(next));
}

controller& chain_plugin::chain() { return *my->chain; }
Expand Down Expand Up @@ -2768,7 +2768,7 @@ void read_write::push_transaction(const read_write::push_transaction_params& par
fc_add_tag(trx_span, "trx_id", input_trx->id());
fc_add_tag(trx_span, "method", "push_transaction");

app().get_method<incoming::methods::transaction_async>()(input_trx, true,
app().get_method<incoming::methods::transaction_async>()(input_trx, true, false, false,
[this, token=trx_trace.get_token(), input_trx, next]
(const std::variant<fc::exception_ptr, transaction_trace_ptr>& result) -> void {

Expand Down Expand Up @@ -2911,7 +2911,7 @@ void read_write::send_transaction(const read_write::send_transaction_params& par
fc_add_tag(trx_span, "trx_id", input_trx->id());
fc_add_tag(trx_span, "method", "send_transaction");

app().get_method<incoming::methods::transaction_async>()(input_trx, true,
app().get_method<incoming::methods::transaction_async>()(input_trx, true, false, false,
[this, token=trx_trace.get_token(), input_trx, next]
(const std::variant<fc::exception_ptr, transaction_trace_ptr>& result) -> void {
auto trx_span = fc_create_span_from_token(token, "Processed");
Expand Down Expand Up @@ -3183,6 +3183,75 @@ read_only::get_transaction_id_result read_only::get_transaction_id( const read_o
return params.id();
}

void read_only::push_ro_transaction(const read_only::push_ro_transaction_params& params, chain::plugin_interface::next_function<read_only::push_ro_transaction_results> next) const {
try {
packed_transaction_v0 input_trx_v0;
auto resolver = make_resolver(db, abi_serializer::create_yield_function( abi_serializer_max_time ));
packed_transaction_ptr input_trx;
try {
abi_serializer::from_variant(params.transaction, input_trx_v0, std::move( resolver ), abi_serializer::create_yield_function( abi_serializer_max_time ));
input_trx = std::make_shared<packed_transaction>( std::move( input_trx_v0 ), true );
} EOS_RETHROW_EXCEPTIONS(chain::packed_transaction_type_exception, "Invalid packed transaction")

auto trx_trace = fc_create_trace_with_id("TransactionReadOnly", input_trx->id());
auto trx_span = fc_create_span(trx_trace, "HTTP Received");
fc_add_tag(trx_span, "trx_id", input_trx->id());
fc_add_tag(trx_span, "method", "send_transaction");

app().get_method<incoming::methods::transaction_async>()(input_trx, true, true, static_cast<const bool>(params.return_failure_traces),
[this, token=trx_trace.get_token(), input_trx, params, next]
(const std::variant<fc::exception_ptr, transaction_trace_ptr>& result) -> void {
heifner marked this conversation as resolved.
Show resolved Hide resolved
auto trx_span = fc_create_span_from_token(token, "Processed");
fc_add_tag(trx_span, "trx_id", input_trx->id());

if (std::holds_alternative<fc::exception_ptr>(result)) {
auto& eptr = std::get<fc::exception_ptr>(result);
fc_add_tag(trx_span, "error", eptr->to_string());
next(eptr);
} else {
auto& trx_trace_ptr = std::get<transaction_trace_ptr>(result);

fc_add_tag(trx_span, "block_num", trx_trace_ptr->block_num);
fc_add_tag(trx_span, "block_time", trx_trace_ptr->block_time.to_time_point());
fc_add_tag(trx_span, "elapsed", trx_trace_ptr->elapsed.count());
if( trx_trace_ptr->receipt ) {
fc_add_tag(trx_span, "status", std::string(trx_trace_ptr->receipt->status));
}
if( trx_trace_ptr->except ) {
fc_add_tag(trx_span, "error", trx_trace_ptr->except->to_string());
}

try {
fc::variant output;
try {
output = db.to_variant_with_abi( *trx_trace_ptr, abi_serializer::create_yield_function( abi_serializer_max_time ) );
} catch( chain::abi_exception& ) {
output = *trx_trace_ptr;
}
const auto& accnt_metadata_obj = db.db().get<account_metadata_object,by_name>( params.account_name );
const auto& receipts = db.get_pending_trx_receipts();
vector<transaction_id_type> pending_transactions;
heifner marked this conversation as resolved.
Show resolved Hide resolved
pending_transactions.reserve(receipts.size());
for( transaction_receipt const& receipt : receipts ) {
if( std::holds_alternative<transaction_id_type>(receipt.trx) ) {
pending_transactions.push_back(std::get<transaction_id_type>(receipt.trx));
}
else {
pending_transactions.push_back(std::get<packed_transaction>(receipt.trx).id());
}
}
next(read_only::push_ro_transaction_results{db.head_block_num(), db.head_block_id(), db.last_irreversible_block_num(), db.last_irreversible_block_id(),
accnt_metadata_obj.code_hash, pending_transactions, output});
} CATCH_AND_CALL(next);
}
});
} catch ( boost::interprocess::bad_alloc& ) {
chain_plugin::handle_db_exhaustion();
} catch ( const std::bad_alloc& ) {
chain_plugin::handle_bad_alloc();
} CATCH_AND_CALL(next);
}

account_query_db::get_accounts_by_authorizers_result read_only::get_accounts_by_authorizers( const account_query_db::get_accounts_by_authorizers_params& args) const
{
EOS_ASSERT(aqdb.has_value(), plugin_config_exception, "Account Queries being accessed when not enabled");
Expand Down
21 changes: 21 additions & 0 deletions plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,24 @@ class read_only {
};
}

struct push_ro_transaction_params {
name account_name;
bool return_failure_traces;
heifner marked this conversation as resolved.
Show resolved Hide resolved
fc::variant transaction;
};

struct push_ro_transaction_results {
uint32_t head_block_num = 0;
chain::block_id_type head_block_id;
uint32_t last_irreversible_block_num = 0;
chain::block_id_type last_irreversible_block_id;
digest_type code_hash;
vector<transaction_id_type> pending_transactions;
fc::variant result;
};

void push_ro_transaction(const push_ro_transaction_params& params, chain::plugin_interface::next_function<push_ro_transaction_results> next ) const;

template<typename KeyValueObj>
static void copy_inline_row(const KeyValueObj& obj, vector<char>& data) {
data.resize( obj.value.size() );
Expand Down Expand Up @@ -1123,3 +1141,6 @@ FC_REFLECT( eosio::chain_apis::read_only::abi_bin_to_json_params, (code)(action)
FC_REFLECT( eosio::chain_apis::read_only::abi_bin_to_json_result, (args) )
FC_REFLECT( eosio::chain_apis::read_only::get_required_keys_params, (transaction)(available_keys) )
FC_REFLECT( eosio::chain_apis::read_only::get_required_keys_result, (required_keys) )
FC_REFLECT( eosio::chain_apis::read_only::push_ro_transaction_params, (account_name)(return_failure_traces)(transaction) )
FC_REFLECT( eosio::chain_apis::read_only::push_ro_transaction_results, (head_block_num)(head_block_id)(last_irreversible_block_num)(last_irreversible_block_id)(code_hash)(pending_transactions)(result) )

Loading