From fabe411fd71369f9e10feef99a350f842c544c44 Mon Sep 17 00:00:00 2001 From: Ruslan Tushov Date: Fri, 29 Dec 2023 12:01:00 +0300 Subject: [PATCH] justification queue (#1904) Signed-off-by: turuslan --- CMakeLists.txt | 4 + cmake/functions.cmake | 3 - core/consensus/grandpa/CMakeLists.txt | 1 + core/consensus/grandpa/authority_manager.hpp | 9 + .../i_verified_justification_queue.hpp | 28 ++ .../grandpa/impl/authority_manager_impl.cpp | 67 +++++ .../grandpa/impl/authority_manager_impl.hpp | 5 + .../grandpa/impl/environment_impl.cpp | 10 +- .../grandpa/impl/environment_impl.hpp | 4 + core/consensus/grandpa/impl/grandpa_impl.cpp | 51 ++-- core/consensus/grandpa/impl/grandpa_impl.hpp | 6 +- .../impl/verified_justification_queue.cpp | 245 ++++++++++++++++++ .../impl/verified_justification_queue.hpp | 78 ++++++ .../grandpa/justification_observer.hpp | 7 +- .../timeline/impl/block_appender_base.cpp | 77 +----- .../timeline/impl/block_appender_base.hpp | 6 - core/injector/application_injector.cpp | 2 + .../adapters/protobuf_block_response.hpp | 9 +- core/network/impl/synchronizer_impl.cpp | 210 ++++++++++----- core/network/impl/synchronizer_impl.hpp | 17 ++ core/network/synchronizer.hpp | 10 + core/network/warp/sync.cpp | 15 +- core/network/warp/sync.hpp | 5 + core/primitives/event_types.hpp | 13 +- core/utils/thread_pool.hpp | 26 +- core/utils/weak_io_context_post.hpp | 17 ++ test/core/consensus/babe/babe_test.cpp | 1 + test/core/consensus/grandpa/chain_test.cpp | 1 + test/core/network/synchronizer_test.cpp | 1 + .../grandpa/authority_manager_mock.hpp | 10 + .../core/consensus/grandpa/grandpa_mock.hpp | 11 +- test/mock/core/network/synchronizer_mock.hpp | 10 + 32 files changed, 745 insertions(+), 214 deletions(-) create mode 100644 core/consensus/grandpa/i_verified_justification_queue.hpp create mode 100644 core/consensus/grandpa/impl/verified_justification_queue.cpp create mode 100644 core/consensus/grandpa/impl/verified_justification_queue.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d6ce6e35a9..8bb26c5b07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,10 @@ cmake_minimum_required(VERSION 3.12) +if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.27") + cmake_policy(SET CMP0144 NEW) +endif() + find_program(CCACHE_FOUND ccache) if(CCACHE_FOUND) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) diff --git a/cmake/functions.cmake b/cmake/functions.cmake index e44cf8f8bf..b031fec310 100644 --- a/cmake/functions.cmake +++ b/cmake/functions.cmake @@ -32,9 +32,6 @@ function(addtest_part test_name) target_sources(${test_name} PUBLIC ${ARGN} ) - target_link_libraries(${test_name} - GTest::gtest - ) endfunction() # conditionally applies flag. If flag is supported by current compiler, it will be added to compile options. diff --git a/core/consensus/grandpa/CMakeLists.txt b/core/consensus/grandpa/CMakeLists.txt index 72ec996b5b..82bb34f6e1 100644 --- a/core/consensus/grandpa/CMakeLists.txt +++ b/core/consensus/grandpa/CMakeLists.txt @@ -9,6 +9,7 @@ add_library(grandpa impl/vote_tracker_impl.cpp impl/vote_crypto_provider_impl.cpp impl/grandpa_impl.cpp + impl/verified_justification_queue.cpp impl/voting_round_impl.cpp impl/votes_cache.cpp impl/environment_impl.cpp diff --git a/core/consensus/grandpa/authority_manager.hpp b/core/consensus/grandpa/authority_manager.hpp index e8c5b9f1c5..c4058531ac 100644 --- a/core/consensus/grandpa/authority_manager.hpp +++ b/core/consensus/grandpa/authority_manager.hpp @@ -41,6 +41,15 @@ namespace kagome::consensus::grandpa { const primitives::BlockInfo &block, IsBlockFinalized finalized) const = 0; + /// Find previous scheduled change with justification + using ScheduledParentResult = + outcome::result>; + virtual ScheduledParentResult scheduledParent( + primitives::BlockInfo block) const = 0; + + /// Find possible scheduled changes with justification + virtual std::vector possibleScheduled() const = 0; + /** * Warp synced to `block` with `authorities`. */ diff --git a/core/consensus/grandpa/i_verified_justification_queue.hpp b/core/consensus/grandpa/i_verified_justification_queue.hpp new file mode 100644 index 0000000000..51596182f8 --- /dev/null +++ b/core/consensus/grandpa/i_verified_justification_queue.hpp @@ -0,0 +1,28 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +namespace kagome::consensus::grandpa { + struct GrandpaJustification; + + using AuthoritySetId = uint64_t; + + /// Finalize scheduled change after finalizing it's parent. + class IVerifiedJustificationQueue { + public: + virtual ~IVerifiedJustificationQueue() = default; + + /// Add verified justification + virtual void addVerified(AuthoritySetId set, + GrandpaJustification justification) = 0; + + /// Warp sync + virtual void warp() = 0; + }; +} // namespace kagome::consensus::grandpa diff --git a/core/consensus/grandpa/impl/authority_manager_impl.cpp b/core/consensus/grandpa/impl/authority_manager_impl.cpp index 27c0c703d2..f19d56a5ce 100644 --- a/core/consensus/grandpa/impl/authority_manager_impl.cpp +++ b/core/consensus/grandpa/impl/authority_manager_impl.cpp @@ -245,4 +245,71 @@ namespace kagome::consensus::grandpa { } indexer_.put(block, {value, std::nullopt}, true); } + + AuthorityManager::ScheduledParentResult AuthorityManagerImpl::scheduledParent( + primitives::BlockInfo block) const { + std::unique_lock lock{mutex_}; + OUTCOME_TRY(authoritiesOutcome(block, true)); + auto skip = true; + while (true) { + auto r = indexer_.get(block); + if (not r) { + break; + } + if (not skip and not r->inherit) { + if (not r->value) { + break; + } + if (r->value->state) { + break; + } + if (not r->value->forced_target) { + return std::make_pair(block, r->value->next_set_id - 1); + } + } else { + skip = false; + } + if (not r->prev) { + break; + } + block = *r->prev; + } + return AuthorityManagerError::NOT_FOUND; + } + + std::vector AuthorityManagerImpl::possibleScheduled() + const { + std::unique_lock lock{mutex_}; + for (auto &hash : block_tree_->getLeaves()) { + if (auto r = block_tree_->getBlockHeader(hash)) { + auto &block = r.value(); + std::ignore = authoritiesOutcome({block.number, hash}, true); + } + } + std::vector possible; + auto finalized = block_tree_->getLastFinalized(); + auto last = finalized; + auto r = indexer_.get(last); + if (not r) { + return possible; + } + if (r->inherit) { + if (not r->prev) { + return possible; + } + last = *r->prev; + r = indexer_.get(last); + if (not r) { + return possible; + } + } + for (auto it = indexer_.map_.upper_bound(finalized); + it != indexer_.map_.end(); + ++it) { + if (not it->second.inherit and it->second.prev == last) { + possible.emplace_back(it->first); + } + } + return possible; + } } // namespace kagome::consensus::grandpa diff --git a/core/consensus/grandpa/impl/authority_manager_impl.hpp b/core/consensus/grandpa/impl/authority_manager_impl.hpp index e7fe42b732..3e6768dd64 100644 --- a/core/consensus/grandpa/impl/authority_manager_impl.hpp +++ b/core/consensus/grandpa/impl/authority_manager_impl.hpp @@ -69,6 +69,11 @@ namespace kagome::consensus::grandpa { const primitives::BlockInfo &target_block, IsBlockFinalized finalized) const override; + ScheduledParentResult scheduledParent( + primitives::BlockInfo block) const override; + + std::vector possibleScheduled() const override; + void warp(const primitives::BlockInfo &block, const primitives::BlockHeader &header, const AuthoritySet &authorities) override; diff --git a/core/consensus/grandpa/impl/environment_impl.cpp b/core/consensus/grandpa/impl/environment_impl.cpp index 7bda3378f0..024229a786 100644 --- a/core/consensus/grandpa/impl/environment_impl.cpp +++ b/core/consensus/grandpa/impl/environment_impl.cpp @@ -14,6 +14,7 @@ #include "blockchain/block_tree.hpp" #include "consensus/grandpa/authority_manager.hpp" #include "consensus/grandpa/has_authority_set_change.hpp" +#include "consensus/grandpa/i_verified_justification_queue.hpp" #include "consensus/grandpa/justification_observer.hpp" #include "consensus/grandpa/movable_round_state.hpp" #include "consensus/grandpa/voting_round_error.hpp" @@ -39,6 +40,7 @@ namespace kagome::consensus::grandpa { std::shared_ptr transmitter, std::shared_ptr approved_ancestor, LazySPtr justification_observer, + std::shared_ptr verified_justification_queue, std::shared_ptr dispute_coordinator, std::shared_ptr parachain_api, std::shared_ptr backing_store, @@ -50,6 +52,7 @@ namespace kagome::consensus::grandpa { transmitter_{std::move(transmitter)}, approved_ancestor_(std::move(approved_ancestor)), justification_observer_(std::move(justification_observer)), + verified_justification_queue_(std::move(verified_justification_queue)), dispute_coordinator_(std::move(dispute_coordinator)), parachain_api_(std::move(parachain_api)), backing_store_(std::move(backing_store)), @@ -393,12 +396,7 @@ namespace kagome::consensus::grandpa { outcome::result EnvironmentImpl::finalize( VoterSetId id, const GrandpaJustification &grandpa_justification) { - primitives::Justification justification; - OUTCOME_TRY(enc, scale::encode(grandpa_justification)); - justification.data.put(enc); - OUTCOME_TRY(block_tree_->finalize(grandpa_justification.block_info.hash, - justification)); - + verified_justification_queue_->addVerified(id, grandpa_justification); return outcome::success(); } diff --git a/core/consensus/grandpa/impl/environment_impl.hpp b/core/consensus/grandpa/impl/environment_impl.hpp index 0e81c40dc8..43e69c6851 100644 --- a/core/consensus/grandpa/impl/environment_impl.hpp +++ b/core/consensus/grandpa/impl/environment_impl.hpp @@ -40,6 +40,7 @@ namespace kagome::parachain { } namespace kagome::consensus::grandpa { + class IVerifiedJustificationQueue; class EnvironmentImpl : public Environment, public std::enable_shared_from_this { @@ -51,6 +52,8 @@ namespace kagome::consensus::grandpa { std::shared_ptr transmitter, std::shared_ptr approved_ancestor, LazySPtr justification_observer, + std::shared_ptr + verified_justification_queue, std::shared_ptr dispute_coordinator, std::shared_ptr parachain_api, std::shared_ptr backing_store, @@ -124,6 +127,7 @@ namespace kagome::consensus::grandpa { std::shared_ptr transmitter_; std::shared_ptr approved_ancestor_; LazySPtr justification_observer_; + std::shared_ptr verified_justification_queue_; std::shared_ptr dispute_coordinator_; std::shared_ptr parachain_api_; std::shared_ptr backing_store_; diff --git a/core/consensus/grandpa/impl/grandpa_impl.cpp b/core/consensus/grandpa/impl/grandpa_impl.cpp index 5eb9acbb67..dba91143fb 100644 --- a/core/consensus/grandpa/impl/grandpa_impl.cpp +++ b/core/consensus/grandpa/impl/grandpa_impl.cpp @@ -1314,16 +1314,9 @@ namespace kagome::consensus::grandpa { }); } - void GrandpaImpl::verifyJustification( + outcome::result GrandpaImpl::verifyJustification( const GrandpaJustification &justification, - const AuthoritySet &authorities, - std::shared_ptr>> promise_res) { - REINVOKE(*internal_thread_context_, - verifyJustification, - justification, - authorities, - std::move(promise_res)); - + const AuthoritySet &authorities) { auto voters = VoterSet::make(authorities).value(); MovableRoundState state; state.round_number = justification.round_number; @@ -1340,8 +1333,7 @@ namespace kagome::consensus::grandpa { primitives::BlockInfo{}, voters, environment_), scheduler_, state); - promise_res->set_value( - round->validatePrecommitJustification(justification)); + return round->validatePrecommitJustification(justification); } void GrandpaImpl::applyJustification( @@ -1351,7 +1343,33 @@ namespace kagome::consensus::grandpa { applyJustification, justification, std::move(callback)); - auto round_opt = selectRound(justification.round_number, std::nullopt); + auto authorities_opt = authority_manager_->authorities( + justification.block_info, IsBlockFinalized{false}); + if (not authorities_opt) { + callbackCall(std::move(callback), + VotingRoundError::NO_KNOWN_AUTHORITIES_FOR_BLOCK); + return; + } + auto &authority_set = authorities_opt.value(); + auto round_opt = selectRound(justification.round_number, authority_set->id); + if (not round_opt + and std::pair{authority_set->id, justification.round_number} + < std::pair{current_round_->voterSetId(), + current_round_->roundNumber()}) { + auto r = verifyJustification(justification, *authority_set); + if (r.has_error()) { + SL_WARN(logger_, + "verify justification block {} set {} round {}: {}", + justification.block_info.number, + authority_set->id, + justification.round_number, + r.error()); + } else { + r = environment_->finalize(authority_set->id, justification); + } + callbackCall(std::move(callback), std::move(r)); + return; + } std::shared_ptr round; bool need_to_make_round_current = false; if (round_opt.has_value()) { @@ -1365,15 +1383,6 @@ namespace kagome::consensus::grandpa { return; } - auto authorities_opt = authority_manager_->authorities( - justification.block_info, IsBlockFinalized{false}); - if (!authorities_opt) { - callbackCall(std::move(callback), - VotingRoundError::NO_KNOWN_AUTHORITIES_FOR_BLOCK); - return; - } - auto &authority_set = authorities_opt.value(); - auto prev_round_opt = selectRound(justification.round_number - 1, authority_set->id); diff --git a/core/consensus/grandpa/impl/grandpa_impl.hpp b/core/consensus/grandpa/impl/grandpa_impl.hpp index 410ca3c49b..b9942a0d50 100644 --- a/core/consensus/grandpa/impl/grandpa_impl.hpp +++ b/core/consensus/grandpa/impl/grandpa_impl.hpp @@ -214,11 +214,9 @@ namespace kagome::consensus::grandpa { /** * Check justification votes signatures, ancestry and threshold. */ - void verifyJustification( + outcome::result verifyJustification( const GrandpaJustification &justification, - const AuthoritySet &authorities, - std::shared_ptr>> promise_res) - override; + const AuthoritySet &authorities) override; /** * Selects round that corresponds for justification, checks justification, diff --git a/core/consensus/grandpa/impl/verified_justification_queue.cpp b/core/consensus/grandpa/impl/verified_justification_queue.cpp new file mode 100644 index 0000000000..f470dbf4fc --- /dev/null +++ b/core/consensus/grandpa/impl/verified_justification_queue.cpp @@ -0,0 +1,245 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "consensus/grandpa/impl/verified_justification_queue.hpp" +#include "application/app_state_manager.hpp" +#include "blockchain/block_tree.hpp" +#include "consensus/grandpa/authority_manager.hpp" +#include "consensus/grandpa/has_authority_set_change.hpp" +#include "network/synchronizer.hpp" +#include "utils/weak_io_context_post.hpp" + +namespace kagome::consensus::grandpa { + /// When to start fetching justification range + constexpr size_t kRangeStart = 512 + 20; + + VerifiedJustificationQueue::VerifiedJustificationQueue( + application::AppStateManager &app_state_manager, + WeakIoContext main_thread, + std::shared_ptr block_tree, + std::shared_ptr authority_manager, + LazySPtr synchronizer, + primitives::events::ChainSubscriptionEnginePtr chain_sub_engine) + : main_thread_{std::move(main_thread)}, + block_tree_{std::move(block_tree)}, + authority_manager_{std::move(authority_manager)}, + synchronizer_{std::move(synchronizer)}, + chain_sub_{chain_sub_engine}, + log_{log::createLogger("VerifiedJustificationQueue")} { + app_state_manager.takeControl(*this); + } + + bool VerifiedJustificationQueue::start() { + if (auto r = authority_manager_->authorities( + block_tree_->getLastFinalized(), true)) { + expected_ = (**r).id; + } + chain_sub_.onHead([weak{weak_from_this()}]() { + if (auto self = weak.lock()) { + self->possibleLoop(); + } + }); + return true; + } + + void VerifiedJustificationQueue::addVerified( + AuthoritySetId set, GrandpaJustification justification) { + REINVOKE(main_thread_, addVerified, set, std::move(justification)); + if (set < expected_) { + return; + } + auto block_res = block_tree_->getBlockHeader(justification.block_info.hash); + if (not block_res) { + return; + } + auto &block = block_res.value(); + consensus::grandpa::HasAuthoritySetChange digest{block}; + required_.erase(justification.block_info); + auto ready = [&] { + if (not digest.scheduled) { + finalize(std::nullopt, justification); + return; + } + finalize(set, justification); + verifiedLoop(); + requiredLoop(); + possibleLoop(); + }; + if (set == expected_) { + ready(); + return; + } + auto parent_res = + authority_manager_->scheduledParent(justification.block_info); + if (not parent_res) { + return; + } + auto &parent = parent_res.value(); + auto expected = parent.second + 1; + if (expected == expected_) { + ready(); + return; + } + while (parent.second >= expected_) { + if (not verified_.contains(parent.second)) { + if (required_.emplace(parent.first).second) { + SL_INFO(log_, + "missing justification for block {} set {}", + parent.first, + parent.second); + } + } + auto parent_res = authority_manager_->scheduledParent(parent.first); + if (not parent_res) { + break; + } + parent = parent_res.value(); + } + requiredLoop(); + if (not digest.scheduled) { + if (not last_ + or justification.block_info.number + > last_->second.block_info.number) { + last_.emplace(set, std::move(justification)); + } + return; + } + verified_.emplace(set, std::make_pair(expected, std::move(justification))); + } + + void VerifiedJustificationQueue::finalize( + std::optional set, + const consensus::grandpa::GrandpaJustification &justification) { + if (auto r = block_tree_->finalize( + justification.block_info.hash, + {common::Buffer{scale::encode(justification).value()}}); + not r) { + return; + } + if (set) { + expected_ = *set + 1; + } + possible_.clear(); + } + + void VerifiedJustificationQueue::verifiedLoop() { + while (not verified_.empty()) { + auto &[set, p] = *verified_.begin(); + auto &[expected, justification] = p; + if (expected > expected_) { + break; + } + if (expected == expected_) { + finalize(set, justification); + } + verified_.erase(verified_.begin()); + } + if (last_) { + auto &[set, justification] = *last_; + if (set < expected_) { + last_.reset(); + } else if (set == expected_) { + finalize(std::nullopt, justification); + last_.reset(); + } + } + } + + void VerifiedJustificationQueue::requiredLoop() { + if (fetching_ or required_.empty()) { + return; + } + auto block = *required_.begin(); + auto cb = [weak{weak_from_this()}, block](outcome::result r) { + auto self = weak.lock(); + if (not self) { + return; + } + self->fetching_ = false; + if (r) { + self->required_.erase(block); + } + self->requiredLoop(); + }; + fetching_ = synchronizer_.get()->fetchJustification(block, std::move(cb)); + } + + void VerifiedJustificationQueue::possibleLoop() { + if (fetching_ or not required_.empty()) { + return; + } + if (not verified_.empty() or last_) { + return; + } + if (possible_.empty()) { + possible_ = authority_manager_->possibleScheduled(); + } + if (possible_.empty()) { + rangeLoop(); + return; + } + auto block = possible_.back(); + possible_.pop_back(); + auto cb = [weak{weak_from_this()}, block](outcome::result r) { + auto self = weak.lock(); + if (not self) { + return; + } + self->fetching_ = false; + self->requiredLoop(); + if (not r) { + self->possibleLoop(); + } else { + SL_INFO( + self->log_, "possible justification for block {}", block.number); + } + }; + fetching_ = synchronizer_.get()->fetchJustification(block, std::move(cb)); + } + + void VerifiedJustificationQueue::rangeLoop() { + auto finalized = block_tree_->getLastFinalized().number; + auto best = block_tree_->bestBlock().number; + if (best - finalized < kRangeStart) { + return; + } + range_ = std::max(range_, finalized + 1); + if (range_ > best) { + range_ = 0; + return; + } + auto cb = [weak{weak_from_this()}]( + outcome::result> r) { + auto self = weak.lock(); + if (not self) { + return; + } + self->fetching_ = false; + if (r) { + if (auto &next = r.value()) { + self->range_ = *next; + } else { + SL_INFO(self->log_, "justification for range {}..", self->range_); + } + } + self->requiredLoop(); + self->possibleLoop(); + }; + fetching_ = + synchronizer_.get()->fetchJustificationRange(range_, std::move(cb)); + if (fetching_) { + SL_INFO(log_, "fething justification range {}..", range_); + } + } + + void VerifiedJustificationQueue::warp() { + if (auto r = authority_manager_->authorities( + block_tree_->getLastFinalized(), true)) { + expected_ = (**r).id; + } + required_.clear(); + } +} // namespace kagome::consensus::grandpa diff --git a/core/consensus/grandpa/impl/verified_justification_queue.hpp b/core/consensus/grandpa/impl/verified_justification_queue.hpp new file mode 100644 index 0000000000..ffe934771d --- /dev/null +++ b/core/consensus/grandpa/impl/verified_justification_queue.hpp @@ -0,0 +1,78 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include + +#include "consensus/grandpa/i_verified_justification_queue.hpp" +#include "consensus/grandpa/structs.hpp" +#include "injector/lazy.hpp" +#include "log/logger.hpp" +#include "primitives/event_types.hpp" +#include "utils/weak_io_context.hpp" + +namespace kagome::application { + class AppStateManager; +} // namespace kagome::application + +namespace kagome::blockchain { + class BlockTree; +} // namespace kagome::blockchain + +namespace kagome::network { + class Synchronizer; +} // namespace kagome::network + +namespace kagome::consensus::grandpa { + class AuthorityManager; + + class VerifiedJustificationQueue + : public IVerifiedJustificationQueue, + public std::enable_shared_from_this { + public: + VerifiedJustificationQueue( + application::AppStateManager &app_state_manager, + WeakIoContext main_thread, + std::shared_ptr block_tree, + std::shared_ptr authority_manager, + LazySPtr synchronizer, + primitives::events::ChainSubscriptionEnginePtr chain_sub_engine); + + bool start(); + + void addVerified(AuthoritySetId set, + GrandpaJustification justification) override; + + void warp() override; + + private: + void finalize( + std::optional set, + const consensus::grandpa::GrandpaJustification &justification); + void verifiedLoop(); + void requiredLoop(); + void possibleLoop(); + void rangeLoop(); + + WeakIoContext main_thread_; + std::shared_ptr block_tree_; + std::shared_ptr authority_manager_; + LazySPtr synchronizer_; + primitives::events::ChainSub chain_sub_; + log::Logger log_; + + using SetAndJustification = std::pair; + AuthoritySetId expected_; + std::map verified_; + std::optional last_; + std::set required_; + std::vector possible_; + primitives::BlockNumber range_ = 0; + bool fetching_ = false; + }; +} // namespace kagome::consensus::grandpa diff --git a/core/consensus/grandpa/justification_observer.hpp b/core/consensus/grandpa/justification_observer.hpp index baedd065f3..21e991bf74 100644 --- a/core/consensus/grandpa/justification_observer.hpp +++ b/core/consensus/grandpa/justification_observer.hpp @@ -6,8 +6,6 @@ #pragma once -#include - #include "consensus/grandpa/structs.hpp" #include "outcome/outcome.hpp" #include "primitives/common.hpp" @@ -26,10 +24,9 @@ namespace kagome::consensus::grandpa { /** * Validate {@param justification} with {@param authorities}. */ - virtual void verifyJustification( + virtual outcome::result verifyJustification( const GrandpaJustification &justification, - const AuthoritySet &authorities, - std::shared_ptr>> promise_res) = 0; + const AuthoritySet &authorities) = 0; /** * Validate provided {@param justification} for finalization. diff --git a/core/consensus/timeline/impl/block_appender_base.cpp b/core/consensus/timeline/impl/block_appender_base.cpp index 4b489849d8..f8cfe66498 100644 --- a/core/consensus/timeline/impl/block_appender_base.cpp +++ b/core/consensus/timeline/impl/block_appender_base.cpp @@ -35,40 +35,12 @@ namespace kagome::consensus { BOOST_ASSERT(babe_config_repo_ != nullptr); BOOST_ASSERT(grandpa_environment_ != nullptr); BOOST_ASSERT(hasher_ != nullptr); - - postponed_justifications_ = std::make_shared< - std::map>(); } void BlockAppenderBase::applyJustifications( const primitives::BlockInfo &block_info, const std::optional &opt_justification, ApplyJustificationCb &&callback) { - // try to apply postponed justifications first if any - if (not postponed_justifications_->empty()) { - for (auto it = postponed_justifications_->begin(); - it != postponed_justifications_->end();) { - const auto &block_justified_for = it->first; - const auto &justification = it->second; - - SL_DEBUG(logger_, - "Try to apply postponed justification received for block {}", - block_justified_for); - grandpa_environment_->applyJustification( - block_justified_for, - justification, - [block_justified_for, - wpp{std::weak_ptr{ - postponed_justifications_}}](auto &&result) mutable { - if (auto pp = wpp.lock()) { - if (result.has_value()) { - pp->erase(block_justified_for); - } - } - }); - } - } - // apply justification if any (must be done strictly after block is // added and its consensus digests are handled) if (opt_justification.has_value()) { @@ -78,48 +50,15 @@ namespace kagome::consensus { grandpa_environment_->applyJustification( block_info, opt_justification.value(), - [wlogger{log::WLogger{logger_}}, - callback{std::move(callback)}, - block_info, - justification{opt_justification.value()}, - wpp{std::weak_ptr{ - postponed_justifications_}}](auto &&result) mutable { - if (auto pp = wpp.lock()) { - if (result.has_error()) { - // If the total weight is not enough, this justification is - // deferred to try to apply it after the next block is added. - // One of the reasons for this error is the presence of - // preliminary votes for future blocks that have not yet been - // applied. - if (result - == outcome::failure( - grandpa::VotingRoundError::NOT_ENOUGH_WEIGHT)) { - pp->emplace(block_info, justification); - if (auto logger = wlogger.lock()) { - SL_VERBOSE( - logger, - "Postpone justification received for block {}: {}", - block_info, - result); - } - } else { - if (auto logger = wlogger.lock()) { - SL_ERROR( - logger, - "Error while applying justification of block {}: {}", - block_info, - result.error()); - } - callback(result.as_failure()); - return; - } - } else { - // safely could be cleared if current justification applied - // successfully - pp->clear(); - } - callback(outcome::success()); + [logger{logger_}, block_info, callback{std::move(callback)}]( + outcome::result result) { + if (result.has_error()) { + SL_ERROR(logger, + "Error while applying justification of block {}: {}", + block_info, + result.error()); } + callback(std::move(result)); }); } else { callback(outcome::success()); diff --git a/core/consensus/timeline/impl/block_appender_base.hpp b/core/consensus/timeline/impl/block_appender_base.hpp index 1522cd588d..836e6e7cac 100644 --- a/core/consensus/timeline/impl/block_appender_base.hpp +++ b/core/consensus/timeline/impl/block_appender_base.hpp @@ -64,12 +64,6 @@ namespace kagome::consensus { private: log::Logger logger_ = log::createLogger("BlockAppender", "babe"); - // Justifications stored for future application (because a justification may - // contain votes for higher blocks, which we have not received yet) - using PostponedJustifications = - std::map; - std::shared_ptr postponed_justifications_; - std::shared_ptr block_tree_; std::shared_ptr babe_config_repo_; const EpochTimings &timings_; diff --git a/core/injector/application_injector.cpp b/core/injector/application_injector.cpp index a2c6df39ec..d2f0982e44 100644 --- a/core/injector/application_injector.cpp +++ b/core/injector/application_injector.cpp @@ -69,6 +69,7 @@ #include "consensus/grandpa/impl/authority_manager_impl.hpp" #include "consensus/grandpa/impl/environment_impl.hpp" #include "consensus/grandpa/impl/grandpa_impl.hpp" +#include "consensus/grandpa/impl/verified_justification_queue.hpp" #include "consensus/production_consensus.hpp" #include "consensus/timeline/impl/block_appender_base.hpp" #include "consensus/timeline/impl/block_executor_impl.hpp" @@ -736,6 +737,7 @@ namespace { di::bind.template to(), di::bind.template to(), di::bind.template to(), + di::bind.template to(), di::bind.template to(), di::bind.template to(), di::bind.template to(), diff --git a/core/network/adapters/protobuf_block_response.hpp b/core/network/adapters/protobuf_block_response.hpp index df534538b5..372ff1cf9f 100644 --- a/core/network/adapters/protobuf_block_response.hpp +++ b/core/network/adapters/protobuf_block_response.hpp @@ -93,9 +93,12 @@ namespace kagome::network { OUTCOME_TRY(hash, primitives::BlockHash::fromString(src_block_data.hash())); - OUTCOME_TRY(header, extract_value([&]() { - return src_block_data.header(); - })); + std::optional header; + if (not src_block_data.header().empty()) { + BOOST_OUTCOME_TRY(header, + extract_value( + [&]() { return src_block_data.header(); })); + } std::optional bodies; for (const auto &b : src_block_data.body()) { diff --git a/core/network/impl/synchronizer_impl.cpp b/core/network/impl/synchronizer_impl.cpp index a6aaf0ee13..3f850cce76 100644 --- a/core/network/impl/synchronizer_impl.cpp +++ b/core/network/impl/synchronizer_impl.cpp @@ -16,6 +16,7 @@ #include "consensus/grandpa/environment.hpp" #include "consensus/grandpa/has_authority_set_change.hpp" #include "network/beefy/i_beefy.hpp" +#include "network/peer_manager.hpp" #include "network/types/block_attributes.hpp" #include "primitives/common.hpp" #include "storage/predefined_keys.hpp" @@ -87,6 +88,7 @@ namespace kagome::network { std::shared_ptr storage, std::shared_ptr trie_pruner, std::shared_ptr router, + std::shared_ptr peer_manager, std::shared_ptr scheduler, std::shared_ptr hasher, primitives::events::ChainSubscriptionEnginePtr chain_sub_engine, @@ -100,6 +102,7 @@ namespace kagome::network { storage_(std::move(storage)), trie_pruner_(std::move(trie_pruner)), router_(std::move(router)), + peer_manager_(std::move(peer_manager)), scheduler_(std::move(scheduler)), hasher_(std::move(hasher)), beefy_{std::move(beefy)}, @@ -362,43 +365,18 @@ namespace kagome::network { primitives::BlockNumber hint, SyncResultHandler &&handler, std::map &&observed) { - // Interrupts process if node is shutting down - if (node_is_shutting_down_) { - handler(Error::SHUTTING_DOWN); - return; - } - network::BlocksRequest request{network::BlockAttribute::HEADER, hint, network::Direction::ASCENDING, 1}; - - auto request_fingerprint = request.fingerprint(); - - if (auto r = recent_requests_.emplace( - std::make_tuple(peer_id, request_fingerprint), "find common block"); - not r.second) { - SL_VERBOSE(log_, - "Can't check if block #{} in #{}..#{} is common with {}: {}", - hint, - lower, - upper - 1, - peer_id, - r.first->second); - handler(Error::DUPLICATE_REQUEST); - return; - } - - scheduleRecentRequestRemoval(peer_id, request_fingerprint); - auto response_handler = [wp = weak_from_this(), lower, upper, target = hint, peer_id, handler = std::move(handler), - observed = std::move(observed), - request_fingerprint](auto &&response_res) mutable { + observed = std::move(observed)]( + auto &&response_res) mutable { auto self = wp.lock(); if (not self) { return; @@ -430,7 +408,6 @@ namespace kagome::network { upper - 1, peer_id); handler(Error::EMPTY_RESPONSE); - self->recent_requests_.erase(std::tuple(peer_id, request_fingerprint)); return; } @@ -527,46 +504,20 @@ namespace kagome::network { lower, upper - 1, peer_id); - - auto protocol = router_->getSyncProtocol(); - BOOST_ASSERT_MSG(protocol, "Router did not provide sync protocol"); - protocol->request(peer_id, std::move(request), std::move(response_handler)); + fetch(peer_id, + std::move(request), + "find common block", + std::move(response_handler)); } void SynchronizerImpl::loadBlocks(const libp2p::peer::PeerId &peer_id, primitives::BlockInfo from, SyncResultHandler &&handler) { - // Interrupts process if node is shutting down - if (node_is_shutting_down_) { - if (handler) { - handler(Error::SHUTTING_DOWN); - } - return; - } - network::BlocksRequest request{attributesForSync(sync_method_), from.hash, network::Direction::ASCENDING, std::nullopt}; - auto request_fingerprint = request.fingerprint(); - - if (auto r = recent_requests_.emplace( - std::make_tuple(peer_id, request_fingerprint), "load blocks"); - not r.second) { - SL_VERBOSE(log_, - "Can't load blocks from {} beginning block {}: {}", - peer_id, - from, - r.first->second); - if (handler) { - handler(Error::DUPLICATE_REQUEST); - } - return; - } - - scheduleRecentRequestRemoval(peer_id, request_fingerprint); - auto response_handler = [wp = weak_from_this(), from, peer_id, @@ -773,9 +724,10 @@ namespace kagome::network { } }; - auto protocol = router_->getSyncProtocol(); - BOOST_ASSERT_MSG(protocol, "Router did not provide sync protocol"); - protocol->request(peer_id, std::move(request), std::move(response_handler)); + fetch(peer_id, + std::move(request), + "load blocks", + std::move(response_handler)); } void SynchronizerImpl::syncState(const libp2p::peer::PeerId &peer_id, @@ -1254,4 +1206,140 @@ namespace kagome::network { asking_blocks_portion_in_progress_ = false; } + void SynchronizerImpl::fetch( + const libp2p::peer::PeerId &peer, + BlocksRequest request, + const char *reason, + std::function)> &&cb) { + if (node_is_shutting_down_) { + cb(Error::SHUTTING_DOWN); + return; + } + auto fingerprint = request.fingerprint(); + if (not recent_requests_.emplace(std::tuple{peer, fingerprint}, reason) + .second) { + cb(Error::DUPLICATE_REQUEST); + return; + } + scheduleRecentRequestRemoval(peer, fingerprint); + router_->getSyncProtocol()->request( + peer, std::move(request), std::move(cb)); + } + + std::optional SynchronizerImpl::chooseJustificationPeer( + primitives::BlockNumber block, BlocksRequest::Fingerprint fingerprint) { + std::optional chosen; + peer_manager_->forEachPeer([&](const PeerId &peer) { + if (chosen) { + return; + } + if (busy_peers_.contains(peer)) { + return; + } + if (recent_requests_.contains({peer, fingerprint})) { + return; + } + auto info = peer_manager_->getPeerState(peer); + if (not info) { + return; + } + if (info->get().last_finalized < block) { + return; + } + chosen = peer; + }); + return chosen; + } + + bool SynchronizerImpl::fetchJustification(const primitives::BlockInfo &block, + CbResultVoid cb) { + BlocksRequest request{ + BlockAttribute::JUSTIFICATION, + block.hash, + Direction::DESCENDING, + 1, + false, + }; + auto chosen = chooseJustificationPeer(block.number, request.fingerprint()); + if (not chosen) { + return false; + } + busy_peers_.emplace(*chosen); + auto cb2 = [weak{weak_from_this()}, + block, + cb{std::move(cb)}, + peer{*chosen}](outcome::result r) mutable { + auto self = weak.lock(); + if (not self) { + return; + } + self->busy_peers_.erase(peer); + if (not r) { + return cb(r.error()); + } + auto &blocks = r.value().blocks; + if (blocks.size() != 1) { + return cb(Error::EMPTY_RESPONSE); + } + auto &justification = blocks[0].justification; + if (not justification) { + return cb(Error::EMPTY_RESPONSE); + } + self->grandpa_environment_->applyJustification( + block, *justification, std::move(cb)); + }; + fetch(*chosen, std::move(request), "justification", std::move(cb2)); + return true; + } + + bool SynchronizerImpl::fetchJustificationRange(primitives::BlockNumber min, + FetchJustificationRangeCb cb) { + BlocksRequest request{ + BlockAttribute::JUSTIFICATION, + min, + Direction::ASCENDING, + std::nullopt, + false, + }; + auto chosen = chooseJustificationPeer(min, request.fingerprint()); + if (not chosen) { + return false; + } + busy_peers_.emplace(*chosen); + auto cb2 = [weak{weak_from_this()}, min, cb{std::move(cb)}, peer{*chosen}]( + outcome::result r) mutable { + auto self = weak.lock(); + if (not self) { + return; + } + self->busy_peers_.erase(peer); + if (not r) { + return cb(r.error()); + } + auto &blocks = r.value().blocks; + if (blocks.empty()) { + return cb(Error::EMPTY_RESPONSE); + } + auto number = min; + for (auto &block : blocks) { + if (block.justification) { + self->grandpa_environment_->applyJustification( + {number, block.hash}, + *block.justification, + [cb{std::move(cb)}](outcome::result r) { + if (not r) { + cb(r.error()); + } else { + cb(std::nullopt); + } + }); + return; + } + ++number; + } + cb(min + blocks.size()); + }; + fetch(*chosen, std::move(request), "justification range", std::move(cb2)); + return true; + } } // namespace kagome::network diff --git a/core/network/impl/synchronizer_impl.hpp b/core/network/impl/synchronizer_impl.hpp index 79eeabc84d..64bdf80e78 100644 --- a/core/network/impl/synchronizer_impl.hpp +++ b/core/network/impl/synchronizer_impl.hpp @@ -49,6 +49,7 @@ namespace kagome::storage::trie { namespace kagome::network { class IBeefy; + class PeerManager; class SynchronizerImpl : public Synchronizer, @@ -97,6 +98,7 @@ namespace kagome::network { std::shared_ptr storage, std::shared_ptr trie_pruner, std::shared_ptr router, + std::shared_ptr peer_manager, std::shared_ptr scheduler, std::shared_ptr hasher, primitives::events::ChainSubscriptionEnginePtr chain_sub_engine, @@ -124,6 +126,12 @@ namespace kagome::network { const libp2p::peer::PeerId &peer_id, SyncResultHandler &&handler) override; + bool fetchJustification(const primitives::BlockInfo &block, + CbResultVoid cb) override; + + bool fetchJustificationRange(primitives::BlockNumber min, + FetchJustificationRangeCb cb) override; + /// Enqueues loading and applying state on block {@param block} /// from peer {@param peer_id}. /// If finished, {@param handler} be called @@ -193,6 +201,14 @@ namespace kagome::network { outcome::result syncState(std::unique_lock &lock, outcome::result &&_res); + void fetch(const libp2p::peer::PeerId &peer, + BlocksRequest request, + const char *reason, + std::function)> &&cb); + + std::optional chooseJustificationPeer( + primitives::BlockNumber block, BlocksRequest::Fingerprint fingerprint); + std::shared_ptr app_state_manager_; std::shared_ptr block_tree_; std::shared_ptr block_appender_; @@ -201,6 +217,7 @@ namespace kagome::network { std::shared_ptr storage_; std::shared_ptr trie_pruner_; std::shared_ptr router_; + std::shared_ptr peer_manager_; std::shared_ptr scheduler_; std::shared_ptr hasher_; std::shared_ptr beefy_; diff --git a/core/network/synchronizer.hpp b/core/network/synchronizer.hpp index 4e0cb2550e..0298b8c76e 100644 --- a/core/network/synchronizer.hpp +++ b/core/network/synchronizer.hpp @@ -43,6 +43,16 @@ namespace kagome::network { const libp2p::peer::PeerId &peer_id, SyncResultHandler &&handler) = 0; + /// Fetch justification + virtual bool fetchJustification(const primitives::BlockInfo &block, + CbResultVoid cb) = 0; + + /// Fetch justification range + using FetchJustificationRangeCb = std::function>)>; + virtual bool fetchJustificationRange(primitives::BlockNumber min, + FetchJustificationRangeCb cb) = 0; + virtual void syncState(const libp2p::peer::PeerId &peer_id, const primitives::BlockInfo &block, SyncResultHandler &&handler) = 0; diff --git a/core/network/warp/sync.cpp b/core/network/warp/sync.cpp index 336af9de68..b7814b24b1 100644 --- a/core/network/warp/sync.cpp +++ b/core/network/warp/sync.cpp @@ -13,6 +13,7 @@ #include "consensus/babe/babe_config_repository.hpp" #include "consensus/grandpa/authority_manager.hpp" #include "consensus/grandpa/has_authority_set_change.hpp" +#include "consensus/grandpa/i_verified_justification_queue.hpp" #include "consensus/grandpa/justification_observer.hpp" #include "network/warp/cache.hpp" #include "storage/predefined_keys.hpp" @@ -28,6 +29,8 @@ namespace kagome::network { std::shared_ptr block_storage, std::shared_ptr warp_sync_cache, std::shared_ptr authority_manager, + std::shared_ptr + verified_justification_queue, std::shared_ptr babe_config_repository, std::shared_ptr block_tree) @@ -36,6 +39,7 @@ namespace kagome::network { block_storage_{std::move(block_storage)}, warp_sync_cache_{std::move(warp_sync_cache)}, authority_manager_{std::move(authority_manager)}, + verified_justification_queue_{std::move(verified_justification_queue)}, babe_config_repository_{std::move(babe_config_repository)}, block_tree_{std::move(block_tree)}, db_{db.getSpace(storage::Space::kDefault)}, @@ -89,14 +93,8 @@ namespace kagome::network { authority_manager_->authorities(block_tree_->getLastFinalized(), true) .value(); - auto promise_res = - std::make_shared>>(); - auto res_future = promise_res->get_future(); - - grandpa_->verifyJustification( - fragment.justification, *authorities, promise_res); - - auto result = res_future.get(); + auto result = + grandpa_->verifyJustification(fragment.justification, *authorities); if (result.has_error()) { return; } @@ -131,6 +129,7 @@ namespace kagome::network { authority_manager_->warp(op.block_info, op.header, op.authorities); block_tree_->warp(op.block_info); babe_config_repository_->warp(op.block_info); + verified_justification_queue_->warp(); db_->remove(storage::kWarpSyncOp).value(); } } // namespace kagome::network diff --git a/core/network/warp/sync.hpp b/core/network/warp/sync.hpp index 4f3500e645..bd15d94ca3 100644 --- a/core/network/warp/sync.hpp +++ b/core/network/warp/sync.hpp @@ -24,6 +24,7 @@ namespace kagome::consensus::babe { } // namespace kagome::consensus::babe namespace kagome::consensus::grandpa { + class IVerifiedJustificationQueue; class JustificationObserver; class AuthorityManager; } // namespace kagome::consensus::grandpa @@ -64,6 +65,8 @@ namespace kagome::network { std::shared_ptr block_storage, std::shared_ptr warp_sync_cache, std::shared_ptr authority_manager, + std::shared_ptr + verified_justification_queue, std::shared_ptr babe_config_repository, std::shared_ptr block_tree); @@ -91,6 +94,8 @@ namespace kagome::network { std::shared_ptr block_storage_; std::shared_ptr warp_sync_cache_; std::shared_ptr authority_manager_; + std::shared_ptr + verified_justification_queue_; std::shared_ptr babe_config_repository_; std::shared_ptr block_tree_; diff --git a/core/primitives/event_types.hpp b/core/primitives/event_types.hpp index 81f933d322..07a005bca8 100644 --- a/core/primitives/event_types.hpp +++ b/core/primitives/event_types.hpp @@ -266,15 +266,14 @@ namespace kagome::primitives::events { : sub{std::make_shared( std::move(engine))} {} - void onFinalize(auto f) { - sub->subscribe(sub->generateSubscriptionSetId(), - ChainEventType::kFinalizedHeads); + void onBlock(ChainEventType type, auto f) { + sub->subscribe(sub->generateSubscriptionSetId(), type); sub->setCallback( [f{std::move(f)}](subscription::SubscriptionSetId, ChainSubscriptionEngine::ReceiverType &, ChainEventType, const ChainEventParams &args) { - auto &block = boost::get(args); + auto &block = boost::get(args).get(); if constexpr (std::is_invocable_v) { f(); } else { @@ -282,6 +281,12 @@ namespace kagome::primitives::events { } }); } + void onFinalize(auto f) { + onBlock(ChainEventType::kFinalizedHeads, std::move(f)); + } + void onHead(auto f) { + onBlock(ChainEventType::kNewHeads, std::move(f)); + } ChainEventSubscriberPtr sub; }; diff --git a/core/utils/thread_pool.hpp b/core/utils/thread_pool.hpp index 98f2f6f445..a30c54c0bf 100644 --- a/core/utils/thread_pool.hpp +++ b/core/utils/thread_pool.hpp @@ -15,8 +15,8 @@ #include #include -#include "utils/weak_io_context_post.hpp" #include "utils/watchdog.hpp" +#include "utils/weak_io_context_post.hpp" namespace kagome { @@ -49,10 +49,18 @@ namespace kagome { } } + friend void post(ThreadHandler &self, auto f) { + return self.execute(std::move(f)); + } + bool isInCurrentThread() const { return runningInThisThread(ioc_); } + friend bool runningInThisThread(const ThreadHandler &self) { + return self.isInCurrentThread(); + } + private: std::atomic execution_state_; WeakIoContext ioc_; @@ -120,19 +128,3 @@ namespace kagome { std::vector threads_; }; } // namespace kagome - -#define REINVOKE(ctx, func, ...) \ - do { \ - if (not(ctx).isInCurrentThread()) { \ - return (ctx).execute([weak = weak_from_this(), \ - args = std::make_tuple(__VA_ARGS__)]() mutable { \ - if (auto self = weak.lock()) { \ - std::apply( \ - [&](auto &&...args) mutable { \ - self->func(std::forward(args)...); \ - }, \ - std::move(args)); \ - } \ - }); \ - } \ - } while (false) diff --git a/core/utils/weak_io_context_post.hpp b/core/utils/weak_io_context_post.hpp index 87588a423e..55c4a43ccd 100644 --- a/core/utils/weak_io_context_post.hpp +++ b/core/utils/weak_io_context_post.hpp @@ -31,3 +31,20 @@ namespace kagome { }; } } // namespace kagome + +#define REINVOKE(ctx, func, ...) \ + do { \ + if (not runningInThisThread(ctx)) { \ + return post(ctx, \ + [weak = weak_from_this(), \ + args = std::make_tuple(__VA_ARGS__)]() mutable { \ + if (auto self = weak.lock()) { \ + std::apply( \ + [&](auto &&...args) mutable { \ + self->func(std::forward(args)...); \ + }, \ + std::move(args)); \ + } \ + }); \ + } \ + } while (false) diff --git a/test/core/consensus/babe/babe_test.cpp b/test/core/consensus/babe/babe_test.cpp index 6932d97bcd..2a18820e13 100644 --- a/test/core/consensus/babe/babe_test.cpp +++ b/test/core/consensus/babe/babe_test.cpp @@ -405,4 +405,5 @@ TEST_F(BabeTest, SlotLeader) { ASSERT_OUTCOME_SUCCESS_TRY(babe->processSlot(slot, best_block_info)); testutil::wait(*thread_pool_.io_context()); + testutil::wait(*thread_pool_.io_context()); } diff --git a/test/core/consensus/grandpa/chain_test.cpp b/test/core/consensus/grandpa/chain_test.cpp index b917aaba76..9ce844fec3 100644 --- a/test/core/consensus/grandpa/chain_test.cpp +++ b/test/core/consensus/grandpa/chain_test.cpp @@ -115,6 +115,7 @@ class ChainTest : public testing::Test { grandpa_transmitter, approved_ancestor, testutil::sptr_to_lazy(grandpa_), + nullptr, dispute_coordinator, parachain_api, backing_store, diff --git a/test/core/network/synchronizer_test.cpp b/test/core/network/synchronizer_test.cpp index 4169d458c7..f1c6af56db 100644 --- a/test/core/network/synchronizer_test.cpp +++ b/test/core/network/synchronizer_test.cpp @@ -94,6 +94,7 @@ class SynchronizerTest storage, state_pruner, router, + nullptr, scheduler, hasher, chain_sub_engine, diff --git a/test/mock/core/consensus/grandpa/authority_manager_mock.hpp b/test/mock/core/consensus/grandpa/authority_manager_mock.hpp index c4609818ba..ee983bd105 100644 --- a/test/mock/core/consensus/grandpa/authority_manager_mock.hpp +++ b/test/mock/core/consensus/grandpa/authority_manager_mock.hpp @@ -18,6 +18,16 @@ namespace kagome::consensus::grandpa { (const primitives::BlockInfo &, IsBlockFinalized), (const, override)); + MOCK_METHOD(ScheduledParentResult, + scheduledParent, + (primitives::BlockInfo), + (const, override)); + + MOCK_METHOD(std::vector, + possibleScheduled, + (), + (const, override)); + MOCK_METHOD(void, warp, (const primitives::BlockInfo &, diff --git a/test/mock/core/consensus/grandpa/grandpa_mock.hpp b/test/mock/core/consensus/grandpa/grandpa_mock.hpp index 91bed29ac5..0d30e77718 100644 --- a/test/mock/core/consensus/grandpa/grandpa_mock.hpp +++ b/test/mock/core/consensus/grandpa/grandpa_mock.hpp @@ -41,13 +41,10 @@ namespace kagome::consensus::grandpa { const network::FullCommitMessage &), (override)); - MOCK_METHOD( - void, - verifyJustification, - (const GrandpaJustification &, - const AuthoritySet &, - std::shared_ptr>> promise_res), - (override)); + MOCK_METHOD(outcome::result, + verifyJustification, + (const GrandpaJustification &, const AuthoritySet &), + (override)); MOCK_METHOD(void, applyJustification, diff --git a/test/mock/core/network/synchronizer_mock.hpp b/test/mock/core/network/synchronizer_mock.hpp index cc8a9b21ab..0c208de17a 100644 --- a/test/mock/core/network/synchronizer_mock.hpp +++ b/test/mock/core/network/synchronizer_mock.hpp @@ -40,6 +40,16 @@ namespace kagome::network { return syncByBlockHeader(block_header, peer_id, handler); } + MOCK_METHOD(bool, + fetchJustification, + (const primitives::BlockInfo &, CbResultVoid), + (override)); + + MOCK_METHOD(bool, + fetchJustificationRange, + (primitives::BlockNumber, FetchJustificationRangeCb), + (override)); + MOCK_METHOD(void, syncState, (const libp2p::peer::PeerId &,