From 801acdb10439708fc38ec82a6713a852a3d0adb1 Mon Sep 17 00:00:00 2001 From: Dmitriy Khaustov Date: Mon, 25 Apr 2022 12:57:26 +0300 Subject: [PATCH] Init first block slot number during syncing and block production (#1182) * feature: sync epoch by call special functor on demand Signed-off-by: Dmitriy Khaustov aka xDimon --- core/blockchain/impl/block_tree_impl.cpp | 13 ++-- core/consensus/babe/babe_util.hpp | 6 +- core/consensus/babe/impl/babe_impl.cpp | 75 +++++++++++++------ core/consensus/babe/impl/babe_util_impl.cpp | 12 ++- core/consensus/babe/impl/babe_util_impl.hpp | 4 +- .../babe/impl/block_executor_impl.cpp | 34 +++++++++ test/core/blockchain/block_tree_test.cpp | 2 +- .../core/consensus/babe/babe_util_mock.hpp | 8 +- 8 files changed, 117 insertions(+), 37 deletions(-) diff --git a/core/blockchain/impl/block_tree_impl.cpp b/core/blockchain/impl/block_tree_impl.cpp index b57958e999..bcaaa86b85 100644 --- a/core/blockchain/impl/block_tree_impl.cpp +++ b/core/blockchain/impl/block_tree_impl.cpp @@ -139,6 +139,8 @@ namespace kagome::blockchain { auto least_leaf = *block_tree_leaves.begin(); auto best_leaf = *block_tree_leaves.rbegin(); + OUTCOME_TRY(last_finalized_block_info, storage->getLastFinalized()); + std::optional curr_epoch_number; // First, look up slot number of block number 1 @@ -172,18 +174,15 @@ namespace kagome::blockchain { // Now we have all to calculate epoch number auto epoch_number = (last_slot_number - first_slot_number) / babe_configuration->epoch_length; - consensus::EpochDescriptor epoch{ - .epoch_number = epoch_number, - .start_slot = first_slot_number - + epoch_number * babe_configuration->epoch_length}; - babe_util->syncEpoch(epoch); + babe_util->syncEpoch([&] { + auto is_first_block_finalized = last_finalized_block_info.number > 0; + return std::tuple(first_slot_number, is_first_block_finalized); + }); curr_epoch_number.emplace(epoch_number); } - OUTCOME_TRY(last_finalized_block_info, storage->getLastFinalized()); - std::optional curr_epoch; std::optional next_epoch; auto hash_tmp = last_finalized_block_info.hash; diff --git a/core/consensus/babe/babe_util.hpp b/core/consensus/babe/babe_util.hpp index f7e44526be..d78144df20 100644 --- a/core/consensus/babe/babe_util.hpp +++ b/core/consensus/babe/babe_util.hpp @@ -21,9 +21,11 @@ namespace kagome::consensus { virtual ~BabeUtil() = default; /** - * Init inner state by {@param epoch_descriptor} + * Init inner state by call {@param f} returning first block slot and flag + * if first block is already finalized */ - virtual void syncEpoch(EpochDescriptor epoch_descriptor) = 0; + virtual BabeSlotNumber syncEpoch( + std::function()> &&f) = 0; /** * @returns current unix time slot number diff --git a/core/consensus/babe/impl/babe_impl.cpp b/core/consensus/babe/impl/babe_impl.cpp index 21d1d672e3..6441f3b96d 100644 --- a/core/consensus/babe/impl/babe_impl.cpp +++ b/core/consensus/babe/impl/babe_impl.cpp @@ -193,20 +193,31 @@ namespace kagome::consensus::babe { } void BabeImpl::adjustEpochDescriptor() { - if (current_epoch_.epoch_number > 1) { - return; - } - - auto res = block_tree_->getBlockHeader(primitives::BlockNumber(1)); - if (res.has_error()) { - return; - } + auto first_slot_number = babe_util_->syncEpoch([&]() { + auto res = block_tree_->getBlockHeader(primitives::BlockNumber(1)); + if (res.has_error()) { + SL_TRACE(log_, + "First block slot is {}: no first block (at adjusting)", + babe_util_->getCurrentSlot()); + return std::tuple(babe_util_->getCurrentSlot(), false); + } - auto &first_block_header = res.value(); - auto babe_digest_res = consensus::getBabeDigests(first_block_header); - BOOST_ASSERT_MSG(babe_digest_res.has_value(), - "Any non genesis block must contain babe digest"); - auto first_slot_number = babe_digest_res.value().second.slot_number; + auto &first_block_header = res.value(); + auto babe_digest_res = consensus::getBabeDigests(first_block_header); + BOOST_ASSERT_MSG(babe_digest_res.has_value(), + "Any non genesis block must contain babe digest"); + auto first_slot_number = babe_digest_res.value().second.slot_number; + + auto is_first_block_finalized = + block_tree_->getLastFinalized().number > 0; + + SL_TRACE( + log_, + "First block slot is {}: by {}finalized first block (at adjusting)", + first_slot_number, + is_first_block_finalized ? "" : "non-"); + return std::tuple(first_slot_number, is_first_block_finalized); + }); auto current_epoch_start_slot = first_slot_number @@ -216,12 +227,10 @@ namespace kagome::consensus::babe { SL_WARN(log_, "Start-slot of current epoch {} has updated from {} to {}", current_epoch_.epoch_number, - current_epoch_start_slot, - current_epoch_.start_slot); + current_epoch_.start_slot, + current_epoch_start_slot); - current_epoch_.start_slot =current_epoch_start_slot; - - babe_util_->syncEpoch(current_epoch_); + current_epoch_.start_slot = current_epoch_start_slot; } } @@ -233,6 +242,8 @@ namespace kagome::consensus::babe { BOOST_ASSERT(keypair_ != nullptr); + adjustEpochDescriptor(); + SL_DEBUG( log_, "Starting an epoch {}. Session key: {:l}. Secondary slots allowed={}", @@ -242,8 +253,6 @@ namespace kagome::consensus::babe { current_epoch_ = epoch; current_slot_ = current_epoch_.start_slot; - babe_util_->syncEpoch(current_epoch_); - runSlot(); } @@ -842,7 +851,31 @@ namespace kagome::consensus::babe { ++current_epoch_.epoch_number; current_epoch_.start_slot = current_slot_; - babe_util_->syncEpoch(current_epoch_); + babe_util_->syncEpoch([&]() { + auto res = block_tree_->getBlockHeader(primitives::BlockNumber(1)); + if (res.has_error()) { + SL_WARN(log_, + "First block slot is {}: no first block (at start next epoch)", + babe_util_->getCurrentSlot()); + return std::tuple(babe_util_->getCurrentSlot(), false); + } + + auto &first_block_header = res.value(); + auto babe_digest_res = consensus::getBabeDigests(first_block_header); + BOOST_ASSERT_MSG(babe_digest_res.has_value(), + "Any non genesis block must contain babe digest"); + auto first_slot_number = babe_digest_res.value().second.slot_number; + + auto is_first_block_finalized = + block_tree_->getLastFinalized().number > 0; + + SL_WARN(log_, + "First block slot is {}: by {}finalized first block (at start " + "next epoch)", + first_slot_number, + is_first_block_finalized ? "" : "non-"); + return std::tuple(first_slot_number, is_first_block_finalized); + }); } bool BabeImpl::isSecondarySlotsAllowed() const { diff --git a/core/consensus/babe/impl/babe_util_impl.cpp b/core/consensus/babe/impl/babe_util_impl.cpp index c23735ce6b..64cc8e4dbf 100644 --- a/core/consensus/babe/impl/babe_util_impl.cpp +++ b/core/consensus/babe/impl/babe_util_impl.cpp @@ -16,10 +16,14 @@ namespace kagome::consensus { "Epoch length must be non zero"); } - void BabeUtilImpl::syncEpoch(EpochDescriptor epoch_descriptor) { - first_block_slot_number_.emplace( - epoch_descriptor.start_slot - - epoch_descriptor.epoch_number * babe_configuration_->epoch_length); + BabeSlotNumber BabeUtilImpl::syncEpoch( + std::function()> &&f) { + if (not is_first_block_finalized_) { + auto [first_block_slot_number, is_first_block_finalized] = f(); + first_block_slot_number_.emplace(first_block_slot_number); + is_first_block_finalized_ = is_first_block_finalized; + } + return first_block_slot_number_.value(); } BabeSlotNumber BabeUtilImpl::getCurrentSlot() const { diff --git a/core/consensus/babe/impl/babe_util_impl.hpp b/core/consensus/babe/impl/babe_util_impl.hpp index 5c98687cac..07c2c2e7ae 100644 --- a/core/consensus/babe/impl/babe_util_impl.hpp +++ b/core/consensus/babe/impl/babe_util_impl.hpp @@ -20,7 +20,8 @@ namespace kagome::consensus { std::shared_ptr babe_configuration, const BabeClock &clock); - void syncEpoch(EpochDescriptor epoch_descriptor) override; + BabeSlotNumber syncEpoch( + std::function()> &&f) override; BabeSlotNumber getCurrentSlot() const override; @@ -42,6 +43,7 @@ namespace kagome::consensus { const BabeClock &clock_; std::optional first_block_slot_number_; + bool is_first_block_finalized_ = false; }; } // namespace kagome::consensus #endif // KAGOME_CONSENSUS_BABEUTILIMPL diff --git a/core/consensus/babe/impl/block_executor_impl.cpp b/core/consensus/babe/impl/block_executor_impl.cpp index 11ef066e23..5fb41c96ee 100644 --- a/core/consensus/babe/impl/block_executor_impl.cpp +++ b/core/consensus/babe/impl/block_executor_impl.cpp @@ -132,6 +132,40 @@ namespace kagome::consensus { const auto &babe_header = babe_digests.second; auto slot_number = babe_header.slot_number; + + babe_util_->syncEpoch([&] { + auto res = block_tree_->getBlockHeader(primitives::BlockNumber(1)); + if (res.has_error()) { + if (block.header.number == 1) { + SL_TRACE(logger_, + "First block slot is {}: it is first block (at executing)", + slot_number); + return std::tuple(slot_number, false); + } else { + SL_TRACE(logger_, + "First block slot is {}: no first block (at executing)", + babe_util_->getCurrentSlot()); + return std::tuple(babe_util_->getCurrentSlot(), false); + } + } + + auto &first_block_header = res.value(); + auto babe_digest_res = consensus::getBabeDigests(first_block_header); + BOOST_ASSERT_MSG(babe_digest_res.has_value(), + "Any non genesis block must contain babe digest"); + auto first_slot_number = babe_digest_res.value().second.slot_number; + + auto is_first_block_finalized = + block_tree_->getLastFinalized().number > 0; + + SL_TRACE( + logger_, + "First block slot is {}: by {}finalized first block (at executing)", + first_slot_number, + is_first_block_finalized ? "" : "non-"); + return std::tuple(first_slot_number, is_first_block_finalized); + }); + auto epoch_number = babe_util_->slotToEpoch(slot_number); logger_->info( diff --git a/test/core/blockchain/block_tree_test.cpp b/test/core/blockchain/block_tree_test.cpp index 4a77e8ebbd..8832a74c7e 100644 --- a/test/core/blockchain/block_tree_test.cpp +++ b/test/core/blockchain/block_tree_test.cpp @@ -124,7 +124,7 @@ struct BlockTreeTest : public testing::Test { babe_config_->epoch_length = 2; babe_util_ = std::make_shared(); - EXPECT_CALL(*babe_util_, syncEpoch(_)).WillRepeatedly(Return()); + EXPECT_CALL(*babe_util_, syncEpoch(_)).WillRepeatedly(Return(1)); EXPECT_CALL(*babe_util_, slotToEpoch(_)).WillRepeatedly(Return(0)); block_tree_ = BlockTreeImpl::create(header_repo_, diff --git a/test/mock/core/consensus/babe/babe_util_mock.hpp b/test/mock/core/consensus/babe/babe_util_mock.hpp index 2ce3ee1446..c0f48f03ba 100644 --- a/test/mock/core/consensus/babe/babe_util_mock.hpp +++ b/test/mock/core/consensus/babe/babe_util_mock.hpp @@ -14,7 +14,13 @@ namespace kagome::consensus { class BabeUtilMock : public BabeUtil { public: - MOCK_METHOD(void, syncEpoch, (EpochDescriptor), (override)); + using SyncFunctor = std::function()>; + + MOCK_METHOD(BabeSlotNumber, syncEpoch, (SyncFunctor &), ()); + + BabeSlotNumber syncEpoch(SyncFunctor &&func) override { + return syncEpoch(func); + } MOCK_METHOD(BabeSlotNumber, getCurrentSlot, (), (const, override));