diff --git a/account-decoder/src/parse_vote.rs b/account-decoder/src/parse_vote.rs index d8388c620a..7f7831f2f3 100644 --- a/account-decoder/src/parse_vote.rs +++ b/account-decoder/src/parse_vote.rs @@ -22,8 +22,8 @@ pub fn parse_vote(data: &[u8]) -> Result { .votes .iter() .map(|lockout| UiLockout { - slot: lockout.slot, - confirmation_count: lockout.confirmation_count, + slot: lockout.slot(), + confirmation_count: lockout.confirmation_count(), }) .collect(); let authorized_voters = vote_state @@ -92,8 +92,8 @@ struct UiLockout { impl From<&Lockout> for UiLockout { fn from(lockout: &Lockout) -> Self { Self { - slot: lockout.slot, - confirmation_count: lockout.confirmation_count, + slot: lockout.slot(), + confirmation_count: lockout.confirmation_count(), } } } diff --git a/cli-output/src/cli_output.rs b/cli-output/src/cli_output.rs index 1baa9c4cc4..d8ffec9249 100644 --- a/cli-output/src/cli_output.rs +++ b/cli-output/src/cli_output.rs @@ -1536,8 +1536,8 @@ pub struct CliLockout { impl From<&Lockout> for CliLockout { fn from(lockout: &Lockout) -> Self { Self { - slot: lockout.slot, - confirmation_count: lockout.confirmation_count, + slot: lockout.slot(), + confirmation_count: lockout.confirmation_count(), } } } diff --git a/core/src/commitment_service.rs b/core/src/commitment_service.rs index 92bab89107..3cd3b2695b 100644 --- a/core/src/commitment_service.rs +++ b/core/src/commitment_service.rs @@ -227,11 +227,11 @@ impl AggregateCommitmentService { } for vote in &vote_state.votes { - while ancestors[ancestors_index] <= vote.slot { + while ancestors[ancestors_index] <= vote.slot() { commitment .entry(ancestors[ancestors_index]) .or_insert_with(BlockCommitment::default) - .increase_confirmation_stake(vote.confirmation_count as usize, lamports); + .increase_confirmation_stake(vote.confirmation_count() as usize, lamports); ancestors_index += 1; if ancestors_index == ancestors.len() { diff --git a/core/src/consensus.rs b/core/src/consensus.rs index 3758d6de92..afbd9814c3 100644 --- a/core/src/consensus.rs +++ b/core/src/consensus.rs @@ -304,22 +304,22 @@ impl Tower { lockout_intervals .entry(vote.last_locked_out_slot()) .or_insert_with(Vec::new) - .push((vote.slot, key)); + .push((vote.slot(), key)); } if key == *vote_account_pubkey { - my_latest_landed_vote = vote_state.nth_recent_vote(0).map(|v| v.slot); + my_latest_landed_vote = vote_state.nth_recent_vote(0).map(|v| v.slot()); debug!("vote state {:?}", vote_state); debug!( "observed slot {}", - vote_state.nth_recent_vote(0).map(|v| v.slot).unwrap_or(0) as i64 + vote_state.nth_recent_vote(0).map(|v| v.slot()).unwrap_or(0) as i64 ); debug!("observed root {}", vote_state.root_slot.unwrap_or(0) as i64); datapoint_info!( "tower-observed", ( "slot", - vote_state.nth_recent_vote(0).map(|v| v.slot).unwrap_or(0), + vote_state.nth_recent_vote(0).map(|v| v.slot()).unwrap_or(0), i64 ), ("root", vote_state.root_slot.unwrap_or(0), i64) @@ -341,27 +341,22 @@ impl Tower { for vote in &vote_state.votes { bank_weight += vote.lockout() as u128 * voted_stake as u128; - vote_slots.insert(vote.slot); + vote_slots.insert(vote.slot()); } if start_root != vote_state.root_slot { if let Some(root) = start_root { - let vote = Lockout { - confirmation_count: MAX_LOCKOUT_HISTORY as u32, - slot: root, - }; - trace!("ROOT: {}", vote.slot); + let vote = + Lockout::new_with_confirmation_count(root, MAX_LOCKOUT_HISTORY as u32); + trace!("ROOT: {}", vote.slot()); bank_weight += vote.lockout() as u128 * voted_stake as u128; - vote_slots.insert(vote.slot); + vote_slots.insert(vote.slot()); } } if let Some(root) = vote_state.root_slot { - let vote = Lockout { - confirmation_count: MAX_LOCKOUT_HISTORY as u32, - slot: root, - }; + let vote = Lockout::new_with_confirmation_count(root, MAX_LOCKOUT_HISTORY as u32); bank_weight += vote.lockout() as u128 * voted_stake as u128; - vote_slots.insert(vote.slot); + vote_slots.insert(vote.slot()); } // The last vote in the vote stack is a simulated vote on bank_slot, which @@ -374,14 +369,14 @@ impl Tower { // this vote stack is the simulated vote, so this fetch should be sufficient // to find the last unsimulated vote. assert_eq!( - vote_state.nth_recent_vote(0).map(|l| l.slot), + vote_state.nth_recent_vote(0).map(|l| l.slot()), Some(bank_slot) ); if let Some(vote) = vote_state.nth_recent_vote(1) { // Update all the parents of this last vote with the stake of this vote account Self::update_ancestor_voted_stakes( &mut voted_stakes, - vote.slot, + vote.slot(), voted_stake, ancestors, ); @@ -443,11 +438,11 @@ impl Tower { local_vote_state .votes .iter() - .map(|v| v.slot) + .map(|v| v.slot()) .skip_while(|s| *s <= last_voted_slot) .collect() } else { - local_vote_state.votes.iter().map(|v| v.slot).collect() + local_vote_state.votes.iter().map(|v| v.slot()).collect() }; VoteTransaction::from(Vote::new(slots, hash)) } @@ -523,7 +518,7 @@ impl Tower { /// Used for tests pub fn increase_lockout(&mut self, confirmation_count_increase: u32) { for vote in self.vote_state.votes.iter_mut() { - vote.confirmation_count += confirmation_count_increase; + vote.increase_confirmation_count(confirmation_count_increase); } } @@ -591,7 +586,7 @@ impl Tower { pub fn has_voted(&self, slot: Slot) -> bool { for vote in &self.vote_state.votes { - if slot == vote.slot { + if slot == vote.slot() { return true; } } @@ -610,7 +605,7 @@ impl Tower { let mut vote_state = self.vote_state.clone(); process_slot_vote_unchecked(&mut vote_state, slot); for vote in &vote_state.votes { - if slot != vote.slot && !ancestors.contains(&vote.slot) { + if slot != vote.slot() && !ancestors.contains(&vote.slot()) { return true; } } @@ -993,16 +988,16 @@ impl Tower { process_slot_vote_unchecked(&mut vote_state, slot); let vote = vote_state.nth_recent_vote(self.threshold_depth); if let Some(vote) = vote { - if let Some(fork_stake) = voted_stakes.get(&vote.slot) { + if let Some(fork_stake) = voted_stakes.get(&vote.slot()) { let lockout = *fork_stake as f64 / total_stake as f64; trace!( "fork_stake slot: {}, vote slot: {}, lockout: {} fork_stake: {} total_stake: {}", - slot, vote.slot, lockout, fork_stake, total_stake + slot, vote.slot(), lockout, fork_stake, total_stake ); - if vote.confirmation_count as usize > self.threshold_depth { + if vote.confirmation_count() as usize > self.threshold_depth { for old_vote in &self.vote_state.votes { - if old_vote.slot == vote.slot - && old_vote.confirmation_count == vote.confirmation_count + if old_vote.slot() == vote.slot() + && old_vote.confirmation_count() == vote.confirmation_count() { return true; } @@ -1058,7 +1053,7 @@ impl Tower { self.vote_state .votes .iter() - .map(|lockout| lockout.slot) + .map(|lockout| lockout.slot()) .collect() } @@ -1270,7 +1265,7 @@ impl Tower { .expect("vote_account isn't a VoteState?") .clone(); self.initialize_root(root); - self.initialize_lockouts(|v| v.slot > root); + self.initialize_lockouts(|v| v.slot() > root); trace!( "Lockouts in tower for {} is initialized using bank {}", self.vote_state.node_pubkey, @@ -1554,9 +1549,9 @@ pub mod test { } for i in 1..5 { - assert_eq!(tower.vote_state.votes[i - 1].slot as usize, i); + assert_eq!(tower.vote_state.votes[i - 1].slot() as usize, i); assert_eq!( - tower.vote_state.votes[i - 1].confirmation_count as usize, + tower.vote_state.votes[i - 1].confirmation_count() as usize, 6 - i ); } @@ -2166,10 +2161,7 @@ pub mod test { tower.record_vote(i as u64, Hash::default()); ancestors.insert(i as u64, (0..i as u64).collect()); } - let root = Lockout { - confirmation_count: MAX_LOCKOUT_HISTORY as u32, - slot: 0, - }; + let root = Lockout::new_with_confirmation_count(0, MAX_LOCKOUT_HISTORY as u32); let root_weight = root.lockout() as u128; let vote_account_expected_weight = tower .vote_state @@ -2200,7 +2192,8 @@ pub mod test { // should be the sum of all the weights for root assert_eq!(bank_weight, expected_bank_weight); - let mut new_votes = latest_validator_votes_for_frozen_banks.take_votes_dirty_set(root.slot); + let mut new_votes = + latest_validator_votes_for_frozen_banks.take_votes_dirty_set(root.slot()); new_votes.sort(); assert_eq!(new_votes, account_latest_votes); } @@ -2325,10 +2318,10 @@ pub mod test { tower.record_vote(1, Hash::default()); assert!(!tower.is_locked_out(4, &ancestors)); tower.record_vote(4, Hash::default()); - assert_eq!(tower.vote_state.votes[0].slot, 0); - assert_eq!(tower.vote_state.votes[0].confirmation_count, 2); - assert_eq!(tower.vote_state.votes[1].slot, 4); - assert_eq!(tower.vote_state.votes[1].confirmation_count, 1); + assert_eq!(tower.vote_state.votes[0].slot(), 0); + assert_eq!(tower.vote_state.votes[0].confirmation_count(), 2); + assert_eq!(tower.vote_state.votes[1].slot(), 4); + assert_eq!(tower.vote_state.votes[1].confirmation_count(), 1); } #[test] @@ -2515,9 +2508,8 @@ pub mod test { let mut tower = Tower::new_for_tests(1, 0.67); let slots = if num_votes > 0 { { 0..num_votes } - .map(|i| Lockout { - slot: i as u64, - confirmation_count: (num_votes as u32) - (i as u32), + .map(|i| { + Lockout::new_with_confirmation_count(i as Slot, (num_votes as u32) - (i as u32)) }) .collect() } else { diff --git a/core/src/replay_stage.rs b/core/src/replay_stage.rs index efa9470039..4dfed9144d 100644 --- a/core/src/replay_stage.rs +++ b/core/src/replay_stage.rs @@ -2840,7 +2840,7 @@ impl ReplayStage { bank_vote_state.root_slot = Some(local_root); bank_vote_state .votes - .retain(|lockout| lockout.slot > local_root); + .retain(|lockout| lockout.slot() > local_root); info!( "Local root is larger than on chain root, overwrote bank root {:?} and updated votes {:?}", @@ -2849,7 +2849,7 @@ impl ReplayStage { if let Some(first_vote) = bank_vote_state.votes.front() { assert!(ancestors - .get(&first_vote.slot) + .get(&first_vote.slot()) .expect( "Ancestors map must contain an entry for all slots on this fork diff --git a/core/src/verified_vote_packets.rs b/core/src/verified_vote_packets.rs index 95f7feba8a..a06a255290 100644 --- a/core/src/verified_vote_packets.rs +++ b/core/src/verified_vote_packets.rs @@ -713,9 +713,8 @@ mod tests { // Now send some new votes for i in 101..201 { let slots = std::iter::zip((i - 30)..(i + 1), (1..32).rev()) - .map(|(slot, confirmation_count)| Lockout { - slot, - confirmation_count, + .map(|(slot, confirmation_count)| { + Lockout::new_with_confirmation_count(slot, confirmation_count) }) .collect::>(); let vote = VoteTransaction::from(VoteStateUpdate::new( diff --git a/core/src/vote_simulator.rs b/core/src/vote_simulator.rs index 6fb3c9bf7a..e87bd2dab8 100644 --- a/core/src/vote_simulator.rs +++ b/core/src/vote_simulator.rs @@ -111,7 +111,7 @@ impl VoteSimulator { .unwrap() .votes .iter() - .any(|lockout| lockout.slot == parent)); + .any(|lockout| lockout.slot() == parent)); } } while new_bank.tick_height() < new_bank.max_tick_height() { diff --git a/ledger-tool/src/main.rs b/ledger-tool/src/main.rs index 0bf6a89238..84e469f843 100644 --- a/ledger-tool/src/main.rs +++ b/ledger-tool/src/main.rs @@ -516,13 +516,13 @@ fn graph_forks(bank_forks: &BankForks, config: &GraphConfig) -> String { let vote_state = vote_state.as_ref().unwrap_or(&default_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, + last_vote.slot(), vote_state.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.slot() { + *entry = (last_vote.slot(), vote_state.clone(), *stake, total_stake); } } } @@ -558,7 +558,7 @@ fn graph_forks(bank_forks: &BankForks, config: &GraphConfig) -> String { if let Some(last_vote) = vote_state.votes.iter().last() { let validator_votes = all_votes.entry(vote_state.node_pubkey).or_default(); validator_votes - .entry(last_vote.slot) + .entry(last_vote.slot()) .or_insert_with(|| vote_state.clone()); } } @@ -662,7 +662,8 @@ fn graph_forks(bank_forks: &BankForks, config: &GraphConfig) -> String { .iter() .map(|vote| format!( "slot {} (conf={})", - vote.slot, vote.confirmation_count + vote.slot(), + vote.confirmation_count() )) .collect::>() .join("\n") @@ -673,7 +674,7 @@ fn graph_forks(bank_forks: &BankForks, config: &GraphConfig) -> String { vote_state .votes .back() - .map(|vote| vote.slot.to_string()) + .map(|vote| vote.slot().to_string()) .unwrap_or_else(|| "none".to_string()) ) }; @@ -721,7 +722,7 @@ fn graph_forks(bank_forks: &BankForks, config: &GraphConfig) -> String { vote_state .votes .iter() - .map(|vote| format!("slot {} (conf={})", vote.slot, vote.confirmation_count)) + .map(|vote| format!("slot {} (conf={})", vote.slot(), vote.confirmation_count())) .collect::>() .join("\n") )); diff --git a/programs/vote/src/vote_state/mod.rs b/programs/vote/src/vote_state/mod.rs index b695d67382..1551781af2 100644 --- a/programs/vote/src/vote_state/mod.rs +++ b/programs/vote/src/vote_state/mod.rs @@ -51,7 +51,7 @@ impl VoteTransaction { VoteTransaction::Vote(vote) => vote.slots[i], VoteTransaction::VoteStateUpdate(vote_state_update) | VoteTransaction::CompactVoteStateUpdate(vote_state_update) => { - vote_state_update.lockouts[i].slot + vote_state_update.lockouts[i].slot() } } } @@ -152,8 +152,8 @@ fn check_update_vote_state_slots_are_valid( } // If the vote state update is not new enough, return - if let Some(last_vote_slot) = vote_state.votes.back().map(|lockout| lockout.slot) { - if vote_state_update.lockouts.back().unwrap().slot <= last_vote_slot { + if let Some(last_vote_slot) = vote_state.votes.back().map(|lockout| lockout.slot()) { + if vote_state_update.lockouts.back().unwrap().slot() <= last_vote_slot { return Err(VoteError::VoteTooOld); } } @@ -162,7 +162,7 @@ fn check_update_vote_state_slots_are_valid( .lockouts .back() .expect("must be nonempty, checked above") - .slot; + .slot(); if slot_hashes.is_empty() { return Err(VoteError::SlotsMismatch); @@ -193,16 +193,16 @@ fn check_update_vote_state_slots_are_valid( let current_root = vote_state_update.root; for lockout in vote_state.votes.iter().rev() { let is_slot_bigger_than_root = current_root - .map(|current_root| lockout.slot > current_root) + .map(|current_root| lockout.slot() > current_root) .unwrap_or(true); // Ensure we're iterating from biggest to smallest vote in the // current vote state - assert!(lockout.slot < prev_slot && is_slot_bigger_than_root); - if lockout.slot <= new_proposed_root { - vote_state_update.root = Some(lockout.slot); + assert!(lockout.slot() < prev_slot && is_slot_bigger_than_root); + if lockout.slot() <= new_proposed_root { + vote_state_update.root = Some(lockout.slot()); break; } - prev_slot = lockout.slot; + prev_slot = lockout.slot(); } } } @@ -236,11 +236,11 @@ fn check_update_vote_state_slots_are_valid( let proposed_vote_slot = if let Some(root) = root_to_check { root } else { - vote_state_update.lockouts[vote_state_update_index].slot + vote_state_update.lockouts[vote_state_update_index].slot() }; if root_to_check.is_none() && vote_state_update_index > 0 - && proposed_vote_slot <= vote_state_update.lockouts[vote_state_update_index - 1].slot + && proposed_vote_slot <= vote_state_update.lockouts[vote_state_update_index - 1].slot() { return Err(VoteError::SlotsNotOrdered); } @@ -530,12 +530,12 @@ pub fn process_new_vote_state( // 2) The confirmations are strictly decreasing // 3) Not zero confirmation votes for vote in &new_state { - if vote.confirmation_count == 0 { + if vote.confirmation_count() == 0 { return Err(VoteError::ZeroConfirmations); - } else if vote.confirmation_count > MAX_LOCKOUT_HISTORY as u32 { + } else if vote.confirmation_count() > MAX_LOCKOUT_HISTORY as u32 { return Err(VoteError::ConfirmationTooLarge); } else if let Some(new_root) = new_root { - if vote.slot <= new_root + if vote.slot() <= new_root && // This check is necessary because // https://github.com/ryoqun/solana/blob/df55bfb46af039cbc597cd60042d49b9d90b5961/core/src/consensus.rs#L120 @@ -548,11 +548,11 @@ pub fn process_new_vote_state( } if let Some(previous_vote) = previous_vote { - if previous_vote.slot >= vote.slot { + if previous_vote.slot() >= vote.slot() { return Err(VoteError::SlotsNotOrdered); - } else if previous_vote.confirmation_count <= vote.confirmation_count { + } else if previous_vote.confirmation_count() <= vote.confirmation_count() { return Err(VoteError::ConfirmationsNotOrdered); - } else if vote.slot > previous_vote.last_locked_out_slot() { + } else if vote.slot() > previous_vote.last_locked_out_slot() { return Err(VoteError::NewVoteStateLockoutMismatch); } } @@ -576,9 +576,9 @@ pub fn process_new_vote_state( for current_vote in &vote_state.votes { // Find the first vote in the current vote state for a slot greater // than the new proposed root - if current_vote.slot <= new_root { + if current_vote.slot() <= new_root { current_vote_state_index += 1; - if current_vote.slot != new_root { + if current_vote.slot() != new_root { finalized_slot_count += 1; } continue; @@ -599,9 +599,9 @@ pub fn process_new_vote_state( // If the current slot is less than the new proposed slot, then the // new slot must have popped off the old slot, so check that the // lockouts are corrects. - match current_vote.slot.cmp(&new_vote.slot) { + match current_vote.slot().cmp(&new_vote.slot()) { Ordering::Less => { - if current_vote.last_locked_out_slot() >= new_vote.slot { + if current_vote.last_locked_out_slot() >= new_vote.slot() { return Err(VoteError::LockoutConflict); } current_vote_state_index += 1; @@ -609,7 +609,7 @@ pub fn process_new_vote_state( Ordering::Equal => { // The new vote state should never have less lockout than // the previous vote state for the same slot - if new_vote.confirmation_count < current_vote.confirmation_count { + if new_vote.confirmation_count() < current_vote.confirmation_count() { return Err(VoteError::ConfirmationRollBack); } @@ -640,7 +640,7 @@ pub fn process_new_vote_state( } } if let Some(timestamp) = timestamp { - let last_slot = new_state.back().unwrap().slot; + let last_slot = new_state.back().unwrap().slot(); vote_state.process_timestamp(last_slot, timestamp)?; } vote_state.root_slot = new_root; @@ -1095,7 +1095,7 @@ mod tests { // One more vote that confirms the entire stack, // the root_slot should change to the // second vote - let top_vote = vote_state.votes.front().unwrap().slot; + let top_vote = vote_state.votes.front().unwrap().slot(); let slot = vote_state.last_lockout().unwrap().last_locked_out_slot(); process_slot_vote_unchecked(&mut vote_state, slot); assert_eq!(Some(top_vote), vote_state.root_slot); @@ -1144,26 +1144,26 @@ mod tests { process_slot_vote_unchecked(&mut vote_state, i as u64); } - assert_eq!(vote_state.votes[0].confirmation_count, 3); + assert_eq!(vote_state.votes[0].confirmation_count(), 3); // Expire the second and third votes - let expire_slot = vote_state.votes[1].slot + vote_state.votes[1].lockout() + 1; + let expire_slot = vote_state.votes[1].slot() + vote_state.votes[1].lockout() + 1; process_slot_vote_unchecked(&mut vote_state, expire_slot); assert_eq!(vote_state.votes.len(), 2); // Check that the old votes expired - assert_eq!(vote_state.votes[0].slot, 0); - assert_eq!(vote_state.votes[1].slot, expire_slot); + assert_eq!(vote_state.votes[0].slot(), 0); + assert_eq!(vote_state.votes[1].slot(), expire_slot); // Process one more vote process_slot_vote_unchecked(&mut vote_state, expire_slot + 1); // Confirmation count for the older first vote should remain unchanged - assert_eq!(vote_state.votes[0].confirmation_count, 3); + assert_eq!(vote_state.votes[0].confirmation_count(), 3); // The later votes should still have increasing confirmation counts - assert_eq!(vote_state.votes[1].confirmation_count, 2); - assert_eq!(vote_state.votes[2].confirmation_count, 1); + assert_eq!(vote_state.votes[1].confirmation_count(), 2); + assert_eq!(vote_state.votes[2].confirmation_count(), 1); } #[test] @@ -1192,8 +1192,8 @@ mod tests { process_slot_vote_unchecked(&mut vote_state, 0); process_slot_vote_unchecked(&mut vote_state, 1); process_slot_vote_unchecked(&mut vote_state, 0); - assert_eq!(vote_state.nth_recent_vote(0).unwrap().slot, 1); - assert_eq!(vote_state.nth_recent_vote(1).unwrap().slot, 0); + assert_eq!(vote_state.nth_recent_vote(0).unwrap().slot(), 1); + assert_eq!(vote_state.nth_recent_vote(1).unwrap().slot(), 0); assert!(vote_state.nth_recent_vote(2).is_none()); } @@ -1206,7 +1206,7 @@ mod tests { } for i in 0..(MAX_LOCKOUT_HISTORY - 1) { assert_eq!( - vote_state.nth_recent_vote(i).unwrap().slot as usize, + vote_state.nth_recent_vote(i).unwrap().slot() as usize, MAX_LOCKOUT_HISTORY - i - 1, ); } @@ -1223,7 +1223,12 @@ mod tests { fn recent_votes(vote_state: &VoteState) -> Vec { let start = vote_state.votes.len().saturating_sub(MAX_RECENT_VOTES); (start..vote_state.votes.len()) - .map(|i| Vote::new(vec![vote_state.votes.get(i).unwrap().slot], Hash::default())) + .map(|i| { + Vote::new( + vec![vote_state.votes.get(i).unwrap().slot()], + Hash::default(), + ) + }) .collect() } @@ -1511,9 +1516,11 @@ mod tests { fn test_process_new_vote_too_many_votes() { let mut vote_state1 = VoteState::default(); let bad_votes: VecDeque = (0..=MAX_LOCKOUT_HISTORY) - .map(|slot| Lockout { - slot: slot as Slot, - confirmation_count: (MAX_LOCKOUT_HISTORY - slot + 1) as u32, + .map(|slot| { + Lockout::new_with_confirmation_count( + slot as Slot, + (MAX_LOCKOUT_HISTORY - slot + 1) as u32, + ) }) .collect(); @@ -1574,14 +1581,8 @@ mod tests { let current_epoch = vote_state1.current_epoch(); let bad_votes: VecDeque = vec![ - Lockout { - slot: 0, - confirmation_count: 0, - }, - Lockout { - slot: 1, - confirmation_count: 1, - }, + Lockout::new_with_confirmation_count(0, 0), + Lockout::new_with_confirmation_count(1, 1), ] .into_iter() .collect(); @@ -1591,14 +1592,8 @@ mod tests { ); let bad_votes: VecDeque = vec![ - Lockout { - slot: 0, - confirmation_count: 2, - }, - Lockout { - slot: 1, - confirmation_count: 0, - }, + Lockout::new_with_confirmation_count(0, 2), + Lockout::new_with_confirmation_count(1, 0), ] .into_iter() .collect(); @@ -1613,10 +1608,10 @@ mod tests { let mut vote_state1 = VoteState::default(); let current_epoch = vote_state1.current_epoch(); - let good_votes: VecDeque = vec![Lockout { - slot: 0, - confirmation_count: MAX_LOCKOUT_HISTORY as u32, - }] + let good_votes: VecDeque = vec![Lockout::new_with_confirmation_count( + 0, + MAX_LOCKOUT_HISTORY as u32, + )] .into_iter() .collect(); @@ -1631,10 +1626,10 @@ mod tests { .unwrap(); let mut vote_state1 = VoteState::default(); - let bad_votes: VecDeque = vec![Lockout { - slot: 0, - confirmation_count: MAX_LOCKOUT_HISTORY as u32 + 1, - }] + let bad_votes: VecDeque = vec![Lockout::new_with_confirmation_count( + 0, + MAX_LOCKOUT_HISTORY as u32 + 1, + )] .into_iter() .collect(); assert_eq!( @@ -1650,14 +1645,8 @@ mod tests { let root_slot = 5; let bad_votes: VecDeque = vec![ - Lockout { - slot: root_slot, - confirmation_count: 2, - }, - Lockout { - slot: root_slot + 1, - confirmation_count: 1, - }, + Lockout::new_with_confirmation_count(root_slot, 2), + Lockout::new_with_confirmation_count(root_slot + 1, 1), ] .into_iter() .collect(); @@ -1674,14 +1663,8 @@ mod tests { ); let bad_votes: VecDeque = vec![ - Lockout { - slot: root_slot - 1, - confirmation_count: 2, - }, - Lockout { - slot: root_slot + 1, - confirmation_count: 1, - }, + Lockout::new_with_confirmation_count(root_slot - 1, 2), + Lockout::new_with_confirmation_count(root_slot + 1, 1), ] .into_iter() .collect(); @@ -1704,14 +1687,8 @@ mod tests { let current_epoch = vote_state1.current_epoch(); let bad_votes: VecDeque = vec![ - Lockout { - slot: 1, - confirmation_count: 2, - }, - Lockout { - slot: 0, - confirmation_count: 1, - }, + Lockout::new_with_confirmation_count(1, 2), + Lockout::new_with_confirmation_count(0, 1), ] .into_iter() .collect(); @@ -1721,14 +1698,8 @@ mod tests { ); let bad_votes: VecDeque = vec![ - Lockout { - slot: 1, - confirmation_count: 2, - }, - Lockout { - slot: 1, - confirmation_count: 1, - }, + Lockout::new_with_confirmation_count(1, 2), + Lockout::new_with_confirmation_count(1, 1), ] .into_iter() .collect(); @@ -1744,14 +1715,8 @@ mod tests { let current_epoch = vote_state1.current_epoch(); let bad_votes: VecDeque = vec![ - Lockout { - slot: 0, - confirmation_count: 1, - }, - Lockout { - slot: 1, - confirmation_count: 2, - }, + Lockout::new_with_confirmation_count(0, 1), + Lockout::new_with_confirmation_count(1, 2), ] .into_iter() .collect(); @@ -1761,14 +1726,8 @@ mod tests { ); let bad_votes: VecDeque = vec![ - Lockout { - slot: 0, - confirmation_count: 1, - }, - Lockout { - slot: 1, - confirmation_count: 1, - }, + Lockout::new_with_confirmation_count(0, 1), + Lockout::new_with_confirmation_count(1, 1), ] .into_iter() .collect(); @@ -1784,14 +1743,8 @@ mod tests { let current_epoch = vote_state1.current_epoch(); let bad_votes: VecDeque = vec![ - Lockout { - slot: 0, - confirmation_count: 2, - }, - Lockout { - slot: 7, - confirmation_count: 1, - }, + Lockout::new_with_confirmation_count(0, 2), + Lockout::new_with_confirmation_count(7, 1), ] .into_iter() .collect(); @@ -1808,33 +1761,18 @@ mod tests { let mut vote_state1 = VoteState::default(); let current_epoch = vote_state1.current_epoch(); let votes: VecDeque = vec![ - Lockout { - slot: 0, - confirmation_count: 4, - }, - Lockout { - slot: 1, - confirmation_count: 3, - }, + Lockout::new_with_confirmation_count(0, 4), + Lockout::new_with_confirmation_count(1, 3), ] .into_iter() .collect(); process_new_vote_state(&mut vote_state1, votes, None, None, current_epoch, None).unwrap(); let votes: VecDeque = vec![ - Lockout { - slot: 0, - confirmation_count: 4, - }, - Lockout { - slot: 1, - // Confirmation count lowered illegally - confirmation_count: 2, - }, - Lockout { - slot: 2, - confirmation_count: 1, - }, + Lockout::new_with_confirmation_count(0, 4), + // Confirmation count lowered illegally + Lockout::new_with_confirmation_count(1, 2), + Lockout::new_with_confirmation_count(2, 1), ] .into_iter() .collect(); @@ -1906,7 +1844,7 @@ mod tests { vote_state1 .votes .iter() - .map(|vote| vote.slot) + .map(|vote| vote.slot()) .collect::>(), vec![1, 5] ); @@ -1918,7 +1856,7 @@ mod tests { vote_state2 .votes .iter() - .map(|vote| vote.slot) + .map(|vote| vote.slot()) .collect::>(), vec![1, 2, 3, 5, 7] ); @@ -1946,7 +1884,7 @@ mod tests { vote_state1 .votes .iter() - .map(|vote| vote.slot) + .map(|vote| vote.slot()) .collect::>(), vec![1, 2, 4, 5] ); @@ -1959,7 +1897,7 @@ mod tests { vote_state2 .votes .iter() - .map(|vote| vote.slot) + .map(|vote| vote.slot()) .collect::>(), vec![1, 2, 3, 5, 7] ); @@ -1987,7 +1925,7 @@ mod tests { vote_state1 .votes .iter() - .map(|vote| vote.slot) + .map(|vote| vote.slot()) .collect::>(), vec![1, 5, 6, 7] ); @@ -2000,7 +1938,7 @@ mod tests { vote_state2 .votes .iter() - .map(|vote| vote.slot) + .map(|vote| vote.slot()) .collect::>(), vec![1, 2, 3, 5, 6, 8] ); @@ -2029,7 +1967,7 @@ mod tests { vote_state1 .votes .iter() - .map(|vote| vote.slot) + .map(|vote| vote.slot()) .collect::>(), vec![1, 9] ); @@ -2041,13 +1979,13 @@ mod tests { // Slot 1 has been expired by 10, but is kept alive by its descendant // 9 which has not been expired yet. - assert_eq!(vote_state2.votes[0].slot, 1); + assert_eq!(vote_state2.votes[0].slot(), 1); assert_eq!(vote_state2.votes[0].last_locked_out_slot(), 9); assert_eq!( vote_state2 .votes .iter() - .map(|vote| vote.slot) + .map(|vote| vote.slot()) .collect::>(), vec![1, 9, 10] ); @@ -2073,22 +2011,16 @@ mod tests { vote_state1 .votes .iter() - .map(|vote| vote.slot) + .map(|vote| vote.slot()) .collect::>(), vec![6, 7, 8] ); // Try to process something with lockout violations let bad_votes: VecDeque = vec![ - Lockout { - slot: 2, - confirmation_count: 5, - }, - Lockout { - // Slot 14 could not have popped off slot 6 yet - slot: 14, - confirmation_count: 1, - }, + Lockout::new_with_confirmation_count(2, 5), + // Slot 14 could not have popped off slot 6 yet + Lockout::new_with_confirmation_count(14, 1), ] .into_iter() .collect(); @@ -2101,14 +2033,8 @@ mod tests { ); let good_votes: VecDeque = vec![ - Lockout { - slot: 2, - confirmation_count: 5, - }, - Lockout { - slot: 15, - confirmation_count: 1, - }, + Lockout::new_with_confirmation_count(2, 5), + Lockout::new_with_confirmation_count(15, 1), ] .into_iter() .collect(); @@ -2157,10 +2083,7 @@ mod tests { process_vote(&mut vote_state, &vote, &slot_hashes, 0, Some(&feature_set)).unwrap(); assert_eq!( vote_state.votes.into_iter().collect::>(), - vec![Lockout { - slot: vote_slot, - confirmation_count: 1, - }] + vec![Lockout::new_with_confirmation_count(vote_slot, 1)] ); } @@ -2341,10 +2264,7 @@ mod tests { let vote_state_update_slots_and_lockouts = vec![(5, 1)]; let vote_state_update_root = 4; let expected_root = Some(4); - let expected_vote_state = vec![Lockout { - slot: 5, - confirmation_count: 1, - }]; + let expected_vote_state = vec![Lockout::new_with_confirmation_count(5, 1)]; run_test_check_update_vote_state_older_than_history_root( earliest_slot_in_history, current_vote_state_slots, @@ -2363,10 +2283,7 @@ mod tests { let vote_state_update_slots_and_lockouts = vec![(5, 1)]; let vote_state_update_root = 4; let expected_root = Some(4); - let expected_vote_state = vec![Lockout { - slot: 5, - confirmation_count: 1, - }]; + let expected_vote_state = vec![Lockout::new_with_confirmation_count(5, 1)]; run_test_check_update_vote_state_older_than_history_root( earliest_slot_in_history, current_vote_state_slots, @@ -2386,14 +2303,8 @@ mod tests { let vote_state_update_root = 3; let expected_root = Some(3); let expected_vote_state = vec![ - Lockout { - slot: 4, - confirmation_count: 2, - }, - Lockout { - slot: 5, - confirmation_count: 1, - }, + Lockout::new_with_confirmation_count(4, 2), + Lockout::new_with_confirmation_count(5, 1), ]; run_test_check_update_vote_state_older_than_history_root( earliest_slot_in_history, @@ -2413,14 +2324,8 @@ mod tests { let vote_state_update_root = 3; let expected_root = Some(2); let expected_vote_state = vec![ - Lockout { - slot: 4, - confirmation_count: 2, - }, - Lockout { - slot: 5, - confirmation_count: 1, - }, + Lockout::new_with_confirmation_count(4, 2), + Lockout::new_with_confirmation_count(5, 1), ]; run_test_check_update_vote_state_older_than_history_root( earliest_slot_in_history, @@ -2441,18 +2346,9 @@ mod tests { let vote_state_update_root = 2; let expected_root = None; let expected_vote_state = vec![ - Lockout { - slot: 3, - confirmation_count: 3, - }, - Lockout { - slot: 4, - confirmation_count: 2, - }, - Lockout { - slot: 5, - confirmation_count: 1, - }, + Lockout::new_with_confirmation_count(3, 3), + Lockout::new_with_confirmation_count(4, 2), + Lockout::new_with_confirmation_count(5, 1), ]; run_test_check_update_vote_state_older_than_history_root( earliest_slot_in_history, @@ -2471,10 +2367,7 @@ mod tests { let vote_state_update_slots_and_lockouts = vec![(5, 1)]; let vote_state_update_root = 2; let expected_root = None; - let expected_vote_state = vec![Lockout { - slot: 5, - confirmation_count: 1, - }]; + let expected_vote_state = vec![Lockout::new_with_confirmation_count(5, 1)]; run_test_check_update_vote_state_older_than_history_root( earliest_slot_in_history, current_vote_state_slots, @@ -2564,14 +2457,8 @@ mod tests { .into_iter() .collect::>(), vec![ - Lockout { - slot: 1, - confirmation_count: 4, - }, - Lockout { - slot: vote_slot, - confirmation_count: 3, - } + Lockout::new_with_confirmation_count(1, 4), + Lockout::new_with_confirmation_count(vote_slot, 3) ] ); assert!(do_process_vote_state_update( @@ -2621,14 +2508,8 @@ mod tests { .into_iter() .collect::>(), vec![ - Lockout { - slot: existing_older_than_history_slot, - confirmation_count: 3, - }, - Lockout { - slot: vote_slot, - confirmation_count: 2, - } + Lockout::new_with_confirmation_count(existing_older_than_history_slot, 3), + Lockout::new_with_confirmation_count(vote_slot, 2) ] ); assert!(do_process_vote_state_update( @@ -2690,18 +2571,9 @@ mod tests { .into_iter() .collect::>(), vec![ - Lockout { - slot: existing_older_than_history_slot, - confirmation_count: 3, - }, - Lockout { - slot: 12, - confirmation_count: 2, - }, - Lockout { - slot: vote_slot, - confirmation_count: 1, - } + Lockout::new_with_confirmation_count(existing_older_than_history_slot, 3), + Lockout::new_with_confirmation_count(12, 2), + Lockout::new_with_confirmation_count(vote_slot, 1) ] ); assert!(do_process_vote_state_update( @@ -2728,7 +2600,7 @@ mod tests { // Have to vote for a slot greater than the last vote in the vote state to avoid VoteTooOld // errors - let vote_slot = vote_state.votes.back().unwrap().slot + 2; + let vote_slot = vote_state.votes.back().unwrap().slot() + 2; let vote_slot_hash = slot_hashes .iter() .find(|(slot, _hash)| *slot == vote_slot) @@ -2838,7 +2710,7 @@ mod tests { // Have to vote for a slot greater than the last vote in the vote state to avoid VoteTooOld // errors - let vote_slot = vote_state.votes.back().unwrap().slot + 2; + let vote_slot = vote_state.votes.back().unwrap().slot() + 2; let vote_slot_hash = slot_hashes .iter() .find(|(slot, _hash)| *slot == vote_slot) @@ -2863,22 +2735,10 @@ mod tests { .into_iter() .collect::>(), vec![ - Lockout { - slot: 2, - confirmation_count: 4, - }, - Lockout { - slot: 4, - confirmation_count: 3, - }, - Lockout { - slot: 6, - confirmation_count: 2, - }, - Lockout { - slot: vote_slot, - confirmation_count: 1, - } + Lockout::new_with_confirmation_count(2, 4), + Lockout::new_with_confirmation_count(4, 3), + Lockout::new_with_confirmation_count(6, 2), + Lockout::new_with_confirmation_count(vote_slot, 1) ] ); @@ -2902,7 +2762,7 @@ mod tests { // Have to vote for a slot greater than the last vote in the vote state to avoid VoteTooOld // errors - let vote_slot = vote_state.votes.back().unwrap().slot + 2; + let vote_slot = vote_state.votes.back().unwrap().slot() + 2; let vote_slot_hash = slot_hashes .iter() .find(|(slot, _hash)| *slot == vote_slot) @@ -2926,14 +2786,8 @@ mod tests { .into_iter() .collect::>(), vec![ - Lockout { - slot: 4, - confirmation_count: 2, - }, - Lockout { - slot: vote_slot, - confirmation_count: 1, - } + Lockout::new_with_confirmation_count(4, 2), + Lockout::new_with_confirmation_count(vote_slot, 1) ] ); @@ -2961,7 +2815,7 @@ mod tests { // Have to vote for a slot greater than the last vote in the vote state to avoid VoteTooOld // errors - let vote_slot = vote_state.votes.back().unwrap().slot + 2; + let vote_slot = vote_state.votes.back().unwrap().slot() + 2; let vote_slot_hash = Hash::new_unique(); let mut vote_state_update = VoteStateUpdate::from(vec![(2, 4), (4, 3), (6, 2), (vote_slot, 1)]); diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index 4c47fbb564..14af32ec64 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -936,7 +936,7 @@ impl JsonRpcRequestProcessor { let vote_state = account.vote_state(); let vote_state = vote_state.as_ref().unwrap_or(&default_vote_state); let last_vote = if let Some(vote) = vote_state.votes.iter().last() { - vote.slot + vote.slot() } else { 0 }; diff --git a/runtime/src/vote_transaction.rs b/runtime/src/vote_transaction.rs index 6351ef34f8..7c52801f25 100644 --- a/runtime/src/vote_transaction.rs +++ b/runtime/src/vote_transaction.rs @@ -19,7 +19,7 @@ impl VoteTransaction { VoteTransaction::VoteStateUpdate(vote_state_update) => vote_state_update .lockouts .iter() - .map(|lockout| lockout.slot) + .map(|lockout| lockout.slot()) .collect(), } } @@ -51,7 +51,7 @@ impl VoteTransaction { match self { VoteTransaction::Vote(vote) => vote.slots.last().copied(), VoteTransaction::VoteStateUpdate(vote_state_update) => { - Some(vote_state_update.lockouts.back()?.slot) + Some(vote_state_update.lockouts.back()?.slot()) } } } diff --git a/sdk/program/src/vote/state/mod.rs b/sdk/program/src/vote/state/mod.rs index 13c36a9ada..6ab557b84d 100644 --- a/sdk/program/src/vote/state/mod.rs +++ b/sdk/program/src/vote/state/mod.rs @@ -58,21 +58,25 @@ impl Vote { #[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Copy, Clone, AbiExample)] pub struct Lockout { - pub slot: Slot, - pub confirmation_count: u32, + slot: Slot, + confirmation_count: u32, } impl Lockout { pub fn new(slot: Slot) -> Self { + Self::new_with_confirmation_count(slot, 1) + } + + pub fn new_with_confirmation_count(slot: Slot, confirmation_count: u32) -> Self { Self { slot, - confirmation_count: 1, + confirmation_count, } } // The number of slots for which this vote is locked pub fn lockout(&self) -> u64 { - (INITIAL_LOCKOUT as u64).pow(self.confirmation_count) + (INITIAL_LOCKOUT as u64).pow(self.confirmation_count()) } // The last slot at which a vote is still locked out. Validators should not @@ -86,6 +90,18 @@ impl Lockout { pub fn is_locked_out_at_slot(&self, slot: Slot) -> bool { self.last_locked_out_slot() >= slot } + + pub fn slot(&self) -> Slot { + self.slot + } + + pub fn confirmation_count(&self) -> u32 { + self.confirmation_count + } + + pub fn increase_confirmation_count(&mut self, by: u32) { + self.confirmation_count = self.confirmation_count.saturating_add(by) + } } #[frozen_abi(digest = "GwJfVFsATSj7nvKwtUkHYzqPRaPY6SLxPGXApuCya3x5")] @@ -105,9 +121,8 @@ impl From> for VoteStateUpdate { fn from(recent_slots: Vec<(Slot, u32)>) -> Self { let lockouts: VecDeque = recent_slots .into_iter() - .map(|(slot, confirmation_count)| Lockout { - slot, - confirmation_count, + .map(|(slot, confirmation_count)| { + Lockout::new_with_confirmation_count(slot, confirmation_count) }) .collect(); Self { @@ -130,11 +145,11 @@ impl VoteStateUpdate { } pub fn slots(&self) -> Vec { - self.lockouts.iter().map(|lockout| lockout.slot).collect() + self.lockouts.iter().map(|lockout| lockout.slot()).collect() } pub fn last_voted_slot(&self) -> Option { - self.lockouts.back().map(|l| l.slot) + self.lockouts.back().map(|l| l.slot()) } } @@ -329,7 +344,7 @@ impl VoteState { /// Returns if the vote state contains a slot `candidate_slot` pub fn contains_slot(&self, candidate_slot: Slot) -> bool { self.votes - .binary_search_by(|lockout| lockout.slot.cmp(&candidate_slot)) + .binary_search_by(|lockout| lockout.slot().cmp(&candidate_slot)) .is_ok() } @@ -365,7 +380,7 @@ impl VoteState { // Once the stack is full, pop the oldest lockout and distribute rewards if self.votes.len() == MAX_LOCKOUT_HISTORY { let vote = self.votes.pop_front().unwrap(); - self.root_slot = Some(vote.slot); + self.root_slot = Some(vote.slot()); self.increment_credits(epoch, 1); } @@ -417,13 +432,13 @@ impl VoteState { } pub fn last_voted_slot(&self) -> Option { - self.last_lockout().map(|v| v.slot) + self.last_lockout().map(|v| v.slot()) } // Upto MAX_LOCKOUT_HISTORY many recent unexpired // vote slots pushed onto the stack. pub fn tower(&self) -> Vec { - self.votes.iter().map(|v| v.slot).collect() + self.votes.iter().map(|v| v.slot()).collect() } pub fn current_epoch(&self) -> Epoch { @@ -544,8 +559,8 @@ impl VoteState { for (i, v) in self.votes.iter_mut().enumerate() { // Don't increase the lockout for this vote until we get more confirmations // than the max number of confirmations this vote has seen - if stack_depth > i + v.confirmation_count as usize { - v.confirmation_count += 1; + if stack_depth > i + v.confirmation_count() as usize { + v.increase_confirmation_count(1); } } } @@ -612,11 +627,11 @@ pub mod serde_compact_vote_state_update { let lockout_offsets = vote_state_update.lockouts.iter().scan( vote_state_update.root.unwrap_or_default(), |slot, lockout| { - let offset = match lockout.slot.checked_sub(*slot) { + let offset = match lockout.slot().checked_sub(*slot) { None => return Some(Err(serde::ser::Error::custom("Invalid vote lockout"))), Some(offset) => offset, }; - let confirmation_count = match u8::try_from(lockout.confirmation_count) { + let confirmation_count = match u8::try_from(lockout.confirmation_count()) { Ok(confirmation_count) => confirmation_count, Err(_) => { return Some(Err(serde::ser::Error::custom("Invalid confirmation count"))) @@ -626,7 +641,7 @@ pub mod serde_compact_vote_state_update { offset, confirmation_count, }; - *slot = lockout.slot; + *slot = lockout.slot(); Some(Ok(lockout_offset)) }, ); @@ -660,10 +675,10 @@ pub mod serde_compact_vote_state_update { } Some(slot) => slot, }; - let lockout = Lockout { - slot: *slot, - confirmation_count: u32::from(lockout_offset.confirmation_count), - }; + let lockout = Lockout::new_with_confirmation_count( + *slot, + u32::from(lockout_offset.confirmation_count), + ); Some(Ok(lockout)) }); Ok(VoteStateUpdate { @@ -1132,16 +1147,17 @@ mod tests { #[allow(clippy::integer_arithmetic)] fn run_serde_compact_vote_state_update(rng: &mut R) { - let lockouts: VecDeque<_> = std::iter::repeat_with(|| Lockout { - slot: 149_303_885 + rng.gen_range(0, 10_000), - confirmation_count: rng.gen_range(0, 33), + let lockouts: VecDeque<_> = std::iter::repeat_with(|| { + let slot = 149_303_885 + rng.gen_range(0, 10_000); + let confirmation_count = rng.gen_range(0, 33); + Lockout::new_with_confirmation_count(slot, confirmation_count) }) .take(32) - .sorted_by_key(|lockout| lockout.slot) + .sorted_by_key(|lockout| lockout.slot()) .collect(); let root = rng .gen_ratio(1, 2) - .then(|| lockouts[0].slot - rng.gen_range(0, 1_000)); + .then(|| lockouts[0].slot() - rng.gen_range(0, 1_000)); let timestamp = rng.gen_ratio(1, 2).then(|| rng.gen()); let hash = Hash::from(rng.gen::<[u8; 32]>()); let vote_state_update = VoteStateUpdate {