Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix grandpa initial round #2157

Merged
merged 2 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 30 additions & 69 deletions core/consensus/grandpa/impl/grandpa_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "consensus/grandpa/environment.hpp"
#include "consensus/grandpa/grandpa_config.hpp"
#include "consensus/grandpa/grandpa_context.hpp"
#include "consensus/grandpa/has_authority_set_change.hpp"
#include "consensus/grandpa/impl/grandpa_thread_pool.hpp"
#include "consensus/grandpa/impl/vote_crypto_provider_impl.hpp"
#include "consensus/grandpa/impl/vote_tracker_impl.hpp"
Expand Down Expand Up @@ -133,52 +134,17 @@ namespace kagome::consensus::grandpa {

bool GrandpaImpl::tryStart() {
// Obtain last completed round
auto round_state_res = getLastCompletedRound();
auto round_state_res = makeRoundAfterLastFinalized();
if (not round_state_res.has_value()) {
logger_->critical(
"Can't retrieve last round data: {}. Stopping grandpa execution",
round_state_res.error());
return false;
}
auto &round_state = round_state_res.value();

SL_DEBUG(logger_,
"Grandpa will be started with round #{}",
round_state.round_number + 1);

auto authorities_res = authority_manager_->authorities(
round_state.last_finalized_block, false);
if (not authorities_res.has_value()) {
logger_->critical(
"Can't retrieve authorities for block {}. Stopping grandpa execution",
round_state.last_finalized_block);
return false;
}
auto &authority_set = authorities_res.value();

auto voters_res = VoterSet::make(*authority_set);
if (not voters_res) {
logger_->critical("Can't make voter set: {}. Stopping grandpa execution",
voters_res.error());
return false;
}
auto &voters = voters_res.value();

current_round_ =
makeInitialRound(round_state, std::move(voters), *authority_set);
BOOST_ASSERT(current_round_ != nullptr);

if (not current_round_->finalizedBlock().has_value()) {
logger_->critical(
"Initial round must be finalized, but it is not. "
"Stopping grandpa execution");
return false;
}

// Timer to send neighbor message if round does not change long time (1 min)
setTimerFallback();

tryExecuteNextRound(current_round_);
current_round_->roundNumber());

chain_sub_.onHead(
[weak{weak_from_this()}](const primitives::BlockHeader &block) {
Expand Down Expand Up @@ -224,9 +190,6 @@ namespace kagome::consensus::grandpa {
scheduler_,
round_state);
applyHistoricalVotes(*new_round);

new_round->end(); // it is okay, because we do not want to actually execute
// this round
return new_round;
}

Expand Down Expand Up @@ -312,36 +275,28 @@ namespace kagome::consensus::grandpa {
return round == nullptr ? std::nullopt : std::make_optional(round);
}

outcome::result<MovableRoundState> GrandpaImpl::getLastCompletedRound()
const {
auto finalized_block = block_tree_->getLastFinalized();

if (finalized_block.number == 0) {
return MovableRoundState{.round_number = 0,
.last_finalized_block = finalized_block,
.votes = {},
.finalized = {finalized_block}};
outcome::result<void> GrandpaImpl::makeRoundAfterLastFinalized() {
auto finalized = block_tree_->getLastFinalized();
auto authorities = authority_manager_->authorities(finalized, true);
if (not authorities) {
return VotingRoundError::NO_KNOWN_AUTHORITIES_FOR_BLOCK;
}
OUTCOME_TRY(voters, VoterSet::make(**authorities));
MovableRoundState state{1, finalized, {}, std::nullopt};
if (finalized.number != 0) {
OUTCOME_TRY(raw_justification,
block_tree_->getBlockJustification(finalized.hash));
OUTCOME_TRY(justification,
scale::decode<GrandpaJustification>(raw_justification.data));
OUTCOME_TRY(header, block_tree_->getBlockHeader(finalized.hash));
HasAuthoritySetChange digests{header};
if (not digests.scheduled) {
state.round_number = justification.round_number + 1;
}
}

OUTCOME_TRY(encoded_justification,
block_tree_->getBlockJustification(finalized_block.hash));

OUTCOME_TRY(
grandpa_justification,
scale::decode<GrandpaJustification>(encoded_justification.data));

MovableRoundState round_state{
.round_number = grandpa_justification.round_number,
.last_finalized_block = grandpa_justification.block_info,
.votes = {},
.finalized = {grandpa_justification.block_info}};

std::transform(std::move_iterator(grandpa_justification.items.begin()),
std::move_iterator(grandpa_justification.items.end()),
std::back_inserter(round_state.votes),
[](auto &&item) { return std::forward<VoteVariant>(item); });

return round_state;
current_round_ = makeInitialRound(state, voters, **authorities);
startCurrentRound();
return outcome::success();
}

void GrandpaImpl::tryExecuteNextRound(
Expand All @@ -358,7 +313,10 @@ namespace kagome::consensus::grandpa {
}
BOOST_ASSERT(res.value() != nullptr);
current_round_ = std::move(res.value());
startCurrentRound();
}

void GrandpaImpl::startCurrentRound() {
setTimerFallback();

// Truncate chain of rounds
Expand Down Expand Up @@ -777,6 +735,7 @@ namespace kagome::consensus::grandpa {
auto &voters = voters_res.value();

round = makeInitialRound(round_state, std::move(voters), *authority_set);
round->end();
}

GrandpaContext grandpa_context;
Expand Down Expand Up @@ -1305,6 +1264,8 @@ namespace kagome::consensus::grandpa {

round =
makeInitialRound(round_state, std::move(voters), *authority_set);
round->end();

need_to_make_round_current = true;
BOOST_ASSERT(round);

Expand Down
6 changes: 4 additions & 2 deletions core/consensus/grandpa/impl/grandpa_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ namespace kagome::consensus::grandpa {
MissingBlocks blocks;
};

void startCurrentRound();

void callbackCall(ApplyJustificationCb &&callback,
outcome::result<void> &&result);
/**
Expand All @@ -197,9 +199,9 @@ namespace kagome::consensus::grandpa {
RoundNumber round_number, std::optional<VoterSetId> voter_set_id);

/**
* @return Get grandpa::MovableRoundState for the last completed round
* Make next round from last saved justification.
*/
outcome::result<MovableRoundState> getLastCompletedRound() const;
outcome::result<void> makeRoundAfterLastFinalized();

/**
* Initializes new round by provided round state and voter. Note that round
Expand Down
40 changes: 13 additions & 27 deletions core/consensus/grandpa/impl/voting_round_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,9 @@ namespace kagome::consensus::grandpa {
// Derive-Primary
// see ctor

if (isPrimary_) {
if (isPrimary_ and previous_round_) {
SL_DEBUG(logger_, "Node is primary proposer at round #{}", round_number_);

BOOST_ASSERT(previous_round_ != nullptr);

// Broadcast Commit-message with previous round best final candidate
// (or last finalized otherwise)
// spec: Broadcast(M vr ¡1;Fin (Best-Final-Candidate(r-1)))
Expand Down Expand Up @@ -392,10 +390,7 @@ namespace kagome::consensus::grandpa {

const bool is_ready_to_end =
finalized_.has_value()
and finalized_->number
>= (previous_round_
? previous_round_->bestFinalCandidate().number
: last_finalized_block_.number);
and finalized_->number >= prevBestFinalCandidate().number;

if (is_ready_to_end) {
SL_DEBUG(logger_,
Expand All @@ -411,10 +406,7 @@ namespace kagome::consensus::grandpa {
on_complete_handler_ = [&] {
const bool is_ready_to_end =
finalized_.has_value()
and finalized_->number
>= (previous_round_
? previous_round_->bestFinalCandidate().number
: last_finalized_block_.number);
and finalized_->number >= prevBestFinalCandidate().number;

if (is_ready_to_end) {
SL_DEBUG(logger_,
Expand Down Expand Up @@ -497,23 +489,18 @@ namespace kagome::consensus::grandpa {
}

void VotingRoundImpl::doPrevote() {
// Doing prevote is no longer actual
if (not previous_round_) {
return;
}

// Don't change defined vote to avoid equivocation
if (prevote_.has_value()) {
sendPrevote(convertToPrevote(prevote_.value()));
return;
}

// spec: L <- Best-Final-Candidate(r-1)
const auto best_final_candicate = previous_round_->bestFinalCandidate();
const auto best_final_candidate = prevBestFinalCandidate();

// spec: Bpv <- GRANDPA-GHOST(r)
const auto best_chain =
env_->bestChainContaining(best_final_candicate.hash, voter_set_->id());
env_->bestChainContaining(best_final_candidate.hash, voter_set_->id());
const auto best_prevote_candidate =
best_chain.has_value() ? convertToBlockInfo(best_chain.value())
: last_finalized_block_;
Expand All @@ -526,7 +513,7 @@ namespace kagome::consensus::grandpa {
const auto &primary = primary_vote_.value();

if (best_prevote_candidate.number >= primary.number
and primary.number > best_final_candicate.number) {
and primary.number > best_final_candidate.number) {
// spec: N <- Bprim
prevote_ = primary;
}
Expand Down Expand Up @@ -557,11 +544,6 @@ namespace kagome::consensus::grandpa {
}

void VotingRoundImpl::doPrecommit() {
// Doing precommit is no longer actual
if (not previous_round_) {
return;
}

// Don't change defined vote to avoid equivocation
if (precommit_.has_value()) {
sendPrecommit(convertToPrecommit(precommit_.value()));
Expand All @@ -574,7 +556,7 @@ namespace kagome::consensus::grandpa {
BOOST_ASSERT(prevote_ghost_.has_value());
const auto &prevote_ghost = prevote_ghost_.value();

auto last_round_estimate = previous_round_->bestFinalCandidate();
auto last_round_estimate = prevBestFinalCandidate();

// We should precommit if current state contains prevote, and it is
// either equal to the last round estimate or is descendant of it
Expand Down Expand Up @@ -1223,8 +1205,7 @@ namespace kagome::consensus::grandpa {
return false;
}

auto current_best = previous_round_ ? previous_round_->bestFinalCandidate()
: last_finalized_block_;
auto current_best = prevBestFinalCandidate();

auto possible_to_prevote = [this](const VoteWeight &weight) {
return weight.total(VoteType::Prevote, prevote_equivocators_, *voter_set_)
Expand Down Expand Up @@ -1605,4 +1586,9 @@ namespace kagome::consensus::grandpa {
VotingRound::Votes VotingRoundImpl::votes() const {
return {prevotes_->getMessages(), precommits_->getMessages()};
}

BlockInfo VotingRoundImpl::prevBestFinalCandidate() const {
return previous_round_ ? previous_round_->bestFinalCandidate()
: last_finalized_block_;
}
} // namespace kagome::consensus::grandpa
2 changes: 2 additions & 0 deletions core/consensus/grandpa/impl/voting_round_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,8 @@ namespace kagome::consensus::grandpa {
void sendPrecommit(const Precommit &precommit);
void pending();

BlockInfo prevBestFinalCandidate() const;

std::shared_ptr<VoterSet> voter_set_;
const RoundNumber round_number_;
std::shared_ptr<VotingRound> previous_round_;
Expand Down
Loading