diff --git a/core/common/span_adl.hpp b/core/common/span_adl.hpp index 7fd8b494d0..cd09a9bb73 100644 --- a/core/common/span_adl.hpp +++ b/core/common/span_adl.hpp @@ -40,8 +40,9 @@ auto operator<=>(const SpanAdl &l_, const auto &r_) } template -bool operator==(const SpanAdl &l_, const auto &r) - requires(requires { std::span{r}; }) +bool operator==(const SpanAdl &l_, const auto &r_) + requires(requires { std::span{r_}; }) { - return (l_ <=> r) == 0; + std::span r{r_}; + return l_.v.size() == r.size() and (l_ <=> r) == 0; } diff --git a/core/consensus/grandpa/environment.hpp b/core/consensus/grandpa/environment.hpp index a366238000..fed719ef55 100644 --- a/core/consensus/grandpa/environment.hpp +++ b/core/consensus/grandpa/environment.hpp @@ -126,6 +126,9 @@ namespace kagome::consensus::grandpa { /// authority set changes. virtual outcome::result reportEquivocation( const VotingRound &round, const Equivocation &equivocation) const = 0; + + virtual outcome::result makeAncestry( + GrandpaJustification &justification) const = 0; }; } // namespace kagome::consensus::grandpa diff --git a/core/consensus/grandpa/impl/environment_impl.cpp b/core/consensus/grandpa/impl/environment_impl.cpp index 6379e8a289..0d61202877 100644 --- a/core/consensus/grandpa/impl/environment_impl.cpp +++ b/core/consensus/grandpa/impl/environment_impl.cpp @@ -20,6 +20,7 @@ #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/make_ancestry.hpp" #include "consensus/grandpa/movable_round_state.hpp" #include "consensus/grandpa/voting_round.hpp" #include "consensus/grandpa/voting_round_error.hpp" @@ -504,4 +505,8 @@ namespace kagome::consensus::grandpa { return outcome::success(); } + outcome::result EnvironmentImpl::makeAncestry( + GrandpaJustification &justification) const { + return grandpa::makeAncestry(justification, *block_tree_); + } } // namespace kagome::consensus::grandpa diff --git a/core/consensus/grandpa/impl/environment_impl.hpp b/core/consensus/grandpa/impl/environment_impl.hpp index 4a4bc161b2..940418b5b0 100644 --- a/core/consensus/grandpa/impl/environment_impl.hpp +++ b/core/consensus/grandpa/impl/environment_impl.hpp @@ -136,6 +136,9 @@ namespace kagome::consensus::grandpa { const VotingRound &round, const Equivocation &equivocation) const override; + outcome::result makeAncestry( + GrandpaJustification &justification) const override; + private: std::shared_ptr block_tree_; std::shared_ptr header_repository_; diff --git a/core/consensus/grandpa/impl/voting_round_impl.cpp b/core/consensus/grandpa/impl/voting_round_impl.cpp index a349eee459..fe808fae71 100644 --- a/core/consensus/grandpa/impl/voting_round_impl.cpp +++ b/core/consensus/grandpa/impl/voting_round_impl.cpp @@ -653,7 +653,10 @@ namespace kagome::consensus::grandpa { .round_number = round_number_, .block_info = block, .items = getPrecommitJustification(block, precommits_->getMessages())}; - // TODO(turuslan): #1931, make justification ancestry + + if (auto r = env_->makeAncestry(justification); not r) { + SL_ERROR(logger_, "doCommit: makeAncestry: {}", r.error()); + } SL_DEBUG(logger_, "Round #{}: Sending commit message for block {}", diff --git a/core/consensus/grandpa/make_ancestry.hpp b/core/consensus/grandpa/make_ancestry.hpp new file mode 100644 index 0000000000..4c009466fe --- /dev/null +++ b/core/consensus/grandpa/make_ancestry.hpp @@ -0,0 +1,40 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +#include "blockchain/block_tree.hpp" +#include "consensus/grandpa/structs.hpp" +#include "consensus/grandpa/voting_round_error.hpp" + +namespace kagome::consensus::grandpa { + /** + * Make ancestry merke proof for GrandpaJustification. + * https://github.com/paritytech/polkadot-sdk/blob/4842faf65d3628586d304fbcb6cb19b17b4a629c/substrate/client/consensus/grandpa/src/justification.rs#L64-L126 + */ + inline outcome::result makeAncestry( + GrandpaJustification &justification, + const blockchain::BlockTree &block_tree) { + std::vector blocks; + std::unordered_set seen; + for (auto &m : justification.items) { + auto info = m.getBlockInfo(); + while (info != justification.block_info and not seen.contains(info)) { + if (info.number <= justification.block_info.number) { + return VotingRoundError::CANT_MAKE_ANCESTRY; + } + OUTCOME_TRY(block, block_tree.getBlockHeader(info.hash)); + seen.emplace(info); + info = *block.parentInfo(); + blocks.emplace_back(std::move(block)); + } + } + justification.votes_ancestries = blocks; + return outcome::success(); + } +} // namespace kagome::consensus::grandpa diff --git a/core/consensus/grandpa/voting_round_error.cpp b/core/consensus/grandpa/voting_round_error.cpp index 966282fa65..51151f9db8 100644 --- a/core/consensus/grandpa/voting_round_error.cpp +++ b/core/consensus/grandpa/voting_round_error.cpp @@ -51,6 +51,8 @@ OUTCOME_CPP_DEFINE_CATEGORY(kagome::consensus::grandpa, VotingRoundError, e) { return "Can't get best prevote candidate"; case E::ROUND_IS_NOT_FINALIZABLE: return "Round is not finalizable"; + case E::CANT_MAKE_ANCESTRY: + return "Can't make ancestry"; } return "Unknown error (invalid VotingRoundError)"; } diff --git a/core/consensus/grandpa/voting_round_error.hpp b/core/consensus/grandpa/voting_round_error.hpp index 3d183917ab..d3270e3c65 100644 --- a/core/consensus/grandpa/voting_round_error.hpp +++ b/core/consensus/grandpa/voting_round_error.hpp @@ -29,7 +29,8 @@ namespace kagome::consensus::grandpa { EQUIVOCATED_VOTE, VOTE_OF_KNOWN_EQUIVOCATOR, NO_PREVOTE_CANDIDATE, - ROUND_IS_NOT_FINALIZABLE + ROUND_IS_NOT_FINALIZABLE, + CANT_MAKE_ANCESTRY, }; } diff --git a/test/mock/core/consensus/grandpa/environment_mock.hpp b/test/mock/core/consensus/grandpa/environment_mock.hpp index 98a33eac02..b4c975e424 100644 --- a/test/mock/core/consensus/grandpa/environment_mock.hpp +++ b/test/mock/core/consensus/grandpa/environment_mock.hpp @@ -81,6 +81,11 @@ namespace kagome::consensus::grandpa { std::vector precommit_justification, BlockInfo best_final_candidate), (override)); + + MOCK_METHOD(outcome::result, + makeAncestry, + (GrandpaJustification &), + (const, override)); }; } // namespace kagome::consensus::grandpa