From d54bc83c095fb8a2689ce9a41ffe31f045173427 Mon Sep 17 00:00:00 2001 From: Bart Wyatt Date: Mon, 21 Aug 2017 20:47:29 -0400 Subject: [PATCH] add processing of GeneratedTransaction sharing code where possible. ref EOSIO/eos#174 --- libraries/chain/chain_controller.cpp | 79 +++++++++++-------- .../include/eos/chain/chain_controller.hpp | 29 ++++--- .../chain/generated_transaction_object.hpp | 11 ++- .../chain/include/eos/chain/transaction.hpp | 8 +- 4 files changed, 83 insertions(+), 44 deletions(-) diff --git a/libraries/chain/chain_controller.cpp b/libraries/chain/chain_controller.cpp index 07886cc0261..77578f864fd 100644 --- a/libraries/chain/chain_controller.cpp +++ b/libraries/chain/chain_controller.cpp @@ -132,6 +132,13 @@ std::vector chain_controller::get_block_ids_on_fork(block_id_type return result; } +const GeneratedTransaction& chain_controller::get_generated_transaction( const generated_transaction_id_type& id ) const { + auto& index = _db.get_index(); + auto itr = index.find(id); + FC_ASSERT(itr != index.end()); + return itr->trx; +} + /** * Push block "may fail" in which case every partial change is unwound. After * push block is successful the block is appended to the chain database on disk. @@ -247,7 +254,7 @@ ProcessedTransaction chain_controller::_push_transaction(const SignedTransaction auto temp_session = _db.start_undo_session(true); validate_referenced_accounts(trx); check_transaction_authorization(trx); - auto pt = _apply_transaction(trx); + auto pt = apply_transaction(trx); _pending_transactions.push_back(trx); // notify_changed_objects(); @@ -297,7 +304,7 @@ signed_block chain_controller::_generate_block( FC_ASSERT( producer_obj.signing_key == block_signing_private_key.get_public_key() ); - auto& generated = _db.get_index(); + const auto& generated = _db.get_index().equal_range(generated_transaction_object::PENDING); vector pending; std::set invalid_pending; @@ -348,11 +355,12 @@ signed_block chain_controller::_generate_block( const auto& t = trx.get>().get(); validate_referenced_accounts(t); check_transaction_authorization(t); - auto processed = _apply_transaction(t); + auto processed = apply_transaction(t); block_thread.user_input.emplace_back(processed); } else if (trx.contains>()) { - // auto processed = _apply_transaction(trx.get>().get()); - // block_thread.generated_input.emplace_back(processed); + const auto& t = trx.get>().get(); + auto processed = apply_transaction(t); + block_thread.generated_input.emplace_back(processed); } else { FC_THROW_EXCEPTION(tx_scheduling_exception, "Unknown transaction type in block_schedule"); } @@ -516,10 +524,12 @@ void chain_controller::_apply_block(const signed_block& next_block) */ for (const auto& cycle : next_block.cycles) { for (const auto& thread : cycle) { - for(const auto& trx : thread.generated_input ) { + for(const auto& ptrx : thread.generated_input ) { + auto const trx = get_generated_transaction(ptrx.id); + apply_transaction(trx); } for(const auto& trx : thread.user_input ) { - _apply_transaction(trx); + apply_transaction(trx); } } } @@ -578,11 +588,6 @@ void chain_controller::check_transaction_authorization(const SignedTransaction& "Transaction bears irrelevant signatures from these keys: ${keys}", ("keys", checker.unused_keys())); } -ProcessedTransaction chain_controller::apply_transaction(const SignedTransaction& trx, uint32_t skip) -{ - return with_skip_flags( skip, [&]() { return _apply_transaction(trx); }); -} - void chain_controller::validate_scope( const Transaction& trx )const { EOS_ASSERT(trx.scope.size() > 0, transaction_exception, "No scope specified by transaction" ); for( uint32_t i = 1; i < trx.scope.size(); ++i ) @@ -621,6 +626,22 @@ void chain_controller::validate_uniqueness( const GeneratedTransaction& trx )con if( !should_check_for_duplicate_transactions() ) return; } +void chain_controller::record_transaction(const SignedTransaction& trx) { + //Insert transaction into unique transactions database. + _db.create([&](transaction_object& transaction) { + transaction.trx_id = trx.id(); /// TODO: consider caching ID + transaction.trx = trx; + }); +} + +void chain_controller::record_transaction(const GeneratedTransaction& trx) { + _db.modify( _db.get(trx.id), [&](generated_transaction_object& transaction) { + transaction.status = generated_transaction_object::PROCESSED; + }); +} + + + void chain_controller::validate_tapos(const Transaction& trx)const { if (!should_check_tapos()) return; @@ -656,7 +677,7 @@ void chain_controller::validate_expiration(const Transaction& trx) const } FC_CAPTURE_AND_RETHROW((trx)) } -void chain_controller::process_message(const ProcessedTransaction& trx, AccountName code, +void chain_controller::process_message(const Transaction& trx, AccountName code, const Message& message, MessageOutput& output, apply_context* parent_context) { apply_context apply_ctx(*this, _db, trx, message, code); apply_message(apply_ctx); @@ -678,7 +699,12 @@ void chain_controller::process_message(const ProcessedTransaction& trx, AccountN } for( auto& asynctrx : apply_ctx.async_transactions ) { - output.async_transactions.emplace_back( std::move( asynctrx ) ); + _db.create([&](generated_transaction_object& transaction) { + transaction.trx = asynctrx; + transaction.status = generated_transaction_object::PENDING; + }); + + output.async_transactions.emplace_back( std::move( asynctrx ) ); } // propagate used_authorizations up the context chain @@ -715,40 +741,31 @@ void chain_controller::apply_message(apply_context& context) } FC_CAPTURE_AND_RETHROW((context.msg)) } -ProcessedTransaction chain_controller::_apply_transaction(const SignedTransaction& trx) +template +typename T::Processed chain_controller::apply_transaction(const T& trx) { try { validate_transaction(trx); - - //Insert transaction into unique transactions database. - if (should_check_for_duplicate_transactions()) - { - _db.create([&](transaction_object& transaction) { - transaction.trx_id = trx.id(); /// TODO: consider caching ID - transaction.trx = trx; - }); - } - + record_transaction(trx); return process_transaction( trx ); } FC_CAPTURE_AND_RETHROW((trx)) } - /** * @pre the transaction is assumed valid and all signatures / duplicate checks have bee performed */ -ProcessedTransaction chain_controller::process_transaction( const SignedTransaction& trx ) +template +typename T::Processed chain_controller::process_transaction( const T& trx ) { try { - ProcessedTransaction ptrx( trx ); + typename T::Processed ptrx( trx ); ptrx.output.resize( trx.messages.size() ); - for( uint32_t i = 0; i < ptrx.messages.size(); ++i ) { - process_message(ptrx, ptrx.messages[i].code, ptrx.messages[i], ptrx.output[i] ); + for( uint32_t i = 0; i < trx.messages.size(); ++i ) { + process_message(trx, trx.messages[i].code, trx.messages[i], ptrx.output[i] ); } return ptrx; } FC_CAPTURE_AND_RETHROW( (trx) ) } - void chain_controller::require_account(const types::AccountName& name) const { auto account = _db.find(name); FC_ASSERT(account != nullptr, "Account not found: ${name}", ("name", name)); diff --git a/libraries/chain/include/eos/chain/chain_controller.hpp b/libraries/chain/include/eos/chain/chain_controller.hpp index 63d39c01578..928ec3519f7 100644 --- a/libraries/chain/include/eos/chain/chain_controller.hpp +++ b/libraries/chain/include/eos/chain/chain_controller.hpp @@ -110,13 +110,15 @@ namespace eos { namespace chain { * @return true if the block is in our fork DB or saved to disk as * part of the official chain, otherwise return false */ - bool is_known_block( const block_id_type& id )const; - bool is_known_transaction( const transaction_id_type& id )const; - block_id_type get_block_id_for_num( uint32_t block_num )const; - optional fetch_block_by_id( const block_id_type& id )const; - optional fetch_block_by_number( uint32_t num )const; - const SignedTransaction& get_recent_transaction( const transaction_id_type& trx_id )const; - std::vector get_block_ids_on_fork(block_id_type head_of_fork)const; + bool is_known_block( const block_id_type& id )const; + bool is_known_transaction( const transaction_id_type& id )const; + block_id_type get_block_id_for_num( uint32_t block_num )const; + optional fetch_block_by_id( const block_id_type& id )const; + optional fetch_block_by_number( uint32_t num )const; + const SignedTransaction& get_recent_transaction( const transaction_id_type& trx_id )const; + std::vector get_block_ids_on_fork(block_id_type head_of_fork)const; + const GeneratedTransaction& get_generated_transaction( const generated_transaction_id_type& id ) const; + /** * This method will convert a variant to a SignedTransaction using a contract's ABI to @@ -275,9 +277,11 @@ namespace eos { namespace chain { void check_transaction_authorization(const SignedTransaction& trx, bool allow_unused_signatures = false)const; - ProcessedTransaction apply_transaction(const SignedTransaction& trx, uint32_t skip = skip_nothing); - ProcessedTransaction _apply_transaction(const SignedTransaction& trx); - ProcessedTransaction process_transaction( const SignedTransaction& trx ); + template + typename T::Processed apply_transaction(const T& trx); + + template + typename T::Processed process_transaction(const T& trx); void require_account(const AccountName& name) const; @@ -304,6 +308,9 @@ namespace eos { namespace chain { void validate_referenced_accounts(const Transaction& trx)const; void validate_expiration(const Transaction& trx) const; void validate_scope(const Transaction& trx) const; + + void record_transaction(const SignedTransaction& trx); + void record_transaction(const GeneratedTransaction& trx); /// @} /** @@ -318,7 +325,7 @@ namespace eos { namespace chain { types::AccountName code_account, types::FuncName type) const; - void process_message(const ProcessedTransaction& trx, AccountName code, const Message& message, + void process_message(const Transaction& trx, AccountName code, const Message& message, MessageOutput& output, apply_context* parent_context = nullptr); void apply_message(apply_context& c); diff --git a/libraries/chain/include/eos/chain/generated_transaction_object.hpp b/libraries/chain/include/eos/chain/generated_transaction_object.hpp index 59e5080032c..c1afb396fcb 100644 --- a/libraries/chain/include/eos/chain/generated_transaction_object.hpp +++ b/libraries/chain/include/eos/chain/generated_transaction_object.hpp @@ -45,14 +45,22 @@ namespace eos { namespace chain { { OBJECT_CTOR(generated_transaction_object) + enum status_type { + PENDING = 0, + PROCESSED + }; + + id_type id; GeneratedTransaction trx; + status_type status; time_point_sec get_expiration()const { return trx.expiration; } generated_transaction_id_type get_id() const { return trx.id; } struct by_trx_id; struct by_expiration; + struct by_status; }; using generated_transaction_multi_index = chainbase::shared_multi_index_container< @@ -60,7 +68,8 @@ namespace eos { namespace chain { indexed_by< ordered_unique, BOOST_MULTI_INDEX_MEMBER(generated_transaction_object, generated_transaction_object::id_type, id)>, hashed_unique, const_mem_fun>, - ordered_non_unique, const_mem_fun> + ordered_non_unique, const_mem_fun>, + ordered_non_unique, BOOST_MULTI_INDEX_MEMBER(generated_transaction_object, generated_transaction_object::status_type, status)> > >; diff --git a/libraries/chain/include/eos/chain/transaction.hpp b/libraries/chain/include/eos/chain/transaction.hpp index 2daae7bfe84..a8229de67a7 100644 --- a/libraries/chain/include/eos/chain/transaction.hpp +++ b/libraries/chain/include/eos/chain/transaction.hpp @@ -52,6 +52,9 @@ namespace eos { namespace chain { * @{ */ + struct ProcessedTransaction; + struct ProcessedGeneratedTransaction; + /** @@ -112,6 +115,8 @@ namespace eos { namespace chain { generated_transaction_id_type id; digest_type merkle_digest() const; + + typedef ProcessedGeneratedTransaction Processed; }; /** @@ -144,9 +149,10 @@ namespace eos { namespace chain { void clear() { transaction_helpers::clear(*this); signatures.clear(); } digest_type merkle_digest() const; + + typedef ProcessedTransaction Processed; }; - struct ProcessedTransaction; struct NotifyOutput;