Skip to content

Commit

Permalink
perf: vote state view
Browse files Browse the repository at this point in the history
  • Loading branch information
jstarry committed Feb 8, 2025
1 parent 8844b27 commit 77728d5
Show file tree
Hide file tree
Showing 28 changed files with 1,018 additions and 208 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions core/src/commitment_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ impl AggregateCommitmentService {
// Override old vote_state in bank with latest one for my own vote pubkey
node_vote_state.clone()
} else {
TowerVoteState::from(account.vote_state().clone())
TowerVoteState::from(account.vote_state_view())
};
Self::aggregate_commitment_for_vote_account(
&mut commitment,
Expand Down Expand Up @@ -540,7 +540,7 @@ mod tests {
fn test_highest_super_majority_root_advance() {
fn get_vote_state(vote_pubkey: Pubkey, bank: &Bank) -> TowerVoteState {
let vote_account = bank.get_vote_account(&vote_pubkey).unwrap();
TowerVoteState::from(vote_account.vote_state().clone())
TowerVoteState::from(vote_account.vote_state_view())
}

let block_commitment_cache = RwLock::new(BlockCommitmentCache::new_for_tests());
Expand Down
21 changes: 10 additions & 11 deletions core/src/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ use {
vote_error::VoteError,
vote_instruction,
vote_state::{
process_slot_vote_unchecked, BlockTimestamp, Lockout, TowerSync, Vote,
VoteState1_14_11, VoteStateUpdate, VoteTransaction, MAX_LOCKOUT_HISTORY,
BlockTimestamp, Lockout, TowerSync, Vote, VoteState1_14_11, VoteStateUpdate,
VoteTransaction, MAX_LOCKOUT_HISTORY,
},
},
std::{
Expand Down Expand Up @@ -406,10 +406,10 @@ impl Tower {
continue;
}
trace!("{} {} with stake {}", vote_account_pubkey, key, voted_stake);
let mut vote_state = account.vote_state().clone();
let mut vote_state = TowerVoteState::from(account.vote_state_view());
for vote in &vote_state.votes {
lockout_intervals
.entry(vote.lockout.last_locked_out_slot())
.entry(vote.last_locked_out_slot())
.or_default()
.push((vote.slot(), key));
}
Expand Down Expand Up @@ -450,7 +450,7 @@ impl Tower {
);
}

process_slot_vote_unchecked(&mut vote_state, bank_slot);
vote_state.process_next_vote_slot(bank_slot);

for vote in &vote_state.votes {
vote_slots.insert(vote.slot());
Expand Down Expand Up @@ -608,8 +608,7 @@ impl Tower {

pub fn last_voted_slot_in_bank(bank: &Bank, vote_account_pubkey: &Pubkey) -> Option<Slot> {
let vote_account = bank.get_vote_account(vote_account_pubkey)?;
let vote_state = vote_account.vote_state();
vote_state.last_voted_slot()
vote_account.vote_state_view().last_voted_slot()
}

pub fn record_bank_vote(&mut self, bank: &Bank) -> Option<Slot> {
Expand Down Expand Up @@ -1618,7 +1617,7 @@ impl Tower {
bank: &Bank,
) {
if let Some(vote_account) = bank.get_vote_account(vote_account_pubkey) {
self.vote_state = TowerVoteState::from(vote_account.vote_state().clone());
self.vote_state = TowerVoteState::from(vote_account.vote_state_view());
self.initialize_root(root);
self.initialize_lockouts(|v| v.slot() > root);
} else {
Expand Down Expand Up @@ -1795,7 +1794,7 @@ pub mod test {
},
solana_vote::vote_account::VoteAccount,
solana_vote_program::vote_state::{
Vote, VoteState, VoteStateVersions, MAX_LOCKOUT_HISTORY,
process_slot_vote_unchecked, Vote, VoteState, VoteStateVersions, MAX_LOCKOUT_HISTORY,
},
std::{
collections::{HashMap, VecDeque},
Expand Down Expand Up @@ -2446,8 +2445,8 @@ pub mod test {
.unwrap()
.get_vote_account(&vote_pubkey)
.unwrap();
let state = observed.vote_state();
info!("observed tower: {:#?}", state.votes);
let state = observed.vote_state_view();
info!("observed tower: {:#?}", state.votes_iter().collect_vec());

let num_slots_to_try = 200;
cluster_votes
Expand Down
10 changes: 10 additions & 0 deletions core/src/consensus/tower_vote_state.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use {
solana_sdk::clock::Slot,
solana_vote::vote_state_view::VoteStateView,
solana_vote_program::vote_state::{Lockout, VoteState, VoteState1_14_11, MAX_LOCKOUT_HISTORY},
std::collections::VecDeque,
};
Expand Down Expand Up @@ -105,6 +106,15 @@ impl From<VoteState1_14_11> for TowerVoteState {
}
}

impl From<&VoteStateView> for TowerVoteState {
fn from(vote_state: &VoteStateView) -> Self {
Self {
votes: vote_state.votes_iter().collect(),
root_slot: vote_state.root_slot(),
}
}
}

impl From<TowerVoteState> for VoteState1_14_11 {
fn from(vote_state: TowerVoteState) -> Self {
let TowerVoteState { votes, root_slot } = vote_state;
Expand Down
26 changes: 17 additions & 9 deletions core/src/replay_stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2559,17 +2559,18 @@ impl ReplayStage {
}
Some(vote_account) => vote_account,
};
let vote_state = vote_account.vote_state();
if vote_state.node_pubkey != node_keypair.pubkey() {
let vote_state_view = vote_account.vote_state_view();
if vote_state_view.node_pubkey() != &node_keypair.pubkey() {
info!(
"Vote account node_pubkey mismatch: {} (expected: {}). Unable to vote",
vote_state.node_pubkey,
vote_state_view.node_pubkey(),
node_keypair.pubkey()
);
return GenerateVoteTxResult::HotSpare;
}

let Some(authorized_voter_pubkey) = vote_state.get_authorized_voter(bank.epoch()) else {
let Some(authorized_voter_pubkey) = vote_state_view.get_authorized_voter(bank.epoch())
else {
warn!(
"Vote account {} has no authorized voter for epoch {}. Unable to vote",
vote_account_pubkey,
Expand All @@ -2580,7 +2581,7 @@ impl ReplayStage {

let authorized_voter_keypair = match authorized_voter_keypairs
.iter()
.find(|keypair| keypair.pubkey() == authorized_voter_pubkey)
.find(|keypair| &keypair.pubkey() == authorized_voter_pubkey)
{
None => {
warn!(
Expand Down Expand Up @@ -3624,7 +3625,7 @@ impl ReplayStage {
let Some(vote_account) = bank.get_vote_account(my_vote_pubkey) else {
return;
};
let mut bank_vote_state = vote_account.vote_state().clone();
let mut bank_vote_state = TowerVoteState::from(vote_account.vote_state_view());
if bank_vote_state.last_voted_slot() <= tower.vote_state.last_voted_slot() {
return;
}
Expand Down Expand Up @@ -3673,8 +3674,8 @@ impl ReplayStage {
}
}

tower.vote_state.root_slot = bank_vote_state.root_slot;
tower.vote_state.votes = bank_vote_state.votes.into_iter().map(Into::into).collect();
// adopt the bank vote state
tower.vote_state = bank_vote_state;

let last_voted_slot = tower.vote_state.last_voted_slot().unwrap_or(
// If our local root is higher than the highest slot in `bank_vote_state` due to
Expand Down Expand Up @@ -7917,7 +7918,14 @@ pub(crate) mod tests {
let vote_account = expired_bank_child
.get_vote_account(&my_vote_pubkey)
.unwrap();
assert_eq!(vote_account.vote_state().tower(), vec![0, 1]);
assert_eq!(
vote_account
.vote_state_view()
.votes_iter()
.map(|lockout| lockout.slot())
.collect_vec(),
vec![0, 1]
);
expired_bank_child.fill_bank_with_ticks_for_tests();
expired_bank_child.freeze();

Expand Down
22 changes: 9 additions & 13 deletions core/src/vote_simulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use {
heaviest_subtree_fork_choice::HeaviestSubtreeForkChoice,
latest_validator_votes_for_frozen_banks::LatestValidatorVotesForFrozenBanks,
progress_map::{ForkProgress, ProgressMap},
tower_vote_state::TowerVoteState,
Tower,
},
repair::cluster_slot_state_verifier::{
Expand All @@ -27,7 +28,7 @@ use {
},
solana_sdk::{clock::Slot, hash::Hash, pubkey::Pubkey, signature::Signer},
solana_vote_program::{
vote_state::{process_vote_unchecked, Lockout, TowerSync},
vote_state::{Lockout, TowerSync},
vote_transaction,
},
std::{
Expand Down Expand Up @@ -104,17 +105,10 @@ impl VoteSimulator {
let tower_sync = if let Some(vote_account) =
parent_bank.get_vote_account(&keypairs.vote_keypair.pubkey())
{
let mut vote_state = vote_account.vote_state().clone();
process_vote_unchecked(
&mut vote_state,
solana_vote_program::vote_state::Vote::new(
vec![parent],
parent_bank.hash(),
),
)
.unwrap();
let mut vote_state = TowerVoteState::from(vote_account.vote_state_view());
vote_state.process_next_vote_slot(parent);
TowerSync::new(
vote_state.votes.iter().map(|vote| vote.lockout).collect(),
vote_state.votes,
vote_state.root_slot,
parent_bank.hash(),
Hash::default(),
Expand Down Expand Up @@ -142,8 +136,10 @@ impl VoteSimulator {
let vote_account = new_bank
.get_vote_account(&keypairs.vote_keypair.pubkey())
.unwrap();
let state = vote_account.vote_state();
assert!(state.votes.iter().any(|lockout| lockout.slot() == parent));
let vote_state_view = vote_account.vote_state_view();
assert!(vote_state_view
.votes_iter()
.any(|lockout| lockout.slot() == parent));
}
}
while new_bank.tick_height() < new_bank.max_tick_height() {
Expand Down
1 change: 1 addition & 0 deletions ledger-tool/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ solana-transaction-status = { workspace = true }
solana-type-overrides = { workspace = true }
solana-unified-scheduler-pool = { workspace = true }
solana-version = { workspace = true }
solana-vote = { workspace = true }
solana-vote-program = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["full"] }
Expand Down
53 changes: 26 additions & 27 deletions ledger-tool/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ use {
solana_stake_program::stake_state,
solana_transaction_status::parse_ui_instruction,
solana_unified_scheduler_pool::DefaultSchedulerPool,
solana_vote::vote_state_view::VoteStateView,
solana_vote_program::{
self,
vote_state::{self, VoteState},
Expand Down Expand Up @@ -218,16 +219,16 @@ fn graph_forks(bank_forks: &BankForks, config: &GraphConfig) -> String {
.map(|(_, (stake, _))| stake)
.sum();
for (stake, vote_account) in bank.vote_accounts().values() {
let vote_state = vote_account.vote_state();
if let Some(last_vote) = vote_state.votes.iter().last() {
let entry = last_votes.entry(vote_state.node_pubkey).or_insert((
last_vote.slot(),
vote_state.clone(),
let vote_state_view = vote_account.vote_state_view();
if let Some(last_vote) = vote_state_view.last_voted_slot() {
let entry = last_votes.entry(*vote_state_view.node_pubkey()).or_insert((
last_vote,
vote_state_view.clone(),
*stake,
total_stake,
));
if entry.0 < last_vote.slot() {
*entry = (last_vote.slot(), vote_state.clone(), *stake, total_stake);
if entry.0 < last_vote {
*entry = (last_vote, vote_state_view.clone(), *stake, total_stake);
}
}
}
Expand All @@ -251,19 +252,20 @@ fn graph_forks(bank_forks: &BankForks, config: &GraphConfig) -> String {
dot.push(" subgraph cluster_banks {".to_string());
dot.push(" style=invis".to_string());
let mut styled_slots = HashSet::new();
let mut all_votes: HashMap<Pubkey, HashMap<Slot, VoteState>> = HashMap::new();
let mut all_votes: HashMap<Pubkey, HashMap<Slot, VoteStateView>> = HashMap::new();
for fork_slot in &fork_slots {
let mut bank = bank_forks[*fork_slot].clone();

let mut first = true;
loop {
for (_, vote_account) in bank.vote_accounts().values() {
let vote_state = vote_account.vote_state();
if let Some(last_vote) = vote_state.votes.iter().last() {
let validator_votes = all_votes.entry(vote_state.node_pubkey).or_default();
let vote_state_view = vote_account.vote_state_view();
if let Some(last_vote) = vote_state_view.last_voted_slot() {
let validator_votes =
all_votes.entry(*vote_state_view.node_pubkey()).or_default();
validator_votes
.entry(last_vote.slot())
.or_insert_with(|| vote_state.clone());
.entry(last_vote)
.or_insert_with(|| vote_state_view.clone());
}
}

Expand Down Expand Up @@ -341,7 +343,7 @@ fn graph_forks(bank_forks: &BankForks, config: &GraphConfig) -> String {
let mut absent_votes = 0;
let mut lowest_last_vote_slot = u64::MAX;
let mut lowest_total_stake = 0;
for (node_pubkey, (last_vote_slot, vote_state, stake, total_stake)) in &last_votes {
for (node_pubkey, (last_vote_slot, vote_state_view, stake, total_stake)) in &last_votes {
all_votes.entry(*node_pubkey).and_modify(|validator_votes| {
validator_votes.remove(last_vote_slot);
});
Expand All @@ -361,9 +363,8 @@ fn graph_forks(bank_forks: &BankForks, config: &GraphConfig) -> String {
if matches!(config.vote_account_mode, GraphVoteAccountMode::WithHistory) {
format!(
"vote history:\n{}",
vote_state
.votes
.iter()
vote_state_view
.votes_iter()
.map(|vote| format!(
"slot {} (conf={})",
vote.slot(),
Expand All @@ -375,10 +376,9 @@ fn graph_forks(bank_forks: &BankForks, config: &GraphConfig) -> String {
} else {
format!(
"last vote slot: {}",
vote_state
.votes
.back()
.map(|vote| vote.slot().to_string())
vote_state_view
.last_voted_slot()
.map(|vote_slot| vote_slot.to_string())
.unwrap_or_else(|| "none".to_string())
)
};
Expand All @@ -387,7 +387,7 @@ fn graph_forks(bank_forks: &BankForks, config: &GraphConfig) -> String {
node_pubkey,
node_pubkey,
lamports_to_sol(*stake),
vote_state.root_slot.unwrap_or(0),
vote_state_view.root_slot().unwrap_or(0),
vote_history,
));

Expand Down Expand Up @@ -416,16 +416,15 @@ fn graph_forks(bank_forks: &BankForks, config: &GraphConfig) -> String {
// Add for vote information from all banks.
if config.include_all_votes {
for (node_pubkey, validator_votes) in &all_votes {
for (vote_slot, vote_state) in validator_votes {
for (vote_slot, vote_state_view) in validator_votes {
dot.push(format!(
r#" "{} vote {}"[shape=box,style=dotted,label="validator vote: {}\nroot slot: {}\nvote history:\n{}"];"#,
node_pubkey,
vote_slot,
node_pubkey,
vote_state.root_slot.unwrap_or(0),
vote_state
.votes
.iter()
vote_state_view.root_slot().unwrap_or(0),
vote_state_view
.votes_iter()
.map(|vote| format!("slot {} (conf={})", vote.slot(), vote.confirmation_count()))
.collect::<Vec<_>>()
.join("\n")
Expand Down
2 changes: 1 addition & 1 deletion ledger/src/blockstore_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2170,7 +2170,7 @@ fn supermajority_root_from_vote_accounts(
return None;
}

Some((account.vote_state().root_slot?, *stake))
Some((account.vote_state_view().root_slot()?, *stake))
})
.collect();

Expand Down
1 change: 1 addition & 0 deletions programs/sbf/Cargo.lock

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

Loading

0 comments on commit 77728d5

Please sign in to comment.