From 29611fb61d9dd3327a44f1ff7ce8ae311f8b4384 Mon Sep 17 00:00:00 2001 From: anatoly yakovenko Date: Mon, 24 Jun 2019 13:41:23 -0700 Subject: [PATCH] tower consensus naming (#4598) s/locktower/tower/g --- book/src/SUMMARY.md | 4 +- book/src/block-confirmation.md | 13 +- book/src/fork-generation.md | 2 +- book/src/leader-rotation.md | 2 +- book/src/ledger-replication-to-implement.md | 2 +- book/src/persistent-account-storage.md | 2 +- book/src/stake-delegation-and-rewards.md | 2 +- book/src/{fork-selection.md => tower-bft.md} | 6 +- core/src/cluster_info_vote_listener.rs | 2 +- core/src/cluster_tests.rs | 2 +- core/src/{locktower.rs => consensus.rs} | 198 +++++++++--------- core/src/lib.rs | 2 +- core/src/replay_stage.rs | 48 ++--- .../dashboards/testnet-monitor.json | 24 +-- runtime/src/bank.rs | 2 +- 15 files changed, 152 insertions(+), 159 deletions(-) rename book/src/{fork-selection.md => tower-bft.md} (98%) rename core/src/{locktower.rs => consensus.rs} (79%) diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 894dd1775..d206512ee 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -62,11 +62,11 @@ - [Blocktree](blocktree.md) - [Cluster Software Installation and Updates](installer.md) - [Deterministic Transaction Fees](transaction-fees.md) - - [Fork Selection](fork-selection.md) + - [Tower BFT](tower-bft.md) - [Leader-to-Leader Transition](leader-leader-transition.md) - [Leader-to-Validator Transition](leader-validator-transition.md) - [Passive Stake Delegation and Rewards](passive-stake-delegation-and-rewards.md) - [Persistent Account Storage](persistent-account-storage.md) - [Reliable Vote Transmission](reliable-vote-transmission.md) - [Repair Service](repair-service.md) - - [Testing Programs](testing-programs.md) \ No newline at end of file + - [Testing Programs](testing-programs.md) diff --git a/book/src/block-confirmation.md b/book/src/block-confirmation.md index e608700f0..dd29c9e30 100644 --- a/book/src/block-confirmation.md +++ b/book/src/block-confirmation.md @@ -4,7 +4,7 @@ A validator votes on a PoH hash for two purposes. First, the vote indicates it believes the ledger is valid up until that point in time. Second, since many valid forks may exist at a given height, the vote also indicates exclusive support for the fork. This document describes only the former. The latter is -described in [fork selection](fork-selection.md). +described in [Tower BFT](tower-bft.md). ## Current Design @@ -50,12 +50,11 @@ log the time since the NewBlock transaction was submitted. ### Finality and Payouts -Locktower is the proposed [fork selection](fork-selection.md) algorithm. It -proposes that payment to miners be postponed until the *stack* of validator -votes reaches a certain depth, at which point rollback is not economically -feasible. The vote program may therefore implement locktower. Vote instructions -would need to reference a global locktower account so that it can track -cross-block state. +[Tower BFT](tower-bft.md) is the proposed fork selection algorithm. It proposes +that payment to miners be postponed until the *stack* of validator votes reaches +a certain depth, at which point rollback is not economically feasible. The vote +program may therefore implement Tower BFT. Vote instructions would need to +reference a global Tower account so that it can track cross-block state. ## Challenges diff --git a/book/src/fork-generation.md b/book/src/fork-generation.md index be1a417bf..906a8267c 100644 --- a/book/src/fork-generation.md +++ b/book/src/fork-generation.md @@ -55,7 +55,7 @@ Validators can ignore forks at other points (e.g. from the wrong leader), or slash the leader responsible for the fork. Validators vote based on a greedy choice to maximize their reward described in -[forks selection](fork-selection.md). +[Tower BFT](tower-bft.md). ### Validator's View diff --git a/book/src/leader-rotation.md b/book/src/leader-rotation.md index 016eab732..55fad4fb8 100644 --- a/book/src/leader-rotation.md +++ b/book/src/leader-rotation.md @@ -96,7 +96,7 @@ ends up scheduled for the first two epochs because the leader schedule is also generated at slot 0 for the next epoch. The length of the first two epochs can be specified in the genesis block as well. The minimum length of the first epochs must be greater than or equal to the maximum rollback depth as defined in -[fork selection](fork-selection.md). +[Tower BFT](tower-bft.md). ## Leader Schedule Generation Algorithm diff --git a/book/src/ledger-replication-to-implement.md b/book/src/ledger-replication-to-implement.md index b490d3dd4..b4ccf3bb2 100644 --- a/book/src/ledger-replication-to-implement.md +++ b/book/src/ledger-replication-to-implement.md @@ -74,7 +74,7 @@ The program should have a list of slots which are valid storage mining slots. This list should be maintained by keeping track of slots which are rooted slots in which a significant portion of the network has voted on with a high lockout value, maybe 32-votes old. Every SLOTS\_PER\_SEGMENT number of slots would be added to this set. The program should check that the slot is in this set. The set can -be maintained by receiving a AdvertiseStorageRecentBlockHash and checking with its bank/locktower state. +be maintained by receiving a AdvertiseStorageRecentBlockHash and checking with its bank/Tower BFT state. The program should do a signature verify check on the signature, public key from the transaction submitter and the message of the previous storage epoch PoH value. diff --git a/book/src/persistent-account-storage.md b/book/src/persistent-account-storage.md index 772a16047..16ec0dc4f 100644 --- a/book/src/persistent-account-storage.md +++ b/book/src/persistent-account-storage.md @@ -60,7 +60,7 @@ The read is satisfied by pointing to a memory-mapped location in the ## Root Forks -The [fork selection algorithm](fork-selection.md) eventually selects a fork as a +[Tower BFT](tower-bft.md) eventually selects a fork as a root fork and the fork is squashed. A squashed/root fork cannot be rolled back. When a fork is squashed, all accounts in its parents not already present in the diff --git a/book/src/stake-delegation-and-rewards.md b/book/src/stake-delegation-and-rewards.md index a3d7734fb..7bed22cf0 100644 --- a/book/src/stake-delegation-and-rewards.md +++ b/book/src/stake-delegation-and-rewards.md @@ -77,7 +77,7 @@ count as stakes. ### VoteInstruction::Vote(Vec) * `account[0]` - RW - The VoteState - `VoteState::lockouts` and `VoteState::credits` are updated according to voting lockout rules see [Fork Selection](fork-selection.md) + `VoteState::lockouts` and `VoteState::credits` are updated according to voting lockout rules see [Tower BFT](tower-bft.md) * `account[1]` - RO - A list of some N most recent slots and their hashes for the vote to be verified against. diff --git a/book/src/fork-selection.md b/book/src/tower-bft.md similarity index 98% rename from book/src/fork-selection.md rename to book/src/tower-bft.md index 3f65fa185..afa627bc1 100644 --- a/book/src/fork-selection.md +++ b/book/src/tower-bft.md @@ -1,7 +1,7 @@ -# Fork Selection +# Tower BFT -This design describes a *Fork Selection* algorithm. It addresses the following -problems: +This design describes Solana's *Tower BFT* algorithm. It addresses the +following problems: * Some forks may not end up accepted by the super-majority of the cluster, and voters need to recover from voting on such forks. diff --git a/core/src/cluster_info_vote_listener.rs b/core/src/cluster_info_vote_listener.rs index 8159301ff..bf256a7d2 100644 --- a/core/src/cluster_info_vote_listener.rs +++ b/core/src/cluster_info_vote_listener.rs @@ -85,7 +85,7 @@ impl Service for ClusterInfoVoteListener { #[cfg(test)] mod tests { - use crate::locktower::MAX_RECENT_VOTES; + use crate::consensus::MAX_RECENT_VOTES; use crate::packet; use solana_sdk::hash::Hash; use solana_sdk::signature::{Keypair, KeypairUtil}; diff --git a/core/src/cluster_tests.rs b/core/src/cluster_tests.rs index c80865540..475d5c266 100644 --- a/core/src/cluster_tests.rs +++ b/core/src/cluster_tests.rs @@ -4,10 +4,10 @@ use crate::blocktree::Blocktree; /// All tests must start from an entry point and a funding keypair and /// discover the rest of the network. use crate::cluster_info::FULLNODE_PORT_RANGE; +use crate::consensus::VOTE_THRESHOLD_DEPTH; use crate::contact_info::ContactInfo; use crate::entry::{Entry, EntrySlice}; use crate::gossip_service::discover_cluster; -use crate::locktower::VOTE_THRESHOLD_DEPTH; use hashbrown::HashSet; use solana_client::thin_client::create_client; use solana_runtime::epoch_schedule::MINIMUM_SLOTS_PER_EPOCH; diff --git a/core/src/locktower.rs b/core/src/consensus.rs similarity index 79% rename from core/src/locktower.rs rename to core/src/consensus.rs index 8bbf9c021..68dcb9366 100644 --- a/core/src/locktower.rs +++ b/core/src/consensus.rs @@ -29,7 +29,7 @@ pub struct StakeLockout { } #[derive(Default)] -pub struct Locktower { +pub struct Tower { epoch_stakes: EpochStakes, threshold_depth: usize, threshold_size: f64, @@ -68,7 +68,7 @@ impl EpochStakes { } } -impl Locktower { +impl Tower { pub fn new_from_forks(bank_forks: &BankForks, my_pubkey: &Pubkey) -> Self { let mut frozen_banks: Vec<_> = bank_forks.frozen_banks().values().cloned().collect(); frozen_banks.sort_by_key(|b| (b.parents().len(), b.slot())); @@ -80,7 +80,7 @@ impl Locktower { } }; - let mut locktower = Self { + let mut tower = Self { epoch_stakes, threshold_depth: VOTE_THRESHOLD_DEPTH, threshold_size: VOTE_THRESHOLD_SIZE, @@ -88,10 +88,9 @@ impl Locktower { recent_votes: VecDeque::default(), }; - let bank = locktower.find_heaviest_bank(bank_forks).unwrap(); - locktower.lockouts = - Self::initialize_lockouts_from_bank(&bank, locktower.epoch_stakes.epoch); - locktower + let bank = tower.find_heaviest_bank(bank_forks).unwrap(); + tower.lockouts = Self::initialize_lockouts_from_bank(&bank, tower.epoch_stakes.epoch); + tower } pub fn new(epoch_stakes: EpochStakes, threshold_depth: usize, threshold_size: f64) -> Self { Self { @@ -120,7 +119,7 @@ impl Locktower { let vote_state = VoteState::from(&account); if vote_state.is_none() { datapoint_warn!( - "locktower_warn", + "tower_warn", ( "warn", format!("Unable to get vote_state from account {}", key), @@ -141,7 +140,7 @@ impl Locktower { ); debug!("observed root {}", vote_state.root_slot.unwrap_or(0) as i64); datapoint_info!( - "locktower-observed", + "tower-observed", ( "slot", vote_state.nth_recent_vote(0).map(|v| v.slot).unwrap_or(0), @@ -223,14 +222,14 @@ impl Locktower { "epoch_stakes cannot move backwards" ); info!( - "Locktower updated epoch bank slot: {} epoch: {}", + "Tower updated epoch bank slot: {} epoch: {}", bank.slot(), self.epoch_stakes.epoch ); self.epoch_stakes = EpochStakes::new_from_bank(bank, &self.epoch_stakes.delegate_pubkey); datapoint_info!( - "locktower-epoch", + "tower-epoch", ("epoch", self.epoch_stakes.epoch, i64), ("self_staked", self.epoch_stakes.self_staked, i64), ("total_staked", self.epoch_stakes.total_staked, i64) @@ -256,7 +255,7 @@ impl Locktower { .retain(|vote| slots.iter().any(|slot| vote.slot == *slot)); datapoint_info!( - "locktower-vote", + "tower-vote", ("latest", slot, i64), ("root", self.lockouts.root_slot.unwrap_or(0), i64) ); @@ -429,11 +428,11 @@ mod test { fn test_collect_vote_lockouts_no_epoch_stakes() { let accounts = gen_stakes(&[(1, &[0])]); let epoch_stakes = EpochStakes::new_for_tests(2); - let locktower = Locktower::new(epoch_stakes, 0, 0.67); + let tower = Tower::new(epoch_stakes, 0, 0.67); let ancestors = vec![(1, vec![0].into_iter().collect()), (0, HashSet::new())] .into_iter() .collect(); - let staked_lockouts = locktower.collect_vote_lockouts(1, accounts.into_iter(), &ancestors); + let staked_lockouts = tower.collect_vote_lockouts(1, accounts.into_iter(), &ancestors); assert!(staked_lockouts.is_empty()); } @@ -442,11 +441,11 @@ mod test { //two accounts voting for slot 0 with 1 token staked let accounts = gen_stakes(&[(1, &[0]), (1, &[0])]); let epoch_stakes = EpochStakes::new_from_stakes(0, &accounts); - let locktower = Locktower::new(epoch_stakes, 0, 0.67); + let tower = Tower::new(epoch_stakes, 0, 0.67); let ancestors = vec![(1, vec![0].into_iter().collect()), (0, HashSet::new())] .into_iter() .collect(); - let staked_lockouts = locktower.collect_vote_lockouts(1, accounts.into_iter(), &ancestors); + let staked_lockouts = tower.collect_vote_lockouts(1, accounts.into_iter(), &ancestors); assert_eq!(staked_lockouts[&0].stake, 2); assert_eq!(staked_lockouts[&0].lockout, 2 + 2 + 4 + 4); } @@ -457,14 +456,14 @@ mod test { //two accounts voting for slot 0 with 1 token staked let accounts = gen_stakes(&[(1, &votes), (1, &votes)]); let epoch_stakes = EpochStakes::new_from_stakes(0, &accounts); - let mut locktower = Locktower::new(epoch_stakes, 0, 0.67); + let mut tower = Tower::new(epoch_stakes, 0, 0.67); let mut ancestors = HashMap::new(); for i in 0..(MAX_LOCKOUT_HISTORY + 1) { - locktower.record_vote(i as u64, Hash::default()); + tower.record_vote(i as u64, Hash::default()); ancestors.insert(i as u64, (0..i as u64).into_iter().collect()); } - assert_eq!(locktower.lockouts.root_slot, Some(0)); - let staked_lockouts = locktower.collect_vote_lockouts( + assert_eq!(tower.lockouts.root_slot, Some(0)); + let staked_lockouts = tower.collect_vote_lockouts( MAX_LOCKOUT_HISTORY as u64, accounts.into_iter(), &ancestors, @@ -478,8 +477,8 @@ mod test { #[test] fn test_calculate_weight_skips_root() { - let mut locktower = Locktower::new(EpochStakes::new_for_tests(2), 0, 0.67); - locktower.lockouts.root_slot = Some(1); + let mut tower = Tower::new(EpochStakes::new_for_tests(2), 0, 0.67); + tower.lockouts.root_slot = Some(1); let stakes = vec![ ( 0, @@ -498,12 +497,12 @@ mod test { ] .into_iter() .collect(); - assert_eq!(locktower.calculate_weight(&stakes), 0u128); + assert_eq!(tower.calculate_weight(&stakes), 0u128); } #[test] fn test_calculate_weight() { - let locktower = Locktower::new(EpochStakes::new_for_tests(2), 0, 0.67); + let tower = Tower::new(EpochStakes::new_for_tests(2), 0, 0.67); let stakes = vec![( 0, StakeLockout { @@ -513,12 +512,12 @@ mod test { )] .into_iter() .collect(); - assert_eq!(locktower.calculate_weight(&stakes), 8u128); + assert_eq!(tower.calculate_weight(&stakes), 8u128); } #[test] fn test_check_vote_threshold_without_votes() { - let locktower = Locktower::new(EpochStakes::new_for_tests(2), 1, 0.67); + let tower = Tower::new(EpochStakes::new_for_tests(2), 1, 0.67); let stakes = vec![( 0, StakeLockout { @@ -528,12 +527,12 @@ mod test { )] .into_iter() .collect(); - assert!(locktower.check_vote_stake_threshold(0, &stakes)); + assert!(tower.check_vote_stake_threshold(0, &stakes)); } #[test] fn test_is_slot_confirmed_not_enough_stake_failure() { - let locktower = Locktower::new(EpochStakes::new_for_tests(2), 1, 0.67); + let tower = Tower::new(EpochStakes::new_for_tests(2), 1, 0.67); let stakes = vec![( 0, StakeLockout { @@ -543,19 +542,19 @@ mod test { )] .into_iter() .collect(); - assert!(!locktower.is_slot_confirmed(0, &stakes)); + assert!(!tower.is_slot_confirmed(0, &stakes)); } #[test] fn test_is_slot_confirmed_unknown_slot() { - let locktower = Locktower::new(EpochStakes::new_for_tests(2), 1, 0.67); + let tower = Tower::new(EpochStakes::new_for_tests(2), 1, 0.67); let stakes = HashMap::new(); - assert!(!locktower.is_slot_confirmed(0, &stakes)); + assert!(!tower.is_slot_confirmed(0, &stakes)); } #[test] fn test_is_slot_confirmed_pass() { - let locktower = Locktower::new(EpochStakes::new_for_tests(2), 1, 0.67); + let tower = Tower::new(EpochStakes::new_for_tests(2), 1, 0.67); let stakes = vec![( 0, StakeLockout { @@ -565,68 +564,68 @@ mod test { )] .into_iter() .collect(); - assert!(locktower.is_slot_confirmed(0, &stakes)); + assert!(tower.is_slot_confirmed(0, &stakes)); } #[test] fn test_is_locked_out_empty() { - let locktower = Locktower::new(EpochStakes::new_for_tests(2), 0, 0.67); + let tower = Tower::new(EpochStakes::new_for_tests(2), 0, 0.67); let descendants = HashMap::new(); - assert!(!locktower.is_locked_out(0, &descendants)); + assert!(!tower.is_locked_out(0, &descendants)); } #[test] fn test_is_locked_out_root_slot_child_pass() { - let mut locktower = Locktower::new(EpochStakes::new_for_tests(2), 0, 0.67); + let mut tower = Tower::new(EpochStakes::new_for_tests(2), 0, 0.67); let descendants = vec![(0, vec![1].into_iter().collect())] .into_iter() .collect(); - locktower.lockouts.root_slot = Some(0); - assert!(!locktower.is_locked_out(1, &descendants)); + tower.lockouts.root_slot = Some(0); + assert!(!tower.is_locked_out(1, &descendants)); } #[test] fn test_is_locked_out_root_slot_sibling_fail() { - let mut locktower = Locktower::new(EpochStakes::new_for_tests(2), 0, 0.67); + let mut tower = Tower::new(EpochStakes::new_for_tests(2), 0, 0.67); let descendants = vec![(0, vec![1].into_iter().collect())] .into_iter() .collect(); - locktower.lockouts.root_slot = Some(0); - assert!(locktower.is_locked_out(2, &descendants)); + tower.lockouts.root_slot = Some(0); + assert!(tower.is_locked_out(2, &descendants)); } #[test] fn test_check_already_voted() { - let mut locktower = Locktower::new(EpochStakes::new_for_tests(2), 0, 0.67); - locktower.record_vote(0, Hash::default()); - assert!(locktower.has_voted(0)); - assert!(!locktower.has_voted(1)); + let mut tower = Tower::new(EpochStakes::new_for_tests(2), 0, 0.67); + tower.record_vote(0, Hash::default()); + assert!(tower.has_voted(0)); + assert!(!tower.has_voted(1)); } #[test] fn test_is_locked_out_double_vote() { - let mut locktower = Locktower::new(EpochStakes::new_for_tests(2), 0, 0.67); + let mut tower = Tower::new(EpochStakes::new_for_tests(2), 0, 0.67); let descendants = vec![(0, vec![1].into_iter().collect()), (1, HashSet::new())] .into_iter() .collect(); - locktower.record_vote(0, Hash::default()); - locktower.record_vote(1, Hash::default()); - assert!(locktower.is_locked_out(0, &descendants)); + tower.record_vote(0, Hash::default()); + tower.record_vote(1, Hash::default()); + assert!(tower.is_locked_out(0, &descendants)); } #[test] fn test_is_locked_out_child() { - let mut locktower = Locktower::new(EpochStakes::new_for_tests(2), 0, 0.67); + let mut tower = Tower::new(EpochStakes::new_for_tests(2), 0, 0.67); let descendants = vec![(0, vec![1].into_iter().collect())] .into_iter() .collect(); - locktower.record_vote(0, Hash::default()); - assert!(!locktower.is_locked_out(1, &descendants)); + tower.record_vote(0, Hash::default()); + assert!(!tower.is_locked_out(1, &descendants)); } #[test] fn test_is_locked_out_sibling() { - let mut locktower = Locktower::new(EpochStakes::new_for_tests(2), 0, 0.67); + let mut tower = Tower::new(EpochStakes::new_for_tests(2), 0, 0.67); let descendants = vec![ (0, vec![1, 2].into_iter().collect()), (1, HashSet::new()), @@ -634,30 +633,30 @@ mod test { ] .into_iter() .collect(); - locktower.record_vote(0, Hash::default()); - locktower.record_vote(1, Hash::default()); - assert!(locktower.is_locked_out(2, &descendants)); + tower.record_vote(0, Hash::default()); + tower.record_vote(1, Hash::default()); + assert!(tower.is_locked_out(2, &descendants)); } #[test] fn test_is_locked_out_last_vote_expired() { - let mut locktower = Locktower::new(EpochStakes::new_for_tests(2), 0, 0.67); + let mut tower = Tower::new(EpochStakes::new_for_tests(2), 0, 0.67); let descendants = vec![(0, vec![1, 4].into_iter().collect()), (1, HashSet::new())] .into_iter() .collect(); - locktower.record_vote(0, Hash::default()); - locktower.record_vote(1, Hash::default()); - assert!(!locktower.is_locked_out(4, &descendants)); - locktower.record_vote(4, Hash::default()); - assert_eq!(locktower.lockouts.votes[0].slot, 0); - assert_eq!(locktower.lockouts.votes[0].confirmation_count, 2); - assert_eq!(locktower.lockouts.votes[1].slot, 4); - assert_eq!(locktower.lockouts.votes[1].confirmation_count, 1); + tower.record_vote(0, Hash::default()); + tower.record_vote(1, Hash::default()); + assert!(!tower.is_locked_out(4, &descendants)); + tower.record_vote(4, Hash::default()); + assert_eq!(tower.lockouts.votes[0].slot, 0); + assert_eq!(tower.lockouts.votes[0].confirmation_count, 2); + assert_eq!(tower.lockouts.votes[1].slot, 4); + assert_eq!(tower.lockouts.votes[1].confirmation_count, 1); } #[test] fn test_check_vote_threshold_below_threshold() { - let mut locktower = Locktower::new(EpochStakes::new_for_tests(2), 1, 0.67); + let mut tower = Tower::new(EpochStakes::new_for_tests(2), 1, 0.67); let stakes = vec![( 0, StakeLockout { @@ -667,12 +666,12 @@ mod test { )] .into_iter() .collect(); - locktower.record_vote(0, Hash::default()); - assert!(!locktower.check_vote_stake_threshold(1, &stakes)); + tower.record_vote(0, Hash::default()); + assert!(!tower.check_vote_stake_threshold(1, &stakes)); } #[test] fn test_check_vote_threshold_above_threshold() { - let mut locktower = Locktower::new(EpochStakes::new_for_tests(2), 1, 0.67); + let mut tower = Tower::new(EpochStakes::new_for_tests(2), 1, 0.67); let stakes = vec![( 0, StakeLockout { @@ -682,13 +681,13 @@ mod test { )] .into_iter() .collect(); - locktower.record_vote(0, Hash::default()); - assert!(locktower.check_vote_stake_threshold(1, &stakes)); + tower.record_vote(0, Hash::default()); + assert!(tower.check_vote_stake_threshold(1, &stakes)); } #[test] fn test_check_vote_threshold_above_threshold_after_pop() { - let mut locktower = Locktower::new(EpochStakes::new_for_tests(2), 1, 0.67); + let mut tower = Tower::new(EpochStakes::new_for_tests(2), 1, 0.67); let stakes = vec![( 0, StakeLockout { @@ -698,18 +697,18 @@ mod test { )] .into_iter() .collect(); - locktower.record_vote(0, Hash::default()); - locktower.record_vote(1, Hash::default()); - locktower.record_vote(2, Hash::default()); - assert!(locktower.check_vote_stake_threshold(6, &stakes)); + tower.record_vote(0, Hash::default()); + tower.record_vote(1, Hash::default()); + tower.record_vote(2, Hash::default()); + assert!(tower.check_vote_stake_threshold(6, &stakes)); } #[test] fn test_check_vote_threshold_above_threshold_no_stake() { - let mut locktower = Locktower::new(EpochStakes::new_for_tests(2), 1, 0.67); + let mut tower = Tower::new(EpochStakes::new_for_tests(2), 1, 0.67); let stakes = HashMap::new(); - locktower.record_vote(0, Hash::default()); - assert!(!locktower.check_vote_stake_threshold(1, &stakes)); + tower.record_vote(0, Hash::default()); + assert!(!tower.check_vote_stake_threshold(1, &stakes)); } #[test] @@ -724,7 +723,7 @@ mod test { ancestors.insert(2, set); let set: HashSet = vec![0u64].into_iter().collect(); ancestors.insert(1, set); - Locktower::update_ancestor_lockouts(&mut stake_lockouts, &vote, &ancestors); + Tower::update_ancestor_lockouts(&mut stake_lockouts, &vote, &ancestors); assert_eq!(stake_lockouts[&0].lockout, 2); assert_eq!(stake_lockouts[&1].lockout, 2); assert_eq!(stake_lockouts[&2].lockout, 2); @@ -742,12 +741,12 @@ mod test { slot: 2, confirmation_count: 1, }; - Locktower::update_ancestor_lockouts(&mut stake_lockouts, &vote, &ancestors); + Tower::update_ancestor_lockouts(&mut stake_lockouts, &vote, &ancestors); let vote = Lockout { slot: 1, confirmation_count: 2, }; - Locktower::update_ancestor_lockouts(&mut stake_lockouts, &vote, &ancestors); + Tower::update_ancestor_lockouts(&mut stake_lockouts, &vote, &ancestors); assert_eq!(stake_lockouts[&0].lockout, 2 + 4); assert_eq!(stake_lockouts[&1].lockout, 2 + 4); assert_eq!(stake_lockouts[&2].lockout, 2); @@ -760,7 +759,7 @@ mod test { account.lamports = 1; let set: HashSet = vec![0u64, 1u64].into_iter().collect(); let ancestors: HashMap> = [(2u64, set)].into_iter().cloned().collect(); - Locktower::update_ancestor_stakes(&mut stake_lockouts, 2, account.lamports, &ancestors); + Tower::update_ancestor_stakes(&mut stake_lockouts, 2, account.lamports, &ancestors); assert_eq!(stake_lockouts[&0].stake, 1); assert_eq!(stake_lockouts[&1].stake, 1); assert_eq!(stake_lockouts[&2].stake, 1); @@ -782,51 +781,48 @@ mod test { let total_stake = 4; let threshold_size = 0.67; let threshold_stake = (f64::ceil(total_stake as f64 * threshold_size)) as u64; - let locktower_votes: Vec = (0..VOTE_THRESHOLD_DEPTH as u64).collect(); + let tower_votes: Vec = (0..VOTE_THRESHOLD_DEPTH as u64).collect(); let accounts = gen_stakes(&[ (threshold_stake, &[(VOTE_THRESHOLD_DEPTH - 2) as u64]), - (total_stake - threshold_stake, &locktower_votes[..]), + (total_stake - threshold_stake, &tower_votes[..]), ]); - // Initialize locktower + // Initialize tower let stakes: HashMap<_, _> = accounts.iter().map(|(pk, (s, _))| (*pk, *s)).collect(); let epoch_stakes = EpochStakes::new(0, stakes, &Pubkey::default()); - let mut locktower = Locktower::new(epoch_stakes, VOTE_THRESHOLD_DEPTH, threshold_size); + let mut tower = Tower::new(epoch_stakes, VOTE_THRESHOLD_DEPTH, threshold_size); - // CASE 1: Record the first VOTE_THRESHOLD locktower votes for fork 2. We want to + // CASE 1: Record the first VOTE_THRESHOLD tower votes for fork 2. We want to // evaluate a vote on slot VOTE_THRESHOLD_DEPTH. The nth most recent vote should be // for slot 0, which is common to all account vote states, so we should pass the // threshold check let vote_to_evaluate = VOTE_THRESHOLD_DEPTH as u64; - for vote in &locktower_votes { - locktower.record_vote(*vote, Hash::default()); + for vote in &tower_votes { + tower.record_vote(*vote, Hash::default()); } - let stakes_lockouts = locktower.collect_vote_lockouts( - vote_to_evaluate, - accounts.clone().into_iter(), - &ancestors, - ); - assert!(locktower.check_vote_stake_threshold(vote_to_evaluate, &stakes_lockouts)); + let stakes_lockouts = + tower.collect_vote_lockouts(vote_to_evaluate, accounts.clone().into_iter(), &ancestors); + assert!(tower.check_vote_stake_threshold(vote_to_evaluate, &stakes_lockouts)); // CASE 2: Now we want to evaluate a vote for slot VOTE_THRESHOLD_DEPTH + 1. This slot // will expire the vote in one of the vote accounts, so we should have insufficient // stake to pass the threshold let vote_to_evaluate = VOTE_THRESHOLD_DEPTH as u64 + 1; let stakes_lockouts = - locktower.collect_vote_lockouts(vote_to_evaluate, accounts.into_iter(), &ancestors); - assert!(!locktower.check_vote_stake_threshold(vote_to_evaluate, &stakes_lockouts)); + tower.collect_vote_lockouts(vote_to_evaluate, accounts.into_iter(), &ancestors); + assert!(!tower.check_vote_stake_threshold(vote_to_evaluate, &stakes_lockouts)); } fn vote_and_check_recent(num_votes: usize) { - let mut locktower = Locktower::new(EpochStakes::new_for_tests(2), 1, 0.67); + let mut tower = Tower::new(EpochStakes::new_for_tests(2), 1, 0.67); let start = num_votes.saturating_sub(MAX_RECENT_VOTES); let expected: Vec<_> = (start..num_votes) .map(|i| Vote::new(i as u64, Hash::default())) .collect(); for i in 0..num_votes { - locktower.record_vote(i as u64, Hash::default()); + tower.record_vote(i as u64, Hash::default()); } - assert_eq!(expected, locktower.recent_votes()) + assert_eq!(expected, tower.recent_votes()) } #[test] diff --git a/core/src/lib.rs b/core/src/lib.rs index 709ef1985..ddb25e87b 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -30,6 +30,7 @@ pub mod cluster; pub mod cluster_info; pub mod cluster_info_repair_listener; pub mod cluster_tests; +pub mod consensus; pub mod entry; pub mod erasure; pub mod fetch_stage; @@ -41,7 +42,6 @@ pub mod leader_schedule_cache; pub mod leader_schedule_utils; pub mod local_cluster; pub mod local_vote_signer_service; -pub mod locktower; pub mod packet; pub mod poh; pub mod poh_recorder; diff --git a/core/src/replay_stage.rs b/core/src/replay_stage.rs index fe4943788..51906c309 100644 --- a/core/src/replay_stage.rs +++ b/core/src/replay_stage.rs @@ -4,10 +4,10 @@ use crate::bank_forks::BankForks; use crate::blocktree::Blocktree; use crate::blocktree_processor; use crate::cluster_info::ClusterInfo; +use crate::consensus::{StakeLockout, Tower}; use crate::entry::{Entry, EntrySlice}; use crate::leader_schedule_cache::LeaderScheduleCache; use crate::leader_schedule_utils; -use crate::locktower::{Locktower, StakeLockout}; use crate::packet::BlobError; use crate::poh_recorder::PohRecorder; use crate::result::{Error, Result}; @@ -102,7 +102,7 @@ impl ReplayStage { let poh_recorder = poh_recorder.clone(); let my_pubkey = *my_pubkey; let mut ticks_per_slot = 0; - let mut locktower = Locktower::new_from_forks(&bank_forks.read().unwrap(), &my_pubkey); + let mut tower = Tower::new_from_forks(&bank_forks.read().unwrap(), &my_pubkey); // Start the replay stage loop let leader_schedule_cache = leader_schedule_cache.clone(); let vote_account = *vote_account; @@ -142,8 +142,7 @@ impl ReplayStage { ticks_per_slot = bank.ticks_per_slot(); } - let votable = - Self::generate_votable_banks(&bank_forks, &locktower, &mut progress); + let votable = Self::generate_votable_banks(&bank_forks, &tower, &mut progress); if let Some((_, bank)) = votable.last() { subscriptions.notify_subscribers(bank.slot(), &bank_forks); @@ -151,7 +150,7 @@ impl ReplayStage { Self::handle_votable_bank( &bank, &bank_forks, - &mut locktower, + &mut tower, &mut progress, &vote_account, &voting_keypair, @@ -318,7 +317,7 @@ impl ReplayStage { fn handle_votable_bank( bank: &Arc, bank_forks: &Arc>, - locktower: &mut Locktower, + tower: &mut Tower, progress: &mut HashMap, vote_account: &Pubkey, voting_keypair: &Option>, @@ -330,7 +329,7 @@ impl ReplayStage { where T: 'static + KeypairUtil + Send + Sync, { - if let Some(new_root) = locktower.record_vote(bank.slot(), bank.hash()) { + if let Some(new_root) = tower.record_vote(bank.slot(), bank.hash()) { // get the root bank before squash let root_bank = bank_forks .read() @@ -352,7 +351,7 @@ impl ReplayStage { Self::handle_new_root(&bank_forks, progress); root_bank_sender.send(rooted_banks)?; } - locktower.update_epoch(&bank); + tower.update_epoch(&bank); if let Some(ref voting_keypair) = voting_keypair { let node_keypair = cluster_info.read().unwrap().keypair.clone(); @@ -360,7 +359,7 @@ impl ReplayStage { let vote_ix = vote_instruction::vote( &vote_account, &voting_keypair.pubkey(), - locktower.recent_votes(), + tower.recent_votes(), ); let mut vote_tx = @@ -438,11 +437,11 @@ impl ReplayStage { fn generate_votable_banks( bank_forks: &Arc>, - locktower: &Locktower, + tower: &Tower, progress: &mut HashMap, ) -> Vec<(u128, Arc)> { - let locktower_start = Instant::now(); - // Locktower voting + let tower_start = Instant::now(); + // Tower voting let descendants = bank_forks.read().unwrap().descendants(); let ancestors = bank_forks.read().unwrap().ancestors(); let frozen_banks = bank_forks.read().unwrap().frozen_banks(); @@ -456,24 +455,24 @@ impl ReplayStage { is_votable }) .filter(|b| { - let is_recent_epoch = locktower.is_recent_epoch(b); + let is_recent_epoch = tower.is_recent_epoch(b); trace!("bank is is_recent_epoch: {} {}", b.slot(), is_recent_epoch); is_recent_epoch }) .filter(|b| { - let has_voted = locktower.has_voted(b.slot()); + let has_voted = tower.has_voted(b.slot()); trace!("bank is has_voted: {} {}", b.slot(), has_voted); !has_voted }) .filter(|b| { - let is_locked_out = locktower.is_locked_out(b.slot(), &descendants); + let is_locked_out = tower.is_locked_out(b.slot(), &descendants); trace!("bank is is_locked_out: {} {}", b.slot(), is_locked_out); !is_locked_out }) .map(|bank| { ( bank, - locktower.collect_vote_lockouts( + tower.collect_vote_lockouts( bank.slot(), bank.vote_accounts().into_iter(), &ancestors, @@ -481,43 +480,42 @@ impl ReplayStage { ) }) .filter(|(b, stake_lockouts)| { - let vote_threshold = - locktower.check_vote_stake_threshold(b.slot(), &stake_lockouts); - Self::confirm_forks(locktower, stake_lockouts, progress, bank_forks); + let vote_threshold = tower.check_vote_stake_threshold(b.slot(), &stake_lockouts); + Self::confirm_forks(tower, stake_lockouts, progress, bank_forks); debug!("bank vote_threshold: {} {}", b.slot(), vote_threshold); vote_threshold }) - .map(|(b, stake_lockouts)| (locktower.calculate_weight(&stake_lockouts), b.clone())) + .map(|(b, stake_lockouts)| (tower.calculate_weight(&stake_lockouts), b.clone())) .collect(); votable.sort_by_key(|b| b.0); - let ms = timing::duration_as_ms(&locktower_start.elapsed()); + let ms = timing::duration_as_ms(&tower_start.elapsed()); trace!("votable_banks {}", votable.len()); if !votable.is_empty() { let weights: Vec = votable.iter().map(|x| x.0).collect(); info!( - "@{:?} locktower duration: {:?} len: {} weights: {:?}", + "@{:?} tower duration: {:?} len: {} weights: {:?}", timing::timestamp(), ms, votable.len(), weights ); } - inc_new_counter_info!("replay_stage-locktower_duration", ms as usize); + inc_new_counter_info!("replay_stage-tower_duration", ms as usize); votable } fn confirm_forks( - locktower: &Locktower, + tower: &Tower, stake_lockouts: &HashMap, progress: &mut HashMap, bank_forks: &Arc>, ) { progress.retain(|slot, prog| { let duration = timing::timestamp() - prog.started_ms; - if locktower.is_slot_confirmed(*slot, stake_lockouts) + if tower.is_slot_confirmed(*slot, stake_lockouts) && bank_forks .read() .unwrap() diff --git a/metrics/scripts/grafana-provisioning/dashboards/testnet-monitor.json b/metrics/scripts/grafana-provisioning/dashboards/testnet-monitor.json index 5d7853cbf..e8e15d5c1 100644 --- a/metrics/scripts/grafana-provisioning/dashboards/testnet-monitor.json +++ b/metrics/scripts/grafana-provisioning/dashboards/testnet-monitor.json @@ -5366,8 +5366,8 @@ { "aliasColors": { "cluster-info.repair": "#ba43a9", - "locktower-observed.squash_account": "#0a437c", - "locktower-observed.squash_cache": "#ea6460", + "tower-observed.squash_account": "#0a437c", + "tower-observed.squash_cache": "#ea6460", "replay_stage-new_leader.last": "#00ffbb", "window-service.receive": "#b7dbab", "window-stage.consumed": "#5195ce" @@ -5465,7 +5465,7 @@ "measurement": "cluster_info-vote-count", "orderByTime": "ASC", "policy": "autogen", - "query": "SELECT mean(\"squash_accounts_ms\") AS \"squash_account\" FROM \"$testnet\".\"autogen\".\"locktower-observed\" WHERE host_id =~ /$hostid/ AND $timeFilter GROUP BY time($__interval)", + "query": "SELECT mean(\"squash_accounts_ms\") AS \"squash_account\" FROM \"$testnet\".\"autogen\".\"tower-observed\" WHERE host_id =~ /$hostid/ AND $timeFilter GROUP BY time($__interval)", "rawQuery": true, "refId": "B", "resultFormat": "time_series", @@ -5504,7 +5504,7 @@ "measurement": "cluster_info-vote-count", "orderByTime": "ASC", "policy": "autogen", - "query": "SELECT mean(\"squash_cache_ms\") AS \"squash_cache\" FROM \"$testnet\".\"autogen\".\"locktower-observed\" WHERE host_id =~ /$hostid/ AND $timeFilter GROUP BY time($__interval)", + "query": "SELECT mean(\"squash_cache_ms\") AS \"squash_cache\" FROM \"$testnet\".\"autogen\".\"tower-observed\" WHERE host_id =~ /$hostid/ AND $timeFilter GROUP BY time($__interval)", "rawQuery": true, "refId": "C", "resultFormat": "time_series", @@ -5576,7 +5576,7 @@ "cluster-info.repair": "#ba43a9", "fetch_stage-discard_forwards.sum": "#00ffbb", "fetch_stage-honor_forwards.sum": "#bf1b00", - "locktower-vote.last": "#00ffbb", + "tower-vote.last": "#00ffbb", "replay_stage-new_leader.last": "#00ffbb", "window-service.receive": "#b7dbab", "window-stage.consumed": "#5195ce" @@ -5892,7 +5892,7 @@ "cluster-info.repair": "#ba43a9", "fetch_stage-discard_forwards.sum": "#00ffbb", "fetch_stage-honor_forwards.sum": "#bf1b00", - "locktower-vote.last": "#00ffbb", + "tower-vote.last": "#00ffbb", "poh_recorder-record_lock_contention.sum": "#5195ce", "poh_recorder-tick_lock_contention.sum": "#962d82", "replay_stage-new_leader.last": "#00ffbb", @@ -7089,7 +7089,7 @@ "measurement": "cluster_info-vote-count", "orderByTime": "ASC", "policy": "autogen", - "query": "SELECT last(\"latest\") - last(\"root\") FROM \"$testnet\".\"autogen\".\"locktower-vote\" WHERE host_id =~ /$hostid/ AND $timeFilter GROUP BY time($__interval)", + "query": "SELECT last(\"latest\") - last(\"root\") FROM \"$testnet\".\"autogen\".\"tower-vote\" WHERE host_id =~ /$hostid/ AND $timeFilter GROUP BY time($__interval)", "rawQuery": true, "refId": "A", "resultFormat": "time_series", @@ -7126,7 +7126,7 @@ ], "orderByTime": "ASC", "policy": "default", - "query": "SELECT last(\"slot\") - last(\"root\") FROM \"$testnet\".\"autogen\".\"locktower-observed\" WHERE host_id =~ /$hostid/ AND $timeFilter GROUP BY time($__interval)", + "query": "SELECT last(\"slot\") - last(\"root\") FROM \"$testnet\".\"autogen\".\"tower-observed\" WHERE host_id =~ /$hostid/ AND $timeFilter GROUP BY time($__interval)", "rawQuery": true, "refId": "B", "resultFormat": "time_series", @@ -7190,7 +7190,7 @@ { "aliasColors": { "cluster-info.repair": "#ba43a9", - "locktower-vote.last": "#00ffbb", + "tower-vote.last": "#00ffbb", "replay_stage-new_leader.last": "#00ffbb", "window-service.receive": "#b7dbab", "window-stage.consumed": "#5195ce" @@ -7249,7 +7249,7 @@ "measurement": "cluster_info-vote-count", "orderByTime": "ASC", "policy": "autogen", - "query": "SELECT last(\"root\") FROM \"$testnet\".\"autogen\".\"locktower-vote\" WHERE host_id =~ /$hostid/ AND $timeFilter GROUP BY time($__interval)", + "query": "SELECT last(\"root\") FROM \"$testnet\".\"autogen\".\"tower-vote\" WHERE host_id =~ /$hostid/ AND $timeFilter GROUP BY time($__interval)", "rawQuery": true, "refId": "A", "resultFormat": "time_series", @@ -7286,7 +7286,7 @@ ], "orderByTime": "ASC", "policy": "default", - "query": "SELECT last(\"root\") FROM \"$testnet\".\"autogen\".\"locktower-observed\" WHERE host_id =~ /$hostid/ AND $timeFilter GROUP BY time($__interval)", + "query": "SELECT last(\"root\") FROM \"$testnet\".\"autogen\".\"tower-observed\" WHERE host_id =~ /$hostid/ AND $timeFilter GROUP BY time($__interval)", "rawQuery": true, "refId": "B", "resultFormat": "time_series", @@ -8100,4 +8100,4 @@ "title": "Testnet Monitor (edge)", "uid": "testnet-edge", "version": 3 -} \ No newline at end of file +} diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 8c473556a..e0c02ece4 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -525,7 +525,7 @@ impl Bank { let squash_cache_ms = duration_as_ms(&squash_cache_start.elapsed()); datapoint_info!( - "locktower-observed", + "tower-observed", ("squash_accounts_ms", squash_accounts_ms, i64), ("squash_cache_ms", squash_cache_ms, i64) );