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

historical votes #2085

Merged
merged 9 commits into from
May 31, 2024
3 changes: 2 additions & 1 deletion core/consensus/grandpa/grandpa.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "consensus/finality_consensus.hpp"
#include "consensus/grandpa/common.hpp"
#include "consensus/grandpa/historical_votes.hpp"

#include <memory>

Expand All @@ -21,7 +22,7 @@ namespace kagome::consensus::grandpa {
* Interface for launching new grandpa rounds. See more details in
* kagome::consensus::grandpa::GrandpaImpl
*/
class Grandpa : public FinalityConsensus {
class Grandpa : public FinalityConsensus, public SaveHistoricalVotes {
public:
virtual ~Grandpa() = default;

Expand Down
45 changes: 45 additions & 0 deletions core/consensus/grandpa/historical_votes.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Copyright Quadrivium LLC
* All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#include "consensus/grandpa/structs.hpp"

namespace kagome::consensus::grandpa {
/**
* Historical votes seen in a round.
* https://github.com/paritytech/finality-grandpa/blob/8c45a664c05657f0c71057158d3ba555ba7d20de/src/lib.rs#L544
*/
struct HistoricalVotes {
SCALE_TIE(3);

std::vector<SignedMessage> seen;
std::optional<uint64_t> prevote_idx, precommit_idx;

/**
* Set the number of messages seen before prevoting.
*/
void set_prevoted_index() {
prevote_idx = seen.size();
turuslan marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Set the number of messages seen before precommiting.
*/
void set_precommitted_index() {
precommit_idx = seen.size();
turuslan marked this conversation as resolved.
Show resolved Hide resolved
}
};

class SaveHistoricalVotes {
public:
virtual ~SaveHistoricalVotes() = default;

virtual void saveHistoricalVotes(AuthoritySetId set,
RoundNumber round,
const HistoricalVotes &votes) = 0;
};
} // namespace kagome::consensus::grandpa
76 changes: 30 additions & 46 deletions core/consensus/grandpa/impl/grandpa_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ namespace kagome::consensus::grandpa {
// https://github.com/paritytech/polkadot/pull/6217
constexpr std::chrono::milliseconds kGossipDuration{1000};

inline auto historicalVotesKey(AuthoritySetId set, RoundNumber round) {
auto key = storage::kGrandpaHistoricalVotesPrefix;
key.putUint64(set);
key.putUint64(round);
return key;
}

GrandpaImpl::GrandpaImpl(
std::shared_ptr<application::AppStateManager> app_state_manager,
std::shared_ptr<crypto::Hasher> hasher,
Expand Down Expand Up @@ -125,12 +132,6 @@ namespace kagome::consensus::grandpa {
}

bool GrandpaImpl::tryStart() {
if (auto r = db_->get(storage::kGrandpaVotesKey)) {
if (auto r2 = scale::decode<CachedVotes>(r.value())) {
cached_votes_ = std::move(r2.value());
}
}

// Obtain last completed round
auto round_state_res = getLastCompletedRound();
if (not round_state_res.has_value()) {
Expand Down Expand Up @@ -211,24 +212,19 @@ namespace kagome::consensus::grandpa {
auto vote_crypto_provider = std::make_shared<VoteCryptoProviderImpl>(
keypair, crypto_provider_, round_state.round_number, config.voters);

auto save_cached_votes = [weak{weak_from_this()}]() {
if (auto self = weak.lock()) {
self->saveCachedVotes();
}
};
auto new_round = std::make_shared<VotingRoundImpl>(
shared_from_this(),
std::move(config),
hasher_,
environment_,
std::move(save_cached_votes),
historicalVotes(authority_set.id, round_state.round_number),
std::move(vote_crypto_provider),
std::make_shared<VoteTrackerImpl>(), // Prevote tracker
std::make_shared<VoteTrackerImpl>(), // Precommit tracker
std::move(vote_graph),
scheduler_,
round_state);
applyCachedVotes(*new_round);
new_round->applyHistoricalVotes();

new_round->end(); // it is okay, because we do not want to actually execute
// this round
Expand Down Expand Up @@ -277,24 +273,19 @@ namespace kagome::consensus::grandpa {
auto vote_crypto_provider = std::make_shared<VoteCryptoProviderImpl>(
keypair, crypto_provider_, new_round_number, config.voters);

auto save_cached_votes = [weak{weak_from_this()}]() {
if (auto self = weak.lock()) {
self->saveCachedVotes();
}
};
auto new_round = std::make_shared<VotingRoundImpl>(
shared_from_this(),
std::move(config),
hasher_,
environment_,
std::move(save_cached_votes),
historicalVotes(authority_set->id, new_round_number),
std::move(vote_crypto_provider),
std::make_shared<VoteTrackerImpl>(), // Prevote tracker
std::make_shared<VoteTrackerImpl>(), // Precommit tracker
std::move(vote_graph),
scheduler_,
round);
applyCachedVotes(*new_round);
new_round->applyHistoricalVotes();
return new_round;
}

Expand Down Expand Up @@ -1192,7 +1183,7 @@ namespace kagome::consensus::grandpa {
GrandpaConfig{voters, justification.round_number, {}, {}},
hasher_,
environment_,
nullptr,
HistoricalVotes{},
std::make_shared<VoteCryptoProviderImpl>(
nullptr, crypto_provider_, justification.round_number, voters),
std::make_shared<VoteTrackerImpl>(),
Expand Down Expand Up @@ -1424,36 +1415,29 @@ namespace kagome::consensus::grandpa {
retain_if(waiting_blocks_, f);
}

void GrandpaImpl::saveCachedVotes() {
CachedVotes rounds;
for (auto round = current_round_; round;
round = round->getPreviousRound()) {
rounds.emplace_back(CachedRound{
round->voterSetId(),
round->roundNumber(),
round->votes(),
});
void GrandpaImpl::saveHistoricalVotes(AuthoritySetId set,
RoundNumber round,
const HistoricalVotes &votes) {
if (votes.seen.empty()) {
return;
}
std::ignore =
db_->put(storage::kGrandpaVotesKey, scale::encode(rounds).value());
db_->put(historicalVotesKey(set, round), scale::encode(votes).value());
}

void GrandpaImpl::applyCachedVotes(VotingRound &round) {
auto it = std::find_if(
cached_votes_.begin(), cached_votes_.end(), [&](const CachedRound &c) {
return c.set == round.voterSetId() and c.round == round.roundNumber();
});
if (it == cached_votes_.end()) {
return;
}
VotingRoundUpdate update{round};
for (auto &vote : it->votes.first) {
update.vote(vote);
}
for (auto &vote : it->votes.second) {
update.vote(vote);
HistoricalVotes GrandpaImpl::historicalVotes(AuthoritySetId set,
RoundNumber round) const {
if (auto r = db_->get(historicalVotesKey(set, round))) {
if (auto r2 = scale::decode<HistoricalVotes>(r.value())) {
return std::move(r2.value());
} else {
SL_ERROR(logger_,
"historicalVotes(set={}, round={}): decode error",
set,
round);
}
turuslan marked this conversation as resolved.
Show resolved Hide resolved
}
update.update();
return {};
}

void GrandpaImpl::setTimerFallback() {
Expand Down
18 changes: 7 additions & 11 deletions core/consensus/grandpa/impl/grandpa_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <libp2p/basic/scheduler.hpp>

#include "consensus/grandpa/historical_votes.hpp"
#include "consensus/grandpa/impl/votes_cache.hpp"
#include "consensus/grandpa/voting_round.hpp"
#include "injector/lazy.hpp"
Expand Down Expand Up @@ -253,6 +254,10 @@ namespace kagome::consensus::grandpa {
*/
void updateNextRound(RoundNumber round_number) override;

void saveHistoricalVotes(AuthoritySetId set,
RoundNumber round,
const HistoricalVotes &votes) override;

private:
struct WaitingBlock {
libp2p::peer::PeerId peer;
Expand Down Expand Up @@ -319,8 +324,8 @@ namespace kagome::consensus::grandpa {
void onHead(const primitives::BlockInfo &block);
void pruneWaitingBlocks();

void saveCachedVotes();
void applyCachedVotes(VotingRound &round);
HistoricalVotes historicalVotes(AuthoritySetId set,
RoundNumber round) const;

void setTimerFallback();

Expand Down Expand Up @@ -357,15 +362,6 @@ namespace kagome::consensus::grandpa {

std::vector<WaitingBlock> waiting_blocks_;

struct CachedRound {
SCALE_TIE(3);
AuthoritySetId set;
RoundNumber round;
VotingRound::Votes votes;
};
using CachedVotes = std::vector<CachedRound>;
CachedVotes cached_votes_;

// Metrics
metrics::RegistryPtr metrics_registry_ = metrics::createRegistry();
metrics::Gauge *metric_highest_round_;
Expand Down
45 changes: 33 additions & 12 deletions core/consensus/grandpa/impl/voting_round_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ namespace kagome::consensus::grandpa {
const GrandpaConfig &config,
std::shared_ptr<crypto::Hasher> hasher,
std::shared_ptr<Environment> env,
SaveCachedVotes save_cached_votes,
HistoricalVotes historical_votes,
std::shared_ptr<VoteCryptoProvider> vote_crypto_provider,
std::shared_ptr<VoteTracker> prevotes,
std::shared_ptr<VoteTracker> precommits,
Expand All @@ -69,7 +69,7 @@ namespace kagome::consensus::grandpa {
grandpa_(grandpa),
hasher_{std::move(hasher)},
env_{std::move(env)},
save_cached_votes_{std::move(save_cached_votes)},
historical_votes_{std::move(historical_votes)},
vote_crypto_provider_{std::move(vote_crypto_provider)},
graph_{std::move(vote_graph)},
scheduler_{std::move(scheduler)},
Expand Down Expand Up @@ -105,7 +105,7 @@ namespace kagome::consensus::grandpa {
const GrandpaConfig &config,
std::shared_ptr<crypto::Hasher> hasher,
const std::shared_ptr<Environment> &env,
SaveCachedVotes save_cached_votes,
HistoricalVotes historical_votes,
const std::shared_ptr<VoteCryptoProvider> &vote_crypto_provider,
const std::shared_ptr<VoteTracker> &prevotes,
const std::shared_ptr<VoteTracker> &precommits,
Expand All @@ -116,7 +116,7 @@ namespace kagome::consensus::grandpa {
config,
std::move(hasher),
env,
std::move(save_cached_votes),
std::move(historical_votes),
vote_crypto_provider,
prevotes,
precommits,
Expand All @@ -134,7 +134,7 @@ namespace kagome::consensus::grandpa {
const GrandpaConfig &config,
std::shared_ptr<crypto::Hasher> hasher,
const std::shared_ptr<Environment> &env,
SaveCachedVotes save_cached_votes,
HistoricalVotes historical_votes,
const std::shared_ptr<VoteCryptoProvider> &vote_crypto_provider,
const std::shared_ptr<VoteTracker> &prevotes,
const std::shared_ptr<VoteTracker> &precommits,
Expand All @@ -145,7 +145,7 @@ namespace kagome::consensus::grandpa {
config,
std::move(hasher),
env,
std::move(save_cached_votes),
std::move(historical_votes),
vote_crypto_provider,
prevotes,
precommits,
Expand Down Expand Up @@ -188,6 +188,10 @@ namespace kagome::consensus::grandpa {
}
}

VotingRoundImpl::~VotingRoundImpl() {
saveHistoricalVotes();
turuslan marked this conversation as resolved.
Show resolved Hide resolved
}

bool VotingRoundImpl::hasKeypair() const {
return id_.has_value();
}
Expand Down Expand Up @@ -555,11 +559,10 @@ namespace kagome::consensus::grandpa {
return;
}
auto &signed_prevote = signed_prevote_opt.value();
set_prevoted_index();
if (onPrevote({}, signed_prevote, Propagation::NEEDLESS)) {
update(false, true, false);
if (save_cached_votes_) {
save_cached_votes_();
}
saveHistoricalVotes();
}
env_->onVoted(round_number_, voter_set_->id(), signed_prevote);
}
Expand Down Expand Up @@ -611,11 +614,10 @@ namespace kagome::consensus::grandpa {
return;
}
auto &signed_precommit = signed_precommit_opt.value();
set_precommitted_index();
if (onPrecommit({}, signed_precommit, Propagation::NEEDLESS)) {
update(false, false, true);
if (save_cached_votes_) {
save_cached_votes_();
}
saveHistoricalVotes();
}
env_->onVoted(round_number_, voter_set_->id(), signed_precommit);
}
Expand All @@ -628,6 +630,8 @@ namespace kagome::consensus::grandpa {
SL_DEBUG(
logger_, "Round #{}: Finalizing on block {}", round_number_, block);

saveHistoricalVotes();

GrandpaJustification justification{
.round_number = round_number_,
.block_info = block,
Expand Down Expand Up @@ -1184,6 +1188,7 @@ namespace kagome::consensus::grandpa {
result.error());
return result.as_failure();
}
historical_votes_.seen.emplace_back(vote);
return outcome::success();
}
case VoteTracker::PushResult::DUPLICATED: {
Expand All @@ -1204,6 +1209,7 @@ namespace kagome::consensus::grandpa {

std::ignore = env_->reportEquivocation(*this, equivocation);

historical_votes_.seen.emplace_back(vote);
return VotingRoundError::EQUIVOCATED_VOTE;
}
default:
Expand Down Expand Up @@ -1610,4 +1616,19 @@ namespace kagome::consensus::grandpa {
VotingRound::Votes VotingRoundImpl::votes() const {
return {prevotes_->getMessages(), precommits_->getMessages()};
}

void VotingRoundImpl::applyHistoricalVotes() {
VotingRoundUpdate update{*this};
for (auto &vote : historical_votes_.seen) {
update.vote(vote);
}
update.update();
}

void VotingRoundImpl::saveHistoricalVotes() {
if (auto grandpa = grandpa_.lock()) {
grandpa->saveHistoricalVotes(
voter_set_->id(), round_number_, historical_votes_);
}
}
} // namespace kagome::consensus::grandpa
Loading
Loading