From 14c938383e37ec33f6168a237263d009ece467f7 Mon Sep 17 00:00:00 2001 From: Jakub Fornadel Date: Wed, 10 Jul 2024 18:08:51 -0700 Subject: [PATCH] fix all edsge case that could make pbdt chain stall --- libraries/aleth/libp2p/ENR.cpp | 3 +- libraries/aleth/libp2p/Host.cpp | 3 +- libraries/aleth/libp2p/NodeTable.h | 5 +- .../config_jsons/default/default_genesis.json | 2 - .../config_jsons/devnet/devnet_genesis.json | 2 - .../config_jsons/mainnet/mainnet_genesis.json | 2 - .../common/include/common/encoding_rlp.hpp | 4 +- libraries/config/include/config/hardfork.hpp | 6 +- libraries/config/src/hardfork.cpp | 29 +- .../core_libs/consensus/include/dag/dag.hpp | 3 +- .../include/final_chain/final_chain.hpp | 5 +- .../include/final_chain/final_chain_impl.hpp | 109 +++ .../consensus/include/pbft/pbft_manager.hpp | 1 + .../pillar_chain/pillar_chain_manager.hpp | 20 +- .../include/pillar_chain/pillar_votes.hpp | 8 - .../src/final_chain/final_chai_impl.cpp | 588 ++++++++++++++++ .../consensus/src/final_chain/final_chain.cpp | 638 ------------------ .../consensus/src/final_chain/trie_common.cpp | 6 +- .../consensus/src/pbft/pbft_manager.cpp | 114 ++-- .../src/pillar_chain/pillar_chain_manager.cpp | 126 +--- .../src/pillar_chain/pillar_votes.cpp | 21 - .../src/vote_manager/vote_manager.cpp | 9 +- libraries/core_libs/network/src/network.cpp | 5 +- .../latest/get_pbft_sync_packet_handler.cpp | 4 +- .../latest/status_packet_handler.cpp | 6 +- .../network/src/threadpool/priority_queue.cpp | 3 +- libraries/core_libs/node/src/node.cpp | 41 +- submodules/taraxa-evm | 2 +- tests/final_chain_test.cpp | 8 +- tests/p2p_test.cpp | 4 +- tests/pillar_chain_test.cpp | 35 +- tests/transaction_test.cpp | 15 +- 32 files changed, 873 insertions(+), 954 deletions(-) create mode 100644 libraries/core_libs/consensus/include/final_chain/final_chain_impl.hpp create mode 100644 libraries/core_libs/consensus/src/final_chain/final_chai_impl.cpp delete mode 100644 libraries/core_libs/consensus/src/final_chain/final_chain.cpp diff --git a/libraries/aleth/libp2p/ENR.cpp b/libraries/aleth/libp2p/ENR.cpp index b5b148c12b..f2b8923ae7 100644 --- a/libraries/aleth/libp2p/ENR.cpp +++ b/libraries/aleth/libp2p/ENR.cpp @@ -204,7 +204,8 @@ PublicCompressed IdentitySchemeV4::publicKey(ENR const& _enr) { } std::ostream& operator<<(std::ostream& _out, ENR const& _enr) { - _out << "[ seq=" << _enr.sequenceNumber() << " " << "id=" << _enr.id() << " "; + _out << "[ seq=" << _enr.sequenceNumber() << " " + << "id=" << _enr.id() << " "; try { auto const pubKey = IdentitySchemeV4::publicKey(_enr); diff --git a/libraries/aleth/libp2p/Host.cpp b/libraries/aleth/libp2p/Host.cpp index 03bb2c7e59..1e773acf73 100644 --- a/libraries/aleth/libp2p/Host.cpp +++ b/libraries/aleth/libp2p/Host.cpp @@ -137,7 +137,8 @@ Host::~Host() { } } // We need to poll both as strand_ is ioc_ - while (0 < session_ioc_.poll() + ioc_.poll()); + while (0 < session_ioc_.poll() + ioc_.poll()) + ; save_state(); ioc_.restart(); diff --git a/libraries/aleth/libp2p/NodeTable.h b/libraries/aleth/libp2p/NodeTable.h index 52e70e6e92..fb61806d7d 100644 --- a/libraries/aleth/libp2p/NodeTable.h +++ b/libraries/aleth/libp2p/NodeTable.h @@ -416,8 +416,9 @@ struct NodeEntry { }; inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable) { - _out << _nodeTable.m_hostNodeID << "\t" << "0\t" << _nodeTable.m_hostNodeEndpoint.address() << ":" - << _nodeTable.m_hostNodeEndpoint.udpPort() << std::endl; + _out << _nodeTable.m_hostNodeID << "\t" + << "0\t" << _nodeTable.m_hostNodeEndpoint.address() << ":" << _nodeTable.m_hostNodeEndpoint.udpPort() + << std::endl; auto s = _nodeTable.snapshot(); for (auto n : s) _out << n.id() << "\t" << n.distance << "\t" << n.endpoint() << "\n"; return _out; diff --git a/libraries/cli/include/cli/config_jsons/default/default_genesis.json b/libraries/cli/include/cli/config_jsons/default/default_genesis.json index dd90eb6e96..c35ad3c10f 100644 --- a/libraries/cli/include/cli/config_jsons/default/default_genesis.json +++ b/libraries/cli/include/cli/config_jsons/default/default_genesis.json @@ -118,8 +118,6 @@ "ficus_hf": { "block_num": 50, "pillar_blocks_interval": 16, - "pillar_chain_sync_interval": 8, - "pbft_inclusion_delay": 6, "bridge_contract_address": "0xcAF2b453FE8382a4B8110356DF0508f6d71F22BF" } } diff --git a/libraries/cli/include/cli/config_jsons/devnet/devnet_genesis.json b/libraries/cli/include/cli/config_jsons/devnet/devnet_genesis.json index e298fdb3fa..dd54012dd0 100644 --- a/libraries/cli/include/cli/config_jsons/devnet/devnet_genesis.json +++ b/libraries/cli/include/cli/config_jsons/devnet/devnet_genesis.json @@ -283,8 +283,6 @@ "ficus_hf": { "block_num": 1000, "pillar_blocks_interval": 100, - "pillar_chain_sync_interval": 25, - "pbft_inclusion_delay": 6, "bridge_contract_address": "0xcAF2b453FE8382a4B8110356DF0508f6d71F22BF" } } diff --git a/libraries/cli/include/cli/config_jsons/mainnet/mainnet_genesis.json b/libraries/cli/include/cli/config_jsons/mainnet/mainnet_genesis.json index 94e4a169fd..4ad1e20333 100644 --- a/libraries/cli/include/cli/config_jsons/mainnet/mainnet_genesis.json +++ b/libraries/cli/include/cli/config_jsons/mainnet/mainnet_genesis.json @@ -1652,8 +1652,6 @@ "ficus_hf": { "block_num": -1, "pillar_blocks_interval": 100, - "pillar_chain_sync_interval": 25, - "pbft_inclusion_delay": 6, "bridge_contract_address": "0x0000000000000000000000000000000000000000" } } diff --git a/libraries/common/include/common/encoding_rlp.hpp b/libraries/common/include/common/encoding_rlp.hpp index cfef0697bc..90cb6918ee 100644 --- a/libraries/common/include/common/encoding_rlp.hpp +++ b/libraries/common/include/common/encoding_rlp.hpp @@ -67,8 +67,8 @@ void rlp(RLPEncoderRef encoding, std::pair const& target) { } template -auto rlp(RLPEncoderRef encoding, Sequence const& target) -> decltype(target.size(), target.begin(), target.end(), - void()) { +auto rlp(RLPEncoderRef encoding, Sequence const& target) + -> decltype(target.size(), target.begin(), target.end(), void()) { encoding.appendList(target.size()); for (auto const& v : target) { rlp(encoding, v); diff --git a/libraries/config/include/config/hardfork.hpp b/libraries/config/include/config/hardfork.hpp index 175fd167b6..2b176bf5d1 100644 --- a/libraries/config/include/config/hardfork.hpp +++ b/libraries/config/include/config/hardfork.hpp @@ -41,11 +41,7 @@ void dec_json(const Json::Value& json, AspenHardfork& obj); struct FicusHardforkConfig { uint64_t block_num{0}; - uint64_t pillar_blocks_interval{100}; // [periods] how often is the new pillar block created - uint64_t pillar_chain_sync_interval{25}; // [periods] how often is pillar chain checked if it is in sync (has all - // previous pillar blocks and 2t+1 signatures for latest pillar block) - uint64_t pbft_inclusion_delay{ - 6}; // [periods] how many periods after the pillar block is created it is included in pbft block + uint64_t pillar_blocks_interval{100}; // [periods] how often is the new pillar block created taraxa::addr_t bridge_contract_address; // [address] of the bridge contract bool isFicusHardfork(taraxa::PbftPeriod period) const; diff --git a/libraries/config/src/hardfork.cpp b/libraries/config/src/hardfork.cpp index 78b6642f17..417ff4a06b 100644 --- a/libraries/config/src/hardfork.cpp +++ b/libraries/config/src/hardfork.cpp @@ -53,12 +53,14 @@ RLP_FIELDS_DEFINE(AspenHardfork, block_num_part_one, block_num_part_two, max_sup bool FicusHardforkConfig::isFicusHardfork(taraxa::PbftPeriod period) const { return period >= block_num; } bool FicusHardforkConfig::isPillarBlockPeriod(taraxa::PbftPeriod period, bool skip_first_pillar_block) const { - return period >= block_num && period >= firstPillarBlockPeriod() + (skip_first_pillar_block ? 1 : 0) * pillar_blocks_interval && + return period >= block_num && + period >= firstPillarBlockPeriod() + (skip_first_pillar_block ? 1 : 0) * pillar_blocks_interval && period % pillar_blocks_interval == 0; } bool FicusHardforkConfig::isPbftWithPillarBlockPeriod(taraxa::PbftPeriod period) const { - return period >= firstPillarBlockPeriod() && period % pillar_blocks_interval == pbft_inclusion_delay; + // Pillar block hash is included in the next pbft block with period +1 + return period >= firstPillarBlockPeriod() && period % pillar_blocks_interval == 1; } // Returns first pillar block period @@ -72,20 +74,12 @@ void FicusHardforkConfig::validate(uint32_t delegation_delay) const { return; } - if (block_num % pillar_blocks_interval) { - throw taraxa::ConfigException("ficus_hf.block_num % ficus_hf.pillar_blocks_interval must == 0"); - } - - if (pillar_blocks_interval <= pillar_chain_sync_interval) { - throw taraxa::ConfigException("ficus_hf.pillar_blocks_interval must be > ficus_hf.pillar_chain_sync_interval"); + if (pillar_blocks_interval <= 1) { + throw taraxa::ConfigException("ficus_hf.pillar_blocks_interval must be > 1"); } - if (pillar_chain_sync_interval <= pbft_inclusion_delay) { - throw taraxa::ConfigException("ficus_hf.pillar_chain_sync_interval must be > ficus_hf.pbft_inclusion_delay"); - } - - if (pbft_inclusion_delay < 1 || pbft_inclusion_delay <= delegation_delay) { - throw taraxa::ConfigException("ficus_hf.pbft_inclusion_delay must be >= 1 && > dpos.delegation_delay"); + if (block_num % pillar_blocks_interval) { + throw taraxa::ConfigException("ficus_hf.block_num % ficus_hf.pillar_blocks_interval must == 0"); } } @@ -93,8 +87,6 @@ Json::Value enc_json(const FicusHardforkConfig& obj) { Json::Value json(Json::objectValue); json["block_num"] = dev::toJS(obj.block_num); json["pillar_blocks_interval"] = dev::toJS(obj.pillar_blocks_interval); - json["pillar_chain_sync_interval"] = dev::toJS(obj.pillar_chain_sync_interval); - json["pbft_inclusion_delay"] = dev::toJS(obj.pbft_inclusion_delay); json["bridge_contract_address"] = dev::toJS(obj.bridge_contract_address); return json; } @@ -102,13 +94,10 @@ Json::Value enc_json(const FicusHardforkConfig& obj) { void dec_json(const Json::Value& json, FicusHardforkConfig& obj) { obj.block_num = json["block_num"].isUInt64() ? dev::getUInt(json["block_num"]) : uint64_t(-1); obj.pillar_blocks_interval = dev::getUInt(json["pillar_blocks_interval"]); - obj.pillar_chain_sync_interval = dev::getUInt(json["pillar_chain_sync_interval"]); - obj.pbft_inclusion_delay = dev::getUInt(json["pbft_inclusion_delay"]); obj.bridge_contract_address = taraxa::addr_t(json["bridge_contract_address"].asString()); } -RLP_FIELDS_DEFINE(FicusHardforkConfig, block_num, pillar_blocks_interval, pillar_chain_sync_interval, - pbft_inclusion_delay, bridge_contract_address) +RLP_FIELDS_DEFINE(FicusHardforkConfig, block_num, pillar_blocks_interval, bridge_contract_address) // Json::Value enc_json(const BambooRedelegation& obj) { // Json::Value json(Json::objectValue); diff --git a/libraries/core_libs/consensus/include/dag/dag.hpp b/libraries/core_libs/consensus/include/dag/dag.hpp index 9fadacd629..9f10ac9fa1 100644 --- a/libraries/core_libs/consensus/include/dag/dag.hpp +++ b/libraries/core_libs/consensus/include/dag/dag.hpp @@ -130,7 +130,8 @@ class vertex_label_writer { vertex_label_writer(Property1 name) : name(name) {} template void operator()(std::ostream &out, const Vertex &v) const { - out << "[label=\"" << name[v].toString().substr(0, 8) << " " << "\"]"; + out << "[label=\"" << name[v].toString().substr(0, 8) << " " + << "\"]"; } private: diff --git a/libraries/core_libs/consensus/include/final_chain/final_chain.hpp b/libraries/core_libs/consensus/include/final_chain/final_chain.hpp index 037dd32377..eeaef817a2 100644 --- a/libraries/core_libs/consensus/include/final_chain/final_chain.hpp +++ b/libraries/core_libs/consensus/include/final_chain/final_chain.hpp @@ -53,7 +53,7 @@ class FinalChain { * @param precommit_ext * @return finalization result */ - virtual std::future> finalize( + virtual std::future> finalize( PeriodData&& period_data, std::vector&& finalized_dag_blk_hashes, std::shared_ptr&& anchor = nullptr) = 0; @@ -270,13 +270,10 @@ class FinalChain { } }; -std::shared_ptr NewFinalChain(const std::shared_ptr& db, const taraxa::FullNodeConfig& config, - const addr_t& node_addr = {}); /** @} */ } // namespace taraxa::final_chain namespace taraxa { using final_chain::FinalChain; -using final_chain::NewFinalChain; } // namespace taraxa diff --git a/libraries/core_libs/consensus/include/final_chain/final_chain_impl.hpp b/libraries/core_libs/consensus/include/final_chain/final_chain_impl.hpp new file mode 100644 index 0000000000..fc462ab093 --- /dev/null +++ b/libraries/core_libs/consensus/include/final_chain/final_chain_impl.hpp @@ -0,0 +1,109 @@ +#pragma once + +#include "final_chain/cache.hpp" +#include "final_chain/final_chain.hpp" +#include "rewards/rewards_stats.hpp" + +namespace taraxa::final_chain { + +class FinalChainImpl final : public FinalChain { + std::shared_ptr db_; + const uint64_t kBlockGasLimit; + StateAPI state_api_; + const bool kLightNode = false; + const uint32_t kMaxLevelsPerPeriod; + rewards::Stats rewards_; + + // It is not prepared to use more then 1 thread. Examine it if you want to change threads count + boost::asio::thread_pool executor_thread_{1}; + + std::atomic num_executed_dag_blk_ = 0; + std::atomic num_executed_trx_ = 0; + + EthBlockNumber delegation_delay_; + + ValueByBlockCache> block_headers_cache_; + ValueByBlockCache> block_hashes_cache_; + ValueByBlockCache transactions_cache_; + ValueByBlockCache> transaction_hashes_cache_; + MapByBlockCache> accounts_cache_; + + ValueByBlockCache total_vote_count_cache_; + MapByBlockCache dpos_vote_count_cache_; + MapByBlockCache dpos_is_eligible_cache_; + + std::condition_variable finalized_cv_; + std::mutex finalized_mtx_; + + std::atomic last_block_number_; + + const HardforksConfig& kHardforksConfig; + LOG_OBJECTS_DEFINE + + public: + FinalChainImpl(const std::shared_ptr& db, const taraxa::FullNodeConfig& config, const addr_t& node_addr); + + void stop() override; + std::future> finalize( + PeriodData&& new_blk, std::vector&& finalized_dag_blk_hashes, + std::shared_ptr&& anchor = nullptr) override; + EthBlockNumber delegation_delay() const override; + SharedTransaction make_bridge_finalization_transaction(); + bool isNeedToFinalize(EthBlockNumber blk_num) const; + std::vector makeSystemTransactions(PbftPeriod blk_num); + std::shared_ptr finalize_(PeriodData&& new_blk, + std::vector&& finalized_dag_blk_hashes, + std::shared_ptr&& anchor); + void prune(EthBlockNumber blk_n) override; + std::shared_ptr append_block(DB::Batch& batch, const addr_t& author, uint64_t timestamp, + uint64_t gas_limit, const h256& state_root, u256 total_reward, + const SharedTransactions& transactions = {}, + const TransactionReceipts& receipts = {}, const bytes& extra_data = {}); + EthBlockNumber last_block_number() const override; + std::optional block_number(const h256& h) const override; + std::optional block_hash(std::optional n = {}) const override; + std::shared_ptr block_header(std::optional n = {}) const override; + std::optional transaction_location(const h256& trx_hash) const override; + std::optional transaction_receipt(const h256& trx_h) const override; + uint64_t transactionCount(std::optional n = {}) const override; + std::shared_ptr transaction_hashes(std::optional n = {}) const override; + const SharedTransactions transactions(std::optional n = {}) const override; + std::vector withBlockBloom(const LogBloom& b, EthBlockNumber from, EthBlockNumber to) const override; + std::optional get_account(const addr_t& addr, + std::optional blk_n = {}) const override; + void update_state_config(const state_api::Config& new_config) override; + h256 get_account_storage(const addr_t& addr, const u256& key, + std::optional blk_n = {}) const override; + bytes get_code(const addr_t& addr, std::optional blk_n = {}) const override; + state_api::ExecutionResult call(const state_api::EVMTransaction& trx, + std::optional blk_n = {}) const override; + std::string trace(std::vector trxs, EthBlockNumber blk_n, + std::optional params = {}) const override; + uint64_t dpos_eligible_total_vote_count(EthBlockNumber blk_num) const override; + uint64_t dpos_eligible_vote_count(EthBlockNumber blk_num, const addr_t& addr) const override; + bool dpos_is_eligible(EthBlockNumber blk_num, const addr_t& addr) const override; + vrf_wrapper::vrf_pk_t dpos_get_vrf_key(EthBlockNumber blk_n, const addr_t& addr) const override; + std::vector dpos_validators_total_stakes(EthBlockNumber blk_num) const override; + virtual uint256_t dpos_total_amount_delegated(EthBlockNumber blk_num) const override; + std::vector dpos_validators_vote_counts(EthBlockNumber blk_num) const override; + void wait_for_finalized() override; + uint64_t dpos_yield(EthBlockNumber blk_num) const override; + u256 dpos_total_supply(EthBlockNumber blk_num) const override; + h256 get_bridge_root(EthBlockNumber blk_num) const override; + h256 get_bridge_epoch(EthBlockNumber blk_num) const override; + + private: + std::shared_ptr get_transaction_hashes(std::optional n = {}) const; + const SharedTransactions get_transactions(std::optional n = {}) const; + std::shared_ptr get_block_header(EthBlockNumber n) const; + std::optional get_block_hash(EthBlockNumber n) const; + EthBlockNumber last_if_absent(const std::optional& client_blk_n) const; + static state_api::EVMTransaction to_evm_transaction(const SharedTransaction& trx); + static void append_evm_transactions(std::vector& evm_trxs, const SharedTransactions& trxs); + BlocksBlooms block_blooms(const h256& chunk_id) const; + static h256 block_blooms_chunk_id(EthBlockNumber level, EthBlockNumber index); + std::vector withBlockBloom(const LogBloom& b, EthBlockNumber from, EthBlockNumber to, + EthBlockNumber level, EthBlockNumber index) const; +}; + +} // namespace taraxa::final_chain \ No newline at end of file diff --git a/libraries/core_libs/consensus/include/pbft/pbft_manager.hpp b/libraries/core_libs/consensus/include/pbft/pbft_manager.hpp index bf0c6d6db6..a93dbdd046 100644 --- a/libraries/core_libs/consensus/include/pbft/pbft_manager.hpp +++ b/libraries/core_libs/consensus/include/pbft/pbft_manager.hpp @@ -598,6 +598,7 @@ class PbftManager { bool already_next_voted_null_block_hash_ = false; bool go_finish_state_ = false; bool loop_back_finish_state_ = false; + bool already_placed_pillar_vote_ = false; // Used to avoid cyclic logging in voting steps that are called repeatedly bool printSecondFinishStepInfo_ = true; diff --git a/libraries/core_libs/consensus/include/pillar_chain/pillar_chain_manager.hpp b/libraries/core_libs/consensus/include/pillar_chain/pillar_chain_manager.hpp index ff88472e2d..fc796f06c9 100644 --- a/libraries/core_libs/consensus/include/pillar_chain/pillar_chain_manager.hpp +++ b/libraries/core_libs/consensus/include/pillar_chain/pillar_chain_manager.hpp @@ -44,31 +44,23 @@ class PillarChainManager { /** * @Process Creates new pillar block * - * @param block_data + * @param block_header * @return pillar block in case block was created, otherwise nullptr */ - std::shared_ptr createPillarBlock(const std::shared_ptr& block_data); + std::shared_ptr createPillarBlock(const std::shared_ptr& block_header); /** * @brief Generate and place pillar vote for provided pillar_block_hash in case the whole pillar block is present and * valid * + * @param period * @param pillar_block_hash * @param node_sk - * @param is_pbft_syncing + * @param broadcast_vote * @return true if vote placed, otherwise false */ - bool genAndPlacePillarVote(const blk_hash_t& pillar_block_hash, const secret_t& node_sk, bool is_pbft_syncing); - - /** - * @brief Check if pillar chain is synced - node has all previous pillar blocks(+votes) and there is > threshold - * votes for latest pillar block. If not, request them - * - * @param block_num - current block number - * - * @return true if synced, otherwise false - */ - bool checkPillarChainSynced(EthBlockNumber block_num) const; + bool genAndPlacePillarVote(PbftPeriod period, const blk_hash_t& pillar_block_hash, const secret_t& node_sk, + bool broadcast_vote); /** * @brief Set network as a weak pointer diff --git a/libraries/core_libs/consensus/include/pillar_chain/pillar_votes.hpp b/libraries/core_libs/consensus/include/pillar_chain/pillar_votes.hpp index 5c20033782..3400509b6e 100644 --- a/libraries/core_libs/consensus/include/pillar_chain/pillar_votes.hpp +++ b/libraries/core_libs/consensus/include/pillar_chain/pillar_votes.hpp @@ -39,14 +39,6 @@ class PillarVotes { */ bool isUniqueVote(const std::shared_ptr vote) const; - /** - * @brief Checks if there above threshold votes for specified period - * - * @param period - * @return - */ - bool hasAboveThresholdVotes(PbftPeriod period, const blk_hash_t& block_hash) const; - /** * @brief Checks if specified period data have been already initialized * diff --git a/libraries/core_libs/consensus/src/final_chain/final_chai_impl.cpp b/libraries/core_libs/consensus/src/final_chain/final_chai_impl.cpp new file mode 100644 index 0000000000..2d35bf26b7 --- /dev/null +++ b/libraries/core_libs/consensus/src/final_chain/final_chai_impl.cpp @@ -0,0 +1,588 @@ +#include "common/encoding_solidity.hpp" +#include "final_chain/final_chain_impl.hpp" +#include "final_chain/trie_common.hpp" + +namespace taraxa::final_chain { + +FinalChainImpl::FinalChainImpl(const std::shared_ptr& db, const taraxa::FullNodeConfig& config, + const addr_t& node_addr) + : db_(db), + kBlockGasLimit(config.genesis.pbft.gas_limit), + state_api_([this](auto n) { return block_hash(n).value_or(ZeroHash()); }, // + config.genesis.state, config.opts_final_chain, + { + db->stateDbStoragePath().string(), + }), + kLightNode(config.is_light_node), + kMaxLevelsPerPeriod(config.max_levels_per_period), + rewards_( + config.genesis.pbft.committee_size, config.genesis.state.hardforks, db_, + [this](EthBlockNumber n) { return dpos_eligible_total_vote_count(n); }, + state_api_.get_last_committed_state_descriptor().blk_num), + block_headers_cache_(config.final_chain_cache_in_blocks, [this](uint64_t blk) { return get_block_header(blk); }), + block_hashes_cache_(config.final_chain_cache_in_blocks, [this](uint64_t blk) { return get_block_hash(blk); }), + transactions_cache_(config.final_chain_cache_in_blocks, [this](uint64_t blk) { return get_transactions(blk); }), + transaction_hashes_cache_(config.final_chain_cache_in_blocks, + [this](uint64_t blk) { return get_transaction_hashes(blk); }), + accounts_cache_(config.final_chain_cache_in_blocks, + [this](uint64_t blk, const addr_t& addr) { return state_api_.get_account(blk, addr); }), + total_vote_count_cache_(config.final_chain_cache_in_blocks, + [this](uint64_t blk) { return state_api_.dpos_eligible_total_vote_count(blk); }), + dpos_vote_count_cache_( + config.final_chain_cache_in_blocks, + [this](uint64_t blk, const addr_t& addr) { return state_api_.dpos_eligible_vote_count(blk, addr); }), + dpos_is_eligible_cache_( + config.final_chain_cache_in_blocks, + [this](uint64_t blk, const addr_t& addr) { return state_api_.dpos_is_eligible(blk, addr); }), + kHardforksConfig(config.genesis.state.hardforks) { + LOG_OBJECTS_CREATE("EXECUTOR"); + num_executed_dag_blk_ = db_->getStatusField(taraxa::StatusDbField::ExecutedBlkCount); + num_executed_trx_ = db_->getStatusField(taraxa::StatusDbField::ExecutedTrxCount); + auto state_db_descriptor = state_api_.get_last_committed_state_descriptor(); + auto last_blk_num = db_->lookup_int(DBMetaKeys::LAST_NUMBER, DB::Columns::final_chain_meta); + // If we don't have genesis block in db then create and push it + if (!last_blk_num) [[unlikely]] { + auto batch = db_->createWriteBatch(); + auto header = append_block(batch, addr_t(), config.genesis.dag_genesis_block.getTimestamp(), kBlockGasLimit, + state_db_descriptor.state_root, u256(0)); + + block_headers_cache_.append(header->number, header); + last_block_number_ = header->number; + db_->commitWriteBatch(batch); + } else { + // We need to recover latest changes as there was shutdown inside finalize function + if (*last_blk_num != state_db_descriptor.blk_num) [[unlikely]] { + auto batch = db_->createWriteBatch(); + for (auto block_n = *last_blk_num; block_n != state_db_descriptor.blk_num; --block_n) { + auto raw_period_data = db_->getPeriodDataRaw(block_n); + assert(raw_period_data.size() > 0); + + const PeriodData period_data(std::move(raw_period_data)); + if (period_data.transactions.size()) { + num_executed_dag_blk_ -= period_data.dag_blocks.size(); + num_executed_trx_ -= period_data.transactions.size(); + } + auto period_system_transactions = db_->getPeriodSystemTransactionsHashes(block_n); + num_executed_trx_ -= period_system_transactions.size(); + } + db_->insert(batch, DB::Columns::status, StatusDbField::ExecutedBlkCount, num_executed_dag_blk_.load()); + db_->insert(batch, DB::Columns::status, StatusDbField::ExecutedTrxCount, num_executed_trx_.load()); + db_->insert(batch, DB::Columns::final_chain_meta, DBMetaKeys::LAST_NUMBER, state_db_descriptor.blk_num); + db_->commitWriteBatch(batch); + last_blk_num = state_db_descriptor.blk_num; + } + last_block_number_ = *last_blk_num; + + int64_t start = 0; + if (*last_blk_num > 5) { + start = *last_blk_num - 5; + } + for (uint64_t num = start; num <= *last_blk_num; ++num) { + block_headers_cache_.get(num); + } + } + + delegation_delay_ = config.genesis.state.dpos.delegation_delay; + const auto kPruneBlocksToKeep = kDagExpiryLevelLimit + kMaxLevelsPerPeriod + 1; + if ((config.db_config.prune_state_db || kLightNode) && last_blk_num.has_value() && + *last_blk_num > kPruneBlocksToKeep) { + LOG(log_si_) << "Pruning state db, this might take several minutes"; + prune(*last_blk_num - kPruneBlocksToKeep); + LOG(log_si_) << "Pruning state db complete"; + } +} + +void FinalChainImpl::stop() { executor_thread_.join(); } + +std::future> FinalChainImpl::finalize( + PeriodData&& new_blk, std::vector&& finalized_dag_blk_hashes, std::shared_ptr&& anchor) { + auto p = std::make_shared>>(); + boost::asio::post(executor_thread_, [this, new_blk = std::move(new_blk), + finalized_dag_blk_hashes = std::move(finalized_dag_blk_hashes), + anchor_block = std::move(anchor), p]() mutable { + p->set_value(finalize_(std::move(new_blk), std::move(finalized_dag_blk_hashes), std::move(anchor_block))); + finalized_cv_.notify_one(); + }); + return p->get_future(); +} + +EthBlockNumber FinalChainImpl::delegation_delay() const { return delegation_delay_; } + +SharedTransaction FinalChainImpl::make_bridge_finalization_transaction() { + const static auto finalize_method = util::EncodingSolidity::packFunctionCall("finalizeEpoch()"); + auto account = get_account(kTaraxaSystemAccount).value_or(state_api::ZeroAccount); + + auto trx = std::make_shared(account.nonce, 0, 0, kBlockGasLimit, finalize_method, + kHardforksConfig.ficus_hf.bridge_contract_address); + return trx; +} + +bool FinalChainImpl::isNeedToFinalize(EthBlockNumber blk_num) const { + const static auto get_bridge_root_method = util::EncodingSolidity::packFunctionCall("shouldFinalizeEpoch()"); + return u256(call(state_api::EVMTransaction{dev::ZeroAddress, 1, kHardforksConfig.ficus_hf.bridge_contract_address, + state_api::ZeroAccount.nonce, 0, 10000000, get_bridge_root_method}, + blk_num) + .code_retval) + .convert_to(); +} + +std::vector FinalChainImpl::makeSystemTransactions(PbftPeriod blk_num) { + std::vector system_transactions; + if (kHardforksConfig.ficus_hf.isPillarBlockPeriod(blk_num)) { + if (const auto bridge_contract = get_account(kHardforksConfig.ficus_hf.bridge_contract_address); bridge_contract) { + if (bridge_contract->code_size && isNeedToFinalize(blk_num - 1)) { + auto finalize_trx = make_bridge_finalization_transaction(); + system_transactions.push_back(finalize_trx); + } + } + } + return system_transactions; +} + +std::shared_ptr FinalChainImpl::finalize_(PeriodData&& new_blk, + std::vector&& finalized_dag_blk_hashes, + std::shared_ptr&& anchor) { + auto batch = db_->createWriteBatch(); + + block_applying_emitter_.emit(block_header()->number + 1); + + /* + // Any dag block producer producing duplicate dag blocks on same level should be slashed + + + std::map, uint32_t> dag_blocks_per_addr_and_level; + std::unordered_map duplicate_dag_blocks_count; + + for (const auto& block : new_blk.dag_blocks) { + dag_blocks_per_addr_and_level[{block.getSender(), block.getLevel()}]++; + } + + for (const auto& it : dag_blocks_per_addr_and_level) { + if (it.second > 1) { + duplicate_dag_blocks_count[it.first.first] += it.second - 1; + } + } */ + + auto system_transactions = makeSystemTransactions(new_blk.pbft_blk->getPeriod()); + + auto all_transactions = new_blk.transactions; + all_transactions.insert(all_transactions.end(), system_transactions.begin(), system_transactions.end()); + std::vector evm_trxs; + append_evm_transactions(evm_trxs, all_transactions); + + const auto& [exec_results] = state_api_.execute_transactions( + {new_blk.pbft_blk->getBeneficiary(), kBlockGasLimit, new_blk.pbft_blk->getTimestamp(), BlockHeader::difficulty()}, + evm_trxs); + TransactionReceipts receipts; + receipts.reserve(exec_results.size()); + std::vector transactions_gas_used; + transactions_gas_used.reserve(exec_results.size()); + + gas_t cumulative_gas_used = 0; + for (const auto& r : exec_results) { + LogEntries logs; + logs.reserve(r.logs.size()); + std::transform(r.logs.cbegin(), r.logs.cend(), std::back_inserter(logs), [](const auto& l) { + return LogEntry{l.address, l.topics, l.data}; + }); + transactions_gas_used.push_back(r.gas_used); + receipts.emplace_back(TransactionReceipt{ + r.code_err.empty() && r.consensus_err.empty(), + r.gas_used, + cumulative_gas_used += r.gas_used, + std::move(logs), + r.new_contract_addr ? std::optional(r.new_contract_addr) : std::nullopt, + }); + } + + auto rewards_stats = rewards_.processStats(new_blk, transactions_gas_used, batch); + const auto& [state_root, total_reward] = state_api_.distribute_rewards(rewards_stats); + + auto blk_header = + append_block(batch, new_blk.pbft_blk->getBeneficiary(), new_blk.pbft_blk->getTimestamp(), kBlockGasLimit, + state_root, total_reward, all_transactions, receipts, new_blk.pbft_blk->getExtraDataRlp()); + + // Update number of executed DAG blocks and transactions + auto num_executed_dag_blk = num_executed_dag_blk_ + finalized_dag_blk_hashes.size(); + auto num_executed_trx = num_executed_trx_ + all_transactions.size(); + if (!finalized_dag_blk_hashes.empty()) { + db_->insert(batch, DB::Columns::status, StatusDbField::ExecutedBlkCount, num_executed_dag_blk); + db_->insert(batch, DB::Columns::status, StatusDbField::ExecutedTrxCount, num_executed_trx); + LOG(log_nf_) << "Executed dag blocks #" << num_executed_dag_blk_ - finalized_dag_blk_hashes.size() << "-" + << num_executed_dag_blk_ - 1 << " , Transactions count: " << all_transactions.size(); + } + + //// Update DAG lvl mapping + if (anchor) { + db_->addProposalPeriodDagLevelsMapToBatch(anchor->getLevel() + kMaxLevelsPerPeriod, new_blk.pbft_blk->getPeriod(), + batch); + } + //// + + //// Commit system transactions + if (!system_transactions.empty()) { + db_->addPeriodSystemTransactions(batch, system_transactions, new_blk.pbft_blk->getPeriod()); + auto position = new_blk.transactions.size() + 1; + for (const auto& trx : system_transactions) { + db_->addSystemTransactionToBatch(batch, trx); + db_->addTransactionLocationToBatch(batch, trx->getHash(), new_blk.pbft_blk->getPeriod(), position, + true /*system_trx*/); + position++; + } + } + //// + + auto result = std::make_shared(FinalizationResult{ + { + new_blk.pbft_blk->getBeneficiary(), + new_blk.pbft_blk->getTimestamp(), + std::move(finalized_dag_blk_hashes), + new_blk.pbft_blk->getBlockHash(), + }, + blk_header, + std::move(all_transactions), + std::move(receipts), + }); + + // Please do not change order of these three lines :) + db_->commitWriteBatch(batch); + state_api_.transition_state_commit(); + rewards_.clear(new_blk.pbft_blk->getPeriod()); + + num_executed_dag_blk_ = num_executed_dag_blk; + num_executed_trx_ = num_executed_trx; + block_headers_cache_.append(blk_header->number, blk_header); + last_block_number_ = blk_header->number; + block_finalized_emitter_.emit(result); + LOG(log_nf_) << " successful finalize block " << result->hash << " with number " << blk_header->number; + + // Creates snapshot if needed + if (db_->createSnapshot(blk_header->number)) { + state_api_.create_snapshot(blk_header->number); + } + + return result; +} + +void FinalChainImpl::prune(EthBlockNumber blk_n) { + LOG(log_nf_) << "Pruning data older than " << blk_n; + auto last_block_to_keep = get_block_header(blk_n); + if (last_block_to_keep) { + auto block_to_keep = last_block_to_keep; + std::vector state_root_to_keep; + while (block_to_keep) { + state_root_to_keep.push_back(block_to_keep->state_root); + block_to_keep = get_block_header(block_to_keep->number + 1); + } + auto block_to_prune = get_block_header(last_block_to_keep->number - 1); + while (block_to_prune && block_to_prune->number > 0) { + db_->remove(DB::Columns::final_chain_blk_by_number, block_to_prune->number); + db_->remove(DB::Columns::final_chain_blk_hash_by_number, block_to_prune->number); + db_->remove(DB::Columns::final_chain_blk_number_by_hash, block_to_prune->hash); + block_to_prune = get_block_header(block_to_prune->number - 1); + } + + db_->compactColumn(DB::Columns::final_chain_blk_by_number); + db_->compactColumn(DB::Columns::final_chain_blk_hash_by_number); + db_->compactColumn(DB::Columns::final_chain_blk_number_by_hash); + + state_api_.prune(state_root_to_keep, last_block_to_keep->number); + } +} + +std::shared_ptr FinalChainImpl::append_block(DB::Batch& batch, const addr_t& author, uint64_t timestamp, + uint64_t gas_limit, const h256& state_root, u256 total_reward, + const SharedTransactions& transactions, + const TransactionReceipts& receipts, + const bytes& extra_data) { + auto blk_header_ptr = std::make_shared(); + auto& blk_header = *blk_header_ptr; + auto last_block = block_header(); + blk_header.number = last_block ? last_block->number + 1 : 0; + blk_header.parent_hash = last_block ? last_block->hash : h256(); + blk_header.author = author; + blk_header.timestamp = timestamp; + blk_header.state_root = state_root; + blk_header.gas_used = receipts.empty() ? 0 : receipts.back().cumulative_gas_used; + blk_header.gas_limit = gas_limit; + blk_header.total_reward = total_reward; + blk_header.extra_data = extra_data; + dev::BytesMap trxs_trie, receipts_trie; + dev::RLPStream rlp_strm; + auto trx_idx = 0; + for (; trx_idx < transactions.size(); ++trx_idx) { + const auto& trx = transactions[trx_idx]; + auto i_rlp = util::rlp_enc(rlp_strm, trx_idx); + trxs_trie[i_rlp] = trx->rlp(); + + const auto& receipt = receipts[trx_idx]; + receipts_trie[i_rlp] = util::rlp_enc(rlp_strm, receipt); + db_->insert(batch, DB::Columns::final_chain_receipt_by_trx_hash, trx->getHash(), rlp_strm.out()); + + blk_header.log_bloom |= receipt.bloom(); + } + blk_header.transactions_root = hash256(trxs_trie); + blk_header.receipts_root = hash256(receipts_trie); + rlp_strm.clear(), blk_header.ethereum_rlp(rlp_strm); + blk_header.hash = dev::sha3(rlp_strm.out()); + db_->insert(batch, DB::Columns::final_chain_blk_by_number, blk_header.number, util::rlp_enc(rlp_strm, blk_header)); + auto log_bloom_for_index = blk_header.log_bloom; + log_bloom_for_index.shiftBloom<3>(sha3(blk_header.author.ref())); + for (uint64_t level = 0, index = blk_header.number; level < c_bloomIndexLevels; ++level, index /= c_bloomIndexSize) { + auto chunk_id = block_blooms_chunk_id(level, index / c_bloomIndexSize); + auto chunk_to_alter = block_blooms(chunk_id); + chunk_to_alter[index % c_bloomIndexSize] |= log_bloom_for_index; + db_->insert(batch, DB::Columns::final_chain_log_blooms_index, chunk_id, util::rlp_enc(rlp_strm, chunk_to_alter)); + } + db_->insert(batch, DB::Columns::final_chain_blk_hash_by_number, blk_header.number, blk_header.hash); + db_->insert(batch, DB::Columns::final_chain_blk_number_by_hash, blk_header.hash, blk_header.number); + db_->insert(batch, DB::Columns::final_chain_meta, DBMetaKeys::LAST_NUMBER, blk_header.number); + + return blk_header_ptr; +} + +EthBlockNumber FinalChainImpl::last_block_number() const { return last_block_number_; } + +std::optional FinalChainImpl::block_number(const h256& h) const { + return db_->lookup_int(h, DB::Columns::final_chain_blk_number_by_hash); +} + +std::optional FinalChainImpl::block_hash(std::optional n) const { + return block_hashes_cache_.get(last_if_absent(n)); +} + +std::shared_ptr FinalChainImpl::block_header(std::optional n) const { + if (!n) { + return block_headers_cache_.last(); + } + return block_headers_cache_.get(*n); +} + +std::optional FinalChainImpl::transaction_location(const h256& trx_hash) const { + return db_->getTransactionLocation(trx_hash); +} + +std::optional FinalChainImpl::transaction_receipt(const h256& trx_h) const { + auto raw = db_->lookup(trx_h, DB::Columns::final_chain_receipt_by_trx_hash); + if (raw.empty()) { + return {}; + } + TransactionReceipt ret; + ret.rlp(dev::RLP(raw)); + return ret; +} + +uint64_t FinalChainImpl::transactionCount(std::optional n) const { + return db_->getTransactionCount(last_if_absent(n)); +} + +std::shared_ptr FinalChainImpl::transaction_hashes(std::optional n) const { + return transaction_hashes_cache_.get(last_if_absent(n)); +} + +const SharedTransactions FinalChainImpl::transactions(std::optional n) const { + return transactions_cache_.get(last_if_absent(n)); +} + +std::vector FinalChainImpl::withBlockBloom(const LogBloom& b, EthBlockNumber from, + EthBlockNumber to) const { + std::vector ret; + // start from the top-level + auto u = int_pow(c_bloomIndexSize, c_bloomIndexLevels); + // run through each of the top-level blocks + for (EthBlockNumber index = from / u; index <= (to + u - 1) / u; ++index) { + dev::operator+=(ret, withBlockBloom(b, from, to, c_bloomIndexLevels - 1, index)); + } + return ret; +} + +std::optional FinalChainImpl::get_account(const addr_t& addr, + std::optional blk_n) const { + return accounts_cache_.get(last_if_absent(blk_n), addr); +} + +void FinalChainImpl::update_state_config(const state_api::Config& new_config) { + delegation_delay_ = new_config.dpos.delegation_delay; + state_api_.update_state_config(new_config); +} + +h256 FinalChainImpl::get_account_storage(const addr_t& addr, const u256& key, + std::optional blk_n) const { + return state_api_.get_account_storage(last_if_absent(blk_n), addr, key); +} + +bytes FinalChainImpl::get_code(const addr_t& addr, std::optional blk_n) const { + return state_api_.get_code_by_address(last_if_absent(blk_n), addr); +} + +state_api::ExecutionResult FinalChainImpl::call(const state_api::EVMTransaction& trx, + std::optional blk_n) const { + auto const blk_header = block_header(last_if_absent(blk_n)); + if (!blk_header) { + throw std::runtime_error("Future block"); + } + return state_api_.dry_run_transaction(blk_header->number, + { + blk_header->author, + blk_header->gas_limit, + blk_header->timestamp, + BlockHeader::difficulty(), + }, + trx); +} + +std::string FinalChainImpl::trace(std::vector trxs, EthBlockNumber blk_n, + std::optional params) const { + const auto blk_header = block_header(last_if_absent(blk_n)); + if (!blk_header) { + throw std::runtime_error("Future block"); + } + return dev::asString(state_api_.trace(blk_header->number, + { + blk_header->author, + blk_header->gas_limit, + blk_header->timestamp, + BlockHeader::difficulty(), + }, + trxs, params)); +} + +uint64_t FinalChainImpl::dpos_eligible_total_vote_count(EthBlockNumber blk_num) const { + return total_vote_count_cache_.get(blk_num); +} + +uint64_t FinalChainImpl::dpos_eligible_vote_count(EthBlockNumber blk_num, const addr_t& addr) const { + return dpos_vote_count_cache_.get(blk_num, addr); +} + +bool FinalChainImpl::dpos_is_eligible(EthBlockNumber blk_num, const addr_t& addr) const { + return dpos_is_eligible_cache_.get(blk_num, addr); +} + +vrf_wrapper::vrf_pk_t FinalChainImpl::dpos_get_vrf_key(EthBlockNumber blk_n, const addr_t& addr) const { + return state_api_.dpos_get_vrf_key(blk_n, addr); +} + +std::vector FinalChainImpl::dpos_validators_total_stakes(EthBlockNumber blk_num) const { + return state_api_.dpos_validators_total_stakes(blk_num); +} + +uint256_t FinalChainImpl::dpos_total_amount_delegated(EthBlockNumber blk_num) const { + return state_api_.dpos_total_amount_delegated(blk_num); +} + +std::vector FinalChainImpl::dpos_validators_vote_counts(EthBlockNumber blk_num) const { + return state_api_.dpos_validators_vote_counts(blk_num); +} + +void FinalChainImpl::wait_for_finalized() { + std::unique_lock lck(finalized_mtx_); + finalized_cv_.wait_for(lck, std::chrono::milliseconds(10)); +} + +uint64_t FinalChainImpl::dpos_yield(EthBlockNumber blk_num) const { return state_api_.dpos_yield(blk_num); } + +u256 FinalChainImpl::dpos_total_supply(EthBlockNumber blk_num) const { return state_api_.dpos_total_supply(blk_num); } + +h256 FinalChainImpl::get_bridge_root(EthBlockNumber blk_num) const { + const static auto get_bridge_root_method = util::EncodingSolidity::packFunctionCall("getBridgeRoot()"); + return h256(call(state_api::EVMTransaction{dev::ZeroAddress, 1, kHardforksConfig.ficus_hf.bridge_contract_address, + state_api::ZeroAccount.nonce, 0, 10000000, get_bridge_root_method}, + blk_num) + .code_retval); +} + +h256 FinalChainImpl::get_bridge_epoch(EthBlockNumber blk_num) const { + const static auto get_bridge_epoch_method = util::EncodingSolidity::packFunctionCall("finalizedEpoch()"); + return h256(call(state_api::EVMTransaction{dev::ZeroAddress, 1, kHardforksConfig.ficus_hf.bridge_contract_address, + state_api::ZeroAccount.nonce, 0, 10000000, get_bridge_epoch_method}, + blk_num) + .code_retval); +} + +std::shared_ptr FinalChainImpl::get_transaction_hashes(std::optional n) const { + const auto& trxs = db_->getPeriodTransactions(last_if_absent(n)); + auto ret = std::make_shared(); + if (!trxs) { + return ret; + } + ret->reserve(trxs->size()); + std::transform(trxs->cbegin(), trxs->cend(), std::back_inserter(*ret), + [](const auto& trx) { return trx->getHash(); }); + return ret; +} + +const SharedTransactions FinalChainImpl::get_transactions(std::optional n) const { + if (auto trxs = db_->getPeriodTransactions(last_if_absent(n))) { + return *trxs; + } + return {}; +} + +std::shared_ptr FinalChainImpl::get_block_header(EthBlockNumber n) const { + if (auto raw = db_->lookup(n, DB::Columns::final_chain_blk_by_number); !raw.empty()) { + auto ret = std::make_shared(); + ret->rlp(dev::RLP(raw)); + return ret; + } + return {}; +} + +std::optional FinalChainImpl::get_block_hash(EthBlockNumber n) const { + auto raw = db_->lookup(n, DB::Columns::final_chain_blk_hash_by_number); + if (raw.empty()) { + return {}; + } + return h256(raw, h256::FromBinary); +} + +EthBlockNumber FinalChainImpl::last_if_absent(const std::optional& client_blk_n) const { + return client_blk_n ? *client_blk_n : last_block_number(); +} + +state_api::EVMTransaction FinalChainImpl::to_evm_transaction(const SharedTransaction& trx) { + return state_api::EVMTransaction{ + trx->getSender(), trx->getGasPrice(), trx->getReceiver(), trx->getNonce(), + trx->getValue(), trx->getGas(), trx->getData(), + }; +} + +void FinalChainImpl::append_evm_transactions(std::vector& evm_trxs, + const SharedTransactions& trxs) { + std::transform(trxs.cbegin(), trxs.cend(), std::back_inserter(evm_trxs), + [](const auto& trx) { return to_evm_transaction(trx); }); +} + +BlocksBlooms FinalChainImpl::block_blooms(const h256& chunk_id) const { + if (auto raw = db_->lookup(chunk_id, DB::Columns::final_chain_log_blooms_index); !raw.empty()) { + return dev::RLP(raw).toArray(); + } + return {}; +} + +h256 FinalChainImpl::block_blooms_chunk_id(EthBlockNumber level, EthBlockNumber index) { + return h256(index * 0xff + level); +} + +std::vector FinalChainImpl::withBlockBloom(const LogBloom& b, EthBlockNumber from, EthBlockNumber to, + EthBlockNumber level, EthBlockNumber index) const { + std::vector ret; + auto uCourse = int_pow(c_bloomIndexSize, level + 1); + auto uFine = int_pow(c_bloomIndexSize, level); + auto obegin = index == from / uCourse ? from / uFine % c_bloomIndexSize : 0; + auto oend = index == to / uCourse ? (to / uFine) % c_bloomIndexSize + 1 : c_bloomIndexSize; + auto bb = block_blooms(block_blooms_chunk_id(level, index)); + for (auto o = obegin; o < oend; ++o) { + if (bb[o].contains(b)) { + // This level has something like what we want. + if (level > 0) { + dev::operator+=(ret, withBlockBloom(b, from, to, level - 1, o + index * c_bloomIndexSize)); + } else { + ret.push_back(o + index * c_bloomIndexSize); + } + } + } + return ret; +} + +} // namespace taraxa::final_chain \ No newline at end of file diff --git a/libraries/core_libs/consensus/src/final_chain/final_chain.cpp b/libraries/core_libs/consensus/src/final_chain/final_chain.cpp deleted file mode 100644 index 4d593ab0b7..0000000000 --- a/libraries/core_libs/consensus/src/final_chain/final_chain.cpp +++ /dev/null @@ -1,638 +0,0 @@ -#include "final_chain/final_chain.hpp" - -#include -#include -#include - -#include "common/constants.hpp" -#include "common/encoding_solidity.hpp" -#include "final_chain/cache.hpp" -#include "final_chain/trie_common.hpp" -#include "rewards/rewards_stats.hpp" -#include "transaction/system_transaction.hpp" - -namespace taraxa::final_chain { - -class FinalChainImpl final : public FinalChain { - std::shared_ptr db_; - const uint64_t kBlockGasLimit; - StateAPI state_api_; - const bool kLightNode = false; - const uint32_t kMaxLevelsPerPeriod; - rewards::Stats rewards_; - - // It is not prepared to use more then 1 thread. Examine it if you want to change threads count - boost::asio::thread_pool executor_thread_{1}; - - std::atomic num_executed_dag_blk_ = 0; - std::atomic num_executed_trx_ = 0; - - EthBlockNumber delegation_delay_; - - ValueByBlockCache> block_headers_cache_; - ValueByBlockCache> block_hashes_cache_; - ValueByBlockCache transactions_cache_; - ValueByBlockCache> transaction_hashes_cache_; - MapByBlockCache> accounts_cache_; - - ValueByBlockCache total_vote_count_cache_; - MapByBlockCache dpos_vote_count_cache_; - MapByBlockCache dpos_is_eligible_cache_; - - std::condition_variable finalized_cv_; - std::mutex finalized_mtx_; - - std::atomic last_block_number_; - - const HardforksConfig& kHardforksConfig; - LOG_OBJECTS_DEFINE - - public: - FinalChainImpl(const std::shared_ptr& db, const taraxa::FullNodeConfig& config, const addr_t& node_addr) - : db_(db), - kBlockGasLimit(config.genesis.pbft.gas_limit), - state_api_([this](auto n) { return block_hash(n).value_or(ZeroHash()); }, // - config.genesis.state, config.opts_final_chain, - { - db->stateDbStoragePath().string(), - }), - kLightNode(config.is_light_node), - kMaxLevelsPerPeriod(config.max_levels_per_period), - rewards_( - config.genesis.pbft.committee_size, config.genesis.state.hardforks, db_, - [this](EthBlockNumber n) { return dpos_eligible_total_vote_count(n); }, - state_api_.get_last_committed_state_descriptor().blk_num), - block_headers_cache_(config.final_chain_cache_in_blocks, - [this](uint64_t blk) { return get_block_header(blk); }), - block_hashes_cache_(config.final_chain_cache_in_blocks, [this](uint64_t blk) { return get_block_hash(blk); }), - transactions_cache_(config.final_chain_cache_in_blocks, [this](uint64_t blk) { return get_transactions(blk); }), - transaction_hashes_cache_(config.final_chain_cache_in_blocks, - [this](uint64_t blk) { return get_transaction_hashes(blk); }), - accounts_cache_(config.final_chain_cache_in_blocks, - [this](uint64_t blk, const addr_t& addr) { return state_api_.get_account(blk, addr); }), - total_vote_count_cache_(config.final_chain_cache_in_blocks, - [this](uint64_t blk) { return state_api_.dpos_eligible_total_vote_count(blk); }), - dpos_vote_count_cache_( - config.final_chain_cache_in_blocks, - [this](uint64_t blk, const addr_t& addr) { return state_api_.dpos_eligible_vote_count(blk, addr); }), - dpos_is_eligible_cache_( - config.final_chain_cache_in_blocks, - [this](uint64_t blk, const addr_t& addr) { return state_api_.dpos_is_eligible(blk, addr); }), - kHardforksConfig(config.genesis.state.hardforks) { - LOG_OBJECTS_CREATE("EXECUTOR"); - num_executed_dag_blk_ = db_->getStatusField(taraxa::StatusDbField::ExecutedBlkCount); - num_executed_trx_ = db_->getStatusField(taraxa::StatusDbField::ExecutedTrxCount); - auto state_db_descriptor = state_api_.get_last_committed_state_descriptor(); - auto last_blk_num = db_->lookup_int(DBMetaKeys::LAST_NUMBER, DB::Columns::final_chain_meta); - // If we don't have genesis block in db then create and push it - if (!last_blk_num) [[unlikely]] { - auto batch = db_->createWriteBatch(); - auto header = append_block(batch, addr_t(), config.genesis.dag_genesis_block.getTimestamp(), kBlockGasLimit, - state_db_descriptor.state_root, u256(0)); - - block_headers_cache_.append(header->number, header); - last_block_number_ = header->number; - db_->commitWriteBatch(batch); - } else { - // We need to recover latest changes as there was shutdown inside finalize function - if (*last_blk_num != state_db_descriptor.blk_num) [[unlikely]] { - auto batch = db_->createWriteBatch(); - for (auto block_n = *last_blk_num; block_n != state_db_descriptor.blk_num; --block_n) { - auto raw_period_data = db_->getPeriodDataRaw(block_n); - assert(raw_period_data.size() > 0); - - const PeriodData period_data(std::move(raw_period_data)); - if (period_data.transactions.size()) { - num_executed_dag_blk_ -= period_data.dag_blocks.size(); - num_executed_trx_ -= period_data.transactions.size(); - } - auto period_system_transactions = db_->getPeriodSystemTransactionsHashes(block_n); - num_executed_trx_ -= period_system_transactions.size(); - } - db_->insert(batch, DB::Columns::status, StatusDbField::ExecutedBlkCount, num_executed_dag_blk_.load()); - db_->insert(batch, DB::Columns::status, StatusDbField::ExecutedTrxCount, num_executed_trx_.load()); - db_->insert(batch, DB::Columns::final_chain_meta, DBMetaKeys::LAST_NUMBER, state_db_descriptor.blk_num); - db_->commitWriteBatch(batch); - last_blk_num = state_db_descriptor.blk_num; - } - last_block_number_ = *last_blk_num; - - int64_t start = 0; - if (*last_blk_num > 5) { - start = *last_blk_num - 5; - } - for (uint64_t num = start; num <= *last_blk_num; ++num) { - block_headers_cache_.get(num); - } - } - - delegation_delay_ = config.genesis.state.dpos.delegation_delay; - const auto kPruneBlocksToKeep = kDagExpiryLevelLimit + kMaxLevelsPerPeriod + 1; - if ((config.db_config.prune_state_db || kLightNode) && last_blk_num.has_value() && - *last_blk_num > kPruneBlocksToKeep) { - LOG(log_si_) << "Pruning state db, this might take several minutes"; - prune(*last_blk_num - kPruneBlocksToKeep); - LOG(log_si_) << "Pruning state db complete"; - } - } - - void stop() override { executor_thread_.join(); } - - std::future> finalize( - PeriodData&& new_blk, std::vector&& finalized_dag_blk_hashes, - std::shared_ptr&& anchor = nullptr) override { - auto p = std::make_shared>>(); - boost::asio::post(executor_thread_, [this, new_blk = std::move(new_blk), - finalized_dag_blk_hashes = std::move(finalized_dag_blk_hashes), - anchor_block = std::move(anchor), p]() mutable { - p->set_value(finalize_(std::move(new_blk), std::move(finalized_dag_blk_hashes), std::move(anchor_block))); - finalized_cv_.notify_one(); - }); - return p->get_future(); - } - - EthBlockNumber delegation_delay() const override { return delegation_delay_; } - - SharedTransaction make_bridge_finalization_transaction() { - const static auto finalize_method = util::EncodingSolidity::packFunctionCall("finalizeEpoch()"); - auto account = get_account(kTaraxaSystemAccount).value_or(state_api::ZeroAccount); - - auto trx = std::make_shared(account.nonce, 0, 0, kBlockGasLimit, finalize_method, - kHardforksConfig.ficus_hf.bridge_contract_address); - return trx; - } - - bool isNeedToFinalize(EthBlockNumber blk_num) const { - const static auto get_bridge_root_method = util::EncodingSolidity::packFunctionCall("shouldFinalizeEpoch()"); - return u256(call(state_api::EVMTransaction{dev::ZeroAddress, 1, kHardforksConfig.ficus_hf.bridge_contract_address, - state_api::ZeroAccount.nonce, 0, 10000000, get_bridge_root_method}, - blk_num) - .code_retval) - .convert_to(); - } - - std::vector makeSystemTransactions(PbftPeriod blk_num) { - std::vector system_transactions; - if (kHardforksConfig.ficus_hf.isPillarBlockPeriod(blk_num)) { - if (const auto bridge_contract = get_account(kHardforksConfig.ficus_hf.bridge_contract_address); - bridge_contract) { - if (bridge_contract->code_size && isNeedToFinalize(blk_num - 1)) { - auto finalize_trx = make_bridge_finalization_transaction(); - system_transactions.push_back(finalize_trx); - } - } - } - return system_transactions; - } - - std::shared_ptr finalize_(PeriodData&& new_blk, - std::vector&& finalized_dag_blk_hashes, - std::shared_ptr&& anchor) { - auto batch = db_->createWriteBatch(); - - block_applying_emitter_.emit(block_header()->number + 1); - - /* - // Any dag block producer producing duplicate dag blocks on same level should be slashed - - - std::map, uint32_t> dag_blocks_per_addr_and_level; - std::unordered_map duplicate_dag_blocks_count; - - for (const auto& block : new_blk.dag_blocks) { - dag_blocks_per_addr_and_level[{block.getSender(), block.getLevel()}]++; - } - - for (const auto& it : dag_blocks_per_addr_and_level) { - if (it.second > 1) { - duplicate_dag_blocks_count[it.first.first] += it.second - 1; - } - } */ - - auto system_transactions = makeSystemTransactions(new_blk.pbft_blk->getPeriod()); - - auto all_transactions = new_blk.transactions; - all_transactions.insert(all_transactions.end(), system_transactions.begin(), system_transactions.end()); - std::vector evm_trxs; - append_evm_transactions(evm_trxs, all_transactions); - - const auto& [exec_results] = - state_api_.execute_transactions({new_blk.pbft_blk->getBeneficiary(), kBlockGasLimit, - new_blk.pbft_blk->getTimestamp(), BlockHeader::difficulty()}, - evm_trxs); - TransactionReceipts receipts; - receipts.reserve(exec_results.size()); - std::vector transactions_gas_used; - transactions_gas_used.reserve(exec_results.size()); - - gas_t cumulative_gas_used = 0; - for (const auto& r : exec_results) { - LogEntries logs; - logs.reserve(r.logs.size()); - std::transform(r.logs.cbegin(), r.logs.cend(), std::back_inserter(logs), - [](const auto& l) { return LogEntry{l.address, l.topics, l.data}; }); - transactions_gas_used.push_back(r.gas_used); - receipts.emplace_back(TransactionReceipt{ - r.code_err.empty() && r.consensus_err.empty(), - r.gas_used, - cumulative_gas_used += r.gas_used, - std::move(logs), - r.new_contract_addr ? std::optional(r.new_contract_addr) : std::nullopt, - }); - } - - auto rewards_stats = rewards_.processStats(new_blk, transactions_gas_used, batch); - const auto& [state_root, total_reward] = state_api_.distribute_rewards(rewards_stats); - - auto blk_header = - append_block(batch, new_blk.pbft_blk->getBeneficiary(), new_blk.pbft_blk->getTimestamp(), kBlockGasLimit, - state_root, total_reward, all_transactions, receipts, new_blk.pbft_blk->getExtraDataRlp()); - - // Update number of executed DAG blocks and transactions - auto num_executed_dag_blk = num_executed_dag_blk_ + finalized_dag_blk_hashes.size(); - auto num_executed_trx = num_executed_trx_ + all_transactions.size(); - if (!finalized_dag_blk_hashes.empty()) { - db_->insert(batch, DB::Columns::status, StatusDbField::ExecutedBlkCount, num_executed_dag_blk); - db_->insert(batch, DB::Columns::status, StatusDbField::ExecutedTrxCount, num_executed_trx); - LOG(log_nf_) << "Executed dag blocks #" << num_executed_dag_blk_ - finalized_dag_blk_hashes.size() << "-" - << num_executed_dag_blk_ - 1 << " , Transactions count: " << all_transactions.size(); - } - - //// Update DAG lvl mapping - if (anchor) { - db_->addProposalPeriodDagLevelsMapToBatch(anchor->getLevel() + kMaxLevelsPerPeriod, new_blk.pbft_blk->getPeriod(), - batch); - } - //// - - //// Commit system transactions - if (!system_transactions.empty()) { - db_->addPeriodSystemTransactions(batch, system_transactions, new_blk.pbft_blk->getPeriod()); - auto position = new_blk.transactions.size() + 1; - for (const auto& trx : system_transactions) { - db_->addSystemTransactionToBatch(batch, trx); - db_->addTransactionLocationToBatch(batch, trx->getHash(), new_blk.pbft_blk->getPeriod(), position, - true /*system_trx*/); - position++; - } - } - //// - - auto result = std::make_shared(FinalizationResult{ - { - new_blk.pbft_blk->getBeneficiary(), - new_blk.pbft_blk->getTimestamp(), - std::move(finalized_dag_blk_hashes), - new_blk.pbft_blk->getBlockHash(), - }, - blk_header, - std::move(all_transactions), - std::move(receipts), - }); - - // Please do not change order of these three lines :) - db_->commitWriteBatch(batch); - state_api_.transition_state_commit(); - rewards_.clear(new_blk.pbft_blk->getPeriod()); - - num_executed_dag_blk_ = num_executed_dag_blk; - num_executed_trx_ = num_executed_trx; - block_headers_cache_.append(blk_header->number, blk_header); - last_block_number_ = blk_header->number; - block_finalized_emitter_.emit(result); - LOG(log_nf_) << " successful finalize block " << result->hash << " with number " << blk_header->number; - - // Creates snapshot if needed - if (db_->createSnapshot(blk_header->number)) { - state_api_.create_snapshot(blk_header->number); - } - - return result; - } - - void prune(EthBlockNumber blk_n) override { - LOG(log_nf_) << "Pruning data older than " << blk_n; - auto last_block_to_keep = get_block_header(blk_n); - if (last_block_to_keep) { - auto block_to_keep = last_block_to_keep; - std::vector state_root_to_keep; - while (block_to_keep) { - state_root_to_keep.push_back(block_to_keep->state_root); - block_to_keep = get_block_header(block_to_keep->number + 1); - } - auto block_to_prune = get_block_header(last_block_to_keep->number - 1); - while (block_to_prune && block_to_prune->number > 0) { - db_->remove(DB::Columns::final_chain_blk_by_number, block_to_prune->number); - db_->remove(DB::Columns::final_chain_blk_hash_by_number, block_to_prune->number); - db_->remove(DB::Columns::final_chain_blk_number_by_hash, block_to_prune->hash); - block_to_prune = get_block_header(block_to_prune->number - 1); - } - - db_->compactColumn(DB::Columns::final_chain_blk_by_number); - db_->compactColumn(DB::Columns::final_chain_blk_hash_by_number); - db_->compactColumn(DB::Columns::final_chain_blk_number_by_hash); - - state_api_.prune(state_root_to_keep, last_block_to_keep->number); - } - } - - std::shared_ptr append_block(DB::Batch& batch, const addr_t& author, uint64_t timestamp, - uint64_t gas_limit, const h256& state_root, u256 total_reward, - const SharedTransactions& transactions = {}, - const TransactionReceipts& receipts = {}, const bytes& extra_data = {}) { - auto blk_header_ptr = std::make_shared(); - auto& blk_header = *blk_header_ptr; - auto last_block = block_header(); - blk_header.number = last_block ? last_block->number + 1 : 0; - blk_header.parent_hash = last_block ? last_block->hash : h256(); - blk_header.author = author; - blk_header.timestamp = timestamp; - blk_header.state_root = state_root; - blk_header.gas_used = receipts.empty() ? 0 : receipts.back().cumulative_gas_used; - blk_header.gas_limit = gas_limit; - blk_header.total_reward = total_reward; - blk_header.extra_data = extra_data; - dev::BytesMap trxs_trie, receipts_trie; - dev::RLPStream rlp_strm; - auto trx_idx = 0; - for (; trx_idx < transactions.size(); ++trx_idx) { - const auto& trx = transactions[trx_idx]; - auto i_rlp = util::rlp_enc(rlp_strm, trx_idx); - trxs_trie[i_rlp] = trx->rlp(); - - const auto& receipt = receipts[trx_idx]; - receipts_trie[i_rlp] = util::rlp_enc(rlp_strm, receipt); - db_->insert(batch, DB::Columns::final_chain_receipt_by_trx_hash, trx->getHash(), rlp_strm.out()); - - blk_header.log_bloom |= receipt.bloom(); - } - blk_header.transactions_root = hash256(trxs_trie); - blk_header.receipts_root = hash256(receipts_trie); - rlp_strm.clear(), blk_header.ethereum_rlp(rlp_strm); - blk_header.hash = dev::sha3(rlp_strm.out()); - db_->insert(batch, DB::Columns::final_chain_blk_by_number, blk_header.number, util::rlp_enc(rlp_strm, blk_header)); - auto log_bloom_for_index = blk_header.log_bloom; - log_bloom_for_index.shiftBloom<3>(sha3(blk_header.author.ref())); - for (uint64_t level = 0, index = blk_header.number; level < c_bloomIndexLevels; - ++level, index /= c_bloomIndexSize) { - auto chunk_id = block_blooms_chunk_id(level, index / c_bloomIndexSize); - auto chunk_to_alter = block_blooms(chunk_id); - chunk_to_alter[index % c_bloomIndexSize] |= log_bloom_for_index; - db_->insert(batch, DB::Columns::final_chain_log_blooms_index, chunk_id, util::rlp_enc(rlp_strm, chunk_to_alter)); - } - db_->insert(batch, DB::Columns::final_chain_blk_hash_by_number, blk_header.number, blk_header.hash); - db_->insert(batch, DB::Columns::final_chain_blk_number_by_hash, blk_header.hash, blk_header.number); - db_->insert(batch, DB::Columns::final_chain_meta, DBMetaKeys::LAST_NUMBER, blk_header.number); - - return blk_header_ptr; - } - - EthBlockNumber last_block_number() const override { return last_block_number_; } - - std::optional block_number(const h256& h) const override { - return db_->lookup_int(h, DB::Columns::final_chain_blk_number_by_hash); - } - - std::optional block_hash(std::optional n = {}) const override { - return block_hashes_cache_.get(last_if_absent(n)); - } - - std::shared_ptr block_header(std::optional n = {}) const override { - if (!n) { - return block_headers_cache_.last(); - } - return block_headers_cache_.get(*n); - } - - std::optional transaction_location(const h256& trx_hash) const override { - return db_->getTransactionLocation(trx_hash); - } - - std::optional transaction_receipt(const h256& trx_h) const override { - auto raw = db_->lookup(trx_h, DB::Columns::final_chain_receipt_by_trx_hash); - if (raw.empty()) { - return {}; - } - TransactionReceipt ret; - ret.rlp(dev::RLP(raw)); - return ret; - } - - uint64_t transactionCount(std::optional n = {}) const override { - return db_->getTransactionCount(last_if_absent(n)); - } - - std::shared_ptr transaction_hashes(std::optional n = {}) const override { - return transaction_hashes_cache_.get(last_if_absent(n)); - } - - const SharedTransactions transactions(std::optional n = {}) const override { - return transactions_cache_.get(last_if_absent(n)); - } - - std::vector withBlockBloom(const LogBloom& b, EthBlockNumber from, EthBlockNumber to) const override { - std::vector ret; - // start from the top-level - auto u = int_pow(c_bloomIndexSize, c_bloomIndexLevels); - // run through each of the top-level blocks - for (EthBlockNumber index = from / u; index <= (to + u - 1) / u; ++index) { - dev::operator+=(ret, withBlockBloom(b, from, to, c_bloomIndexLevels - 1, index)); - } - return ret; - } - - std::optional get_account(const addr_t& addr, - std::optional blk_n = {}) const override { - return accounts_cache_.get(last_if_absent(blk_n), addr); - } - - void update_state_config(const state_api::Config& new_config) override { - delegation_delay_ = new_config.dpos.delegation_delay; - state_api_.update_state_config(new_config); - } - - h256 get_account_storage(const addr_t& addr, const u256& key, - std::optional blk_n = {}) const override { - return state_api_.get_account_storage(last_if_absent(blk_n), addr, key); - } - - bytes get_code(const addr_t& addr, std::optional blk_n = {}) const override { - return state_api_.get_code_by_address(last_if_absent(blk_n), addr); - } - - state_api::ExecutionResult call(const state_api::EVMTransaction& trx, - std::optional blk_n = {}) const override { - auto const blk_header = block_header(last_if_absent(blk_n)); - if (!blk_header) { - throw std::runtime_error("Future block"); - } - return state_api_.dry_run_transaction(blk_header->number, - { - blk_header->author, - blk_header->gas_limit, - blk_header->timestamp, - BlockHeader::difficulty(), - }, - trx); - } - - std::string trace(std::vector trxs, EthBlockNumber blk_n, - std::optional params = {}) const override { - const auto blk_header = block_header(last_if_absent(blk_n)); - if (!blk_header) { - throw std::runtime_error("Future block"); - } - return dev::asString(state_api_.trace(blk_header->number, - { - blk_header->author, - blk_header->gas_limit, - blk_header->timestamp, - BlockHeader::difficulty(), - }, - trxs, params)); - } - - uint64_t dpos_eligible_total_vote_count(EthBlockNumber blk_num) const override { - return total_vote_count_cache_.get(blk_num); - } - - uint64_t dpos_eligible_vote_count(EthBlockNumber blk_num, const addr_t& addr) const override { - return dpos_vote_count_cache_.get(blk_num, addr); - } - - bool dpos_is_eligible(EthBlockNumber blk_num, const addr_t& addr) const override { - return dpos_is_eligible_cache_.get(blk_num, addr); - } - - vrf_wrapper::vrf_pk_t dpos_get_vrf_key(EthBlockNumber blk_n, const addr_t& addr) const override { - return state_api_.dpos_get_vrf_key(blk_n, addr); - } - - std::vector dpos_validators_total_stakes(EthBlockNumber blk_num) const override { - return state_api_.dpos_validators_total_stakes(blk_num); - } - - virtual uint256_t dpos_total_amount_delegated(EthBlockNumber blk_num) const override { - return state_api_.dpos_total_amount_delegated(blk_num); - } - - std::vector dpos_validators_vote_counts(EthBlockNumber blk_num) const override { - return state_api_.dpos_validators_vote_counts(blk_num); - } - - void wait_for_finalized() override { - std::unique_lock lck(finalized_mtx_); - finalized_cv_.wait_for(lck, std::chrono::milliseconds(10)); - } - - uint64_t dpos_yield(EthBlockNumber blk_num) const override { return state_api_.dpos_yield(blk_num); } - - u256 dpos_total_supply(EthBlockNumber blk_num) const override { return state_api_.dpos_total_supply(blk_num); } - - h256 get_bridge_root(EthBlockNumber blk_num) const override { - const static auto get_bridge_root_method = util::EncodingSolidity::packFunctionCall("getBridgeRoot()"); - return h256(call(state_api::EVMTransaction{dev::ZeroAddress, 1, kHardforksConfig.ficus_hf.bridge_contract_address, - state_api::ZeroAccount.nonce, 0, 10000000, get_bridge_root_method}, - blk_num) - .code_retval); - } - - h256 get_bridge_epoch(EthBlockNumber blk_num) const override { - const static auto get_bridge_epoch_method = util::EncodingSolidity::packFunctionCall("finalizedEpoch()"); - return h256(call(state_api::EVMTransaction{dev::ZeroAddress, 1, kHardforksConfig.ficus_hf.bridge_contract_address, - state_api::ZeroAccount.nonce, 0, 10000000, get_bridge_epoch_method}, - blk_num) - .code_retval); - } - - private: - std::shared_ptr get_transaction_hashes(std::optional n = {}) const { - const auto& trxs = db_->getPeriodTransactions(last_if_absent(n)); - auto ret = std::make_shared(); - if (!trxs) { - return ret; - } - ret->reserve(trxs->size()); - std::transform(trxs->cbegin(), trxs->cend(), std::back_inserter(*ret), - [](const auto& trx) { return trx->getHash(); }); - return ret; - } - - const SharedTransactions get_transactions(std::optional n = {}) const { - if (auto trxs = db_->getPeriodTransactions(last_if_absent(n))) { - return *trxs; - } - return {}; - } - - std::shared_ptr get_block_header(EthBlockNumber n) const { - if (auto raw = db_->lookup(n, DB::Columns::final_chain_blk_by_number); !raw.empty()) { - auto ret = std::make_shared(); - ret->rlp(dev::RLP(raw)); - return ret; - } - return {}; - } - - std::optional get_block_hash(EthBlockNumber n) const { - auto raw = db_->lookup(n, DB::Columns::final_chain_blk_hash_by_number); - if (raw.empty()) { - return {}; - } - return h256(raw, h256::FromBinary); - } - - EthBlockNumber last_if_absent(const std::optional& client_blk_n) const { - return client_blk_n ? *client_blk_n : last_block_number(); - } - - static state_api::EVMTransaction to_evm_transaction(const SharedTransaction& trx) { - return state_api::EVMTransaction{ - trx->getSender(), trx->getGasPrice(), trx->getReceiver(), trx->getNonce(), - trx->getValue(), trx->getGas(), trx->getData(), - }; - } - - static void append_evm_transactions(std::vector& evm_trxs, - const SharedTransactions& trxs) { - std::transform(trxs.cbegin(), trxs.cend(), std::back_inserter(evm_trxs), - [](const auto& trx) { return to_evm_transaction(trx); }); - } - - BlocksBlooms block_blooms(const h256& chunk_id) const { - if (auto raw = db_->lookup(chunk_id, DB::Columns::final_chain_log_blooms_index); !raw.empty()) { - return dev::RLP(raw).toArray(); - } - return {}; - } - - static h256 block_blooms_chunk_id(EthBlockNumber level, EthBlockNumber index) { return h256(index * 0xff + level); } - - std::vector withBlockBloom(const LogBloom& b, EthBlockNumber from, EthBlockNumber to, - EthBlockNumber level, EthBlockNumber index) const { - std::vector ret; - auto uCourse = int_pow(c_bloomIndexSize, level + 1); - auto uFine = int_pow(c_bloomIndexSize, level); - auto obegin = index == from / uCourse ? from / uFine % c_bloomIndexSize : 0; - auto oend = index == to / uCourse ? (to / uFine) % c_bloomIndexSize + 1 : c_bloomIndexSize; - auto bb = block_blooms(block_blooms_chunk_id(level, index)); - for (auto o = obegin; o < oend; ++o) { - if (bb[o].contains(b)) { - // This level has something like what we want. - if (level > 0) { - dev::operator+=(ret, withBlockBloom(b, from, to, level - 1, o + index * c_bloomIndexSize)); - } else { - ret.push_back(o + index * c_bloomIndexSize); - } - } - } - return ret; - } -}; - -std::shared_ptr NewFinalChain(const std::shared_ptr& db, const taraxa::FullNodeConfig& config, - const addr_t& node_addr) { - return make_shared(db, config, node_addr); -} - -} // namespace taraxa::final_chain diff --git a/libraries/core_libs/consensus/src/final_chain/trie_common.cpp b/libraries/core_libs/consensus/src/final_chain/trie_common.cpp index 3c6ff1b963..3c3a33d519 100644 --- a/libraries/core_libs/consensus/src/final_chain/trie_common.cpp +++ b/libraries/core_libs/consensus/src/final_chain/trie_common.cpp @@ -55,7 +55,8 @@ void hash256rlp(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_i for (auto i = std::next(_begin); i != _end && sharedPre; ++i, ++c) { unsigned x = std::min(sharedPre, std::min((unsigned)_begin->first.size(), (unsigned)i->first.size())); unsigned shared = _preLen; - for (; shared < x && _begin->first[shared] == i->first[shared]; ++shared); + for (; shared < x && _begin->first[shared] == i->first[shared]; ++shared) + ; sharedPre = std::min(shared, sharedPre); } if (sharedPre > _preLen) { @@ -71,7 +72,8 @@ void hash256rlp(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_i } for (auto i = 0; i < 16; ++i) { auto n = b; - for (; n != _end && n->first[_preLen] == i; ++n); + for (; n != _end && n->first[_preLen] == i; ++n) + ; if (b == n) { _rlp << ""; } else { diff --git a/libraries/core_libs/consensus/src/pbft/pbft_manager.cpp b/libraries/core_libs/consensus/src/pbft/pbft_manager.cpp index 60df06b9ff..6318734496 100644 --- a/libraries/core_libs/consensus/src/pbft/pbft_manager.cpp +++ b/libraries/core_libs/consensus/src/pbft/pbft_manager.cpp @@ -17,7 +17,7 @@ #include "vote_manager/vote_manager.hpp" namespace taraxa { -using vrf_output_t = vrf_wrapper::vrf_output_t; +using namespace std::chrono_literals; constexpr std::chrono::milliseconds kPollingIntervalMs{100}; constexpr PbftStep kMaxSteps{13}; // Need to be a odd number @@ -307,6 +307,7 @@ bool PbftManager::advancePeriod() { resetPbftConsensus(1 /* round */); broadcast_reward_votes_counter_ = 1; rebroadcast_reward_votes_counter_ = 1; + already_placed_pillar_vote_ = false; current_period_start_datetime_ = std::chrono::system_clock::now(); const auto new_period = getPbftPeriod(); @@ -721,9 +722,10 @@ std::shared_ptr PbftManager::getValidPbftProposedBlock(PbftPeriod per bool PbftManager::placeVote(const std::shared_ptr &vote, std::string_view log_vote_id, const std::shared_ptr &voted_block) { + const PbftPeriod period = vote->getPeriod(); if (!vote_mgr_->addVerifiedVote(vote)) { LOG(log_er_) << "Unable to place vote " << vote->getHash() << " for block " << vote->getBlockHash() << ", period " - << vote->getPeriod() << ", round " << vote->getRound() << ", step " << vote->getStep(); + << period << ", round " << vote->getRound() << ", step " << vote->getStep(); return false; } @@ -733,8 +735,8 @@ bool PbftManager::placeVote(const std::shared_ptr &vote, std::string_v vote_mgr_->saveOwnVerifiedVote(vote); LOG(log_nf_) << "Placed " << log_vote_id << " " << vote->getHash() << " for block " << vote->getBlockHash() - << ", vote weight " << *vote->getWeight() << ", period " << vote->getPeriod() << ", round " - << vote->getRound() << ", step " << vote->getStep(); + << ", vote weight " << *vote->getWeight() << ", period " << period << ", round " << vote->getRound() + << ", step " << vote->getStep(); return true; } @@ -1180,6 +1182,10 @@ PbftManager::proposePbftBlock() { // Creates pillar block's extra data const auto extra_data = createPbftBlockExtraData(current_pbft_period); + if (!extra_data.has_value()) { + LOG(log_er_) << "Unable to propose pbft block due to wrong pillar block, pbft period: " << current_pbft_period; + return {}; + } auto ghost = dag_mgr_->getGhostPath(last_period_dag_anchor_block_hash); LOG(log_dg_) << "GHOST size " << ghost.size(); @@ -1286,9 +1292,8 @@ std::optional PbftManager::createPbftBlockExtraData(PbftPeri return {}; } - if (pillar_block->getPeriod() != pbft_period - kGenesisConfig.state.hardforks.ficus_hf.pbft_inclusion_delay) { + if (pillar_block->getPeriod() != pbft_period - 1) { LOG(log_er_) << "Wrong pillar block period: " << pillar_block->getPeriod() << ", pbft period: " << pbft_period; - assert(false); return {}; } @@ -1418,14 +1423,14 @@ bool PbftManager::validatePillarDataInPeriodData(const PeriodData &period_data) const auto block_period = period_data.pbft_blk->getPeriod(); // Validate optional pillar votes presence - if (kGenesisConfig.state.hardforks.ficus_hf.isPillarBlockPeriod(block_period, true /* skip first pillar block */)) { + if (kGenesisConfig.state.hardforks.ficus_hf.isPbftWithPillarBlockPeriod(block_period)) { if (!period_data.pillar_votes_.has_value()) { - LOG(log_er_) << "PBFT block " << period_data.pbft_blk->getBlockHash() << ", period " << block_period + LOG(log_er_) << "Sync PBFT block " << period_data.pbft_blk->getBlockHash() << ", period " << block_period << " does not contain pillar votes"; return false; } } else if (period_data.pillar_votes_.has_value()) { - LOG(log_er_) << "PBFT block " << period_data.pbft_blk->getBlockHash() << ", period " + LOG(log_er_) << "Sync PBFT block " << period_data.pbft_blk->getBlockHash() << ", period " << period_data.pbft_blk->getPeriod() << " contains pillar votes even though it should not"; return false; } @@ -1460,47 +1465,22 @@ bool PbftManager::validatePbftBlock(const std::shared_ptr &pbft_block return false; } - const auto block_period = pbft_block->getPeriod(); - if (kGenesisConfig.state.hardforks.ficus_hf.isPillarBlockPeriod(block_period, true /* skip first pillar block */)) { - const auto last_finalized_pillar_block = pillar_chain_mgr_->getLastFinalizedPillarBlock(); - if (!last_finalized_pillar_block) { - // This should never happen - LOG(log_er_) << "Unable to validate PBFT block " << pbft_block_hash << ", period " << block_period - << ". No last finalized pillar block present"; - return false; - } - - if (last_finalized_pillar_block->getPeriod() != - block_period - kGenesisConfig.state.hardforks.ficus_hf.pillar_blocks_interval) { - LOG(log_er_) << "Unable to validate PBFT block " << pbft_block_hash << ", period " << block_period - << ". Pillar chain missing finalized block. Last finalized block period " - << last_finalized_pillar_block->getPeriod() << ", expected period " - << block_period - kGenesisConfig.state.hardforks.ficus_hf.pillar_blocks_interval; - // Trigger pillar chain votes syncing - pillar_chain_mgr_->checkPillarChainSynced(block_period); - return false; - } - } - // Validate optional pillar block hash + const auto block_period = pbft_block->getPeriod(); if (kGenesisConfig.state.hardforks.ficus_hf.isPbftWithPillarBlockPeriod(block_period)) { const auto current_pillar_block = pillar_chain_mgr_->getCurrentPillarBlock(); if (!current_pillar_block) { // This should never happen LOG(log_er_) << "Unable to validate PBFT block " << pbft_block_hash << ", period " << block_period << ". No current pillar block present in node"; - assert(false); return false; } if (*pbft_block->getExtraData()->getPillarBlockHash() != current_pillar_block->getHash()) { - LOG(log_er_) << "PBFT block " << pbft_block_hash << " contains pillar block hash " - << *pbft_block->getExtraData()->getPillarBlockHash() + LOG(log_er_) << "PBFT block " << pbft_block_hash << " with period " << pbft_block->getPeriod() + << " contains pillar block hash " << *pbft_block->getExtraData()->getPillarBlockHash() << ", which is different than the local current pillar block" << current_pillar_block->getHash() - << ", period " << pbft_block->getPeriod(); - - // Trigger pillar chain votes syncing - pillar_chain_mgr_->checkPillarChainSynced(block_period); + << " with period " << current_pillar_block->getPeriod(); return false; } } @@ -1680,10 +1660,33 @@ void PbftManager::finalize_(PeriodData &&period_data, std::vector &&finali } } - const auto result = + const auto period = period_data.pbft_blk->getPeriod(); + auto result = final_chain_->finalize(std::move(period_data), std::move(finalized_dag_blk_hashes), std::move(anchor_block)); - if (synchronous_processing) { + + bool is_pillar_block_period = kGenesisConfig.state.hardforks.ficus_hf.isPillarBlockPeriod(period); + if (synchronous_processing || is_pillar_block_period) { result.wait(); + + if (!is_pillar_block_period) { + return; + } + + // Create new pillar block + const auto finalization_data = result.get(); + const auto pillar_block = pillar_chain_mgr_->createPillarBlock(finalization_data->final_chain_blk); + + // Check if node is eligible to vote for pillar block + // Note: No need to catch ErrFutureBlock because pillar block is create only after pbft block with is + // finalized Note: period is used instead of period -1 because at this moment, block with period was + // already finalized + if (final_chain_->dpos_is_eligible(period, node_addr_)) { + if (pillar_block) { + pillar_chain_mgr_->genAndPlacePillarVote(period, pillar_block->getHash(), node_sk_, periodDataQueueEmpty()); + } else { + LOG(log_er_) << "Unable to vote for pillar block with period " << period << ". Block was not created"; + } + } } } @@ -1699,10 +1702,27 @@ bool PbftManager::pushPbftBlock_(PeriodData &&period_data, std::vectorgetPeriod(); + + // To finalize the pbft block that includes pillar block hash, there needs to be enough pillar votes as well as pbft + // votes + if (kGenesisConfig.state.hardforks.ficus_hf.isPbftWithPillarBlockPeriod(pbft_period)) { + // Note: presence of pillar block hash in extra data was already validated in validatePbftBlock + const auto pillar_block_hash = period_data.pbft_blk->getExtraData()->getPillarBlockHash(); + if (!pillar_chain_mgr_->isPillarBlockLatestFinalized(*pillar_block_hash)) { + LOG(log_er_) << "Cannot push PBFT block " << period_data.pbft_blk->getBlockHash() << ", period " << pbft_period + << ". Not enough pillar votes for pillar block " << *pillar_block_hash << ". Request it"; + if (auto net = network_.lock()) { + net->requestPillarBlockVotesBundle(pbft_period - 1, *pillar_block_hash); + } + + return false; + } + } + assert(cert_votes.empty() == false); assert(pbft_block_hash == cert_votes[0]->getBlockHash()); - auto pbft_period = period_data.pbft_blk->getPeriod(); auto null_anchor = period_data.pbft_blk->getPivotDagBlockHash() == kNullBlockHash; auto batch = db_->createWriteBatch(); @@ -1774,7 +1794,8 @@ PbftPeriod PbftManager::pbftSyncingPeriod() const { std::optional>>> PbftManager::processPeriodData() { auto [period_data, cert_votes, node_id] = sync_queue_.pop(); auto pbft_block_hash = period_data.pbft_blk->getBlockHash(); - LOG(log_dg_) << "Pop pbft block " << pbft_block_hash << " from synced queue"; + LOG(log_dg_) << "Pop pbft block " << pbft_block_hash << " with period " << period_data.pbft_blk->getPeriod() + << " from synced queue"; if (pbft_chain_->findPbftBlockInChain(pbft_block_hash)) { LOG(log_dg_) << "PBFT block " << pbft_block_hash << " already present in chain."; @@ -1890,7 +1911,7 @@ std::optional>>> Pbf const auto block_period = period_data.pbft_blk->getPeriod(); // Validate pillar votes - if (kGenesisConfig.state.hardforks.ficus_hf.isPillarBlockPeriod(block_period, true /* skip first pillar block */) && + if (kGenesisConfig.state.hardforks.ficus_hf.isPbftWithPillarBlockPeriod(block_period) && !validatePbftBlockPillarVotes(period_data)) { LOG(log_er_) << "Synced PBFT block " << pbft_block_hash << ", period " << block_period << " doesn't have enough valid pillar votes. Clear synced PBFT blocks!"; @@ -1994,13 +2015,12 @@ bool PbftManager::validatePbftBlockPillarVotes(const PeriodData &period_data) co } const auto &pbft_block_hash = period_data.pbft_blk->getBlockHash(); - const auto required_votes_period = - period_data.pbft_blk->getPeriod() - kGenesisConfig.state.hardforks.ficus_hf.pillar_blocks_interval; + const auto required_votes_period = period_data.pbft_blk->getPeriod() - 1; const auto current_pillar_block = pillar_chain_mgr_->getCurrentPillarBlock(); if (current_pillar_block->getPeriod() != required_votes_period) { - LOG(log_er_) << "Sync pillar votes required period " << required_votes_period - << " != " << " current pillar block period " << current_pillar_block->getPeriod(); + LOG(log_er_) << "Sync pillar votes required period " << required_votes_period << " != " + << " current pillar block period " << current_pillar_block->getPeriod(); return false; } diff --git a/libraries/core_libs/consensus/src/pillar_chain/pillar_chain_manager.cpp b/libraries/core_libs/consensus/src/pillar_chain/pillar_chain_manager.cpp index 8f7f80e9a0..a9e51653c9 100644 --- a/libraries/core_libs/consensus/src/pillar_chain/pillar_chain_manager.cpp +++ b/libraries/core_libs/consensus/src/pillar_chain/pillar_chain_manager.cpp @@ -44,8 +44,8 @@ PillarChainManager::PillarChainManager(const FicusHardforkConfig& ficus_hf_confi } std::shared_ptr PillarChainManager::createPillarBlock( - const std::shared_ptr& block_data) { - const auto block_num = block_data->final_chain_blk->number; + const std::shared_ptr& block_header) { + const auto block_num = block_header->number; blk_hash_t previous_pillar_block_hash{}; // null block hash auto new_vote_counts = final_chain_->dpos_validators_vote_counts(block_num); @@ -61,30 +61,24 @@ std::shared_ptr PillarChainManager::createPillarBlock( static_cast(vote_count.vote_count)); }); } else { - const auto current_pillar_block = getCurrentPillarBlock(); - if (!current_pillar_block) { - LOG(log_er_) << "Empty previous pillar block, new pillar block period " << block_num; + const auto last_finalized_pillar_block = getLastFinalizedPillarBlock(); + // This should never happen !!! + if (!last_finalized_pillar_block) { + LOG(log_er_) << "Empty last finalized pillar block, new pillar block period " << block_num; assert(false); return nullptr; } - // Try to finalize current pillar block in case it is not yet finalized - if (!finalizePillarBlock(current_pillar_block)) { - LOG(log_er_) << "Unable to create new pillar block, the current pillar block " << current_pillar_block->getHash() - << " needs to be finalized first"; - return nullptr; - } - // !!!Note: No need to protect current_pillar_block_vote_counts_ as it is read & written only in this function, // which is always called once in a time + // This should never happen !!! if (current_pillar_block_vote_counts_.empty()) { - // This should never happen LOG(log_er_) << "Empty current pillar block vote counts, new pillar block period " << block_num; assert(false); return nullptr; } - previous_pillar_block_hash = current_pillar_block->getHash(); + previous_pillar_block_hash = last_finalized_pillar_block->getHash(); // Get validators vote counts changes between the current and previous pillar block votes_count_changes = getOrderedValidatorsVoteCountsChanges(new_vote_counts, current_pillar_block_vote_counts_); @@ -93,8 +87,8 @@ std::shared_ptr PillarChainManager::createPillarBlock( h256 bridge_root = final_chain_->get_bridge_root(block_num); u256 bridge_epoch = final_chain_->get_bridge_epoch(block_num); const auto pillar_block = - std::make_shared(block_num, block_data->final_chain_blk->state_root, previous_pillar_block_hash, - bridge_root, bridge_epoch, std::move(votes_count_changes)); + std::make_shared(block_num, block_header->state_root, previous_pillar_block_hash, bridge_root, + bridge_epoch, std::move(votes_count_changes)); // Check if some pillar block was not skipped if (!isValidPillarBlock(pillar_block)) { @@ -123,30 +117,9 @@ void PillarChainManager::saveNewPillarBlock(std::shared_ptr pillar_ current_pillar_block_vote_counts_ = std::move(data.vote_counts); } -bool PillarChainManager::genAndPlacePillarVote(const blk_hash_t& pillar_block_hash, const secret_t& node_sk, - bool is_pbft_syncing) { - const auto current_pillar_block = getCurrentPillarBlock(); - if (!current_pillar_block) { - // This should never happen - LOG(log_er_) << "Unable to gen pillar vote. No pillar block present, pillar_block_hash " << pillar_block_hash; - assert(false); - return false; - } - - // No need to catch ErrFutureBlock because pillar block as well as pillar vote are created only after the pbft block - // with current_pillar_block->getPeriod() was finalized - if (!final_chain_->dpos_is_eligible(current_pillar_block->getPeriod() - 1, node_addr_)) { - return false; - } - - if (pillar_block_hash != current_pillar_block->getHash()) { - LOG(log_er_) << "Unable to gen pillar vote. Provided pillar_block_hash(" << pillar_block_hash - << ") != current pillar block hash(" << current_pillar_block->getHash() << ")"; - return false; - } - - const auto vote = - std::make_shared(node_sk, current_pillar_block->getPeriod(), current_pillar_block->getHash()); +bool PillarChainManager::genAndPlacePillarVote(PbftPeriod period, const blk_hash_t& pillar_block_hash, + const secret_t& node_sk, bool broadcast_vote) { + const auto vote = std::make_shared(node_sk, period, pillar_block_hash); // Broadcasts pillar vote const auto vote_weight = addVerifiedPillarVote(vote); @@ -155,14 +128,14 @@ bool PillarChainManager::genAndPlacePillarVote(const blk_hash_t& pillar_block_ha << vote->getHash(); return false; } - db_->saveOwnPillarBlockVote(vote); - if (!is_pbft_syncing) { - if (auto net = network_.lock()) { - net->gossipPillarBlockVote(vote); - } - LOG(log_nf_) << "Placed pillar vote " << vote->getHash() << " for block " << vote->getBlockHash() << ", period " + if (auto net = network_.lock(); net && broadcast_vote) { + net->gossipPillarBlockVote(vote); + LOG(log_nf_) << "Created & broadcast pillar vote " << vote->getHash() << " for block " << vote->getBlockHash() + << ", period " << vote->getPeriod() << ", weight " << vote_weight; + } else { + LOG(log_nf_) << "Created pillar vote " << vote->getHash() << " for block " << vote->getBlockHash() << ", period " << vote->getPeriod() << ", weight " << vote_weight; } @@ -171,7 +144,7 @@ bool PillarChainManager::genAndPlacePillarVote(const blk_hash_t& pillar_block_ha bool PillarChainManager::finalizePillarBlock(const std::shared_ptr& pillar_block) { if (isPillarBlockLatestFinalized(pillar_block->getHash())) { - LOG(log_dg_) << "Pillar block " << pillar_block->getHash() << " already finalized"; + LOG(log_tr_) << "Pillar block " << pillar_block->getHash() << " already finalized"; return true; } @@ -182,7 +155,7 @@ bool PillarChainManager::finalizePillarBlock(const std::shared_ptr& auto above_threshold_votes = pillar_votes_.getVerifiedVotes(pillar_block->getPeriod(), pillar_block->getHash(), true); if (above_threshold_votes.empty()) { - LOG(log_dg_) << "Unable to finalize pillar block " << pillar_block->getHash() + LOG(log_tr_) << "Unable to finalize pillar block " << pillar_block->getHash() << ", period: " << pillar_block->getPeriod() << ". Not enough votes"; return false; } @@ -227,49 +200,6 @@ std::shared_ptr PillarChainManager::getCurrentPillarBlock() const { return current_pillar_block_; } -bool PillarChainManager::checkPillarChainSynced(EthBlockNumber block_num) const { - const auto current_pillar_block = getCurrentPillarBlock(); - - // No current pillar block registered... This should happen only before the first pillar block is created - if (!current_pillar_block) [[unlikely]] { - LOG(log_er_) << "No current pillar block saved, period " << block_num; - assert(false); - return false; - } - - // Check > threshold votes for the current pillar block - if (!pillar_votes_.hasAboveThresholdVotes(current_pillar_block->getPeriod(), current_pillar_block->getHash())) { - // There is < threshold pillar votes, request it - if (auto net = network_.lock()) { - LOG(log_dg_) << "There is < threshold pillar votes for pillar block " << current_pillar_block->getHash() - << ", period " << current_pillar_block->getPeriod() << ". Request it"; - net->requestPillarBlockVotesBundle(current_pillar_block->getPeriod(), current_pillar_block->getHash()); - } else { - LOG(log_er_) << "checkPillarChainSynced: Unable to obtain net"; - } - - return false; - } - - PbftPeriod expected_pillar_block_period = 0; - if (block_num % kFicusHfConfig.pillar_blocks_interval == 0) { - expected_pillar_block_period = block_num - kFicusHfConfig.pillar_blocks_interval; - } else { - expected_pillar_block_period = block_num - (block_num % kFicusHfConfig.pillar_blocks_interval); - } - - if (expected_pillar_block_period != current_pillar_block->getPeriod()) { - // This should never happen - LOG(log_er_) << "Pillar chain is out of sync. Current pbft period " << block_num << ", current pillar block period " - << current_pillar_block->getPeriod() << ", expected pillar block period " - << expected_pillar_block_period; - assert(false); - return false; - } - - return true; -} - bool PillarChainManager::isRelevantPillarVote(const std::shared_ptr vote) const { const auto current_pillar_block = getCurrentPillarBlock(); @@ -315,7 +245,9 @@ bool PillarChainManager::validatePillarVote(const std::shared_ptr vo // Check if signer is eligible validator try { - if (!final_chain_->dpos_is_eligible(period - 1, validator)) { + // Note: period is used instead of period - 1 because pillar votes are created only after pbft block with + // is finalized + if (!final_chain_->dpos_is_eligible(period, validator)) { LOG(log_er_) << "Validator is not eligible. Pillar vote " << vote->getHash(); return false; } @@ -336,7 +268,9 @@ bool PillarChainManager::validatePillarVote(const std::shared_ptr vo uint64_t PillarChainManager::addVerifiedPillarVote(const std::shared_ptr& vote) { uint64_t validator_vote_count = 0; try { - validator_vote_count = final_chain_->dpos_eligible_vote_count(vote->getPeriod() - 1, vote->getVoterAddr()); + // Note: period is used instead of period - 1 because pillar votes are created only after pbft block with + // is finalized + validator_vote_count = final_chain_->dpos_eligible_vote_count(vote->getPeriod(), vote->getVoterAddr()); } catch (state_api::ErrFutureBlock& e) { LOG(log_er_) << "Pillar vote " << vote->getHash() << " with period " << vote->getPeriod() << " is too far ahead of DPOS. " << e.what(); @@ -350,9 +284,11 @@ uint64_t PillarChainManager::addVerifiedPillarVote(const std::shared_ptrgetPeriod())) { - const auto threshold = getPillarConsensusThreshold(vote->getPeriod() - 1); + // Note: period is used instead of period - 1 because pillar votes are created only after pbft block with + // is finalized + const auto threshold = getPillarConsensusThreshold(vote->getPeriod()); if (!threshold) { - LOG(log_er_) << "Unable to get pillar consensus threshold for period " << vote->getPeriod() - 1; + LOG(log_er_) << "Unable to get pillar consensus threshold for period " << vote->getPeriod(); return 0; } pillar_votes_.initializePeriodData(vote->getPeriod(), *threshold); diff --git a/libraries/core_libs/consensus/src/pillar_chain/pillar_votes.cpp b/libraries/core_libs/consensus/src/pillar_chain/pillar_votes.cpp index 2b23aa50bc..f60a49dc9e 100644 --- a/libraries/core_libs/consensus/src/pillar_chain/pillar_votes.cpp +++ b/libraries/core_libs/consensus/src/pillar_chain/pillar_votes.cpp @@ -38,27 +38,6 @@ bool PillarVotes::isUniqueVote(const std::shared_ptr vote) const { return false; } -bool PillarVotes::hasAboveThresholdVotes(PbftPeriod period, const blk_hash_t& block_hash) const { - std::shared_lock lock(mutex_); - - const auto found_period_votes = votes_.find(period); - if (found_period_votes == votes_.end()) [[unlikely]] { - return false; - } - - const auto found_pillar_block_votes = found_period_votes->second.pillar_block_votes.find(block_hash); - if (found_pillar_block_votes == found_period_votes->second.pillar_block_votes.end()) [[unlikely]] { - return false; - } - - if (found_pillar_block_votes->second.weight < found_period_votes->second.threshold) { - return false; - } - - // There is > threshold votes - return true; -} - std::vector> PillarVotes::getVerifiedVotes(PbftPeriod period, const blk_hash_t& pillar_block_hash, bool above_threshold) const { diff --git a/libraries/core_libs/consensus/src/vote_manager/vote_manager.cpp b/libraries/core_libs/consensus/src/vote_manager/vote_manager.cpp index c7787765be..0ce0835c93 100644 --- a/libraries/core_libs/consensus/src/vote_manager/vote_manager.cpp +++ b/libraries/core_libs/consensus/src/vote_manager/vote_manager.cpp @@ -416,8 +416,9 @@ std::pair> VoteManager::isUniqueVote(const std:: } std::stringstream err; - err << "Non unique vote: " << ", new vote hash (voted value): " << vote->getHash().abridged() << " (" - << vote->getBlockHash().abridged() << ")" + err << "Non unique vote: " + << ", new vote hash (voted value): " << vote->getHash().abridged() << " (" << vote->getBlockHash().abridged() + << ")" << ", orig. vote hash (voted value): " << found_voter_it->second.first->getHash().abridged() << " (" << found_voter_it->second.first->getBlockHash().abridged() << ")"; if (found_voter_it->second.second != nullptr) { @@ -482,8 +483,8 @@ std::pair> VoteManager::insertUniqueVote(const s } std::stringstream err; - err << "Unable to insert new unique vote(race condition): " << ", new vote hash (voted value): " - << vote->getHash().abridged() << " (" << vote->getBlockHash() << ")" + err << "Unable to insert new unique vote(race condition): " + << ", new vote hash (voted value): " << vote->getHash().abridged() << " (" << vote->getBlockHash() << ")" << ", orig. vote hash (voted value): " << inserted_vote.first->second.first->getHash().abridged() << " (" << inserted_vote.first->second.first->getBlockHash() << ")"; if (inserted_vote.first->second.second != nullptr) { diff --git a/libraries/core_libs/network/src/network.cpp b/libraries/core_libs/network/src/network.cpp index e690a77243..9091c68571 100644 --- a/libraries/core_libs/network/src/network.cpp +++ b/libraries/core_libs/network/src/network.cpp @@ -106,7 +106,10 @@ Network::Network(const FullNodeConfig &config, const h256 &genesis_hash, std::fi registerPeriodicEvents(pbft_mgr, trx_mgr); for (uint i = 0; i < tp_.capacity(); ++i) { - tp_.post_loop({100 + i * 20}, [this] { while (0 < host_->do_work()); }); + tp_.post_loop({100 + i * 20}, [this] { + while (0 < host_->do_work()) + ; + }); } LOG(log_nf_) << "Configured host. Listening on address: " << config.network.listen_ip << ":" diff --git a/libraries/core_libs/network/src/tarcap/packets_handlers/latest/get_pbft_sync_packet_handler.cpp b/libraries/core_libs/network/src/tarcap/packets_handlers/latest/get_pbft_sync_packet_handler.cpp index 3f612d5b3e..e7e38bf99e 100644 --- a/libraries/core_libs/network/src/tarcap/packets_handlers/latest/get_pbft_sync_packet_handler.cpp +++ b/libraries/core_libs/network/src/tarcap/packets_handlers/latest/get_pbft_sync_packet_handler.cpp @@ -87,10 +87,10 @@ void GetPbftSyncPacketHandler::sendPbftBlocks(const std::shared_ptr // Add pillar votes to period data const auto &ficus_hf_conf = kConf.genesis.state.hardforks.ficus_hf; - if (ficus_hf_conf.isPillarBlockPeriod(block_period, true /* skip first pillar block */)) { + if (ficus_hf_conf.isPbftWithPillarBlockPeriod(block_period)) { // TODO: not ideal solution: should not decode PeriodData, add pillar votes and then encode it again... PeriodData period_data{data}; - auto pillar_data = db_->getPillarBlockData(block_period - ficus_hf_conf.pillar_blocks_interval); + auto pillar_data = db_->getPillarBlockData(block_period - 1); if (!pillar_data.has_value()) { LOG(log_er_) << "DB corrupted. Cannot find pillar votes for period " << block_period << " in db"; return; diff --git a/libraries/core_libs/network/src/tarcap/packets_handlers/latest/status_packet_handler.cpp b/libraries/core_libs/network/src/tarcap/packets_handlers/latest/status_packet_handler.cpp index 71eecf31e1..855df89d43 100644 --- a/libraries/core_libs/network/src/tarcap/packets_handlers/latest/status_packet_handler.cpp +++ b/libraries/core_libs/network/src/tarcap/packets_handlers/latest/status_packet_handler.cpp @@ -82,9 +82,9 @@ void StatusPacketHandler::process(const threadpool::PacketData& packet_data, con if (pbft_synced_period + node_history < peer_pbft_chain_size) { LOG((peers_state_->getPeersCount()) ? log_nf_ : log_er_) << "Light node " << packet_data.from_node_id_.abridged() - << " would not be able to serve our syncing request. " << "Current synced period " << pbft_synced_period - << ", peer synced period " << pbft_synced_period << ", peer light node history " << node_history - << ". Peer will be disconnected"; + << " would not be able to serve our syncing request. " + << "Current synced period " << pbft_synced_period << ", peer synced period " << pbft_synced_period + << ", peer light node history " << node_history << ". Peer will be disconnected"; disconnect(packet_data.from_node_id_, dev::p2p::UserReason); return; } diff --git a/libraries/core_libs/network/src/threadpool/priority_queue.cpp b/libraries/core_libs/network/src/threadpool/priority_queue.cpp index 8e71f7f585..8311626ddb 100644 --- a/libraries/core_libs/network/src/threadpool/priority_queue.cpp +++ b/libraries/core_libs/network/src/threadpool/priority_queue.cpp @@ -24,7 +24,8 @@ PriorityQueue::PriorityQueue(size_t tp_workers_count, const addr_t& node_addr) packets_queues_[PacketData::PacketPriority::Mid].setMaxWorkersCount(mid_priority_queue_workers); packets_queues_[PacketData::PacketPriority::Low].setMaxWorkersCount(low_priority_queue_workers); - LOG(log_nf_) << "Priority queues initialized accordingly: " << "total num of workers = " << MAX_TOTAL_WORKERS_COUNT + LOG(log_nf_) << "Priority queues initialized accordingly: " + << "total num of workers = " << MAX_TOTAL_WORKERS_COUNT << ", High priority packets max num of workers = " << high_priority_queue_workers << ", Mid priority packets max num of workers = " << mid_priority_queue_workers << ", Low priority packets max num of workers = " << low_priority_queue_workers; diff --git a/libraries/core_libs/node/src/node.cpp b/libraries/core_libs/node/src/node.cpp index c17beaad07..cb65d26a3a 100644 --- a/libraries/core_libs/node/src/node.cpp +++ b/libraries/core_libs/node/src/node.cpp @@ -11,6 +11,7 @@ #include "dag/dag.hpp" #include "dag/dag_block.hpp" #include "dag/dag_block_proposer.hpp" +#include "final_chain/final_chain_impl.hpp" #include "graphql/http_processor.hpp" #include "graphql/ws_server.hpp" #include "key_manager/key_manager.hpp" @@ -112,7 +113,7 @@ void FullNode::init() { } gas_pricer_ = std::make_shared(conf_.genesis.gas_price, conf_.is_light_node, db_); - final_chain_ = NewFinalChain(db_, conf_, node_addr); + final_chain_ = std::make_shared(db_, conf_, node_addr); key_manager_ = std::make_shared(final_chain_); trx_mgr_ = std::make_shared(conf_, db_, final_chain_, node_addr); @@ -138,7 +139,6 @@ void FullNode::init() { pbft_chain_, final_chain_, key_manager_, slashing_manager); pillar_chain_mgr_ = std::make_shared(conf_.genesis.state.hardforks.ficus_hf, db_, final_chain_, key_manager_, node_addr); - pbft_mgr_ = std::make_shared(conf_.genesis, node_addr, db_, pbft_chain_, vote_mgr_, dag_mgr_, trx_mgr_, final_chain_, pillar_chain_mgr_, kp_.secret()); dag_block_proposer_ = std::make_shared( @@ -327,43 +327,6 @@ void FullNode::start() { }, subscription_pool_); - // Pillar blocks creation - final_chain_->block_finalized_.subscribe( - [ficus_hf_config = conf_.genesis.state.hardforks.ficus_hf, pillar_chain_weak = as_weak(pillar_chain_mgr_), - network_weak = as_weak(network_), node_secret = kp_.secret()](const auto &res) { - const auto block_num = res->final_chain_blk->number; - if (!ficus_hf_config.isFicusHardfork(block_num)) { - return; - } - - auto pillar_chain = pillar_chain_weak.lock(); - if (!pillar_chain) { - return; - } - - auto is_pbft_syncing = [network_weak]() -> bool { - auto network = network_weak.lock(); - if (!network) { - return false; - } - - return network->pbft_syncing(); - }; - - if (ficus_hf_config.isPillarBlockPeriod(block_num)) { - const auto pillar_block = pillar_chain->createPillarBlock(res); - if (pillar_block) { - pillar_chain->genAndPlacePillarVote(pillar_block->getHash(), node_secret, is_pbft_syncing()); - } - } else if (block_num > ficus_hf_config.firstPillarBlockPeriod() && - block_num % ficus_hf_config.pillar_chain_sync_interval == 0) { - if (!is_pbft_syncing()) { - pillar_chain->checkPillarChainSynced(block_num); - } - } - }, - subscription_pool_); - pillar_chain_mgr_->pillar_block_finalized_.subscribe( [ws_weak = as_weak(jsonrpc_ws_)](const auto &pillar_block_data) { if (auto ws = ws_weak.lock()) { diff --git a/submodules/taraxa-evm b/submodules/taraxa-evm index d4e89bca8b..5ad48bf9a8 160000 --- a/submodules/taraxa-evm +++ b/submodules/taraxa-evm @@ -1 +1 @@ -Subproject commit d4e89bca8b77ee1bd1dd1120be02672d5fdddebb +Subproject commit 5ad48bf9a87bfa3496000ad130e191d12962232d diff --git a/tests/final_chain_test.cpp b/tests/final_chain_test.cpp index 726dcd1648..283d016813 100644 --- a/tests/final_chain_test.cpp +++ b/tests/final_chain_test.cpp @@ -1,11 +1,10 @@ -#include "final_chain/final_chain.hpp" - #include #include #include "common/constants.hpp" #include "common/vrf_wrapper.hpp" #include "config/config.hpp" +#include "final_chain/final_chain_impl.hpp" #include "final_chain/trie_common.hpp" #include "libdevcore/CommonJS.h" #include "network/rpc/eth/Eth.h" @@ -46,7 +45,7 @@ struct FinalChainTest : WithDataDir { } void init() { - SUT = NewFinalChain(db, cfg); + SUT = std::make_shared(db, cfg, addr_t{}); const auto& effective_balances = effective_initial_balances(cfg.genesis.state); cfg.genesis.state.dpos.yield_percentage = 0; for (const auto& [addr, _] : cfg.genesis.state.initial_balances) { @@ -103,7 +102,8 @@ struct FinalChainTest : WithDataDir { EXPECT_EQ(blk_h.timestamp, pbft_block->getTimestamp()); EXPECT_EQ(receipts.size(), trxs.size()); EXPECT_EQ(blk_h.transactions_root, - trieRootOver(trxs.size(), [&](auto i) { return dev::rlp(i); }, [&](auto i) { return trxs[i]->rlp(); })); + trieRootOver( + trxs.size(), [&](auto i) { return dev::rlp(i); }, [&](auto i) { return trxs[i]->rlp(); })); EXPECT_EQ(blk_h.receipts_root, trieRootOver( trxs.size(), [&](auto i) { return dev::rlp(i); }, [&](auto i) { return util::rlp_enc(receipts[i]); })); diff --git a/tests/p2p_test.cpp b/tests/p2p_test.cpp index edc96f0777..1f84dbdbfb 100644 --- a/tests/p2p_test.cpp +++ b/tests/p2p_test.cpp @@ -105,8 +105,8 @@ TEST_F(P2PTest, multiple_capabilities) { dev::p2p::NetworkConfig net_conf("127.0.0.1", 20001, false, true); TaraxaNetworkConfig taraxa_net_conf; taraxa_net_conf.is_boot_node = true; - auto boot_node = - Host::make("TaraxaNode", [](auto /*host*/) { return Host::CapabilityList{}; }, key, net_conf, taraxa_net_conf); + auto boot_node = Host::make( + "TaraxaNode", [](auto /*host*/) { return Host::CapabilityList{}; }, key, net_conf, taraxa_net_conf); const auto &boot_node_key = boot_node->id(); util::ThreadPool boot_node_tp; diff --git a/tests/pillar_chain_test.cpp b/tests/pillar_chain_test.cpp index fa63f60d44..ffd3842419 100644 --- a/tests/pillar_chain_test.cpp +++ b/tests/pillar_chain_test.cpp @@ -89,8 +89,6 @@ TEST_F(PillarChainTest, pillar_blocks_create) { node_cfg.genesis.state.dpos.delegation_delay = 1; node_cfg.genesis.state.hardforks.ficus_hf.block_num = 0; node_cfg.genesis.state.hardforks.ficus_hf.pillar_blocks_interval = 4; - node_cfg.genesis.state.hardforks.ficus_hf.pillar_chain_sync_interval = 3; - node_cfg.genesis.state.hardforks.ficus_hf.pbft_inclusion_delay = 2; } auto nodes = launch_nodes(node_cfgs); @@ -101,8 +99,7 @@ TEST_F(PillarChainTest, pillar_blocks_create) { pillar_blocks_count * node_cfgs[0].genesis.state.hardforks.ficus_hf.pillar_blocks_interval; ASSERT_HAPPENS({20s, 250ms}, [&](auto& ctx) { for (const auto& node : nodes) { - WAIT_EXPECT_GE(ctx, node->getPbftChain()->getPbftChainSize(), - min_amount_of_pbft_blocks + node_cfgs[0].genesis.state.hardforks.ficus_hf.pbft_inclusion_delay) + WAIT_EXPECT_GE(ctx, node->getPbftChain()->getPbftChainSize(), min_amount_of_pbft_blocks + 1) } }); @@ -125,8 +122,6 @@ TEST_F(PillarChainTest, votes_count_changes) { node_cfg.genesis.state.dpos.delegation_delay = 1; node_cfg.genesis.state.hardforks.ficus_hf.block_num = 0; node_cfg.genesis.state.hardforks.ficus_hf.pillar_blocks_interval = 4; - node_cfg.genesis.state.hardforks.ficus_hf.pillar_chain_sync_interval = 3; - node_cfg.genesis.state.hardforks.ficus_hf.pbft_inclusion_delay = 2; } std::vector validators_vote_counts; @@ -144,8 +139,7 @@ TEST_F(PillarChainTest, votes_count_changes) { const auto first_pillar_block_period = node_cfgs[0].genesis.state.hardforks.ficus_hf.firstPillarBlockPeriod(); ASSERT_HAPPENS({20s, 250ms}, [&](auto& ctx) { for (const auto& node : nodes) { - WAIT_EXPECT_GE(ctx, node->getPbftChain()->getPbftChainSize(), - first_pillar_block_period + node_cfgs[0].genesis.state.hardforks.ficus_hf.pbft_inclusion_delay) + WAIT_EXPECT_GE(ctx, node->getPbftChain()->getPbftChainSize(), first_pillar_block_period + 1) } }); @@ -186,8 +180,7 @@ TEST_F(PillarChainTest, votes_count_changes) { node_cfgs[0].genesis.state.hardforks.ficus_hf.pillar_blocks_interval; ASSERT_HAPPENS({20s, 250ms}, [&](auto& ctx) { for (const auto& node : nodes) { - WAIT_EXPECT_GE(ctx, node->getPbftChain()->getPbftChainSize(), - new_pillar_block_period + node_cfgs[0].genesis.state.hardforks.ficus_hf.pbft_inclusion_delay) + WAIT_EXPECT_GE(ctx, node->getPbftChain()->getPbftChainSize(), new_pillar_block_period + 1) } }); @@ -214,8 +207,6 @@ TEST_F(PillarChainTest, pillar_chain_syncing) { node_cfg.genesis.state.dpos.delegation_delay = 1; node_cfg.genesis.state.hardforks.ficus_hf.block_num = 0; node_cfg.genesis.state.hardforks.ficus_hf.pillar_blocks_interval = 4; - node_cfg.genesis.state.hardforks.ficus_hf.pillar_chain_sync_interval = 3; - node_cfg.genesis.state.hardforks.ficus_hf.pbft_inclusion_delay = 2; } // Start first node @@ -224,9 +215,8 @@ TEST_F(PillarChainTest, pillar_chain_syncing) { // Wait until node1 creates at least 3 pillar blocks const auto pillar_blocks_count = 3; ASSERT_HAPPENS({20s, 250ms}, [&](auto& ctx) { - WAIT_EXPECT_GE(ctx, node1->getPbftChain()->getPbftChainSize(), - pillar_blocks_count * node_cfgs[0].genesis.state.hardforks.ficus_hf.pillar_blocks_interval + - node_cfgs[0].genesis.state.hardforks.ficus_hf.pbft_inclusion_delay) + WAIT_EXPECT_GE(ctx, node1->getFinalChain()->last_block_number(), + pillar_blocks_count * node_cfgs[0].genesis.state.hardforks.ficus_hf.pillar_blocks_interval + 1) }); node1->getPbftManager()->stop(); @@ -234,19 +224,21 @@ TEST_F(PillarChainTest, pillar_chain_syncing) { auto node2 = launch_nodes({node_cfgs[1]})[0]; // Wait until node2 syncs pbft chain with node1 ASSERT_HAPPENS({20s, 250ms}, [&](auto& ctx) { - WAIT_EXPECT_EQ(ctx, node2->getPbftChain()->getPbftChainSize(), node1->getPbftChain()->getPbftChainSize()) + WAIT_EXPECT_EQ(ctx, node2->getFinalChain()->last_block_number(), node1->getFinalChain()->last_block_number()) }); // Pbft/pillar chain syncing works in a way that pbft block with period N contains pillar votes for pillar block with // period N-ficus_hf.pillar_blocks_interval. const auto node2_latest_finalized_pillar_block_data = node2->getDB()->getLatestPillarBlockData(); ASSERT_TRUE(node2_latest_finalized_pillar_block_data.has_value()); + // ASSERT_EQ(node2_latest_finalized_pillar_block_data->block_->getPeriod(), + // (pillar_blocks_count - 1) * node_cfgs[0].genesis.state.hardforks.ficus_hf.pillar_blocks_interval); ASSERT_EQ(node2_latest_finalized_pillar_block_data->block_->getPeriod(), - (pillar_blocks_count - 1) * node_cfgs[0].genesis.state.hardforks.ficus_hf.pillar_blocks_interval); + pillar_blocks_count * node_cfgs[0].genesis.state.hardforks.ficus_hf.pillar_blocks_interval); // Trigger pillar votes syncing - node2->getPillarChainManager()->checkPillarChainSynced( - pillar_blocks_count * node_cfgs[0].genesis.state.hardforks.ficus_hf.pillar_blocks_interval); + // node2->getPillarChainManager()->checkPillarChainSynced( + // pillar_blocks_count * node_cfgs[0].genesis.state.hardforks.ficus_hf.pillar_blocks_interval); // Wait until node2 gets pillar votes and finalized pillar block #3 ASSERT_HAPPENS({20s, 250ms}, [&](auto& ctx) { WAIT_EXPECT_EQ(ctx, node2->getDB()->getLatestPillarBlockData()->block_->getPeriod(), @@ -472,8 +464,6 @@ TEST_F(PillarChainTest, finalize_root_in_pillar_block) { node_cfg.genesis.state.dpos.delegation_delay = 1; node_cfg.genesis.state.hardforks.ficus_hf.block_num = 0; node_cfg.genesis.state.hardforks.ficus_hf.pillar_blocks_interval = 4; - node_cfg.genesis.state.hardforks.ficus_hf.pillar_chain_sync_interval = 3; - node_cfg.genesis.state.hardforks.ficus_hf.pbft_inclusion_delay = 2; node_cfg.genesis.state.hardforks.ficus_hf.bridge_contract_address = dev::Address("0xc5b7d26bec6acdc3a0d33fe4c70be346a47a3a33"); } @@ -500,8 +490,7 @@ TEST_F(PillarChainTest, finalize_root_in_pillar_block) { pillar_blocks_count * node_cfgs[0].genesis.state.hardforks.ficus_hf.pillar_blocks_interval; ASSERT_HAPPENS({20s, 250ms}, [&](auto& ctx) { for (const auto& node : nodes) { - WAIT_EXPECT_GE(ctx, node->getPbftChain()->getPbftChainSize(), - min_amount_of_pbft_blocks + node_cfgs[0].genesis.state.hardforks.ficus_hf.pbft_inclusion_delay) + WAIT_EXPECT_GE(ctx, node->getPbftChain()->getPbftChainSize(), min_amount_of_pbft_blocks + 1) } }); diff --git a/tests/transaction_test.cpp b/tests/transaction_test.cpp index 295ea9c45f..897ba5a63f 100644 --- a/tests/transaction_test.cpp +++ b/tests/transaction_test.cpp @@ -8,6 +8,7 @@ #include "common/static_init.hpp" #include "config/genesis.hpp" +#include "final_chain/final_chain_impl.hpp" #include "final_chain/trie_common.hpp" #include "logger/logger.hpp" #include "pbft/pbft_manager.hpp" @@ -121,7 +122,7 @@ TEST_F(TransactionTest, sig) { TEST_F(TransactionTest, verifiers) { auto db = std::make_shared(data_dir); auto cfg = node_cfgs.front(); - auto final_chain = NewFinalChain(db, cfg); + auto final_chain = std::make_shared(db, cfg, addr_t{}); TransactionManager trx_mgr(cfg, db, final_chain, addr_t()); // insert trx std::thread t([&trx_mgr]() { @@ -142,7 +143,7 @@ TEST_F(TransactionTest, verifiers) { TEST_F(TransactionTest, transaction_limit) { auto db = std::make_shared(data_dir); auto cfg = node_cfgs.front(); - TransactionManager trx_mgr(cfg, db, NewFinalChain(db, cfg), addr_t()); + TransactionManager trx_mgr(cfg, db, std::make_shared(db, cfg, addr_t{}), addr_t()); // insert trx std::thread t([&trx_mgr]() { for (auto const& t : *g_signed_trx_samples) { @@ -163,7 +164,7 @@ TEST_F(TransactionTest, transaction_limit) { TEST_F(TransactionTest, prepare_signed_trx_for_propose) { auto db = std::make_shared(data_dir); auto cfg = node_cfgs.front(); - TransactionManager trx_mgr(cfg, db, NewFinalChain(db, cfg), addr_t()); + TransactionManager trx_mgr(cfg, db, std::make_shared(db, cfg, addr_t{}), addr_t()); std::thread insertTrx([&trx_mgr]() { for (auto const& t : *g_signed_trx_samples) { trx_mgr.insertTransaction(t); @@ -193,7 +194,7 @@ TEST_F(TransactionTest, prepare_signed_trx_for_propose) { TEST_F(TransactionTest, transaction_low_nonce) { auto db = std::make_shared(data_dir); auto cfg = node_cfgs.front(); - auto final_chain = NewFinalChain(db, cfg); + auto final_chain = std::make_shared(db, cfg, addr_t{}); TransactionManager trx_mgr(cfg, db, final_chain, addr_t()); const auto& trx_2 = g_signed_trx_samples[1]; auto& trx_1 = g_signed_trx_samples[0]; @@ -265,7 +266,7 @@ TEST_F(TransactionTest, transaction_low_nonce) { TEST_F(TransactionTest, transaction_concurrency) { auto db = std::make_shared(data_dir); auto cfg = node_cfgs.front(); - TransactionManager trx_mgr(cfg, db, NewFinalChain(db, cfg), addr_t()); + TransactionManager trx_mgr(cfg, db, std::make_shared(db, cfg, addr_t{}), addr_t()); bool stopped = false; // Insert transactions to memory pool and keep trying to insert them again on separate thread, it should always fail std::thread insertTrx([&trx_mgr, &stopped]() { @@ -649,7 +650,7 @@ TEST_F(TransactionTest, typed_deserialization) { TEST_F(TransactionTest, zero_gas_price_limit) { auto db = std::make_shared(data_dir); auto cfg = node_cfgs.front(); - auto final_chain = NewFinalChain(db, cfg); + auto final_chain = std::make_shared(db, cfg, addr_t{}); TransactionManager trx_mgr(cfg, db, final_chain, addr_t()); auto make_trx_with_price = [](uint64_t price) { return std::make_shared(1, 100, price, 100000, dev::bytes(), g_secret, addr_t::random()); @@ -672,7 +673,7 @@ TEST_F(TransactionTest, gas_price_limiting) { auto db = std::make_shared(data_dir); auto cfg = node_cfgs.front(); auto minimum_price = cfg.genesis.gas_price.minimum_price = 10; - auto final_chain = NewFinalChain(db, cfg); + auto final_chain = std::make_shared(db, cfg, addr_t{}); TransactionManager trx_mgr(cfg, db, final_chain, addr_t()); auto make_trx_with_price = [](uint64_t price) { return std::make_shared(1, 100, price, 100000, dev::bytes(), g_secret, addr_t::random());