From de723bb2aa5759e35257c18a211276e298d14a17 Mon Sep 17 00:00:00 2001 From: abitmore Date: Fri, 16 Sep 2022 15:26:27 +0000 Subject: [PATCH 1/5] Add is_virtual field to operation_history_object --- libraries/chain/db_block.cpp | 20 +++++++++---------- .../chain/include/graphene/chain/database.hpp | 7 +++++-- .../chain/operation_history_object.hpp | 6 +++++- libraries/chain/small_objects.cpp | 2 +- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index 2a9ebfb22d..fcf8e44a54 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -342,7 +342,7 @@ processed_transaction database::push_proposal(const proposal_object& proposal) _undo_db.set_max_size( _undo_db.size() + 1 ); auto session = _undo_db.start_undo_session(true); for( auto& op : proposal.proposed_transaction.operations ) - eval_state.operation_results.emplace_back(apply_operation(eval_state, op)); + eval_state.operation_results.emplace_back(apply_operation(eval_state, op)); // This is a virtual operation // Make sure there is no unpaid samet fund debt const auto& samet_fund_idx = get_index_type().indices().get(); FC_ASSERT( samet_fund_idx.empty() || samet_fund_idx.begin()->unpaid_amount == 0, @@ -532,14 +532,11 @@ void database::clear_pending() _pending_tx_session.reset(); } FC_CAPTURE_AND_RETHROW() } -uint32_t database::push_applied_operation( const operation& op ) +uint32_t database::push_applied_operation( const operation& op, bool is_virtual /* = true */ ) { - _applied_ops.emplace_back(op); - operation_history_object& oh = *(_applied_ops.back()); - oh.block_num = _current_block_num; - oh.trx_in_block = _current_trx_in_block; - oh.op_in_trx = _current_op_in_trx; - oh.virtual_op = _current_virtual_op++; + _applied_ops.emplace_back( operation_history_object( op, _current_block_num, _current_trx_in_block, + _current_op_in_trx, _current_virtual_op, is_virtual ) ); + ++_current_virtual_op; return _applied_ops.size() - 1; } void database::set_applied_operation_result( uint32_t op_id, const operation_result& result ) @@ -758,7 +755,7 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx for( const auto& op : ptrx.operations ) { _current_virtual_op = 0; - eval_state.operation_results.emplace_back(apply_operation(eval_state, op)); + eval_state.operation_results.emplace_back(apply_operation(eval_state, op, false)); // This is NOT a virtual op ++_current_op_in_trx; } ptrx.operation_results = std::move(eval_state.operation_results); @@ -771,7 +768,8 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx return ptrx; } FC_CAPTURE_AND_RETHROW( (trx) ) } -operation_result database::apply_operation(transaction_evaluation_state& eval_state, const operation& op) +operation_result database::apply_operation( transaction_evaluation_state& eval_state, const operation& op, + bool is_virtual /* = true */ ) { try { int i_which = op.which(); uint64_t u_which = uint64_t( i_which ); @@ -779,7 +777,7 @@ operation_result database::apply_operation(transaction_evaluation_state& eval_st FC_ASSERT( u_which < _operation_evaluators.size(), "No registered evaluator for operation ${op}", ("op",op) ); unique_ptr& eval = _operation_evaluators[ u_which ]; FC_ASSERT( eval, "No registered evaluator for operation ${op}", ("op",op) ); - auto op_id = push_applied_operation( op ); + auto op_id = push_applied_operation( op, is_virtual ); auto result = eval->evaluate( eval_state, op, true ); set_applied_operation_result( op_id, result ); return result; diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index cbcbadb61a..b953f4fdba 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -585,10 +585,12 @@ namespace graphene { namespace chain { * as any implied/virtual operations that resulted, such as filling an order. The * applied operations is cleared after applying each block and calling the block * observers which may want to index these operations. + * @param The operation to push + * @param is_virtual Whether the operation is a virtual operation * * @return the op_id which can be used to set the result after it has finished being applied. */ - uint32_t push_applied_operation( const operation& op ); + uint32_t push_applied_operation( const operation& op, bool is_virtual = true ); void set_applied_operation_result( uint32_t op_id, const operation_result& r ); const vector >& get_applied_operations()const; @@ -681,7 +683,8 @@ namespace graphene { namespace chain { // these were formerly private, but they have a fairly well-defined API, so let's make them public void apply_block( const signed_block& next_block, uint32_t skip = skip_nothing ); processed_transaction apply_transaction( const signed_transaction& trx, uint32_t skip = skip_nothing ); - operation_result apply_operation( transaction_evaluation_state& eval_state, const operation& op ); + operation_result apply_operation( transaction_evaluation_state& eval_state, const operation& op, + bool is_virtual = true ); private: void _apply_block( const signed_block& next_block ); diff --git a/libraries/chain/include/graphene/chain/operation_history_object.hpp b/libraries/chain/include/graphene/chain/operation_history_object.hpp index 086e3e440f..10cb4bdad1 100644 --- a/libraries/chain/include/graphene/chain/operation_history_object.hpp +++ b/libraries/chain/include/graphene/chain/operation_history_object.hpp @@ -51,8 +51,10 @@ namespace graphene { namespace chain { static constexpr uint8_t space_id = protocol_ids; static constexpr uint8_t type_id = operation_history_object_type; - operation_history_object( const operation& o ):op(o){} + explicit operation_history_object( const operation& o ):op(o){} operation_history_object(){} + operation_history_object( const operation& o, uint32_t bn, uint16_t tib, uint16_t oit, uint32_t vo, bool iv ) + : op(o), block_num(bn), trx_in_block(tib), op_in_trx(oit), virtual_op(vo), is_virtual(iv) {} operation op; operation_result result; @@ -64,6 +66,8 @@ namespace graphene { namespace chain { uint16_t op_in_trx = 0; /** any virtual operations implied by operation in block */ uint32_t virtual_op = 0; + /** Whether this is a virtual operation */ + bool is_virtual = false; }; /** diff --git a/libraries/chain/small_objects.cpp b/libraries/chain/small_objects.cpp index 87e58e2586..e860143013 100644 --- a/libraries/chain/small_objects.cpp +++ b/libraries/chain/small_objects.cpp @@ -139,7 +139,7 @@ FC_REFLECT_DERIVED_NO_TYPENAME( graphene::chain::htlc_object, (graphene::db::obj (transfer) (conditions) (memo) ) FC_REFLECT_DERIVED_NO_TYPENAME( graphene::chain::operation_history_object, (graphene::chain::object), - (op)(result)(block_num)(trx_in_block)(op_in_trx)(virtual_op) ) + (op)(result)(block_num)(trx_in_block)(op_in_trx)(virtual_op)(is_virtual) ) FC_REFLECT_DERIVED_NO_TYPENAME( graphene::chain::account_history_object, (graphene::chain::object), (account)(operation_id)(sequence)(next) ) From 1ff5d8e2cae2b7ea80e3de0fa2b4d82aae87aded Mon Sep 17 00:00:00 2001 From: abitmore Date: Fri, 16 Sep 2022 15:32:38 +0000 Subject: [PATCH 2/5] Add block_time field to operation_history_object --- libraries/chain/db_block.cpp | 2 +- .../include/graphene/chain/operation_history_object.hpp | 7 +++++-- libraries/chain/small_objects.cpp | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index fcf8e44a54..92440e4dbe 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -535,7 +535,7 @@ void database::clear_pending() uint32_t database::push_applied_operation( const operation& op, bool is_virtual /* = true */ ) { _applied_ops.emplace_back( operation_history_object( op, _current_block_num, _current_trx_in_block, - _current_op_in_trx, _current_virtual_op, is_virtual ) ); + _current_op_in_trx, _current_virtual_op, is_virtual, _current_block_time ) ); ++_current_virtual_op; return _applied_ops.size() - 1; } diff --git a/libraries/chain/include/graphene/chain/operation_history_object.hpp b/libraries/chain/include/graphene/chain/operation_history_object.hpp index 10cb4bdad1..380a0292d0 100644 --- a/libraries/chain/include/graphene/chain/operation_history_object.hpp +++ b/libraries/chain/include/graphene/chain/operation_history_object.hpp @@ -53,8 +53,9 @@ namespace graphene { namespace chain { explicit operation_history_object( const operation& o ):op(o){} operation_history_object(){} - operation_history_object( const operation& o, uint32_t bn, uint16_t tib, uint16_t oit, uint32_t vo, bool iv ) - : op(o), block_num(bn), trx_in_block(tib), op_in_trx(oit), virtual_op(vo), is_virtual(iv) {} + operation_history_object( const operation& o, uint32_t bn, uint16_t tib, uint16_t oit, uint32_t vo, bool iv, + const time_point_sec& bt ) + : op(o), block_num(bn), trx_in_block(tib), op_in_trx(oit), virtual_op(vo), is_virtual(iv), block_time(bt) {} operation op; operation_result result; @@ -68,6 +69,8 @@ namespace graphene { namespace chain { uint32_t virtual_op = 0; /** Whether this is a virtual operation */ bool is_virtual = false; + /** The timestamp of the block that caused this operation */ + time_point_sec block_time; }; /** diff --git a/libraries/chain/small_objects.cpp b/libraries/chain/small_objects.cpp index e860143013..291eac1230 100644 --- a/libraries/chain/small_objects.cpp +++ b/libraries/chain/small_objects.cpp @@ -139,7 +139,7 @@ FC_REFLECT_DERIVED_NO_TYPENAME( graphene::chain::htlc_object, (graphene::db::obj (transfer) (conditions) (memo) ) FC_REFLECT_DERIVED_NO_TYPENAME( graphene::chain::operation_history_object, (graphene::chain::object), - (op)(result)(block_num)(trx_in_block)(op_in_trx)(virtual_op)(is_virtual) ) + (op)(result)(block_num)(trx_in_block)(op_in_trx)(virtual_op)(is_virtual)(block_time) ) FC_REFLECT_DERIVED_NO_TYPENAME( graphene::chain::account_history_object, (graphene::chain::object), (account)(operation_id)(sequence)(next) ) From 21bd95b5a25046c87264b5b8974b6eb98f273f68 Mon Sep 17 00:00:00 2001 From: abitmore Date: Fri, 16 Sep 2022 16:05:11 +0000 Subject: [PATCH 3/5] Bump DB_VERSION --- libraries/chain/include/graphene/chain/config.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index 598df91053..4dc548855f 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -32,7 +32,7 @@ #define GRAPHENE_MAX_NESTED_OBJECTS (200) -const std::string GRAPHENE_CURRENT_DB_VERSION = "20220913"; +const std::string GRAPHENE_CURRENT_DB_VERSION = "20220916"; #define GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT 4 #define GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT 3 From b1455989d86acfdadf87972366e12388aec8eeb6 Mon Sep 17 00:00:00 2001 From: abitmore Date: Fri, 16 Sep 2022 18:24:41 +0000 Subject: [PATCH 4/5] Handle block_time and is_virtual fields in plugins --- libraries/plugins/account_history/account_history_plugin.cpp | 2 ++ libraries/plugins/elasticsearch/elasticsearch_plugin.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/libraries/plugins/account_history/account_history_plugin.cpp b/libraries/plugins/account_history/account_history_plugin.cpp index 8270af3f31..c391724802 100644 --- a/libraries/plugins/account_history/account_history_plugin.cpp +++ b/libraries/plugins/account_history/account_history_plugin.cpp @@ -108,6 +108,8 @@ void account_history_plugin_impl::update_account_histories( const signed_block& h.trx_in_block = o_op->trx_in_block; h.op_in_trx = o_op->op_in_trx; h.virtual_op = o_op->virtual_op; + h.is_virtual = o_op->is_virtual; + h.block_time = o_op->block_time; } } ) ); }; diff --git a/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp b/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp index 298e459a34..c7ed9eec90 100644 --- a/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp +++ b/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp @@ -148,6 +148,8 @@ void elasticsearch_plugin_impl::update_account_histories( const signed_block& b h.trx_in_block = o_op->trx_in_block; h.op_in_trx = o_op->op_in_trx; h.virtual_op = o_op->virtual_op; + h.is_virtual = o_op->is_virtual; + h.block_time = o_op->block_time; } })); }; From d07cb031dace12875f827abaab1bc78f615839a2 Mon Sep 17 00:00:00 2001 From: abitmore Date: Fri, 16 Sep 2022 18:25:29 +0000 Subject: [PATCH 5/5] Add tests for block_time and is_virtual fields --- tests/tests/history_api_tests.cpp | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/tests/history_api_tests.cpp b/tests/tests/history_api_tests.cpp index 7b0a98d8b4..f448aaf6d2 100644 --- a/tests/tests/history_api_tests.cpp +++ b/tests/tests/history_api_tests.cpp @@ -61,6 +61,8 @@ BOOST_AUTO_TEST_CASE(get_account_history) { BOOST_CHECK_EQUAL(histories.size(), 3u); BOOST_CHECK_EQUAL(histories[2].id.instance(), 0u); BOOST_CHECK_EQUAL(histories[2].op.which(), asset_create_op_id); + BOOST_CHECK( histories[2].block_time == db.head_block_time() ); + BOOST_CHECK( !histories[2].is_virtual ); // 1 account_create op larger than id1 histories = hist_api.get_account_history("1.2.0", operation_history_id_type(1), @@ -100,6 +102,38 @@ BOOST_AUTO_TEST_CASE(get_account_history) { } } +BOOST_AUTO_TEST_CASE(get_account_history_virtual_operation_test) { + try { + graphene::app::history_api hist_api(app); + + asset_id_type usd_id = create_user_issued_asset("USD").id; + + ACTORS( (dan)(bob) ); + fund( dan, asset(100) ); + issue_uia( bob_id, asset(100, usd_id) ); + + create_sell_order( dan_id, asset(100), asset(100, usd_id) ); + create_sell_order( bob_id, asset(100, usd_id), asset(100) ); + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + auto fill_order_op_id = operation::tag::value; + + vector histories = hist_api.get_account_history("dan", operation_history_id_type(), + 100, operation_history_id_type()); + + BOOST_REQUIRE_GT( histories.size(), 0 ); + BOOST_CHECK_EQUAL( histories.front().op.which(), fill_order_op_id ); + BOOST_CHECK( histories.front().block_time == db.head_block_time() ); + BOOST_CHECK( histories.front().is_virtual ); + + } catch (fc::exception &e) { + edump((e.to_detail_string())); + throw; + } +} + BOOST_AUTO_TEST_CASE(get_account_history_notify_all_on_creation) { try { // Pass hard fork time