From af351031cfc5d7e73d5e961ccf6def70ae7e9331 Mon Sep 17 00:00:00 2001 From: Jakub Fornadel Date: Tue, 20 Feb 2024 12:11:18 -0800 Subject: [PATCH] stop pbft chain progress and trigger pillar votes syncing if < 2t+1 votes --- .../pillar_chain/pillar_chain_manager.hpp | 9 ++++ .../consensus/src/pbft/pbft_manager.cpp | 41 +++++++++++++++++-- .../src/pillar_chain/pillar_chain_manager.cpp | 6 ++- .../latest/pbft_sync_packet_handler.cpp | 2 +- 4 files changed, 53 insertions(+), 5 deletions(-) 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 a42628a070..49e636fe72 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 @@ -113,6 +113,15 @@ class PillarChainManager { std::vector> getVerifiedPillarVotes(PbftPeriod period, const PillarBlock::Hash pillar_block_hash) const; + /** + * @brief Check if there is 2t+1 pillar votes for a combination of period & block_hash + * + * @param period + * @param block_hash + * @return true if there is 2t+1 pillar votes for a combination of period & block_hash + */ + bool hasTwoTPlusOneVotes(PbftPeriod period, const blk_hash_t& block_hash) const; + /** * @return period of the latest 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 f7bcb9fbec..a9c89d3e35 100644 --- a/libraries/core_libs/consensus/src/pbft/pbft_manager.cpp +++ b/libraries/core_libs/consensus/src/pbft/pbft_manager.cpp @@ -1423,13 +1423,48 @@ bool PbftManager::validatePbftBlock(const std::shared_ptr &pbft_block } } + const auto kBlockPeriod = pbft_block->getPeriod(); + + // Check if we have pillar votes for current pillar block + if (kBlockPeriod >= 2 * kGenesisConfig.state.hardforks.ficus_hf.pillar_block_periods && + kBlockPeriod % kGenesisConfig.state.hardforks.ficus_hf.pillar_block_periods == 0) { + 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 " << kBlockPeriod << ". No previous pillar block saved"; + assert(false); + return false; + } + + if (kBlockPeriod != current_pillar_block->getPeriod() + kGenesisConfig.state.hardforks.ficus_hf.pillar_block_periods) { + LOG(log_er_) << "Unable to validate pbft block " << pbft_block_hash << ", period " << kBlockPeriod << ". Previous pillar block period " << current_pillar_block->getPeriod(); + assert(false); + return false; + } + + // Check if there is 2t+1 pillar votes for current pillar block + if (!pillar_chain_mgr_->hasTwoTPlusOneVotes(current_pillar_block->getPeriod(), current_pillar_block->getHash())) { + LOG(log_er_) << "Unable to validate pbft block " << pbft_block_hash << ", period " << kBlockPeriod << ". There is < 2t+1 pillar votes for current pillar block " << current_pillar_block->getHash(); + + if (auto net = network_.lock(); net) { + LOG(log_nf_) << "Request pillar votes for block " << current_pillar_block->getHash() << ", period " << current_pillar_block->getPeriod(); + net->requestPillarBlockVotesBundle(current_pillar_block->getPeriod(), current_pillar_block->getHash()); + } else { + LOG(log_er_) << "validatePbftBlock: Failed to obtain net !"; + } + + return false; + } + } + + // Validate optional pillar block hash if (const auto pillar_block_hash = pbft_block->getPillarBlockHash(); - pbft_block->getPeriod() >= kGenesisConfig.state.hardforks.ficus_hf.pillar_block_periods && - pbft_block->getPeriod() % kGenesisConfig.state.hardforks.ficus_hf.pillar_block_periods == + kBlockPeriod >= kGenesisConfig.state.hardforks.ficus_hf.pillar_block_periods && + kBlockPeriod % kGenesisConfig.state.hardforks.ficus_hf.pillar_block_periods == kGenesisConfig.state.dpos.delegation_delay) { if (!pillar_block_hash.has_value()) { LOG(log_er_) << "PBFT block " << pbft_block_hash << " does not contain pillar block hash, period " - << pbft_block->getPeriod(); + << kBlockPeriod; 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 02b41b1a17..e21a419812 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 @@ -70,7 +70,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() - << ", period: " << current_pillar_block_->getPeriod(); + << ", period: " << current_pillar_block_->getPeriod() << ". Current period " << block_num; return; } @@ -325,6 +325,10 @@ std::vector> PillarChainManager::getVerifiedPillarVo return pillar_votes_.getVerifiedVotes(period, pillar_block_hash); } +bool PillarChainManager::hasTwoTPlusOneVotes(PbftPeriod period, const blk_hash_t& block_hash) const { + return pillar_votes_.hasTwoTPlusOneVotes(period, block_hash); +} + std::optional PillarChainManager::getLastFinalizedPillarBlockPeriod() const { std::shared_lock lock(mutex_); 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 605f9ca28a..adedab7b39 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,7 +29,7 @@ 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::kBaseRlpItemCount) { + if (packet_data.rlp_[1].itemCount() != PeriodData::kBaseRlpItemCount && packet_data.rlp_[1].itemCount() != PeriodData::kBaseRlpItemCount + 1) { throw InvalidRlpItemsCountException(packet_data.type_str_ + ":PeriodData", packet_data.rlp_[1].itemCount(), PeriodData::kBaseRlpItemCount); }