Skip to content

Commit

Permalink
Support cross-epoch leader reputation (aptos-labs#2603)
Browse files Browse the repository at this point in the history
Description

Instead of restarting history on every epoch, we stop special treating epoch boundary, and look at the window size history.

In order to do so, we need to know historical validator sets, to understand indices in the arrays, and that is the main complexity in this diff

Also removing ActiveInactive leader reputation heuristic, as it is unnecessary and replaced by the ProposerAndVoter heuristic. (we kept the old one for the rollout of ProposerAndVoter, in case we need to fall back, time to clean it up)

Test Plan

leader_reputation and aptos_cli.test_join_and_leave_validator tests
  • Loading branch information
igor-aptos authored Aug 10, 2022
1 parent 72d8186 commit 515e072
Show file tree
Hide file tree
Showing 8 changed files with 437 additions and 351 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,7 @@
{
"type": "0x1::consensus_config::ConsensusConfig",
"data": {
"config": "0x00010a0000000000000014000000000000000201e8030000000000000a0000000000000001000000000000000a0000000a000000000000000100000000000000010a00000000000000"
"config": "0x00010a0000000000000014000000000000000200e8030000000000000a0000000000000001000000000000000a0000000a00000000000000010000000000000001050000000a00000000000000"
}
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,7 @@
{
"type": "0x1::consensus_config::ConsensusConfig",
"data": {
"config": "0x00010a0000000000000014000000000000000201e8030000000000000a0000000000000001000000000000000a0000000a000000000000000100000000000000010a00000000000000"
"config": "0x00010a0000000000000014000000000000000200e8030000000000000a0000000000000001000000000000000a0000000a00000000000000010000000000000001050000000a00000000000000"
}
}
]
1 change: 1 addition & 0 deletions consensus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ tokio = { version = "1.18.2", features = ["full"] }
aptos-config = { path = "../config" }
aptos-crypto = { path = "../crates/aptos-crypto" }
aptos-infallible = { path = "../crates/aptos-infallible" }
aptos-keygen = { path = "../crates/aptos-keygen" }
aptos-logger = { path = "../crates/aptos-logger" }
aptos-mempool = { path = "../mempool" }
aptos-metrics-core = { path = "../crates/aptos-metrics-core" }
Expand Down
76 changes: 51 additions & 25 deletions consensus/src/epoch_manager.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::liveness::leader_reputation::extract_epoch_to_proposers;
use crate::monitor;
use crate::{
block_storage::BlockStore,
Expand All @@ -15,8 +16,7 @@ use crate::{
liveness::{
cached_proposer_election::CachedProposerElection,
leader_reputation::{
ActiveInactiveHeuristic, AptosDBBackend, LeaderReputation, ProposerAndVoterHeuristic,
ReputationHeuristic,
AptosDBBackend, LeaderReputation, ProposerAndVoterHeuristic, ReputationHeuristic,
},
proposal_generator::ProposalGenerator,
proposer_election::ProposerElection,
Expand Down Expand Up @@ -65,8 +65,10 @@ use futures::{
},
SinkExt, StreamExt,
};
use itertools::Itertools;
use network::protocols::network::{ApplicationNetworkSender, Event};
use safety_rules::SafetyRulesManager;
use std::collections::HashMap;
use std::{
cmp::Ordering,
mem::{discriminant, Discriminant},
Expand Down Expand Up @@ -205,24 +207,12 @@ impl EpochManager {
Box::new(RotatingProposer::new(vec![proposer], *contiguous_rounds))
}
ProposerElectionType::LeaderReputation(leader_reputation_type) => {
let (heuristic, window_size, weight_by_voting_power) = match &leader_reputation_type
{
LeaderReputationType::ActiveInactive(active_inactive_config) => {
let window_size = proposers.len()
* active_inactive_config.window_num_validators_multiplier;
let heuristic: Box<dyn ReputationHeuristic> =
Box::new(ActiveInactiveHeuristic::new(
self.author,
active_inactive_config.active_weight,
active_inactive_config.inactive_weight,
window_size,
));
(
heuristic,
window_size,
active_inactive_config.weight_by_voting_power,
)
}
let (
heuristic,
window_size,
weight_by_voting_power,
use_history_from_previous_epoch_max_count,
) = match &leader_reputation_type {
LeaderReputationType::ProposerAndVoter(proposer_and_voter_config) => {
let proposer_window_size = proposers.len()
* proposer_and_voter_config.proposer_window_num_validators_multiplier;
Expand All @@ -242,16 +232,18 @@ impl EpochManager {
heuristic,
std::cmp::max(proposer_window_size, voter_window_size),
proposer_and_voter_config.weight_by_voting_power,
proposer_and_voter_config.use_history_from_previous_epoch_max_count,
)
}
};

let seek_len = onchain_config.leader_reputation_exclude_round() as usize
+ onchain_config.max_failed_authors_to_store()
+ PROPSER_ROUND_BEHIND_STORAGE_BUFFER;

let backend = Box::new(AptosDBBackend::new(
epoch_state.epoch,
window_size,
onchain_config.leader_reputation_exclude_round() as usize
+ onchain_config.max_failed_authors_to_store()
+ PROPSER_ROUND_BEHIND_STORAGE_BUFFER,
seek_len,
self.storage.aptos_db(),
));
let voting_powers: Vec<_> = if weight_by_voting_power {
Expand All @@ -263,9 +255,43 @@ impl EpochManager {
vec![1; proposers.len()]
};

// First block (after genesis) is epoch=1, so that is the first epoch we consider. (Genesis is epoch=0)
let first_epoch_to_consider = std::cmp::max(
1,
epoch_state
.epoch
.saturating_sub(use_history_from_previous_epoch_max_count as u64),
);
// If we are considering beyond the current epoch, we need to fetch validators for those epochs
let epoch_to_proposers = if epoch_state.epoch > first_epoch_to_consider {
self.storage
.aptos_db()
.get_epoch_ending_ledger_infos(first_epoch_to_consider - 1, epoch_state.epoch)
.and_then(|proof| {
ensure!(proof.ledger_info_with_sigs.len() as u64 == (epoch_state.epoch - (first_epoch_to_consider - 1)));
extract_epoch_to_proposers(proof, epoch_state.epoch, &proposers, (window_size + seek_len) as u64)
})
.unwrap_or_else(|err| {
error!("Couldn't create leader reputation with history across epochs, {:?}", err);
HashMap::from([(epoch_state.epoch, proposers)])
})
} else {
HashMap::from([(epoch_state.epoch, proposers)])
};

info!(
"Starting epoch {}: proposers across epochs for leader election: {:?}",
epoch_state.epoch,
epoch_to_proposers
.iter()
.map(|(epoch, proposers)| (epoch, proposers.len()))
.sorted()
.collect::<Vec<_>>()
);

let proposer_election = Box::new(LeaderReputation::new(
epoch_state.epoch,
proposers,
epoch_to_proposers,
voting_powers,
backend,
heuristic,
Expand Down
Loading

0 comments on commit 515e072

Please sign in to comment.