Skip to content

Commit

Permalink
Merge pull request #145 from eosnetworkfoundation/enfs-30-pwo-get-tra…
Browse files Browse the repository at this point in the history
…nsaction-status

Add get_transaction_status to chain_plugin
  • Loading branch information
brianjohnson5972 authored Apr 27, 2022
2 parents e75287a + 6cc7012 commit bed209c
Show file tree
Hide file tree
Showing 11 changed files with 138 additions and 16 deletions.
35 changes: 35 additions & 0 deletions docs/02_cleos/03_command-reference/get/transaction-status.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## Description

Gets current blockchain state and, if available, transaction information given the transaction id

## Position Parameters

- `id` _TEXT_ - The string ID of the transaction to retrieve status about (required)

## Options
- `-h` - --help Print this help message and exit
## Example


```sh
cleos get transaction-status 6438df82216dfaf46978f703fb818b49110dbfc5d9b521b5d08c342277438b29
```

This command simply returns the current chain status and transaction status information (if available).

```json
{
"state": "IN_BLOCK",
"block_number": 90,
"block_id": "0000005accfd59ba80a05380f60d51687406337b2aedd28b7daa33fdb8c16b5a",
"block_timestamp": "2022-04-27T16:11:26.500",
"expiration": "2022-04-27T16:11:56.000",
"head_number": 186,
"head_id": "000000bab27da51f76f483bb629b532510c22e2eb1acc632f5b37b421adecf63",
"head_timestamp": "2022-04-27T16:12:14.500",
"irreversible_number": 25,
"irreversible_id": "0000001922118216bc16bf2c60d950598d80af3beca820eab751f7beecdb29e4",
"irreversible_timestamp": "2022-04-27T16:10:54.000",
"last_tracked_block_id": "000000129cee97f3e27312f0184d52d006a470f0e620553dfb4c5b4f3c856ab2"
}
```
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 @@ -161,6 +161,7 @@ void chain_api_plugin::plugin_startup() {
CHAIN_RO_CALL(abi_bin_to_json, 200),
CHAIN_RO_CALL(get_required_keys, 200),
CHAIN_RO_CALL(get_transaction_id, 200),
CHAIN_RO_CALL_WITH_400(get_transaction_status, 200),
CHAIN_RO_CALL_ASYNC_WITH_400(compute_transaction, chain_apis::read_only::compute_transaction_results, 200),
CHAIN_RW_CALL_ASYNC(push_block, chain_apis::read_write::push_block_results, 202),
CHAIN_RW_CALL_ASYNC(push_transaction, chain_apis::read_write::push_transaction_results, 202),
Expand Down
47 changes: 43 additions & 4 deletions plugins/chain_plugin/chain_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,9 +794,15 @@ void chain_plugin::plugin_initialize(const variables_map& options) {
my->_trx_signals_processor.emplace();
if (my->_trx_finality_status_processing) {
my->_trx_signals_processor->register_callbacks(
[]( const chain::signals_processor::trx_deque& trxs, const chain::block_state_ptr& blk ) {},
[]( const chain::block_state_ptr& blk ) {},
[]( uint32_t block_num ) {}
[this]( const chain::signals_processor::trx_deque& trxs, const chain::block_state_ptr& blk ) {
my->_trx_finality_status_processing->signal_applied_transactions(trxs, blk);
},
[this]( const chain::block_state_ptr& blk ) {
my->_trx_finality_status_processing->signal_irreversible_block(blk);
},
[this]( uint32_t block_num ) {
my->_trx_finality_status_processing->signal_block_start(block_num);
}
);
}
}
Expand Down Expand Up @@ -1362,7 +1368,7 @@ chain_apis::read_write chain_plugin::get_read_write_api() {
}

chain_apis::read_only chain_plugin::get_read_only_api() const {
return chain_apis::read_only(chain(), my->_account_query_db, get_abi_serializer_max_time(), my->producer_plug);
return chain_apis::read_only(chain(), my->_account_query_db, get_abi_serializer_max_time(), my->producer_plug, my->_trx_finality_status_processing.get());
}


Expand Down Expand Up @@ -1683,6 +1689,39 @@ read_only::get_info_results read_only::get_info(const read_only::get_info_params
};
}

read_only::get_transaction_status_results read_only::get_transaction_status(const read_only::get_transaction_status_params& param) const {
transaction_id_type input_id;
auto input_id_length = param.id.size();
try
{
FC_ASSERT(input_id_length <= 64, "hex string is too long to represent an actual transaction id");
FC_ASSERT(input_id_length >= 8, "hex string representing transaction id should be at least 8 characters long to avoid excessive collisions");
input_id = transaction_id_type(param.id);
}
EOS_RETHROW_EXCEPTIONS(transaction_id_type_exception, "Invalid transaction ID: ${transaction_id}", ("transaction_id", param.id))

EOS_ASSERT(trx_finality_status_proc, unsupported_feature, "Transaction Status Interface not enabled. To enable, configure nodeos with '--transaction-finality-status-max-storage-size-gb <size>'.");

trx_finality_status_processing::chain_state ch_state = trx_finality_status_proc->get_chain_state();

auto trx_st = trx_finality_status_proc->get_trx_state(input_id);

return {
trx_st ? trx_st->status : "UNKNOWN",
trx_st ? std::optional<uint32_t>(chain::block_header::num_from_id(trx_st->block_id)) : std::optional<uint32_t>{},
trx_st ? std::optional<chain::block_id_type>(trx_st->block_id) : std::optional<chain::block_id_type>{},
trx_st ? std::optional<fc::time_point>(trx_st->block_timestamp) : std::optional<fc::time_point>{},
trx_st ? std::optional<fc::time_point_sec>(trx_st->expiration) : std::optional<fc::time_point_sec>{},
chain::block_header::num_from_id(ch_state.head_id),
ch_state.head_id,
ch_state.head_block_timestamp,
chain::block_header::num_from_id(ch_state.irr_id),
ch_state.irr_id,
ch_state.irr_block_timestamp,
ch_state.last_tracked_block_id
};
}

read_only::get_activated_protocol_features_results
read_only::get_activated_protocol_features( const read_only::get_activated_protocol_features_params& params )const {
read_only::get_activated_protocol_features_results result;
Expand Down
30 changes: 28 additions & 2 deletions plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include <eosio/chain_plugin/account_query_db.hpp>
#include <eosio/chain_plugin/trx_retry_db.hpp>
#include <eosio/chain_plugin/trx_finality_status_processing.hpp>

#include <fc/static_variant.hpp>

Expand Down Expand Up @@ -86,12 +87,13 @@ class read_only {
const fc::microseconds abi_serializer_max_time;
bool shorten_abi_errors = true;
const producer_plugin* producer_plug;
const trx_finality_status_processing* trx_finality_status_proc;

public:
static const string KEYi64;

read_only(const controller& db, const std::optional<account_query_db>& aqdb, const fc::microseconds& abi_serializer_max_time, const producer_plugin* producer_plug)
: db(db), aqdb(aqdb), abi_serializer_max_time(abi_serializer_max_time), producer_plug(producer_plug) {
read_only(const controller& db, const std::optional<account_query_db>& aqdb, const fc::microseconds& abi_serializer_max_time, const producer_plugin* producer_plug, const trx_finality_status_processing* trx_finality_status_proc)
: db(db), aqdb(aqdb), abi_serializer_max_time(abi_serializer_max_time), producer_plug(producer_plug), trx_finality_status_proc(trx_finality_status_proc) {
}

void validate() const {}
Expand Down Expand Up @@ -126,6 +128,27 @@ class read_only {
};
get_info_results get_info(const get_info_params&) const;

struct get_transaction_status_params {
string id;
};

struct get_transaction_status_results {
string state;
std::optional<uint32_t> block_number;
std::optional<chain::block_id_type> block_id;
std::optional<fc::time_point> block_timestamp;
std::optional<fc::time_point> expiration;
uint32_t head_number = 0;
chain::block_id_type head_id;
fc::time_point head_timestamp;
uint32_t irreversible_number = 0;
chain::block_id_type irreversible_id;
fc::time_point irreversible_timestamp;
chain::block_id_type last_tracked_block_id;
};
get_transaction_status_results get_transaction_status(const get_transaction_status_params& params) const;


struct get_activated_protocol_features_params {
std::optional<uint32_t> lower_bound;
std::optional<uint32_t> upper_bound;
Expand Down Expand Up @@ -790,6 +813,9 @@ FC_REFLECT(eosio::chain_apis::read_only::get_info_results,
(head_block_id)(head_block_time)(head_block_producer)
(virtual_block_cpu_limit)(virtual_block_net_limit)(block_cpu_limit)(block_net_limit)
(server_version_string)(fork_db_head_block_num)(fork_db_head_block_id)(server_full_version_string)(total_cpu_weight)(total_net_weight) )
FC_REFLECT(eosio::chain_apis::read_only::get_transaction_status_params, (id) )
FC_REFLECT(eosio::chain_apis::read_only::get_transaction_status_results, (state)(block_number)(block_id)(block_timestamp)(expiration)(head_number)(head_id)
(head_timestamp)(irreversible_number)(irreversible_id)(irreversible_timestamp)(last_tracked_block_id) )
FC_REFLECT(eosio::chain_apis::read_only::get_activated_protocol_features_params, (lower_bound)(upper_bound)(limit)(search_by_block_num)(reverse) )
FC_REFLECT(eosio::chain_apis::read_only::get_activated_protocol_features_results, (activated_protocol_features)(more) )
FC_REFLECT(eosio::chain_apis::read_only::get_block_params, (block_num_or_id))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,18 @@ namespace eosio::chain_apis {
public:

struct chain_state {
chain::block_id_type head_id;
chain::block_id_type irr_id;
chain::block_id_type last_tracked_block_id;
chain::block_id_type head_id;
chain::block_timestamp_type head_block_timestamp;
chain::block_id_type irr_id;
chain::block_timestamp_type irr_block_timestamp;
chain::block_id_type last_tracked_block_id;
};

struct trx_state {
chain::block_id_type block_id;
fc::time_point block_timestamp;
fc::time_point received;
fc::time_point expiration;
std::string status;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ BOOST_AUTO_TEST_CASE(trx_finality_status_logic) { try {
BOOST_REQUIRE(ts);
BOOST_CHECK(ts->block_id == bs_20->id);
BOOST_CHECK(ts->block_timestamp == bs_20->block->timestamp);
BOOST_CHECK(fc::time_point_sec(ts->expiration) == (std::get<1>(trx_pairs_20[1])->expiration()));
BOOST_CHECK_EQUAL(std::string(ts->received), pre_block_20_time);
BOOST_CHECK_EQUAL(ts->status, "IN_BLOCK");

Expand Down Expand Up @@ -706,6 +707,7 @@ BOOST_AUTO_TEST_CASE(trx_finality_status_logic) { try {
cs = status.get_chain_state();
BOOST_CHECK(cs.head_id == bs_19_alt->id);
BOOST_CHECK(cs.irr_id == bs_19_alt->id);
BOOST_CHECK(cs.irr_block_timestamp == bs_19_alt->block->timestamp);
BOOST_CHECK(cs.last_tracked_block_id == bs_19_alt->id);


Expand Down Expand Up @@ -1004,7 +1006,9 @@ BOOST_AUTO_TEST_CASE(trx_finality_status_storage_reduction) { try {

cs = status.get_chain_state();
BOOST_CHECK(cs.head_id == b_12.bs->id);
BOOST_CHECK(cs.head_block_timestamp == b_12.bs->block->timestamp);
BOOST_CHECK(cs.irr_id == eosio::chain::block_id_type{});
BOOST_CHECK(cs.irr_block_timestamp == eosio::chain::block_timestamp_type{});
BOOST_CHECK(cs.last_tracked_block_id == b_03.bs->id);


Expand Down
8 changes: 6 additions & 2 deletions plugins/chain_plugin/trx_finality_status_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ namespace eosio::chain_apis {
fc::tracked_storage<finality_status_multi_index> _storage;
uint32_t _last_proc_block_num = finality_status::no_block_num;
chain::block_id_type _head_block_id;
chain::block_timestamp_type _head_block_timestamp;
chain::block_id_type _irr_block_id;
chain::block_timestamp_type _irr_block_timestamp;
chain::block_id_type _last_tracked_block_id;
const fc::microseconds _success_duration;
const fc::microseconds _failure_duration;
Expand All @@ -44,6 +46,7 @@ namespace eosio::chain_apis {

void trx_finality_status_processing::signal_irreversible_block( const chain::block_state_ptr& bsp ) {
_my->_irr_block_id = bsp->id;
_my->_irr_block_timestamp = bsp->block->timestamp;
}

void trx_finality_status_processing::signal_block_start( uint32_t block_num ) {
Expand All @@ -57,6 +60,7 @@ namespace eosio::chain_apis {
chain::block_timestamp_type block_timestamp;
if (bsp) {
_head_block_id = block_id;
_head_block_timestamp = bsp->block->timestamp;
block_timestamp = bsp->block->timestamp;
if (chain::block_header::num_from_id(_head_block_id) <= _last_proc_block_num) {
handle_rollback();
Expand Down Expand Up @@ -235,7 +239,7 @@ namespace eosio::chain_apis {
}

trx_finality_status_processing::chain_state trx_finality_status_processing::get_chain_state() const {
return { .head_id = _my->_head_block_id, .irr_id = _my->_irr_block_id, .last_tracked_block_id = _my->_last_tracked_block_id };
return { .head_id = _my->_head_block_id, .head_block_timestamp = _my->_head_block_timestamp, .irr_id = _my->_irr_block_id, .irr_block_timestamp = _my->_irr_block_timestamp, .last_tracked_block_id = _my->_last_tracked_block_id };
}

std::optional<trx_finality_status_processing::trx_state> trx_finality_status_processing::get_trx_state( const chain::transaction_id_type& id ) const {
Expand All @@ -258,7 +262,7 @@ namespace eosio::chain_apis {
const auto lib = chain::block_header::num_from_id(_my->_irr_block_id);
status = (block_num > lib) ? "IN_BLOCK" : "IRREVERSIBLE";
}
return trx_finality_status_processing::trx_state{ .block_id = iter->block_id, .block_timestamp = iter->block_timestamp, .received = iter->received, .status = status };
return trx_finality_status_processing::trx_state{ .block_id = iter->block_id, .block_timestamp = iter->block_timestamp, .received = iter->received, .expiration = iter->trx_expiry, .status = status };
}

size_t trx_finality_status_processing::get_storage_memory_size() const {
Expand Down
1 change: 1 addition & 0 deletions programs/cleos/httpc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ namespace eosio { namespace client { namespace http {

const string chain_func_base = "/v1/chain";
const string get_info_func = chain_func_base + "/get_info";
const string get_transaction_status_func = chain_func_base + "/get_transaction_status";
const string send_txn_func = chain_func_base + "/send_transaction";
const string push_txn_func = chain_func_base + "/push_transaction";
const string send2_txn_func = chain_func_base + "/send_transaction2";
Expand Down
9 changes: 9 additions & 0 deletions programs/cleos/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2625,6 +2625,15 @@ int main( int argc, char** argv ) {
std::cout << fc::json::to_pretty_string(get_info()) << std::endl;
});

// get transaction status
string status_transaction_id_str;
auto getTransactionStatus = get->add_subcommand("transaction-status", localized("Get transaction status information"));
getTransactionStatus->add_option("id", status_transaction_id_str, localized("ID of the transaction to retrieve"))->required();
getTransactionStatus->callback([&status_transaction_id_str] {
auto arg= fc::mutable_variant_object( "id", status_transaction_id_str);
std::cout << fc::json::to_pretty_string(call(get_transaction_status_func, arg)) << std::endl;
});

// get block
string blockArg;
bool get_bhs = false;
Expand Down
2 changes: 1 addition & 1 deletion tests/chain_plugin_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ BOOST_FIXTURE_TEST_CASE( get_block_with_invalid_abi, TESTER ) try {
char headnumstr[20];
sprintf(headnumstr, "%d", headnum);
chain_apis::read_only::get_block_params param{headnumstr};
chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), {});
chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), {}, {});

// block should be decoded successfully
std::string block_str = json::to_pretty_string(plugin.get_block(param));
Expand Down
8 changes: 4 additions & 4 deletions tests/get_table_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ BOOST_FIXTURE_TEST_CASE( get_scope_test, TESTER ) try {
produce_blocks(1);

// iterate over scope
eosio::chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), {});
eosio::chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), {}, {});
eosio::chain_apis::read_only::get_table_by_scope_params param{"eosio.token"_n, "accounts"_n, "inita", "", 10};
eosio::chain_apis::read_only::get_table_by_scope_result result = plugin.read_only::get_table_by_scope(param);

Expand Down Expand Up @@ -194,7 +194,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_test, TESTER ) try {
produce_blocks(1);

// get table: normal case
eosio::chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), {});
eosio::chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), {}, {});
eosio::chain_apis::read_only::get_table_rows_params p;
p.code = "eosio.token"_n;
p.scope = "inita";
Expand Down Expand Up @@ -363,7 +363,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_by_seckey_test, TESTER ) try {
produce_blocks(1);

// get table: normal case
eosio::chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), {});
eosio::chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), {}, {});
eosio::chain_apis::read_only::get_table_rows_params p;
p.code = "eosio"_n;
p.scope = "eosio";
Expand Down Expand Up @@ -515,7 +515,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_next_key_test, TESTER ) try {
// }


chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), {});
chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), {}, {});
chain_apis::read_only::get_table_rows_params params{
.json=true,
.code="test"_n,
Expand Down

0 comments on commit bed209c

Please sign in to comment.