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

perf: vote state view #4834

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
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
26 changes: 26 additions & 0 deletions Cargo.lock

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

5 changes: 5 additions & 0 deletions ci/test-miri.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ source ci/rust-version.sh nightly
# miri is very slow; so only run very few of selective tests!
_ cargo "+${rust_nightly}" miri test -p solana-unified-scheduler-logic

# test big endian branch
_ cargo "+${rust_nightly}" miri test --target s390x-unknown-linux-gnu -p solana-vote -- "vote_state_view" --skip "arbitrary"
# test little endian branch for UB
_ cargo "+${rust_nightly}" miri test -p solana-vote -- "vote_state_view" --skip "arbitrary"

# run intentionally-#[ignored] ub triggering tests for each to make sure they fail
(! _ cargo "+${rust_nightly}" miri test -p solana-unified-scheduler-logic -- \
--ignored --exact "utils::tests::test_ub_illegally_created_multiple_tokens")
Expand Down
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 @@ -537,7 +537,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
11 changes: 5 additions & 6 deletions core/src/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ impl Tower {
continue;
}
trace!("{} {} with stake {}", vote_account_pubkey, key, voted_stake);
let mut vote_state = TowerVoteState::from(account.vote_state().clone());
let mut vote_state = TowerVoteState::from(account.vote_state_view());
for vote in &vote_state.votes {
lockout_intervals
.entry(vote.last_locked_out_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 @@ -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
22 changes: 15 additions & 7 deletions core/src/replay_stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2512,17 +2512,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 @@ -2533,7 +2534,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 @@ -3577,7 +3578,7 @@ impl ReplayStage {
let Some(vote_account) = bank.get_vote_account(my_vote_pubkey) else {
return;
};
let mut bank_vote_state = TowerVoteState::from(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 @@ -7957,7 +7958,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
9 changes: 5 additions & 4 deletions core/src/vote_simulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,7 @@ impl VoteSimulator {
let tower_sync = if let Some(vote_account) =
parent_bank.get_vote_account(&keypairs.vote_keypair.pubkey())
{
let mut vote_state =
TowerVoteState::from(vote_account.vote_state().clone());
let mut vote_state = TowerVoteState::from(vote_account.vote_state_view());
vote_state.process_next_vote_slot(parent);
TowerSync::new(
vote_state.votes,
Expand Down Expand Up @@ -135,8 +134,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 @@ -57,6 +57,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 @@ -83,6 +83,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 @@ -221,16 +222,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 @@ -254,19 +255,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 @@ -344,7 +346,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 @@ -364,9 +366,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 @@ -378,10 +379,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 @@ -390,7 +390,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 @@ -419,16 +419,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 @@ -2176,7 +2176,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
Loading
Loading