From 8b86c6b6244cbf49a8f87101c734015466019392 Mon Sep 17 00:00:00 2001 From: Jakub Fornadel Date: Wed, 14 Feb 2024 07:08:55 -0800 Subject: [PATCH 1/2] implement pillar votes syncing --- .../consensus/include/pbft/pbft_manager.hpp | 8 +++ .../include/pillar_chain/pillar_block.hpp | 5 +- .../consensus/src/pbft/pbft_manager.cpp | 59 ++++++++++++++++++- .../src/pillar_chain/pillar_block.cpp | 19 +++++- .../src/pillar_chain/pillar_votes.cpp | 2 + .../latest/get_pbft_sync_packet_handler.hpp | 4 +- .../common/ext_votes_packet_handler.cpp | 2 +- .../latest/get_pbft_sync_packet_handler.cpp | 16 ++++- .../latest/pbft_sync_packet_handler.cpp | 6 +- .../latest/votes_bundle_packet_handler.cpp | 6 +- libraries/core_libs/storage/src/storage.cpp | 8 +-- .../pbft_block/include/pbft/period_data.hpp | 9 ++- .../types/pbft_block/src/period_data.cpp | 46 +++++++-------- .../types/vote/include/vote/pillar_vote.hpp | 1 + .../vote/include/vote/votes_bundle_rlp.hpp | 30 ++++++++-- libraries/types/vote/src/pillar_vote.cpp | 5 ++ libraries/types/vote/src/votes_bundle_rlp.cpp | 56 ++++++++++++++---- 17 files changed, 221 insertions(+), 61 deletions(-) diff --git a/libraries/core_libs/consensus/include/pbft/pbft_manager.hpp b/libraries/core_libs/consensus/include/pbft/pbft_manager.hpp index 36d54bbda8..6f1fe66e44 100644 --- a/libraries/core_libs/consensus/include/pbft/pbft_manager.hpp +++ b/libraries/core_libs/consensus/include/pbft/pbft_manager.hpp @@ -502,6 +502,14 @@ class PbftManager { bool validatePbftBlockCertVotes(const std::shared_ptr pbft_block, const std::vector> &cert_votes) const; + /** + @brief Validates PBFT block [illar] votes + * + * @param period_data + * @return + */ + bool validatePbftBlockPillarVotes(const PeriodData &period_data) const; + /** * @param period * @return true if node can participate in consensus - is dpos eligible to vote and create blocks for specified period diff --git a/libraries/core_libs/consensus/include/pillar_chain/pillar_block.hpp b/libraries/core_libs/consensus/include/pillar_chain/pillar_block.hpp index 20884586ca..69ac69fdfc 100644 --- a/libraries/core_libs/consensus/include/pillar_chain/pillar_block.hpp +++ b/libraries/core_libs/consensus/include/pillar_chain/pillar_block.hpp @@ -93,7 +93,10 @@ struct PillarBlockData { std::shared_ptr block; std::vector> pillar_votes; - HAS_RLP_FIELDS + PillarBlockData(const dev::RLP& rlp); + dev::bytes getRlp() const; + + const static size_t kRlpItemCount = 2; }; /** @}*/ diff --git a/libraries/core_libs/consensus/src/pbft/pbft_manager.cpp b/libraries/core_libs/consensus/src/pbft/pbft_manager.cpp index 9eb9782810..ceef8dcb64 100644 --- a/libraries/core_libs/consensus/src/pbft/pbft_manager.cpp +++ b/libraries/core_libs/consensus/src/pbft/pbft_manager.cpp @@ -928,7 +928,8 @@ void PbftManager::certifyBlock_() { // Generate pillar vote in case pillar block hash is present in pbft block if (const auto pillar_block_hash = soft_voted_block->getPillarBlockHash(); pillar_block_hash.has_value()) { - // Creates pillar vote + // TODO: validate and save pillar_block_hash in pbft_manager, then try to vote for it during each period if node did + // not vote yet, otherwise it might not vote ever, if this block was pushed through syncing Creates pillar vote pillar_chain_mgr_->genAndPlacePillarVote(*pillar_block_hash, node_sk_); } } @@ -1788,6 +1789,57 @@ std::optional>>> Pbf } } + // Validate optional pillar block hash + const auto kBlockPeriod = period_data.pbft_blk->getPeriod(); + if (kBlockPeriod > kGenesisConfig.state.hardforks.ficus_hf.pillar_block_periods && + kBlockPeriod % kGenesisConfig.state.hardforks.ficus_hf.pillar_block_periods == + kGenesisConfig.state.dpos.delegation_delay) { + if (!period_data.pbft_blk->getPillarBlockHash().has_value()) { + LOG(log_er_) << "Synced PBFT block " << pbft_block_hash << ", period " << kBlockPeriod + << " does not contain pillar block hash"; + sync_queue_.clear(); + net->handleMaliciousSyncPeer(node_id); + return std::nullopt; + } + } else { + if (period_data.pbft_blk->getPillarBlockHash().has_value()) { + LOG(log_er_) << "Synced PBFT block " << pbft_block_hash << ", period " << period_data.pbft_blk->getPeriod() + << " contains pillar block hash"; + sync_queue_.clear(); + net->handleMaliciousSyncPeer(node_id); + return std::nullopt; + } + } + + // Validate optional pillar votes + if (kBlockPeriod >= 2 * kGenesisConfig.state.hardforks.ficus_hf.pillar_block_periods && + kBlockPeriod % kGenesisConfig.state.hardforks.ficus_hf.pillar_block_periods == 0) { + if (!period_data.pillar_votes_.has_value()) { + LOG(log_er_) << "Synced PBFT block " << pbft_block_hash << ", period " << kBlockPeriod + << " does not contain pillar votes"; + sync_queue_.clear(); + net->handleMaliciousSyncPeer(node_id); + return std::nullopt; + } + + // Validate pillar votes + if (!validatePbftBlockPillarVotes(period_data)) { + LOG(log_er_) << "Synced PBFT block " << pbft_block_hash << ", period " << kBlockPeriod + << " doesn't have enough valid pillar votes. Clear synced PBFT blocks!"; + sync_queue_.clear(); + net->handleMaliciousSyncPeer(node_id); + return std::nullopt; + } + } else { + if (period_data.pillar_votes_.has_value()) { + LOG(log_er_) << "Synced PBFT block " << pbft_block_hash << ", period " << period_data.pbft_blk->getPeriod() + << " contains pillar votes"; + sync_queue_.clear(); + net->handleMaliciousSyncPeer(node_id); + return std::nullopt; + } + } + return std::optional>>>( {std::move(period_data), std::move(cert_votes)}); } @@ -1875,6 +1927,11 @@ bool PbftManager::validatePbftBlockCertVotes(const std::shared_ptr pb return true; } +bool PbftManager::validatePbftBlockPillarVotes(const PeriodData &period_data) const { + // TODO: implement validation - similar to validatePbftBlockCertVotes + return false; +} + bool PbftManager::canParticipateInConsensus(PbftPeriod period) const { try { return final_chain_->dpos_is_eligible(period, node_addr_); diff --git a/libraries/core_libs/consensus/src/pillar_chain/pillar_block.cpp b/libraries/core_libs/consensus/src/pillar_chain/pillar_block.cpp index c670056374..fd2eff7ae9 100644 --- a/libraries/core_libs/consensus/src/pillar_chain/pillar_block.cpp +++ b/libraries/core_libs/consensus/src/pillar_chain/pillar_block.cpp @@ -4,6 +4,7 @@ #include "common/encoding_rlp.hpp" #include "vote/pillar_vote.hpp" +#include "vote/votes_bundle_rlp.hpp" namespace taraxa::pillar_chain { @@ -55,6 +56,22 @@ PillarBlock::Hash PillarBlock::getHash() { } RLP_FIELDS_DEFINE(PillarBlock, period_, state_root_, previous_pillar_block_hash_, validators_stakes_changes_) -RLP_FIELDS_DEFINE(PillarBlockData, block, pillar_votes) + +PillarBlockData::PillarBlockData(const dev::RLP& rlp) { + if (rlp.itemCount() != kRlpItemCount) { + throw std::runtime_error("PillarBlockData invalid itemCount: " + std::to_string(rlp.itemCount())); + } + + block = std::make_shared(rlp[0]); + pillar_votes = decodePillarVotesBundleRlp(rlp[1]); +} + +dev::bytes PillarBlockData::getRlp() const { + dev::RLPStream s(kRlpItemCount); + s.appendRaw(util::rlp_enc(block)); + s.appendRaw(encodePillarVotesBundleRlp(pillar_votes)); + + return s.invalidate(); +} } // namespace taraxa::pillar_chain 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 853b730fc9..9aa70fe63e 100644 --- a/libraries/core_libs/consensus/src/pillar_chain/pillar_votes.cpp +++ b/libraries/core_libs/consensus/src/pillar_chain/pillar_votes.cpp @@ -3,6 +3,8 @@ namespace taraxa::pillar_chain { bool PillarVotes::voteExists(const std::shared_ptr vote) const { + std::shared_lock lock(mutex_); + const auto found_period_votes = votes_.find(vote->getPeriod()); if (found_period_votes == votes_.end()) { return false; diff --git a/libraries/core_libs/network/include/network/tarcap/packets_handlers/latest/get_pbft_sync_packet_handler.hpp b/libraries/core_libs/network/include/network/tarcap/packets_handlers/latest/get_pbft_sync_packet_handler.hpp index 763bebb372..1097c3c423 100644 --- a/libraries/core_libs/network/include/network/tarcap/packets_handlers/latest/get_pbft_sync_packet_handler.hpp +++ b/libraries/core_libs/network/include/network/tarcap/packets_handlers/latest/get_pbft_sync_packet_handler.hpp @@ -6,6 +6,7 @@ namespace taraxa { class PbftChain; class DbStorage; class VoteManager; +class PillarChainManager; } // namespace taraxa namespace taraxa::network::tarcap { @@ -17,7 +18,7 @@ class GetPbftSyncPacketHandler : public PacketHandler { GetPbftSyncPacketHandler(const FullNodeConfig& conf, std::shared_ptr peers_state, std::shared_ptr packets_stats, std::shared_ptr pbft_syncing_state, std::shared_ptr pbft_chain, - std::shared_ptr vote_mgr, std::shared_ptr db, + std::shared_ptr vote_mgr, std::shared_ptr pillar_chain_mgr, std::shared_ptr db, const addr_t& node_addr, const std::string& logs_prefix = "GET_PBFT_SYNC_PH"); // Packet type that is processed by this handler @@ -34,6 +35,7 @@ class GetPbftSyncPacketHandler : public PacketHandler { std::shared_ptr pbft_syncing_state_; std::shared_ptr pbft_chain_; std::shared_ptr vote_mgr_; + std::shared_ptr pillar_chain_mgr_; std::shared_ptr db_; }; diff --git a/libraries/core_libs/network/src/tarcap/packets_handlers/latest/common/ext_votes_packet_handler.cpp b/libraries/core_libs/network/src/tarcap/packets_handlers/latest/common/ext_votes_packet_handler.cpp index ccc35e0078..d46d4a2431 100644 --- a/libraries/core_libs/network/src/tarcap/packets_handlers/latest/common/ext_votes_packet_handler.cpp +++ b/libraries/core_libs/network/src/tarcap/packets_handlers/latest/common/ext_votes_packet_handler.cpp @@ -182,7 +182,7 @@ void ExtVotesPacketHandler::sendPbftVotesBundle(const std::shared_ptr> &&votes) { - auto votes_bytes = encodeVotesBundleRlp(std::move(votes), false); + auto votes_bytes = encodePbftVotesBundleRlp(std::move(votes)); if (votes_bytes.empty()) { LOG(log_er_) << "Unable to send VotesBundle rlp"; return; 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 34dd1e6f82..2c4b700e8c 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 @@ -13,13 +13,15 @@ GetPbftSyncPacketHandler::GetPbftSyncPacketHandler(const FullNodeConfig &conf, s std::shared_ptr packets_stats, std::shared_ptr pbft_syncing_state, std::shared_ptr pbft_chain, - std::shared_ptr vote_mgr, std::shared_ptr db, + std::shared_ptr vote_mgr, std::shared_ptr pillar_chain_mgr, + std::shared_ptr db, const addr_t &node_addr, const std::string &logs_prefix) : PacketHandler(conf, std::move(peers_state), std::move(packets_stats), node_addr, logs_prefix + "GET_PBFT_SYNC_PH"), pbft_syncing_state_(std::move(pbft_syncing_state)), pbft_chain_(std::move(pbft_chain)), vote_mgr_(std::move(vote_mgr)), + pillar_chain_mgr_(std::move(pillar_chain_mgr)), db_(std::move(db)) {} void GetPbftSyncPacketHandler::validatePacketRlpFormat(const threadpool::PacketData &packet_data) const { @@ -81,6 +83,16 @@ void GetPbftSyncPacketHandler::sendPbftBlocks(const std::shared_ptr return; } + // Add pillar votes to period data + if (block_period >= 2 * kConf.genesis.state.hardforks.ficus_hf.pillar_block_periods && + block_period % kConf.genesis.state.hardforks.ficus_hf.pillar_block_periods == 0) { + const auto pillar_votes = db_->getPillarBlockData(block_period - kConf.genesis.state.hardforks.ficus_hf.pillar_block_periods); + if (!pillar_votes.has_value()) { + LOG(log_er_) << "DB corrupted. Cannot find pillar votes for period " << block_period << " in db"; + return; + } + } + dev::RLPStream s; if (pbft_chain_synced && last_block) { // Latest finalized block cert votes are saved in db as reward votes for new blocks @@ -91,7 +103,7 @@ void GetPbftSyncPacketHandler::sendPbftBlocks(const std::shared_ptr s.appendList(3); s << last_block; s.appendRaw(data); - s.appendRaw(encodeVotesBundleRlp(reward_votes, false)); + s.appendRaw(encodePbftVotesBundleRlp(reward_votes)); } else { s.appendList(2); s << last_block; diff --git a/libraries/core_libs/network/src/tarcap/packets_handlers/latest/pbft_sync_packet_handler.cpp b/libraries/core_libs/network/src/tarcap/packets_handlers/latest/pbft_sync_packet_handler.cpp index a178b7247f..6d3442b669 100644 --- a/libraries/core_libs/network/src/tarcap/packets_handlers/latest/pbft_sync_packet_handler.cpp +++ b/libraries/core_libs/network/src/tarcap/packets_handlers/latest/pbft_sync_packet_handler.cpp @@ -29,9 +29,9 @@ void PbftSyncPacketHandler::validatePacketRlpFormat(const threadpool::PacketData // PeriodData rlp parsing cannot be done through util::rlp_tuple, which automatically checks the rlp size so it is // checked here manually - if (packet_data.rlp_[1].itemCount() != PeriodData::kRlpItemCount) { + if (packet_data.rlp_[1].itemCount() != PeriodData::kBaseRlpItemCount) { throw InvalidRlpItemsCountException(packet_data.type_str_ + ":PeriodData", packet_data.rlp_[1].itemCount(), - PeriodData::kRlpItemCount); + PeriodData::kBaseRlpItemCount); } } @@ -230,7 +230,7 @@ PeriodData PbftSyncPacketHandler::decodePeriodData(const dev::RLP &period_data_r std::vector> PbftSyncPacketHandler::decodeVotesBundle( const dev::RLP &votes_bundle_rlp) const { - return decodeVotesBundleRlp(votes_bundle_rlp); + return decodePbftVotesBundleRlp(votes_bundle_rlp); } void PbftSyncPacketHandler::pbftSyncComplete() { diff --git a/libraries/core_libs/network/src/tarcap/packets_handlers/latest/votes_bundle_packet_handler.cpp b/libraries/core_libs/network/src/tarcap/packets_handlers/latest/votes_bundle_packet_handler.cpp index 6b080bef8b..d77aa960e3 100644 --- a/libraries/core_libs/network/src/tarcap/packets_handlers/latest/votes_bundle_packet_handler.cpp +++ b/libraries/core_libs/network/src/tarcap/packets_handlers/latest/votes_bundle_packet_handler.cpp @@ -20,11 +20,11 @@ VotesBundlePacketHandler::VotesBundlePacketHandler(const FullNodeConfig &conf, s void VotesBundlePacketHandler::validatePacketRlpFormat( [[maybe_unused]] const threadpool::PacketData &packet_data) const { auto items = packet_data.rlp_.itemCount(); - if (items != kVotesBundleRlpSize) { - throw InvalidRlpItemsCountException(packet_data.type_str_, items, kVotesBundleRlpSize); + if (items != kPbftVotesBundleRlpSize) { + throw InvalidRlpItemsCountException(packet_data.type_str_, items, kPbftVotesBundleRlpSize); } - auto votes_count = packet_data.rlp_[kVotesBundleRlpSize - 1].itemCount(); + auto votes_count = packet_data.rlp_[kPbftVotesBundleRlpSize - 1].itemCount(); if (votes_count == 0 || votes_count > kMaxVotesInBundleRlp) { throw InvalidRlpItemsCountException(packet_data.type_str_, items, kMaxVotesInBundleRlp); } diff --git a/libraries/core_libs/storage/src/storage.cpp b/libraries/core_libs/storage/src/storage.cpp index 72301f69b2..38aca9f867 100644 --- a/libraries/core_libs/storage/src/storage.cpp +++ b/libraries/core_libs/storage/src/storage.cpp @@ -681,7 +681,7 @@ dev::bytes DbStorage::getPeriodDataRaw(PbftPeriod period) const { } void DbStorage::savePillarBlockData(const pillar_chain::PillarBlockData& pillar_block_data) { - insert(Columns::pillar_block_data, pillar_block_data.block->getPeriod(), util::rlp_enc(pillar_block_data)); + insert(Columns::pillar_block_data, pillar_block_data.block->getPeriod(), pillar_block_data.getRlp()); } std::optional DbStorage::getPillarBlockData(PbftPeriod period) const { @@ -690,7 +690,7 @@ std::optional DbStorage::getPillarBlockData(PbftP return {}; } - return util::rlp_dec(dev::RLP(bytes)); + return pillar_chain::PillarBlockData(dev::RLP(bytes)); } std::optional DbStorage::getLatestPillarBlockData() const { @@ -700,7 +700,7 @@ std::optional DbStorage::getLatestPillarBlockData return {}; } - return util::rlp_dec(dev::RLP(it->value().ToString())); + return pillar_chain::PillarBlockData(dev::RLP(it->value().ToString())); } void DbStorage::saveOwnPillarBlockVote(const std::shared_ptr& vote) { @@ -874,7 +874,7 @@ std::vector> DbStorage::getPeriodCertVotes(PbftPeriod if (votes_rlp.itemCount() == 0) { return {}; } - return decodeVotesBundleRlp(votes_rlp); + return decodePbftVotesBundleRlp(votes_rlp); } std::optional DbStorage::getPeriodTransactions(PbftPeriod period) const { diff --git a/libraries/types/pbft_block/include/pbft/period_data.hpp b/libraries/types/pbft_block/include/pbft/period_data.hpp index 71d0691cbc..cd75078677 100644 --- a/libraries/types/pbft_block/include/pbft/period_data.hpp +++ b/libraries/types/pbft_block/include/pbft/period_data.hpp @@ -17,6 +17,7 @@ namespace taraxa { class PbftVote; class PbftBlock; +class PillarVote; /** * @brief PeriodData class is for block execution, that includes PBFT block, certify votes, DAG blocks, and transactions @@ -25,7 +26,8 @@ class PeriodData { public: PeriodData() = default; PeriodData(std::shared_ptr pbft_blk, - const std::vector>& previous_block_cert_votes); + const std::vector>& previous_block_cert_votes, + std::optional>>&& pillar_votes = {}); explicit PeriodData(const dev::RLP& all_rlp); explicit PeriodData(bytes const& all_rlp); @@ -35,7 +37,10 @@ class PeriodData { std::vector dag_blocks; SharedTransactions transactions; - const static size_t kRlpItemCount = 4; + // Pillar votes should be present only if pbft block contains also pillar block hash + std::optional>> pillar_votes_; + + const static size_t kBaseRlpItemCount = 4; /** * @brief Recursive Length Prefix diff --git a/libraries/types/pbft_block/src/period_data.cpp b/libraries/types/pbft_block/src/period_data.cpp index 0f9fa92662..8bb8ba795a 100644 --- a/libraries/types/pbft_block/src/period_data.cpp +++ b/libraries/types/pbft_block/src/period_data.cpp @@ -13,54 +13,44 @@ namespace taraxa { using namespace std; PeriodData::PeriodData(std::shared_ptr pbft_blk, - const std::vector>& previous_block_cert_votes) - : pbft_blk(std::move(pbft_blk)), previous_block_cert_votes(previous_block_cert_votes) {} + const std::vector>& previous_block_cert_votes, + std::optional>>&& pillar_votes) + : pbft_blk(std::move(pbft_blk)), + previous_block_cert_votes(previous_block_cert_votes), + pillar_votes_(std::move(pillar_votes)) {} PeriodData::PeriodData(const dev::RLP& rlp) { - // TODO[2587] Old Data - if (rlp.itemCount() == 4) { - try { - pbft_blk = std::make_shared(rlp[0]); - for (auto const vote_rlp : rlp[1]) { - previous_block_cert_votes.emplace_back(std::make_shared(vote_rlp)); - } - - for (auto const dag_block_rlp : rlp[2]) { - dag_blocks.emplace_back(dag_block_rlp); - } - - for (auto const trx_rlp : rlp[3]) { - transactions.emplace_back(std::make_shared(trx_rlp)); - } - return; - } catch (...) { - } - } auto it = rlp.begin(); pbft_blk = std::make_shared(*it++); const auto votes_bundle_rlp = *it++; if (pbft_blk->getPeriod() > 1) [[likely]] { - previous_block_cert_votes = decodeVotesBundleRlp(votes_bundle_rlp); + previous_block_cert_votes = decodePbftVotesBundleRlp(votes_bundle_rlp); } for (auto const dag_block_rlp : *it++) { dag_blocks.emplace_back(dag_block_rlp); } - for (auto const trx_rlp : *it) { + for (auto const trx_rlp : *it++) { transactions.emplace_back(std::make_shared(trx_rlp)); } + + // Pillar votes are optional data of period data since ficus hardfork + if (rlp.itemCount() == 5) { + pillar_votes_ = decodePillarVotesBundleRlp(*it); + } } PeriodData::PeriodData(bytes const& all_rlp) : PeriodData(dev::RLP(all_rlp)) {} bytes PeriodData::rlp() const { - dev::RLPStream s(kRlpItemCount); + const auto kRlpSize = pillar_votes_.has_value() ? kBaseRlpItemCount + 1 : kBaseRlpItemCount; + dev::RLPStream s(kRlpSize); s.appendRaw(pbft_blk->rlp(true)); if (pbft_blk->getPeriod() > 1) [[likely]] { - s.appendRaw(encodeVotesBundleRlp(previous_block_cert_votes, false)); + s.appendRaw(encodePbftVotesBundleRlp(previous_block_cert_votes)); } else { s.append(""); } @@ -75,6 +65,11 @@ bytes PeriodData::rlp() const { s.appendRaw(t->rlp()); } + // Pillar votes are optional data of period data since ficus hardfork + if (pillar_votes_.has_value()) { + s.appendRaw(encodePillarVotesBundleRlp(*pillar_votes_)); + } + return s.invalidate(); } @@ -83,6 +78,7 @@ void PeriodData::clear() { dag_blocks.clear(); transactions.clear(); previous_block_cert_votes.clear(); + pillar_votes_.reset(); } std::ostream& operator<<(std::ostream& strm, PeriodData const& b) { diff --git a/libraries/types/vote/include/vote/pillar_vote.hpp b/libraries/types/vote/include/vote/pillar_vote.hpp index 036c0676ce..ca871fc8c9 100644 --- a/libraries/types/vote/include/vote/pillar_vote.hpp +++ b/libraries/types/vote/include/vote/pillar_vote.hpp @@ -22,6 +22,7 @@ class PillarVote : public Vote { public: PillarVote() = default; PillarVote(const secret_t& node_sk, PbftPeriod period, const blk_hash_t& block_hash); + PillarVote(PbftPeriod period, const blk_hash_t& block_hash, sig_t&& signature); explicit PillarVote(const dev::RLP& rlp); explicit PillarVote(const bytes& rlp); diff --git a/libraries/types/vote/include/vote/votes_bundle_rlp.hpp b/libraries/types/vote/include/vote/votes_bundle_rlp.hpp index 4d1dd70400..8a1a1072cc 100644 --- a/libraries/types/vote/include/vote/votes_bundle_rlp.hpp +++ b/libraries/types/vote/include/vote/votes_bundle_rlp.hpp @@ -8,29 +8,47 @@ namespace taraxa { class PbftVote; +class PillarVote; /** @addtogroup Vote * @{ */ -constexpr static size_t kVotesBundleRlpSize{5}; +constexpr static size_t kPbftVotesBundleRlpSize{5}; /** - * @brief Encodes votes into optimized votes bundle rlp + * @brief Encodes pbft votes into optimized votes bundle rlp * * @param votes - * @param validate_common_data validate if all votes have the same block_hash, period, round and step * @return votes bundle rlp bytes */ -dev::bytes encodeVotesBundleRlp(const std::vector>& votes, bool validate_common_data); +dev::bytes encodePbftVotesBundleRlp(const std::vector>& votes); /** - * @brief Decodes votes from optimized votes bundle rlp + * @brief Decodes pbft votes from optimized votes bundle rlp * * @param votes_bundle_rlp * @return votes */ -std::vector> decodeVotesBundleRlp(const dev::RLP& votes_bundle_rlp); +std::vector> decodePbftVotesBundleRlp(const dev::RLP& votes_bundle_rlp); + +constexpr static size_t kPillarVotesBundleRlpSize{3}; + +/** + * @brief Encodes pillar votes into optimized votes bundle rlp + * + * @param votes + * @return votes bundle rlp bytes + */ +dev::bytes encodePillarVotesBundleRlp(const std::vector>& votes); + +/** + * @brief Decodes pillar votes from optimized votes bundle rlp + * + * @param votes_bundle_rlp + * @return votes + */ +std::vector> decodePillarVotesBundleRlp(const dev::RLP& votes_bundle_rlp); /** @}*/ diff --git a/libraries/types/vote/src/pillar_vote.cpp b/libraries/types/vote/src/pillar_vote.cpp index 21f18077ae..fcdf20f8da 100644 --- a/libraries/types/vote/src/pillar_vote.cpp +++ b/libraries/types/vote/src/pillar_vote.cpp @@ -11,6 +11,11 @@ PillarVote::PillarVote(const secret_t& node_sk, PbftPeriod period, const blk_has signVote(node_sk); } +PillarVote::PillarVote(PbftPeriod period, const blk_hash_t& block_hash, sig_t&& signature) + : Vote(block_hash), period_(period) { + vote_signature_ = std::move(signature); +} + PillarVote::PillarVote(const dev::RLP& rlp) { util::rlp_tuple(util::RLPDecoderRef(rlp, true), period_, block_hash_, vote_signature_); vote_hash_ = sha3(true); diff --git a/libraries/types/vote/src/votes_bundle_rlp.cpp b/libraries/types/vote/src/votes_bundle_rlp.cpp index fb3ca631f9..57f2fc1628 100644 --- a/libraries/types/vote/src/votes_bundle_rlp.cpp +++ b/libraries/types/vote/src/votes_bundle_rlp.cpp @@ -1,10 +1,11 @@ #include "vote/votes_bundle_rlp.hpp" #include "vote/pbft_vote.hpp" +#include "vote/pillar_vote.hpp" namespace taraxa { -dev::bytes encodeVotesBundleRlp(const std::vector>& votes, bool validate_common_data) { +dev::bytes encodePbftVotesBundleRlp(const std::vector>& votes) { if (votes.empty()) { assert(false); return {}; @@ -15,7 +16,7 @@ dev::bytes encodeVotesBundleRlp(const std::vector>& vo const auto reference_round = votes.back()->getRound(); const auto reference_step = votes.back()->getStep(); - dev::RLPStream votes_bundle_rlp(kVotesBundleRlpSize); + dev::RLPStream votes_bundle_rlp(kPbftVotesBundleRlpSize); votes_bundle_rlp.append(reference_block_hash); votes_bundle_rlp.append(reference_period); votes_bundle_rlp.append(reference_round); @@ -23,21 +24,14 @@ dev::bytes encodeVotesBundleRlp(const std::vector>& vo votes_bundle_rlp.appendList(votes.size()); for (const auto& vote : votes) { - if (validate_common_data && - (vote->getBlockHash() != reference_block_hash || vote->getPeriod() != reference_period || - vote->getRound() != reference_round || vote->getStep() != reference_step)) { - assert(false); - return {}; - } - votes_bundle_rlp.appendRaw(vote->optimizedRlp()); } return votes_bundle_rlp.invalidate(); } -std::vector> decodeVotesBundleRlp(const dev::RLP& votes_bundle_rlp) { - assert(votes_bundle_rlp.itemCount() == kVotesBundleRlpSize); +std::vector> decodePbftVotesBundleRlp(const dev::RLP& votes_bundle_rlp) { + assert(votes_bundle_rlp.itemCount() == kPbftVotesBundleRlpSize); const blk_hash_t votes_bundle_block_hash = votes_bundle_rlp[0].toHash(); const PbftPeriod votes_bundle_pbft_period = votes_bundle_rlp[1].toInt(); @@ -56,4 +50,44 @@ std::vector> decodeVotesBundleRlp(const dev::RLP& vote return votes; } +dev::bytes encodePillarVotesBundleRlp(const std::vector>& votes, + bool validate_common_data) { + if (votes.empty()) { + assert(false); + return {}; + } + + const auto& reference_block_hash = votes.back()->getBlockHash(); + const auto reference_period = votes.back()->getPeriod(); + + dev::RLPStream votes_bundle_rlp(kPillarVotesBundleRlpSize); + votes_bundle_rlp.append(reference_block_hash); + votes_bundle_rlp.append(reference_period); + votes_bundle_rlp.appendList(votes.size()); + + for (const auto& vote : votes) { + votes_bundle_rlp.appendRaw(util::rlp_enc(vote->getVoteSignature())); + } + + return votes_bundle_rlp.invalidate(); +} + +std::vector> decodePillarVotesBundleRlp(const dev::RLP& votes_bundle_rlp) { + assert(votes_bundle_rlp.itemCount() == kPillarVotesBundleRlpSize); + + const blk_hash_t votes_bundle_block_hash = votes_bundle_rlp[0].toHash(); + const PbftPeriod votes_bundle_pbft_period = votes_bundle_rlp[1].toInt(); + + std::vector> votes; + votes.reserve(votes_bundle_rlp[2].itemCount()); + + for (const auto sig_rlp : votes_bundle_rlp[2]) { + auto vote_sig = util::rlp_dec(sig_rlp); + auto vote = std::make_shared(votes_bundle_pbft_period, votes_bundle_block_hash, std::move(vote_sig)); + votes.push_back(std::move(vote)); + } + + return votes; +} + } // namespace taraxa \ No newline at end of file From 5091263d316d3646f52fcf92a664526679d3a972 Mon Sep 17 00:00:00 2001 From: Jakub Fornadel Date: Fri, 16 Feb 2024 13:22:56 -0800 Subject: [PATCH 2/2] implement pillar votes syncing as part of pbft syncing --- .../include/pillar_chain/pillar_block.hpp | 5 +- .../pillar_chain/pillar_chain_manager.hpp | 4 +- .../consensus/src/pbft/pbft_manager.cpp | 56 ++++++++++++++++++- .../src/pillar_chain/pillar_block.cpp | 11 ++-- .../src/pillar_chain/pillar_chain_manager.cpp | 26 ++++----- .../latest/get_pbft_sync_packet_handler.hpp | 13 +++-- .../latest/get_pbft_sync_packet_handler.cpp | 23 +++++--- .../get_pillar_chain_sync_packet_handler.cpp | 2 +- .../latest/pbft_sync_packet_handler.cpp | 37 ++++++++++++ .../pillar_chain_sync_packet_handler.cpp | 30 +++++----- .../network/src/tarcap/taraxa_capability.cpp | 5 +- libraries/core_libs/storage/src/storage.cpp | 2 +- libraries/types/vote/src/votes_bundle_rlp.cpp | 3 +- tests/full_node_test.cpp | 18 +++--- tests/test_util/src/test_util.cpp | 1 + 15 files changed, 172 insertions(+), 64 deletions(-) diff --git a/libraries/core_libs/consensus/include/pillar_chain/pillar_block.hpp b/libraries/core_libs/consensus/include/pillar_chain/pillar_block.hpp index 69ac69fdfc..bd1b9d26f3 100644 --- a/libraries/core_libs/consensus/include/pillar_chain/pillar_block.hpp +++ b/libraries/core_libs/consensus/include/pillar_chain/pillar_block.hpp @@ -90,9 +90,10 @@ class PillarBlock { }; struct PillarBlockData { - std::shared_ptr block; - std::vector> pillar_votes; + std::shared_ptr block_; + std::vector> pillar_votes_; + PillarBlockData(std::shared_ptr block, std::vector>&& pillar_votes); PillarBlockData(const dev::RLP& rlp); dev::bytes getRlp() const; 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 bf1ca2973f..a42628a070 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 @@ -85,9 +85,9 @@ class PillarChainManager { * @brief Add a vote to the pillar votes map * @param vote vote * - * @return true if vote was successfully added, otherwise false + * @return vote's weight if vote was successfully added, otherwise 0 */ - bool addVerifiedPillarVote(const std::shared_ptr& vote); + uint64_t addVerifiedPillarVote(const std::shared_ptr& vote); /** * @brief Push new finalized pillar block diff --git a/libraries/core_libs/consensus/src/pbft/pbft_manager.cpp b/libraries/core_libs/consensus/src/pbft/pbft_manager.cpp index ceef8dcb64..f7bcb9fbec 100644 --- a/libraries/core_libs/consensus/src/pbft/pbft_manager.cpp +++ b/libraries/core_libs/consensus/src/pbft/pbft_manager.cpp @@ -1928,8 +1928,60 @@ bool PbftManager::validatePbftBlockCertVotes(const std::shared_ptr pb } bool PbftManager::validatePbftBlockPillarVotes(const PeriodData &period_data) const { - // TODO: implement validation - similar to validatePbftBlockCertVotes - return false; + if (!period_data.pillar_votes_.has_value() || period_data.pillar_votes_->empty()) { + LOG(log_er_) << "No pillar votes provided, pbft block period " << period_data.pbft_blk->getPeriod() + << ". The synced PBFT block comes from a malicious player"; + return false; + } + + const auto &pbft_block_hash = period_data.pbft_blk->getBlockHash(); + const auto kRequiredVotesPeriod = + period_data.pbft_blk->getPeriod() - kGenesisConfig.state.hardforks.ficus_hf.pillar_block_periods; + + size_t votes_weight = 0; + + const auto current_pillar_block = pillar_chain_mgr_->getCurrentPillarBlock(); + + for (const auto &vote : *period_data.pillar_votes_) { + // Any info is wrong that can determine the synced PBFT block comes from a malicious player + if (vote->getPeriod() != kRequiredVotesPeriod) { + LOG(log_er_) << "Invalid pillar vote " << vote->getHash() << " period " << vote->getPeriod() << ", PBFT block " + << pbft_block_hash << ", kRequiredVotesPeriod " << kRequiredVotesPeriod; + return false; + } + + if (vote->getBlockHash() != current_pillar_block->getHash()) { + LOG(log_er_) << "Invalid pillar vote " << vote->getHash() << ", vote period " << vote->getPeriod() + << ", vote block hash " << vote->getBlockHash() << ", current pillar block " + << current_pillar_block->getHash() << ", block period " << current_pillar_block->getPeriod(); + return false; + } + + if (!pillar_chain_mgr_->validatePillarVote(vote)) { + LOG(log_er_) << "Invalid pillar vote " << vote->getHash(); + return false; + } + + if (const auto vote_weight = pillar_chain_mgr_->addVerifiedPillarVote(vote); vote_weight) { + votes_weight += vote_weight; + } else { + LOG(log_er_) << "Unable to add pillar vote " << vote->getHash() << " during syncing"; + return false; + } + } + + const auto two_t_plus_one = vote_mgr_->getPbftTwoTPlusOne(kRequiredVotesPeriod - 1, PbftVoteTypes::cert_vote); + if (!two_t_plus_one.has_value()) { + return false; + } + + if (votes_weight < *two_t_plus_one) { + LOG(log_wr_) << "Invalid pillar votes weight " << votes_weight << " < two_t_plus_one " << *two_t_plus_one + << ", period " << kRequiredVotesPeriod - 1; + return false; + } + + return true; } bool PbftManager::canParticipateInConsensus(PbftPeriod period) const { diff --git a/libraries/core_libs/consensus/src/pillar_chain/pillar_block.cpp b/libraries/core_libs/consensus/src/pillar_chain/pillar_block.cpp index fd2eff7ae9..c666642551 100644 --- a/libraries/core_libs/consensus/src/pillar_chain/pillar_block.cpp +++ b/libraries/core_libs/consensus/src/pillar_chain/pillar_block.cpp @@ -57,19 +57,22 @@ PillarBlock::Hash PillarBlock::getHash() { RLP_FIELDS_DEFINE(PillarBlock, period_, state_root_, previous_pillar_block_hash_, validators_stakes_changes_) +PillarBlockData::PillarBlockData(std::shared_ptr block, + std::vector>&& pillar_votes) + : block_(std::move(block)), pillar_votes_(std::move(pillar_votes)) {} PillarBlockData::PillarBlockData(const dev::RLP& rlp) { if (rlp.itemCount() != kRlpItemCount) { throw std::runtime_error("PillarBlockData invalid itemCount: " + std::to_string(rlp.itemCount())); } - block = std::make_shared(rlp[0]); - pillar_votes = decodePillarVotesBundleRlp(rlp[1]); + block_ = std::make_shared(rlp[0]); + pillar_votes_ = decodePillarVotesBundleRlp(rlp[1]); } dev::bytes PillarBlockData::getRlp() const { dev::RLPStream s(kRlpItemCount); - s.appendRaw(util::rlp_enc(block)); - s.appendRaw(encodePillarVotesBundleRlp(pillar_votes)); + s.appendRaw(util::rlp_enc(block_)); + s.appendRaw(encodePillarVotesBundleRlp(pillar_votes_)); return s.invalidate(); } 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 e5dd53e0e5..02b41b1a17 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 @@ -32,7 +32,7 @@ PillarChainManager::PillarChainManager(const FicusHardforkConfig& ficusHfConfig, } if (auto&& latest_pillar_block_data = db_->getLatestPillarBlockData(); latest_pillar_block_data.has_value()) { - last_finalized_pillar_block_ = std::move(latest_pillar_block_data->block); + last_finalized_pillar_block_ = std::move(latest_pillar_block_data->block_); // TODO: probably dont need this ??? // for (const auto& vote : latest_pillar_block_data->votes) { // addVerifiedPillarVote(vote); @@ -66,7 +66,7 @@ void PillarChainManager::createPillarBlock(const std::shared_ptrgetPeriod(), current_pillar_block_->getHash(), true); if (two_t_plus_one_votes.empty()) { LOG(log_er_) << "There is < 2t+1 votes for current pillar block " << current_pillar_block_->getHash() @@ -75,7 +75,7 @@ void PillarChainManager::createPillarBlock(const std::shared_ptrgetHash() << ", period " << current_pillar_block_->getPeriod(); @@ -163,18 +163,18 @@ bool PillarChainManager::genAndPlacePillarVote(const PillarBlock::Hash& pillar_b bool PillarChainManager::pushPillarBlock(const PillarBlockData& pillarBlockData) { // Note: 2t+1 votes should be validated before calling pushPillarBlock - if (!isValidPillarBlock(pillarBlockData.block)) { + if (!isValidPillarBlock(pillarBlockData.block_)) { LOG(log_er_) << "Trying to push invalid pillar block"; return false; } db_->savePillarBlockData(pillarBlockData); - LOG(log_nf_) << "Pillar block " << pillarBlockData.block->getHash() << " with period " - << pillarBlockData.block->getPeriod() << " pushed into the pillar chain"; + LOG(log_nf_) << "Pillar block " << pillarBlockData.block_->getHash() << " with period " + << pillarBlockData.block_->getPeriod() << " pushed into the pillar chain"; { std::scoped_lock lock(mutex_); - last_finalized_pillar_block_ = pillarBlockData.block; + last_finalized_pillar_block_ = pillarBlockData.block_; // Erase votes that are no longer needed pillar_votes_.eraseVotes(last_finalized_pillar_block_->getPeriod()); @@ -279,20 +279,20 @@ bool PillarChainManager::validatePillarVote(const std::shared_ptr vo return true; } -bool PillarChainManager::addVerifiedPillarVote(const std::shared_ptr& vote) { +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(), 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(); - return false; + return 0; } if (!validator_vote_count) { LOG(log_er_) << "Zero stake for pillar vote: " << vote->getHash() << ", author: " << vote->getVoterAddr() << ", period: " << vote->getPeriod(); - return false; + return 0; } if (!pillar_votes_.periodDataInitialized(vote->getPeriod())) { @@ -306,18 +306,18 @@ bool PillarChainManager::addVerifiedPillarVote(const std::shared_ptr // happen as this exception is caught above when calling dpos_eligible_vote_count LOG(log_er_) << "Unable to get 2t+1 for period " << vote->getPeriod(); assert(false); - return false; + return 0; } } if (!pillar_votes_.addVerifiedVote(vote, validator_vote_count)) { LOG(log_er_) << "Non-unique pillar vote " << vote->getHash() << ", validator " << vote->getVoterAddr(); - return false; + return 0; } LOG(log_dg_) << "Pillar vote " << vote->getHash() << " with period " << vote->getPeriod() << " for block " << vote->getBlockHash() << " added to the verified votes"; - return true; + return validator_vote_count; } std::vector> PillarChainManager::getVerifiedPillarVotes( diff --git a/libraries/core_libs/network/include/network/tarcap/packets_handlers/latest/get_pbft_sync_packet_handler.hpp b/libraries/core_libs/network/include/network/tarcap/packets_handlers/latest/get_pbft_sync_packet_handler.hpp index 1097c3c423..c5c899e36c 100644 --- a/libraries/core_libs/network/include/network/tarcap/packets_handlers/latest/get_pbft_sync_packet_handler.hpp +++ b/libraries/core_libs/network/include/network/tarcap/packets_handlers/latest/get_pbft_sync_packet_handler.hpp @@ -6,9 +6,12 @@ namespace taraxa { class PbftChain; class DbStorage; class VoteManager; -class PillarChainManager; } // namespace taraxa +namespace taraxa::pillar_chain { +class PillarChainManager; +} + namespace taraxa::network::tarcap { class PbftSyncingState; @@ -18,8 +21,10 @@ class GetPbftSyncPacketHandler : public PacketHandler { GetPbftSyncPacketHandler(const FullNodeConfig& conf, std::shared_ptr peers_state, std::shared_ptr packets_stats, std::shared_ptr pbft_syncing_state, std::shared_ptr pbft_chain, - std::shared_ptr vote_mgr, std::shared_ptr pillar_chain_mgr, std::shared_ptr db, - const addr_t& node_addr, const std::string& logs_prefix = "GET_PBFT_SYNC_PH"); + std::shared_ptr vote_mgr, + std::shared_ptr pillar_chain_mgr, + std::shared_ptr db, const addr_t& node_addr, + const std::string& logs_prefix = "GET_PBFT_SYNC_PH"); // Packet type that is processed by this handler static constexpr SubprotocolPacketType kPacketType_ = SubprotocolPacketType::GetPbftSyncPacket; @@ -35,7 +40,7 @@ class GetPbftSyncPacketHandler : public PacketHandler { std::shared_ptr pbft_syncing_state_; std::shared_ptr pbft_chain_; std::shared_ptr vote_mgr_; - std::shared_ptr pillar_chain_mgr_; + std::shared_ptr pillar_chain_mgr_; std::shared_ptr db_; }; 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 2c4b700e8c..e1ee6b3435 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 @@ -2,6 +2,7 @@ #include "network/tarcap/shared_states/pbft_syncing_state.hpp" #include "pbft/pbft_chain.hpp" +#include "pillar_chain/pillar_chain_manager.hpp" #include "storage/storage.hpp" #include "vote/pbft_vote.hpp" #include "vote/votes_bundle_rlp.hpp" @@ -13,9 +14,10 @@ GetPbftSyncPacketHandler::GetPbftSyncPacketHandler(const FullNodeConfig &conf, s std::shared_ptr packets_stats, std::shared_ptr pbft_syncing_state, std::shared_ptr pbft_chain, - std::shared_ptr vote_mgr, std::shared_ptr pillar_chain_mgr, - std::shared_ptr db, - const addr_t &node_addr, const std::string &logs_prefix) + std::shared_ptr vote_mgr, + std::shared_ptr pillar_chain_mgr, + std::shared_ptr db, const addr_t &node_addr, + const std::string &logs_prefix) : PacketHandler(conf, std::move(peers_state), std::move(packets_stats), node_addr, logs_prefix + "GET_PBFT_SYNC_PH"), pbft_syncing_state_(std::move(pbft_syncing_state)), @@ -83,14 +85,19 @@ void GetPbftSyncPacketHandler::sendPbftBlocks(const std::shared_ptr return; } + // TODO: bad solution: should not decode PeriodData, add pillar votes and then encode it... + PeriodData period_data{data}; // Add pillar votes to period data if (block_period >= 2 * kConf.genesis.state.hardforks.ficus_hf.pillar_block_periods && block_period % kConf.genesis.state.hardforks.ficus_hf.pillar_block_periods == 0) { - const auto pillar_votes = db_->getPillarBlockData(block_period - kConf.genesis.state.hardforks.ficus_hf.pillar_block_periods); - if (!pillar_votes.has_value()) { + auto pillar_data = + db_->getPillarBlockData(block_period - kConf.genesis.state.hardforks.ficus_hf.pillar_block_periods); + if (!pillar_data.has_value()) { LOG(log_er_) << "DB corrupted. Cannot find pillar votes for period " << block_period << " in db"; return; } + + period_data.pillar_votes_ = std::move(pillar_data->pillar_votes_); } dev::RLPStream s; @@ -102,17 +109,17 @@ void GetPbftSyncPacketHandler::sendPbftBlocks(const std::shared_ptr if (reward_votes[0]->getPeriod() == block_period) { s.appendList(3); s << last_block; - s.appendRaw(data); + s.appendRaw(period_data.rlp()); s.appendRaw(encodePbftVotesBundleRlp(reward_votes)); } else { s.appendList(2); s << last_block; - s.appendRaw(data); + s.appendRaw(period_data.rlp()); } } else { s.appendList(2); s << last_block; - s.appendRaw(data); + s.appendRaw(period_data.rlp()); } LOG(log_dg_) << "Sending PbftSyncPacket period " << block_period << " to " << peer_id; sealAndSend(peer_id, SubprotocolPacketType::PbftSyncPacket, std::move(s)); diff --git a/libraries/core_libs/network/src/tarcap/packets_handlers/latest/get_pillar_chain_sync_packet_handler.cpp b/libraries/core_libs/network/src/tarcap/packets_handlers/latest/get_pillar_chain_sync_packet_handler.cpp index 59cfd9bf89..f789e6e46c 100644 --- a/libraries/core_libs/network/src/tarcap/packets_handlers/latest/get_pillar_chain_sync_packet_handler.cpp +++ b/libraries/core_libs/network/src/tarcap/packets_handlers/latest/get_pillar_chain_sync_packet_handler.cpp @@ -45,7 +45,7 @@ void GetPillarChainSyncPacketHandler::process(const threadpool::PacketData &pack } dev::RLPStream s; - s.appendRaw(util::rlp_enc(*pillar_block_data)); + // s.appendRaw(util::rlp_enc(*pillar_block_data)); LOG(log_dg_) << "Sending PillarChainSyncPacket for period " << period << " to " << peer_id; sealAndSend(peer_id, SubprotocolPacketType::PillarChainSyncPacket, std::move(s)); diff --git a/libraries/core_libs/network/src/tarcap/packets_handlers/latest/pbft_sync_packet_handler.cpp b/libraries/core_libs/network/src/tarcap/packets_handlers/latest/pbft_sync_packet_handler.cpp index 6d3442b669..605f9ca28a 100644 --- a/libraries/core_libs/network/src/tarcap/packets_handlers/latest/pbft_sync_packet_handler.cpp +++ b/libraries/core_libs/network/src/tarcap/packets_handlers/latest/pbft_sync_packet_handler.cpp @@ -131,6 +131,43 @@ void PbftSyncPacketHandler::process(const threadpool::PacketData &packet_data, } } + // Validate optional pillar block hash + const auto kFicusHfConfig = kConf.genesis.state.hardforks.ficus_hf; + if (pbft_block_period > kFicusHfConfig.pillar_block_periods && + pbft_block_period % kFicusHfConfig.pillar_block_periods == kConf.genesis.state.dpos.delegation_delay) { + if (!period_data.pbft_blk->getPillarBlockHash().has_value()) { + LOG(log_er_) << "Synced PBFT block " << pbft_blk_hash << ", period " << pbft_block_period + << " does not contain pillar block hash"; + handleMaliciousSyncPeer(packet_data.from_node_id_); + return; + } + } else { + if (period_data.pbft_blk->getPillarBlockHash().has_value()) { + LOG(log_er_) << "Synced PBFT block " << pbft_blk_hash << ", period " << period_data.pbft_blk->getPeriod() + << " contains pillar block hash"; + handleMaliciousSyncPeer(packet_data.from_node_id_); + return; + } + } + + // Validate optional pillar votes + if (pbft_block_period >= 2 * kFicusHfConfig.pillar_block_periods && + pbft_block_period % kFicusHfConfig.pillar_block_periods == 0) { + if (!period_data.pillar_votes_.has_value()) { + LOG(log_er_) << "Synced PBFT block " << pbft_blk_hash << ", period " << pbft_block_period + << " does not contain pillar votes"; + handleMaliciousSyncPeer(packet_data.from_node_id_); + return; + } + } else { + if (period_data.pillar_votes_.has_value()) { + LOG(log_er_) << "Synced PBFT block " << pbft_blk_hash << ", period " << period_data.pbft_blk->getPeriod() + << " contains pillar votes"; + handleMaliciousSyncPeer(packet_data.from_node_id_); + return; + } + } + auto order_hash = PbftManager::calculateOrderHash(period_data.dag_blocks); if (order_hash != period_data.pbft_blk->getOrderHash()) { { // This is just log related stuff diff --git a/libraries/core_libs/network/src/tarcap/packets_handlers/latest/pillar_chain_sync_packet_handler.cpp b/libraries/core_libs/network/src/tarcap/packets_handlers/latest/pillar_chain_sync_packet_handler.cpp index 210d988d70..71f44883d2 100644 --- a/libraries/core_libs/network/src/tarcap/packets_handlers/latest/pillar_chain_sync_packet_handler.cpp +++ b/libraries/core_libs/network/src/tarcap/packets_handlers/latest/pillar_chain_sync_packet_handler.cpp @@ -38,23 +38,23 @@ void PillarChainSyncPacketHandler::process(const threadpool::PacketData &packet_ // return; // } - auto pillar_block_data = util::rlp_dec(packet_data.rlp_); - - if (!pillar_chain_manager_->isValidPillarBlock(pillar_block_data.block)) { - LOG(log_er_) << "Invalid sync pillar block received from peer " << peer->getId(); - return; - } - - // Validate signatures - // TODO: this will not work for light nodes because pbft might already be too far ahead... - // for (const auto signature: pillar_block_data.signatures) { + // auto pillar_block_data = util::rlp_dec(packet_data.rlp_); // + // if (!pillar_chain_manager_->isValidPillarBlock(pillar_block_data.block_)) { + // LOG(log_er_) << "Invalid sync pillar block received from peer " << peer->getId(); + // return; + // } + // + // // Validate signatures + // // TODO: this will not work for light nodes because pbft might already be too far ahead... + // // for (const auto signature: pillar_block_data.signatures) { + // // + // // } + // + // if (!pillar_chain_manager_->pushPillarBlock(pillar_block_data)) { + // LOG(log_er_) << "Unable to push sync pillar block received from peer " << peer->getId(); + // return; // } - - if (!pillar_chain_manager_->pushPillarBlock(pillar_block_data)) { - LOG(log_er_) << "Unable to push sync pillar block received from peer " << peer->getId(); - return; - } } } // namespace taraxa::network::tarcap diff --git a/libraries/core_libs/network/src/tarcap/taraxa_capability.cpp b/libraries/core_libs/network/src/tarcap/taraxa_capability.cpp index 68b85f9877..1da6794033 100644 --- a/libraries/core_libs/network/src/tarcap/taraxa_capability.cpp +++ b/libraries/core_libs/network/src/tarcap/taraxa_capability.cpp @@ -247,8 +247,9 @@ const TaraxaCapability::InitPacketsHandlers TaraxaCapability::kInitLatestVersion pbft_chain, pbft_mgr, dag_mgr, trx_mgr, db, node_addr, logs_prefix); - packets_handlers->registerHandler( - config, peers_state, packets_stats, pbft_syncing_state, pbft_chain, vote_mgr, db, node_addr, logs_prefix); + packets_handlers->registerHandler(config, peers_state, packets_stats, + pbft_syncing_state, pbft_chain, vote_mgr, + pillar_chain_mgr, db, node_addr, logs_prefix); packets_handlers->registerHandler(config, peers_state, packets_stats, pbft_syncing_state, pbft_chain, pbft_mgr, dag_mgr, vote_mgr, db, node_addr, diff --git a/libraries/core_libs/storage/src/storage.cpp b/libraries/core_libs/storage/src/storage.cpp index 38aca9f867..4ecb93a035 100644 --- a/libraries/core_libs/storage/src/storage.cpp +++ b/libraries/core_libs/storage/src/storage.cpp @@ -681,7 +681,7 @@ dev::bytes DbStorage::getPeriodDataRaw(PbftPeriod period) const { } void DbStorage::savePillarBlockData(const pillar_chain::PillarBlockData& pillar_block_data) { - insert(Columns::pillar_block_data, pillar_block_data.block->getPeriod(), pillar_block_data.getRlp()); + insert(Columns::pillar_block_data, pillar_block_data.block_->getPeriod(), pillar_block_data.getRlp()); } std::optional DbStorage::getPillarBlockData(PbftPeriod period) const { diff --git a/libraries/types/vote/src/votes_bundle_rlp.cpp b/libraries/types/vote/src/votes_bundle_rlp.cpp index 57f2fc1628..d557dace94 100644 --- a/libraries/types/vote/src/votes_bundle_rlp.cpp +++ b/libraries/types/vote/src/votes_bundle_rlp.cpp @@ -50,8 +50,7 @@ std::vector> decodePbftVotesBundleRlp(const dev::RLP& return votes; } -dev::bytes encodePillarVotesBundleRlp(const std::vector>& votes, - bool validate_common_data) { +dev::bytes encodePillarVotesBundleRlp(const std::vector>& votes) { if (votes.empty()) { assert(false); return {}; diff --git a/tests/full_node_test.cpp b/tests/full_node_test.cpp index 9cfa8787bd..9e3356b9ee 100644 --- a/tests/full_node_test.cpp +++ b/tests/full_node_test.cpp @@ -219,21 +219,23 @@ TEST_F(FullNodeTest, db_test) { const auto previous_pillar_block = std::make_shared( block_num - 1, h256{}, std::vector{}, blk_hash_t{}); - db.savePillarBlockData(pillar_chain::PillarBlockData{pillar_block, pillar_votes}); - db.savePillarBlockData(pillar_chain::PillarBlockData{previous_pillar_block, {}}); + db.savePillarBlockData( + pillar_chain::PillarBlockData{pillar_block, std::vector>{pillar_votes}}); + db.savePillarBlockData( + pillar_chain::PillarBlockData{previous_pillar_block, std::vector>{pillar_votes}}); const auto pillar_block_data_db = db.getPillarBlockData(pillar_block->getPeriod()); - EXPECT_EQ(pillar_block->getHash(), pillar_block_data_db->block->getHash()); - EXPECT_EQ(pillar_votes.size(), pillar_block_data_db->pillar_votes.size()); + EXPECT_EQ(pillar_block->getHash(), pillar_block_data_db->block_->getHash()); + EXPECT_EQ(pillar_votes.size(), pillar_block_data_db->pillar_votes_.size()); for (size_t idx = 0; idx < pillar_votes.size(); idx++) { - EXPECT_EQ(pillar_votes[idx]->getHash(), pillar_block_data_db->pillar_votes[idx]->getHash()); + EXPECT_EQ(pillar_votes[idx]->getHash(), pillar_block_data_db->pillar_votes_[idx]->getHash()); } const auto latest_pillar_block_data_db = db.getLatestPillarBlockData(); - EXPECT_EQ(pillar_block->getHash(), latest_pillar_block_data_db->block->getHash()); - EXPECT_EQ(pillar_votes.size(), latest_pillar_block_data_db->pillar_votes.size()); + EXPECT_EQ(pillar_block->getHash(), latest_pillar_block_data_db->block_->getHash()); + EXPECT_EQ(pillar_votes.size(), latest_pillar_block_data_db->pillar_votes_.size()); for (size_t idx = 0; idx < pillar_votes.size(); idx++) { - EXPECT_EQ(pillar_votes[idx]->getHash(), latest_pillar_block_data_db->pillar_votes[idx]->getHash()); + EXPECT_EQ(pillar_votes[idx]->getHash(), latest_pillar_block_data_db->pillar_votes_[idx]->getHash()); } // Pillar chain - pillar vote diff --git a/tests/test_util/src/test_util.cpp b/tests/test_util/src/test_util.cpp index da4e1b3ca5..524474f58c 100644 --- a/tests/test_util/src/test_util.cpp +++ b/tests/test_util/src/test_util.cpp @@ -200,6 +200,7 @@ NodesTest::NodesTest() { cfg.network.rpc->http_port = 7778 + i; cfg.network.rpc->ws_port = 8778 + i; cfg.node_secret = dev::KeyPair::create().secret(); + cfg.vrf_secret = taraxa::vdf_sortition::getVrfKeyPair().second; cfg.network.listen_port = 10003 + i; cfg.genesis.gas_price.minimum_price = 0;