Skip to content

Commit

Permalink
Implement timely vote credits feature. (solana-labs#32957)
Browse files Browse the repository at this point in the history
  • Loading branch information
bji authored and jeffwashington committed Sep 13, 2023
1 parent acd7ad9 commit 1a6d7c7
Show file tree
Hide file tree
Showing 8 changed files with 713 additions and 113 deletions.
25 changes: 9 additions & 16 deletions accounts-db/src/accounts_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1597,38 +1597,31 @@ impl<T: IndexValue, U: DiskIndexValue + From<T> + Into<T>> AccountsIndex<T, U> {
// this assumes the largest bin contains twice the expected amount of the average size per bin
let bins = self.bins();
let expected_items_per_bin = item_len * 2 / bins;
// offset bin 0 in the 'binned' array by a random amount.
// This results in calls to insert_new_entry_if_missing_with_lock from different threads starting at different bins.
let random_offset = thread_rng().gen_range(0..bins);
let use_disk = self.storage.storage.disk.is_some();
let mut binned = (0..bins)
.map(|mut pubkey_bin| {
// opposite of (pubkey_bin + random_offset) % bins
pubkey_bin = if pubkey_bin < random_offset {
pubkey_bin + bins - random_offset
} else {
pubkey_bin - random_offset
};
(pubkey_bin, Vec::with_capacity(expected_items_per_bin))
})
.map(|_| Vec::with_capacity(expected_items_per_bin))
.collect::<Vec<_>>();
let mut dirty_pubkeys = items
.filter_map(|(pubkey, account_info)| {
let pubkey_bin = self.bin_calculator.bin_from_pubkey(&pubkey);
let binned_index = (pubkey_bin + random_offset) % bins;
// this value is equivalent to what update() below would have created if we inserted a new item
let is_zero_lamport = account_info.is_zero_lamport();
let result = if is_zero_lamport { Some(pubkey) } else { None };

binned[binned_index].1.push((pubkey, (slot, account_info)));
binned[pubkey_bin].push((pubkey, (slot, account_info)));
result
})
.collect::<Vec<_>>();
binned.retain(|x| !x.1.is_empty());

let insertion_time = AtomicU64::new(0);

binned.into_iter().for_each(|(pubkey_bin, items)| {
let random_offset = thread_rng().gen_range(0..bins);
(0..bins).for_each(|pubkey_bin| {
let pubkey_bin = (pubkey_bin + random_offset) % bins;
let items = std::mem::take(&mut binned[pubkey_bin]);
if items.is_empty() {
return;
}
let r_account_maps = &self.account_maps[pubkey_bin];
let mut insert_time = Measure::start("insert_into_primary_index");
if use_disk {
Expand Down
36 changes: 16 additions & 20 deletions cli-output/src/cli_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@ use {
},
solana_vote_program::{
authorized_voters::AuthorizedVoters,
vote_state::{
BlockTimestamp, LandedVote, Lockout, MAX_EPOCH_CREDITS_HISTORY, MAX_LOCKOUT_HISTORY,
},
vote_state::{BlockTimestamp, LandedVote, MAX_EPOCH_CREDITS_HISTORY, MAX_LOCKOUT_HISTORY},
},
std::{
collections::{BTreeMap, HashMap},
Expand Down Expand Up @@ -1047,7 +1045,7 @@ impl fmt::Display for CliKeyedEpochRewards {

fn show_votes_and_credits(
f: &mut fmt::Formatter,
votes: &[CliLockout],
votes: &[CliLandedVote],
epoch_voting_history: &[CliEpochVotingHistory],
) -> fmt::Result {
if votes.is_empty() {
Expand All @@ -1070,11 +1068,16 @@ fn show_votes_and_credits(
)?;

for vote in votes.iter().rev() {
writeln!(
write!(
f,
"- slot: {} (confirmation count: {})",
vote.slot, vote.confirmation_count
)?;
if vote.latency == 0 {
writeln!(f)?;
} else {
writeln!(f, " (latency {})", vote.latency)?;
}
}
if let Some(newest) = newest_history_entry {
writeln!(
Expand Down Expand Up @@ -1555,7 +1558,7 @@ pub struct CliVoteAccount {
pub commission: u8,
pub root_slot: Option<Slot>,
pub recent_timestamp: BlockTimestamp,
pub votes: Vec<CliLockout>,
pub votes: Vec<CliLandedVote>,
pub epoch_voting_history: Vec<CliEpochVotingHistory>,
#[serde(skip_serializing)]
pub use_lamports_unit: bool,
Expand Down Expand Up @@ -1637,25 +1640,18 @@ pub struct CliEpochVotingHistory {

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliLockout {
pub struct CliLandedVote {
pub latency: u8,
pub slot: Slot,
pub confirmation_count: u32,
}

impl From<&Lockout> for CliLockout {
fn from(lockout: &Lockout) -> Self {
Self {
slot: lockout.slot(),
confirmation_count: lockout.confirmation_count(),
}
}
}

impl From<&LandedVote> for CliLockout {
fn from(vote: &LandedVote) -> Self {
impl From<&LandedVote> for CliLandedVote {
fn from(landed_vote: &LandedVote) -> Self {
Self {
slot: vote.slot(),
confirmation_count: vote.confirmation_count(),
latency: landed_vote.latency,
slot: landed_vote.slot(),
confirmation_count: landed_vote.confirmation_count(),
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions cli/src/vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use {
offline::*,
},
solana_cli_output::{
return_signers_with_config, CliEpochVotingHistory, CliLockout, CliVoteAccount,
return_signers_with_config, CliEpochVotingHistory, CliLandedVote, CliVoteAccount,
ReturnSignersConfig,
},
solana_remote_wallet::remote_wallet::RemoteWalletManager,
Expand Down Expand Up @@ -1215,7 +1215,7 @@ pub fn process_show_vote_account(

let epoch_schedule = rpc_client.get_epoch_schedule()?;

let mut votes: Vec<CliLockout> = vec![];
let mut votes: Vec<CliLandedVote> = vec![];
let mut epoch_voting_history: Vec<CliEpochVotingHistory> = vec![];
if !vote_state.votes.is_empty() {
for vote in &vote_state.votes {
Expand Down
2 changes: 1 addition & 1 deletion programs/vote/benches/process_vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ fn create_accounts() -> (Slot, SlotHashes, Vec<TransactionAccount>, Vec<AccountM
);

for next_vote_slot in 0..num_initial_votes {
vote_state.process_next_vote_slot(next_vote_slot, 0);
vote_state.process_next_vote_slot(next_vote_slot, 0, 0);
}
let mut vote_account_data: Vec<u8> = vec![0; VoteState::size_of()];
let versioned = VoteStateVersions::new_current(vote_state);
Expand Down
Loading

0 comments on commit 1a6d7c7

Please sign in to comment.