solana_vote_program/vote_state/
mod.rs

1//! Vote state, vote program
2//! Receive and processes votes from validators
3#[cfg(test)]
4use solana_sdk::epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET;
5use {
6    crate::{authorized_voters::AuthorizedVoters, id, vote_error::VoteError},
7    bincode::{deserialize, serialize_into, ErrorKind},
8    log::*,
9    serde_derive::{Deserialize, Serialize},
10    solana_metrics::datapoint_debug,
11    solana_sdk::{
12        account::{AccountSharedData, ReadableAccount, WritableAccount},
13        clock::{Epoch, Slot, UnixTimestamp},
14        epoch_schedule::EpochSchedule,
15        feature_set::{self, filter_votes_outside_slot_hashes, FeatureSet},
16        hash::Hash,
17        instruction::InstructionError,
18        pubkey::Pubkey,
19        rent::Rent,
20        slot_hashes::SlotHash,
21        sysvar::clock::Clock,
22        transaction_context::{BorrowedAccount, InstructionContext, TransactionContext},
23    },
24    std::{
25        cmp::Ordering,
26        collections::{HashSet, VecDeque},
27        fmt::Debug,
28    },
29};
30
31mod vote_state_0_23_5;
32pub mod vote_state_versions;
33pub use vote_state_versions::*;
34
35// Maximum number of votes to keep around, tightly coupled with epoch_schedule::MINIMUM_SLOTS_PER_EPOCH
36pub const MAX_LOCKOUT_HISTORY: usize = 31;
37pub const INITIAL_LOCKOUT: usize = 2;
38
39// Maximum number of credits history to keep around
40pub const MAX_EPOCH_CREDITS_HISTORY: usize = 64;
41
42// Offset of VoteState::prior_voters, for determining initialization status without deserialization
43const DEFAULT_PRIOR_VOTERS_OFFSET: usize = 82;
44
45#[frozen_abi(digest = "4RSrLCthxW7e6KgpzDCf1kQUxa2v2aCg9mxn3975V7bm")]
46#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, AbiEnumVisitor, AbiExample)]
47pub enum VoteTransaction {
48    Vote(Vote),
49    VoteStateUpdate(VoteStateUpdate),
50    #[serde(with = "serde_compact_vote_state_update")]
51    CompactVoteStateUpdate(VoteStateUpdate),
52}
53
54impl VoteTransaction {
55    pub fn slots(&self) -> Vec<Slot> {
56        match self {
57            VoteTransaction::Vote(vote) => vote.slots.clone(),
58            VoteTransaction::VoteStateUpdate(vote_state_update) => vote_state_update.slots(),
59            VoteTransaction::CompactVoteStateUpdate(vote_state_update) => vote_state_update.slots(),
60        }
61    }
62
63    pub fn slot(&self, i: usize) -> Slot {
64        match self {
65            VoteTransaction::Vote(vote) => vote.slots[i],
66            VoteTransaction::VoteStateUpdate(vote_state_update)
67            | VoteTransaction::CompactVoteStateUpdate(vote_state_update) => {
68                vote_state_update.lockouts[i].slot
69            }
70        }
71    }
72
73    pub fn len(&self) -> usize {
74        match self {
75            VoteTransaction::Vote(vote) => vote.slots.len(),
76            VoteTransaction::VoteStateUpdate(vote_state_update)
77            | VoteTransaction::CompactVoteStateUpdate(vote_state_update) => {
78                vote_state_update.lockouts.len()
79            }
80        }
81    }
82
83    pub fn is_empty(&self) -> bool {
84        match self {
85            VoteTransaction::Vote(vote) => vote.slots.is_empty(),
86            VoteTransaction::VoteStateUpdate(vote_state_update)
87            | VoteTransaction::CompactVoteStateUpdate(vote_state_update) => {
88                vote_state_update.lockouts.is_empty()
89            }
90        }
91    }
92
93    pub fn hash(&self) -> Hash {
94        match self {
95            VoteTransaction::Vote(vote) => vote.hash,
96            VoteTransaction::VoteStateUpdate(vote_state_update) => vote_state_update.hash,
97            VoteTransaction::CompactVoteStateUpdate(vote_state_update) => vote_state_update.hash,
98        }
99    }
100
101    pub fn timestamp(&self) -> Option<UnixTimestamp> {
102        match self {
103            VoteTransaction::Vote(vote) => vote.timestamp,
104            VoteTransaction::VoteStateUpdate(vote_state_update)
105            | VoteTransaction::CompactVoteStateUpdate(vote_state_update) => {
106                vote_state_update.timestamp
107            }
108        }
109    }
110
111    pub fn set_timestamp(&mut self, ts: Option<UnixTimestamp>) {
112        match self {
113            VoteTransaction::Vote(vote) => vote.timestamp = ts,
114            VoteTransaction::VoteStateUpdate(vote_state_update)
115            | VoteTransaction::CompactVoteStateUpdate(vote_state_update) => {
116                vote_state_update.timestamp = ts
117            }
118        }
119    }
120
121    pub fn last_voted_slot(&self) -> Option<Slot> {
122        match self {
123            VoteTransaction::Vote(vote) => vote.slots.last().copied(),
124            VoteTransaction::VoteStateUpdate(vote_state_update)
125            | VoteTransaction::CompactVoteStateUpdate(vote_state_update) => {
126                Some(vote_state_update.lockouts.back()?.slot)
127            }
128        }
129    }
130
131    pub fn last_voted_slot_hash(&self) -> Option<(Slot, Hash)> {
132        Some((self.last_voted_slot()?, self.hash()))
133    }
134}
135
136impl From<Vote> for VoteTransaction {
137    fn from(vote: Vote) -> Self {
138        VoteTransaction::Vote(vote)
139    }
140}
141
142impl From<VoteStateUpdate> for VoteTransaction {
143    fn from(vote_state_update: VoteStateUpdate) -> Self {
144        VoteTransaction::VoteStateUpdate(vote_state_update)
145    }
146}
147
148#[frozen_abi(digest = "Ch2vVEwos2EjAVqSHCyJjnN2MNX1yrpapZTGhMSCjWUH")]
149#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone, AbiExample)]
150pub struct Vote {
151    /// A stack of votes starting with the oldest vote
152    pub slots: Vec<Slot>,
153    /// signature of the bank's state at the last slot
154    pub hash: Hash,
155    /// processing timestamp of last slot
156    pub timestamp: Option<UnixTimestamp>,
157}
158
159impl Vote {
160    pub fn new(slots: Vec<Slot>, hash: Hash) -> Self {
161        Self {
162            slots,
163            hash,
164            timestamp: None,
165        }
166    }
167}
168
169#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Copy, Clone, AbiExample)]
170pub struct Lockout {
171    pub slot: Slot,
172    pub confirmation_count: u32,
173}
174
175impl Lockout {
176    pub fn new(slot: Slot) -> Self {
177        Self {
178            slot,
179            confirmation_count: 1,
180        }
181    }
182
183    // The number of slots for which this vote is locked
184    pub fn lockout(&self) -> u64 {
185        (INITIAL_LOCKOUT as u64).pow(self.confirmation_count)
186    }
187
188    // The last slot at which a vote is still locked out. Validators should not
189    // vote on a slot in another fork which is less than or equal to this slot
190    // to avoid having their stake slashed.
191    pub fn last_locked_out_slot(&self) -> Slot {
192        self.slot + self.lockout()
193    }
194
195    pub fn is_locked_out_at_slot(&self, slot: Slot) -> bool {
196        self.last_locked_out_slot() >= slot
197    }
198}
199
200#[frozen_abi(digest = "BctadFJjUKbvPJzr6TszbX6rBfQUNSRKpKKngkzgXgeY")]
201#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone, AbiExample)]
202pub struct VoteStateUpdate {
203    /// The proposed tower
204    pub lockouts: VecDeque<Lockout>,
205    /// The proposed root
206    pub root: Option<Slot>,
207    /// signature of the bank's state at the last slot
208    pub hash: Hash,
209    /// processing timestamp of last slot
210    pub timestamp: Option<UnixTimestamp>,
211}
212
213impl From<Vec<(Slot, u32)>> for VoteStateUpdate {
214    fn from(recent_slots: Vec<(Slot, u32)>) -> Self {
215        let lockouts: VecDeque<Lockout> = recent_slots
216            .into_iter()
217            .map(|(slot, confirmation_count)| Lockout {
218                slot,
219                confirmation_count,
220            })
221            .collect();
222        Self {
223            lockouts,
224            root: None,
225            hash: Hash::default(),
226            timestamp: None,
227        }
228    }
229}
230
231impl VoteStateUpdate {
232    pub fn new(lockouts: VecDeque<Lockout>, root: Option<Slot>, hash: Hash) -> Self {
233        Self {
234            lockouts,
235            root,
236            hash,
237            timestamp: None,
238        }
239    }
240
241    pub fn slots(&self) -> Vec<Slot> {
242        self.lockouts.iter().map(|lockout| lockout.slot).collect()
243    }
244}
245
246#[derive(Default, Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
247pub struct VoteInit {
248    pub node_pubkey: Pubkey,
249    pub authorized_voter: Pubkey,
250    pub authorized_withdrawer: Pubkey,
251    pub commission: u8,
252}
253
254#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
255pub enum VoteAuthorize {
256    Voter,
257    Withdrawer,
258}
259
260#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
261pub struct VoteAuthorizeWithSeedArgs {
262    pub authorization_type: VoteAuthorize,
263    pub current_authority_derived_key_owner: Pubkey,
264    pub current_authority_derived_key_seed: String,
265    pub new_authority: Pubkey,
266}
267
268#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
269pub struct VoteAuthorizeCheckedWithSeedArgs {
270    pub authorization_type: VoteAuthorize,
271    pub current_authority_derived_key_owner: Pubkey,
272    pub current_authority_derived_key_seed: String,
273}
274
275#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone, AbiExample)]
276pub struct BlockTimestamp {
277    pub slot: Slot,
278    pub timestamp: UnixTimestamp,
279}
280
281// this is how many epochs a voter can be remembered for slashing
282const MAX_ITEMS: usize = 32;
283
284#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, AbiExample)]
285pub struct CircBuf<I> {
286    buf: [I; MAX_ITEMS],
287    /// next pointer
288    idx: usize,
289    is_empty: bool,
290}
291
292impl<I: Default + Copy> Default for CircBuf<I> {
293    fn default() -> Self {
294        Self {
295            buf: [I::default(); MAX_ITEMS],
296            idx: MAX_ITEMS - 1,
297            is_empty: true,
298        }
299    }
300}
301
302impl<I> CircBuf<I> {
303    pub fn append(&mut self, item: I) {
304        // remember prior delegate and when we switched, to support later slashing
305        self.idx += 1;
306        self.idx %= MAX_ITEMS;
307
308        self.buf[self.idx] = item;
309        self.is_empty = false;
310    }
311
312    pub fn buf(&self) -> &[I; MAX_ITEMS] {
313        &self.buf
314    }
315
316    pub fn last(&self) -> Option<&I> {
317        if !self.is_empty {
318            Some(&self.buf[self.idx])
319        } else {
320            None
321        }
322    }
323}
324
325#[frozen_abi(digest = "331ZmXrmsUcwbKhzR3C1UEU6uNwZr48ExE54JDKGWA4w")]
326#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone, AbiExample)]
327pub struct VoteState {
328    /// the node that votes in this account
329    pub node_pubkey: Pubkey,
330
331    /// the signer for withdrawals
332    pub authorized_withdrawer: Pubkey,
333    /// percentage (0-100) that represents what part of a rewards
334    ///  payout should be given to this VoteAccount
335    pub commission: u8,
336
337    pub votes: VecDeque<Lockout>,
338
339    // This usually the last Lockout which was popped from self.votes.
340    // However, it can be arbitrary slot, when being used inside Tower
341    pub root_slot: Option<Slot>,
342
343    /// the signer for vote transactions
344    authorized_voters: AuthorizedVoters,
345
346    /// history of prior authorized voters and the epochs for which
347    /// they were set, the bottom end of the range is inclusive,
348    /// the top of the range is exclusive
349    prior_voters: CircBuf<(Pubkey, Epoch, Epoch)>,
350
351    /// history of how many credits earned by the end of each epoch
352    ///  each tuple is (Epoch, credits, prev_credits)
353    pub epoch_credits: Vec<(Epoch, u64, u64)>,
354
355    /// most recent timestamp submitted with a vote
356    pub last_timestamp: BlockTimestamp,
357}
358
359impl VoteState {
360    pub fn new(vote_init: &VoteInit, clock: &Clock) -> Self {
361        Self {
362            node_pubkey: vote_init.node_pubkey,
363            authorized_voters: AuthorizedVoters::new(clock.epoch, vote_init.authorized_voter),
364            authorized_withdrawer: vote_init.authorized_withdrawer,
365            commission: vote_init.commission,
366            ..VoteState::default()
367        }
368    }
369
370    pub fn get_authorized_voter(&self, epoch: Epoch) -> Option<Pubkey> {
371        self.authorized_voters.get_authorized_voter(epoch)
372    }
373
374    pub fn authorized_voters(&self) -> &AuthorizedVoters {
375        &self.authorized_voters
376    }
377
378    pub fn prior_voters(&mut self) -> &CircBuf<(Pubkey, Epoch, Epoch)> {
379        &self.prior_voters
380    }
381
382    pub fn get_rent_exempt_reserve(rent: &Rent) -> u64 {
383        rent.minimum_balance(VoteState::size_of())
384    }
385
386    /// Upper limit on the size of the Vote State
387    /// when votes.len() is MAX_LOCKOUT_HISTORY.
388    pub const fn size_of() -> usize {
389        3731 // see test_vote_state_size_of.
390    }
391
392    // utility function, used by Stakes, tests
393    pub fn from<T: ReadableAccount>(account: &T) -> Option<VoteState> {
394        Self::deserialize(account.data()).ok()
395    }
396
397    // utility function, used by Stakes, tests
398    pub fn to<T: WritableAccount>(versioned: &VoteStateVersions, account: &mut T) -> Option<()> {
399        Self::serialize(versioned, account.data_as_mut_slice()).ok()
400    }
401
402    pub fn deserialize(input: &[u8]) -> Result<Self, InstructionError> {
403        deserialize::<VoteStateVersions>(input)
404            .map(|versioned| versioned.convert_to_current())
405            .map_err(|_| InstructionError::InvalidAccountData)
406    }
407
408    pub fn serialize(
409        versioned: &VoteStateVersions,
410        output: &mut [u8],
411    ) -> Result<(), InstructionError> {
412        serialize_into(output, versioned).map_err(|err| match *err {
413            ErrorKind::SizeLimit => InstructionError::AccountDataTooSmall,
414            _ => InstructionError::GenericError,
415        })
416    }
417
418    pub fn credits_from<T: ReadableAccount>(account: &T) -> Option<u64> {
419        Self::from(account).map(|state| state.credits())
420    }
421
422    /// returns commission split as (voter_portion, staker_portion, was_split) tuple
423    ///
424    ///  if commission calculation is 100% one way or other,
425    ///   indicate with false for was_split
426    pub fn commission_split(&self, on: u64) -> (u64, u64, bool) {
427        match self.commission.min(100) {
428            0 => (0, on, false),
429            100 => (on, 0, false),
430            split => {
431                let on = u128::from(on);
432                // Calculate mine and theirs independently and symmetrically instead of
433                // using the remainder of the other to treat them strictly equally.
434                // This is also to cancel the rewarding if either of the parties
435                // should receive only fractional lamports, resulting in not being rewarded at all.
436                // Thus, note that we intentionally discard any residual fractional lamports.
437                let mine = on * u128::from(split) / 100u128;
438                let theirs = on * u128::from(100 - split) / 100u128;
439
440                (mine as u64, theirs as u64, true)
441            }
442        }
443    }
444
445    /// Returns if the vote state contains a slot `candidate_slot`
446    pub fn contains_slot(&self, candidate_slot: Slot) -> bool {
447        self.votes
448            .binary_search_by(|lockout| lockout.slot.cmp(&candidate_slot))
449            .is_ok()
450    }
451
452    #[cfg(test)]
453    fn get_max_sized_vote_state() -> VoteState {
454        let mut authorized_voters = AuthorizedVoters::default();
455        for i in 0..=MAX_LEADER_SCHEDULE_EPOCH_OFFSET {
456            authorized_voters.insert(i, solana_sdk::pubkey::new_rand());
457        }
458
459        VoteState {
460            votes: VecDeque::from(vec![Lockout::default(); MAX_LOCKOUT_HISTORY]),
461            root_slot: Some(std::u64::MAX),
462            epoch_credits: vec![(0, 0, 0); MAX_EPOCH_CREDITS_HISTORY],
463            authorized_voters,
464            ..Self::default()
465        }
466    }
467
468    fn check_update_vote_state_slots_are_valid(
469        &self,
470        vote_state_update: &mut VoteStateUpdate,
471        slot_hashes: &[(Slot, Hash)],
472        feature_set: Option<&FeatureSet>,
473    ) -> Result<(), VoteError> {
474        if vote_state_update.lockouts.is_empty() {
475            return Err(VoteError::EmptySlots);
476        }
477
478        // If the vote state update is not new enough, return
479        if let Some(last_vote_slot) = self.votes.back().map(|lockout| lockout.slot) {
480            if vote_state_update.lockouts.back().unwrap().slot <= last_vote_slot {
481                return Err(VoteError::VoteTooOld);
482            }
483        }
484
485        let last_vote_state_update_slot = vote_state_update
486            .lockouts
487            .back()
488            .expect("must be nonempty, checked above")
489            .slot;
490
491        if slot_hashes.is_empty() {
492            return Err(VoteError::SlotsMismatch);
493        }
494        let earliest_slot_hash_in_history = slot_hashes.last().unwrap().0;
495
496        // Check if the proposed vote is too old to be in the SlotHash history
497        if last_vote_state_update_slot < earliest_slot_hash_in_history {
498            // If this is the last slot in the vote update, it must be in SlotHashes,
499            // otherwise we have no way of confirming if the hash matches
500            return Err(VoteError::VoteTooOld);
501        }
502
503        // Check if the proposed root is too old
504        let is_root_fix_enabled = feature_set
505            .map(|feature_set| {
506                feature_set.is_active(&feature_set::vote_state_update_root_fix::id())
507            })
508            .unwrap_or(false);
509
510        let original_proposed_root = vote_state_update.root;
511        if let Some(new_proposed_root) = original_proposed_root {
512            // If the new proposed root `R` is less than the earliest slot hash in the history
513            // such that we cannot verify whether the slot was actually was on this fork, set
514            // the root to the latest vote in the current vote that's less than R.
515            if earliest_slot_hash_in_history > new_proposed_root {
516                vote_state_update.root = self.root_slot;
517                if is_root_fix_enabled {
518                    let mut prev_slot = Slot::MAX;
519                    let current_root = vote_state_update.root;
520                    for lockout in self.votes.iter().rev() {
521                        let is_slot_bigger_than_root = current_root
522                            .map(|current_root| lockout.slot > current_root)
523                            .unwrap_or(true);
524                        // Ensure we're iterating from biggest to smallest vote in the
525                        // current vote state
526                        assert!(lockout.slot < prev_slot && is_slot_bigger_than_root);
527                        if lockout.slot <= new_proposed_root {
528                            vote_state_update.root = Some(lockout.slot);
529                            break;
530                        }
531                        prev_slot = lockout.slot;
532                    }
533                }
534            }
535        }
536
537        // Index into the new proposed vote state's slots, starting with the root if it exists then
538        // we use this mutable root to fold checking the root slot into the below loop
539        // for performance
540        let mut root_to_check = vote_state_update.root;
541        let mut vote_state_update_index = 0;
542
543        // index into the slot_hashes, starting at the oldest known
544        // slot hash
545        let mut slot_hashes_index = slot_hashes.len();
546
547        let mut vote_state_update_indexes_to_filter = vec![];
548
549        // Note:
550        //
551        // 1) `vote_state_update.lockouts` is sorted from oldest/smallest vote to newest/largest
552        // vote, due to the way votes are applied to the vote state (newest votes
553        // pushed to the back).
554        //
555        // 2) Conversely, `slot_hashes` is sorted from newest/largest vote to
556        // the oldest/smallest vote
557        //
558        // Unlike for vote updates, vote state updates here can't only check votes older than the last vote
559        // because have to ensure that every slot is actually part of the history, not just the most
560        // recent ones
561        while vote_state_update_index < vote_state_update.lockouts.len() && slot_hashes_index > 0 {
562            let proposed_vote_slot = if let Some(root) = root_to_check {
563                root
564            } else {
565                vote_state_update.lockouts[vote_state_update_index].slot
566            };
567            if root_to_check.is_none()
568                && vote_state_update_index > 0
569                && proposed_vote_slot
570                    <= vote_state_update.lockouts[vote_state_update_index - 1].slot
571            {
572                return Err(VoteError::SlotsNotOrdered);
573            }
574            let ancestor_slot = slot_hashes[slot_hashes_index - 1].0;
575
576            // Find if this slot in the proposed vote state exists in the SlotHashes history
577            // to confirm if it was a valid ancestor on this fork
578            match proposed_vote_slot.cmp(&ancestor_slot) {
579                Ordering::Less => {
580                    if slot_hashes_index == slot_hashes.len() {
581                        // The vote slot does not exist in the SlotHashes history because it's too old,
582                        // i.e. older than the oldest slot in the history.
583                        assert!(proposed_vote_slot < earliest_slot_hash_in_history);
584                        if !self.contains_slot(proposed_vote_slot) && root_to_check.is_none() {
585                            // If the vote slot is both:
586                            // 1) Too old
587                            // 2) Doesn't already exist in vote state
588                            //
589                            // Then filter it out
590                            vote_state_update_indexes_to_filter.push(vote_state_update_index);
591                        }
592                        if let Some(new_proposed_root) = root_to_check {
593                            if is_root_fix_enabled {
594                                // 1. Because `root_to_check.is_some()`, then we know that
595                                // we haven't checked the root yet in this loop, so
596                                // `proposed_vote_slot` == `new_proposed_root` == `vote_state_update.root`.
597                                assert_eq!(new_proposed_root, proposed_vote_slot);
598                                // 2. We know from the assert earlier in the function that
599                                // `proposed_vote_slot < earliest_slot_hash_in_history`,
600                                // so from 1. we know that `new_proposed_root < earliest_slot_hash_in_history`.
601                                assert!(new_proposed_root < earliest_slot_hash_in_history);
602                            } else {
603                                // If the vote state update has a root < earliest_slot_hash_in_history
604                                // then we use the current root. The only case where this can happen
605                                // is if the current root itself is not in slot hashes.
606                                assert!(self.root_slot.unwrap() < earliest_slot_hash_in_history);
607                            }
608                            root_to_check = None;
609                        } else {
610                            vote_state_update_index += 1;
611                        }
612                        continue;
613                    } else {
614                        // If the vote slot is new enough to be in the slot history,
615                        // but is not part of the slot history, then it must belong to another fork,
616                        // which means this vote state update is invalid.
617                        if root_to_check.is_some() {
618                            return Err(VoteError::RootOnDifferentFork);
619                        } else {
620                            return Err(VoteError::SlotsMismatch);
621                        }
622                    }
623                }
624                Ordering::Greater => {
625                    // Decrement `slot_hashes_index` to find newer slots in the SlotHashes history
626                    slot_hashes_index -= 1;
627                    continue;
628                }
629                Ordering::Equal => {
630                    // Once the slot in `vote_state_update.lockouts` is found, bump to the next slot
631                    // in `vote_state_update.lockouts` and continue. If we were checking the root,
632                    // start checking the vote state instead.
633                    if root_to_check.is_some() {
634                        root_to_check = None;
635                    } else {
636                        vote_state_update_index += 1;
637                        slot_hashes_index -= 1;
638                    }
639                }
640            }
641        }
642
643        if vote_state_update_index != vote_state_update.lockouts.len() {
644            // The last vote slot in the update did not exist in SlotHashes
645            return Err(VoteError::SlotsMismatch);
646        }
647
648        // This assertion must be true at this point because we can assume by now:
649        // 1) vote_state_update_index == vote_state_update.lockouts.len()
650        // 2) last_vote_state_update_slot >= earliest_slot_hash_in_history
651        // 3) !vote_state_update.lockouts.is_empty()
652        //
653        // 1) implies that during the last iteration of the loop above,
654        // `vote_state_update_index` was equal to `vote_state_update.lockouts.len() - 1`,
655        // and was then incremented to `vote_state_update.lockouts.len()`.
656        // This means in that last loop iteration,
657        // `proposed_vote_slot ==
658        //  vote_state_update.lockouts[vote_state_update.lockouts.len() - 1] ==
659        //  last_vote_state_update_slot`.
660        //
661        // Then we know the last comparison `match proposed_vote_slot.cmp(&ancestor_slot)`
662        // is equivalent to `match last_vote_state_update_slot.cmp(&ancestor_slot)`. The result
663        // of this match to increment `vote_state_update_index` must have been either:
664        //
665        // 1) The Equal case ran, in which case then we know this assertion must be true
666        // 2) The Less case ran, and more specifically the case
667        // `proposed_vote_slot < earliest_slot_hash_in_history` ran, which is equivalent to
668        // `last_vote_state_update_slot < earliest_slot_hash_in_history`, but this is impossible
669        // due to assumption 3) above.
670        assert_eq!(
671            last_vote_state_update_slot,
672            slot_hashes[slot_hashes_index].0
673        );
674
675        if slot_hashes[slot_hashes_index].1 != vote_state_update.hash {
676            // This means the newest vote in the slot has a match that
677            // doesn't match the expected hash for that slot on this
678            // fork
679            warn!(
680                "{} dropped vote {:?} failed to match hash {} {}",
681                self.node_pubkey,
682                vote_state_update,
683                vote_state_update.hash,
684                slot_hashes[slot_hashes_index].1
685            );
686            inc_new_counter_info!("dropped-vote-hash", 1);
687            return Err(VoteError::SlotHashMismatch);
688        }
689
690        // Filter out the irrelevant votes
691        let mut vote_state_update_index = 0;
692        let mut filter_votes_index = 0;
693        vote_state_update.lockouts.retain(|_lockout| {
694            let should_retain = if filter_votes_index == vote_state_update_indexes_to_filter.len() {
695                true
696            } else if vote_state_update_index
697                == vote_state_update_indexes_to_filter[filter_votes_index]
698            {
699                filter_votes_index += 1;
700                false
701            } else {
702                true
703            };
704
705            vote_state_update_index += 1;
706            should_retain
707        });
708
709        Ok(())
710    }
711
712    fn check_slots_are_valid(
713        &self,
714        vote_slots: &[Slot],
715        vote_hash: &Hash,
716        slot_hashes: &[(Slot, Hash)],
717    ) -> Result<(), VoteError> {
718        // index into the vote's slots, starting at the oldest
719        // slot
720        let mut i = 0;
721
722        // index into the slot_hashes, starting at the oldest known
723        // slot hash
724        let mut j = slot_hashes.len();
725
726        // Note:
727        //
728        // 1) `vote_slots` is sorted from oldest/smallest vote to newest/largest
729        // vote, due to the way votes are applied to the vote state (newest votes
730        // pushed to the back).
731        //
732        // 2) Conversely, `slot_hashes` is sorted from newest/largest vote to
733        // the oldest/smallest vote
734        while i < vote_slots.len() && j > 0 {
735            // 1) increment `i` to find the smallest slot `s` in `vote_slots`
736            // where `s` >= `last_voted_slot`
737            if self
738                .last_voted_slot()
739                .map_or(false, |last_voted_slot| vote_slots[i] <= last_voted_slot)
740            {
741                i += 1;
742                continue;
743            }
744
745            // 2) Find the hash for this slot `s`.
746            if vote_slots[i] != slot_hashes[j - 1].0 {
747                // Decrement `j` to find newer slots
748                j -= 1;
749                continue;
750            }
751
752            // 3) Once the hash for `s` is found, bump `s` to the next slot
753            // in `vote_slots` and continue.
754            i += 1;
755            j -= 1;
756        }
757
758        if j == slot_hashes.len() {
759            // This means we never made it to steps 2) or 3) above, otherwise
760            // `j` would have been decremented at least once. This means
761            // there are not slots in `vote_slots` greater than `last_voted_slot`
762            debug!(
763                "{} dropped vote slots {:?}, vote hash: {:?} slot hashes:SlotHash {:?}, too old ",
764                self.node_pubkey, vote_slots, vote_hash, slot_hashes
765            );
766            return Err(VoteError::VoteTooOld);
767        }
768        if i != vote_slots.len() {
769            // This means there existed some slot for which we couldn't find
770            // a matching slot hash in step 2)
771            info!(
772                "{} dropped vote slots {:?} failed to match slot hashes: {:?}",
773                self.node_pubkey, vote_slots, slot_hashes,
774            );
775            inc_new_counter_info!("dropped-vote-slot", 1);
776            return Err(VoteError::SlotsMismatch);
777        }
778        if &slot_hashes[j].1 != vote_hash {
779            // This means the newest slot in the `vote_slots` has a match that
780            // doesn't match the expected hash for that slot on this
781            // fork
782            warn!(
783                "{} dropped vote slots {:?} failed to match hash {} {}",
784                self.node_pubkey, vote_slots, vote_hash, slot_hashes[j].1
785            );
786            inc_new_counter_info!("dropped-vote-hash", 1);
787            return Err(VoteError::SlotHashMismatch);
788        }
789        Ok(())
790    }
791
792    // `Ensure check_update_vote_state_slots_are_valid()` runs on the slots in `new_state`
793    // before `process_new_vote_state()` is called
794
795    // This function should guarantee the following about `new_state`:
796    //
797    // 1) It's well ordered, i.e. the slots are sorted from smallest to largest,
798    // and the confirmations sorted from largest to smallest.
799    // 2) Confirmations `c` on any vote slot satisfy `0 < c <= MAX_LOCKOUT_HISTORY`
800    // 3) Lockouts are not expired by consecutive votes, i.e. for every consecutive
801    // `v_i`, `v_{i + 1}` satisfy `v_i.last_locked_out_slot() >= v_{i + 1}`.
802
803    // We also guarantee that compared to the current vote state, `new_state`
804    // introduces no rollback. This means:
805    //
806    // 1) The last slot in `new_state` is always greater than any slot in the
807    // current vote state.
808    //
809    // 2) From 1), this means that for every vote `s` in the current state:
810    //    a) If there exists an `s'` in `new_state` where `s.slot == s'.slot`, then
811    //    we must guarantee `s.confirmations <= s'.confirmations`
812    //
813    //    b) If there does not exist any such `s'` in `new_state`, then there exists
814    //    some `t` that is the smallest vote in `new_state` where `t.slot > s.slot`.
815    //    `t` must have expired/popped off s', so it must be guaranteed that
816    //    `s.last_locked_out_slot() < t`.
817
818    // Note these two above checks do not guarantee that the vote state being submitted
819    // is a vote state that could have been created by iteratively building a tower
820    // by processing one vote at a time. For instance, the tower:
821    //
822    // { slot 0, confirmations: 31 }
823    // { slot 1, confirmations: 30 }
824    //
825    // is a legal tower that could be submitted on top of a previously empty tower. However,
826    // there is no way to create this tower from the iterative process, because slot 1 would
827    // have to have at least one other slot on top of it, even if the first 30 votes were all
828    // popped off.
829    pub fn process_new_vote_state(
830        &mut self,
831        new_state: VecDeque<Lockout>,
832        new_root: Option<Slot>,
833        timestamp: Option<i64>,
834        epoch: Epoch,
835        feature_set: Option<&FeatureSet>,
836    ) -> Result<(), VoteError> {
837        assert!(!new_state.is_empty());
838        if new_state.len() > MAX_LOCKOUT_HISTORY {
839            return Err(VoteError::TooManyVotes);
840        }
841
842        match (new_root, self.root_slot) {
843            (Some(new_root), Some(current_root)) => {
844                if new_root < current_root {
845                    return Err(VoteError::RootRollBack);
846                }
847            }
848            (None, Some(_)) => {
849                return Err(VoteError::RootRollBack);
850            }
851            _ => (),
852        }
853
854        let mut previous_vote: Option<&Lockout> = None;
855
856        // Check that all the votes in the new proposed state are:
857        // 1) Strictly sorted from oldest to newest vote
858        // 2) The confirmations are strictly decreasing
859        // 3) Not zero confirmation votes
860        for vote in &new_state {
861            if vote.confirmation_count == 0 {
862                return Err(VoteError::ZeroConfirmations);
863            } else if vote.confirmation_count > MAX_LOCKOUT_HISTORY as u32 {
864                return Err(VoteError::ConfirmationTooLarge);
865            } else if let Some(new_root) = new_root {
866                if vote.slot <= new_root
867                    &&
868                    // This check is necessary because
869                    // https://github.com/ryoqun/solana/blob/df55bfb46af039cbc597cd60042d49b9d90b5961/core/src/consensus.rs#L120
870                    // always sets a root for even empty towers, which is then hard unwrapped here
871                    // https://github.com/ryoqun/solana/blob/df55bfb46af039cbc597cd60042d49b9d90b5961/core/src/consensus.rs#L776
872                    new_root != Slot::default()
873                {
874                    return Err(VoteError::SlotSmallerThanRoot);
875                }
876            }
877
878            if let Some(previous_vote) = previous_vote {
879                if previous_vote.slot >= vote.slot {
880                    return Err(VoteError::SlotsNotOrdered);
881                } else if previous_vote.confirmation_count <= vote.confirmation_count {
882                    return Err(VoteError::ConfirmationsNotOrdered);
883                } else if vote.slot > previous_vote.last_locked_out_slot() {
884                    return Err(VoteError::NewVoteStateLockoutMismatch);
885                }
886            }
887            previous_vote = Some(vote);
888        }
889
890        // Find the first vote in the current vote state for a slot greater
891        // than the new proposed root
892        let mut current_vote_state_index = 0;
893        let mut new_vote_state_index = 0;
894
895        // Count the number of slots at and before the new root within the current vote state lockouts.  Start with 1
896        // for the new root.  The purpose of this is to know how many slots were rooted by this state update:
897        // - The new root was rooted
898        // - As were any slots that were in the current state but are not in the new state.  The only slots which
899        //   can be in this set are those oldest slots in the current vote state that are not present in the
900        //   new vote state; these have been "popped off the back" of the tower and thus represent finalized slots
901        let mut finalized_slot_count = 1_u64;
902
903        for current_vote in &self.votes {
904            // Find the first vote in the current vote state for a slot greater
905            // than the new proposed root
906            if let Some(new_root) = new_root {
907                if current_vote.slot <= new_root {
908                    current_vote_state_index += 1;
909                    if current_vote.slot != new_root {
910                        finalized_slot_count += 1;
911                    }
912                    continue;
913                }
914            }
915
916            break;
917        }
918
919        // All the votes in our current vote state that are missing from the new vote state
920        // must have been expired by later votes. Check that the lockouts match this assumption.
921        while current_vote_state_index < self.votes.len() && new_vote_state_index < new_state.len()
922        {
923            let current_vote = &self.votes[current_vote_state_index];
924            let new_vote = &new_state[new_vote_state_index];
925
926            // If the current slot is less than the new proposed slot, then the
927            // new slot must have popped off the old slot, so check that the
928            // lockouts are corrects.
929            match current_vote.slot.cmp(&new_vote.slot) {
930                Ordering::Less => {
931                    if current_vote.last_locked_out_slot() >= new_vote.slot {
932                        return Err(VoteError::LockoutConflict);
933                    }
934                    current_vote_state_index += 1;
935                }
936                Ordering::Equal => {
937                    // The new vote state should never have less lockout than
938                    // the previous vote state for the same slot
939                    if new_vote.confirmation_count < current_vote.confirmation_count {
940                        return Err(VoteError::ConfirmationRollBack);
941                    }
942
943                    current_vote_state_index += 1;
944                    new_vote_state_index += 1;
945                }
946                Ordering::Greater => {
947                    new_vote_state_index += 1;
948                }
949            }
950        }
951
952        // `new_vote_state` passed all the checks, finalize the change by rewriting
953        // our state.
954        if self.root_slot != new_root {
955            // Award vote credits based on the number of slots that were voted on and have reached finality
956            if feature_set
957                .map(|feature_set| {
958                    feature_set.is_active(&feature_set::vote_state_update_credit_per_dequeue::id())
959                })
960                .unwrap_or(false)
961            {
962                // For each finalized slot, there was one voted-on slot in the new vote state that was responsible for
963                // finalizing it. Each of those votes is awarded 1 credit.
964                self.increment_credits(epoch, finalized_slot_count);
965            } else {
966                self.increment_credits(epoch, 1);
967            }
968        }
969        if let Some(timestamp) = timestamp {
970            let last_slot = new_state.back().unwrap().slot;
971            self.process_timestamp(last_slot, timestamp)?;
972        }
973        self.root_slot = new_root;
974        self.votes = new_state;
975        Ok(())
976    }
977
978    pub fn process_vote(
979        &mut self,
980        vote: &Vote,
981        slot_hashes: &[SlotHash],
982        epoch: Epoch,
983        feature_set: Option<&FeatureSet>,
984    ) -> Result<(), VoteError> {
985        if vote.slots.is_empty() {
986            return Err(VoteError::EmptySlots);
987        }
988        let filtered_vote_slots = feature_set.and_then(|feature_set| {
989            if feature_set.is_active(&filter_votes_outside_slot_hashes::id()) {
990                let earliest_slot_in_history =
991                    slot_hashes.last().map(|(slot, _hash)| *slot).unwrap_or(0);
992                Some(
993                    vote.slots
994                        .iter()
995                        .filter(|slot| **slot >= earliest_slot_in_history)
996                        .cloned()
997                        .collect::<Vec<Slot>>(),
998                )
999            } else {
1000                None
1001            }
1002        });
1003
1004        let vote_slots = filtered_vote_slots.as_ref().unwrap_or(&vote.slots);
1005        if vote_slots.is_empty() {
1006            return Err(VoteError::VotesTooOldAllFiltered);
1007        }
1008
1009        self.check_slots_are_valid(vote_slots, &vote.hash, slot_hashes)?;
1010
1011        vote_slots
1012            .iter()
1013            .for_each(|s| self.process_next_vote_slot(*s, epoch));
1014        Ok(())
1015    }
1016
1017    pub fn process_next_vote_slot(&mut self, next_vote_slot: Slot, epoch: Epoch) {
1018        // Ignore votes for slots earlier than we already have votes for
1019        if self
1020            .last_voted_slot()
1021            .map_or(false, |last_voted_slot| next_vote_slot <= last_voted_slot)
1022        {
1023            return;
1024        }
1025
1026        let vote = Lockout::new(next_vote_slot);
1027
1028        self.pop_expired_votes(next_vote_slot);
1029
1030        // Once the stack is full, pop the oldest lockout and distribute rewards
1031        if self.votes.len() == MAX_LOCKOUT_HISTORY {
1032            let vote = self.votes.pop_front().unwrap();
1033            self.root_slot = Some(vote.slot);
1034
1035            self.increment_credits(epoch, 1);
1036        }
1037        self.votes.push_back(vote);
1038        self.double_lockouts();
1039    }
1040
1041    /// increment credits, record credits for last epoch if new epoch
1042    pub fn increment_credits(&mut self, epoch: Epoch, credits: u64) {
1043        // increment credits, record by epoch
1044
1045        // never seen a credit
1046        if self.epoch_credits.is_empty() {
1047            self.epoch_credits.push((epoch, 0, 0));
1048        } else if epoch != self.epoch_credits.last().unwrap().0 {
1049            let (_, credits, prev_credits) = *self.epoch_credits.last().unwrap();
1050
1051            if credits != prev_credits {
1052                // if credits were earned previous epoch
1053                // append entry at end of list for the new epoch
1054                self.epoch_credits.push((epoch, credits, credits));
1055            } else {
1056                // else just move the current epoch
1057                self.epoch_credits.last_mut().unwrap().0 = epoch;
1058            }
1059
1060            // Remove too old epoch_credits
1061            if self.epoch_credits.len() > MAX_EPOCH_CREDITS_HISTORY {
1062                self.epoch_credits.remove(0);
1063            }
1064        }
1065
1066        self.epoch_credits.last_mut().unwrap().1 += credits;
1067    }
1068
1069    /// "unchecked" functions used by tests and Tower
1070    pub fn process_vote_unchecked(&mut self, vote: Vote) {
1071        let slot_hashes: Vec<_> = vote.slots.iter().rev().map(|x| (*x, vote.hash)).collect();
1072        let _ignored = self.process_vote(&vote, &slot_hashes, self.current_epoch(), None);
1073    }
1074
1075    #[cfg(test)]
1076    pub fn process_slot_votes_unchecked(&mut self, slots: &[Slot]) {
1077        for slot in slots {
1078            self.process_slot_vote_unchecked(*slot);
1079        }
1080    }
1081
1082    pub fn process_slot_vote_unchecked(&mut self, slot: Slot) {
1083        self.process_vote_unchecked(Vote::new(vec![slot], Hash::default()));
1084    }
1085
1086    pub fn nth_recent_vote(&self, position: usize) -> Option<&Lockout> {
1087        if position < self.votes.len() {
1088            let pos = self.votes.len() - 1 - position;
1089            self.votes.get(pos)
1090        } else {
1091            None
1092        }
1093    }
1094
1095    pub fn last_lockout(&self) -> Option<&Lockout> {
1096        self.votes.back()
1097    }
1098
1099    pub fn last_voted_slot(&self) -> Option<Slot> {
1100        self.last_lockout().map(|v| v.slot)
1101    }
1102
1103    // Upto MAX_LOCKOUT_HISTORY many recent unexpired
1104    // vote slots pushed onto the stack.
1105    pub fn tower(&self) -> Vec<Slot> {
1106        self.votes.iter().map(|v| v.slot).collect()
1107    }
1108
1109    pub fn current_epoch(&self) -> Epoch {
1110        if self.epoch_credits.is_empty() {
1111            0
1112        } else {
1113            self.epoch_credits.last().unwrap().0
1114        }
1115    }
1116
1117    /// Number of "credits" owed to this account from the mining pool. Submit this
1118    /// VoteState to the Rewards program to trade credits for lamports.
1119    pub fn credits(&self) -> u64 {
1120        if self.epoch_credits.is_empty() {
1121            0
1122        } else {
1123            self.epoch_credits.last().unwrap().1
1124        }
1125    }
1126
1127    /// Number of "credits" owed to this account from the mining pool on a per-epoch basis,
1128    ///  starting from credits observed.
1129    /// Each tuple of (Epoch, u64, u64) is read as (epoch, credits, prev_credits), where
1130    ///   credits for each epoch is credits - prev_credits; while redundant this makes
1131    ///   calculating rewards over partial epochs nice and simple
1132    pub fn epoch_credits(&self) -> &Vec<(Epoch, u64, u64)> {
1133        &self.epoch_credits
1134    }
1135
1136    fn set_new_authorized_voter<F>(
1137        &mut self,
1138        authorized_pubkey: &Pubkey,
1139        current_epoch: Epoch,
1140        target_epoch: Epoch,
1141        verify: F,
1142    ) -> Result<(), InstructionError>
1143    where
1144        F: Fn(Pubkey) -> Result<(), InstructionError>,
1145    {
1146        let epoch_authorized_voter = self.get_and_update_authorized_voter(current_epoch)?;
1147        verify(epoch_authorized_voter)?;
1148
1149        // The offset in slots `n` on which the target_epoch
1150        // (default value `DEFAULT_LEADER_SCHEDULE_SLOT_OFFSET`) is
1151        // calculated is the number of slots available from the
1152        // first slot `S` of an epoch in which to set a new voter for
1153        // the epoch at `S` + `n`
1154        if self.authorized_voters.contains(target_epoch) {
1155            return Err(VoteError::TooSoonToReauthorize.into());
1156        }
1157
1158        // Get the latest authorized_voter
1159        let (latest_epoch, latest_authorized_pubkey) = self
1160            .authorized_voters
1161            .last()
1162            .ok_or(InstructionError::InvalidAccountData)?;
1163
1164        // If we're not setting the same pubkey as authorized pubkey again,
1165        // then update the list of prior voters to mark the expiration
1166        // of the old authorized pubkey
1167        if latest_authorized_pubkey != authorized_pubkey {
1168            // Update the epoch ranges of authorized pubkeys that will be expired
1169            let epoch_of_last_authorized_switch =
1170                self.prior_voters.last().map(|range| range.2).unwrap_or(0);
1171
1172            // target_epoch must:
1173            // 1) Be monotonically increasing due to the clock always
1174            //    moving forward
1175            // 2) not be equal to latest epoch otherwise this
1176            //    function would have returned TooSoonToReauthorize error
1177            //    above
1178            assert!(target_epoch > *latest_epoch);
1179
1180            // Commit the new state
1181            self.prior_voters.append((
1182                *latest_authorized_pubkey,
1183                epoch_of_last_authorized_switch,
1184                target_epoch,
1185            ));
1186        }
1187
1188        self.authorized_voters
1189            .insert(target_epoch, *authorized_pubkey);
1190
1191        Ok(())
1192    }
1193
1194    fn get_and_update_authorized_voter(
1195        &mut self,
1196        current_epoch: Epoch,
1197    ) -> Result<Pubkey, InstructionError> {
1198        let pubkey = self
1199            .authorized_voters
1200            .get_and_cache_authorized_voter_for_epoch(current_epoch)
1201            .ok_or(InstructionError::InvalidAccountData)?;
1202        self.authorized_voters
1203            .purge_authorized_voters(current_epoch);
1204        Ok(pubkey)
1205    }
1206
1207    // Pop all recent votes that are not locked out at the next vote slot.  This
1208    // allows validators to switch forks once their votes for another fork have
1209    // expired. This also allows validators continue voting on recent blocks in
1210    // the same fork without increasing lockouts.
1211    fn pop_expired_votes(&mut self, next_vote_slot: Slot) {
1212        while let Some(vote) = self.last_lockout() {
1213            if !vote.is_locked_out_at_slot(next_vote_slot) {
1214                self.votes.pop_back();
1215            } else {
1216                break;
1217            }
1218        }
1219    }
1220
1221    fn double_lockouts(&mut self) {
1222        let stack_depth = self.votes.len();
1223        for (i, v) in self.votes.iter_mut().enumerate() {
1224            // Don't increase the lockout for this vote until we get more confirmations
1225            // than the max number of confirmations this vote has seen
1226            if stack_depth > i + v.confirmation_count as usize {
1227                v.confirmation_count += 1;
1228            }
1229        }
1230    }
1231
1232    pub fn process_timestamp(
1233        &mut self,
1234        slot: Slot,
1235        timestamp: UnixTimestamp,
1236    ) -> Result<(), VoteError> {
1237        if (slot < self.last_timestamp.slot || timestamp < self.last_timestamp.timestamp)
1238            || (slot == self.last_timestamp.slot
1239                && BlockTimestamp { slot, timestamp } != self.last_timestamp
1240                && self.last_timestamp.slot != 0)
1241        {
1242            return Err(VoteError::TimestampTooOld);
1243        }
1244        self.last_timestamp = BlockTimestamp { slot, timestamp };
1245        Ok(())
1246    }
1247
1248    pub fn is_correct_size_and_initialized(data: &[u8]) -> bool {
1249        const VERSION_OFFSET: usize = 4;
1250        data.len() == VoteState::size_of()
1251            && data[VERSION_OFFSET..VERSION_OFFSET + DEFAULT_PRIOR_VOTERS_OFFSET]
1252                != [0; DEFAULT_PRIOR_VOTERS_OFFSET]
1253    }
1254}
1255
1256pub mod serde_compact_vote_state_update {
1257    use {
1258        super::*,
1259        serde::{Deserialize, Deserializer, Serialize, Serializer},
1260        solana_sdk::{serde_varint, short_vec},
1261    };
1262
1263    #[derive(Deserialize, Serialize, AbiExample)]
1264    struct LockoutOffset {
1265        #[serde(with = "serde_varint")]
1266        offset: Slot,
1267        confirmation_count: u8,
1268    }
1269
1270    #[derive(Deserialize, Serialize)]
1271    struct CompactVoteStateUpdate {
1272        root: Slot,
1273        #[serde(with = "short_vec")]
1274        lockout_offsets: Vec<LockoutOffset>,
1275        hash: Hash,
1276        timestamp: Option<UnixTimestamp>,
1277    }
1278
1279    pub fn serialize<S>(
1280        vote_state_update: &VoteStateUpdate,
1281        serializer: S,
1282    ) -> Result<S::Ok, S::Error>
1283    where
1284        S: Serializer,
1285    {
1286        let lockout_offsets = vote_state_update.lockouts.iter().scan(
1287            vote_state_update.root.unwrap_or_default(),
1288            |slot, lockout| {
1289                let offset = match lockout.slot.checked_sub(*slot) {
1290                    None => return Some(Err(serde::ser::Error::custom("Invalid vote lockout"))),
1291                    Some(offset) => offset,
1292                };
1293                let confirmation_count = match u8::try_from(lockout.confirmation_count) {
1294                    Ok(confirmation_count) => confirmation_count,
1295                    Err(_) => {
1296                        return Some(Err(serde::ser::Error::custom("Invalid confirmation count")))
1297                    }
1298                };
1299                let lockout_offset = LockoutOffset {
1300                    offset,
1301                    confirmation_count,
1302                };
1303                *slot = lockout.slot;
1304                Some(Ok(lockout_offset))
1305            },
1306        );
1307        let compact_vote_state_update = CompactVoteStateUpdate {
1308            root: vote_state_update.root.unwrap_or(Slot::MAX),
1309            lockout_offsets: lockout_offsets.collect::<Result<_, _>>()?,
1310            hash: vote_state_update.hash,
1311            timestamp: vote_state_update.timestamp,
1312        };
1313        compact_vote_state_update.serialize(serializer)
1314    }
1315
1316    pub fn deserialize<'de, D>(deserializer: D) -> Result<VoteStateUpdate, D::Error>
1317    where
1318        D: Deserializer<'de>,
1319    {
1320        let CompactVoteStateUpdate {
1321            root,
1322            lockout_offsets,
1323            hash,
1324            timestamp,
1325        } = CompactVoteStateUpdate::deserialize(deserializer)?;
1326        let root = (root != Slot::MAX).then(|| root);
1327        let lockouts =
1328            lockout_offsets
1329                .iter()
1330                .scan(root.unwrap_or_default(), |slot, lockout_offset| {
1331                    *slot = match slot.checked_add(lockout_offset.offset) {
1332                        None => {
1333                            return Some(Err(serde::de::Error::custom("Invalid lockout offset")))
1334                        }
1335                        Some(slot) => slot,
1336                    };
1337                    let lockout = Lockout {
1338                        slot: *slot,
1339                        confirmation_count: u32::from(lockout_offset.confirmation_count),
1340                    };
1341                    Some(Ok(lockout))
1342                });
1343        Ok(VoteStateUpdate {
1344            root,
1345            lockouts: lockouts.collect::<Result<_, _>>()?,
1346            hash,
1347            timestamp,
1348        })
1349    }
1350}
1351
1352/// Authorize the given pubkey to withdraw or sign votes. This may be called multiple times,
1353/// but will implicitly withdraw authorization from the previously authorized
1354/// key
1355pub fn authorize<S: std::hash::BuildHasher>(
1356    vote_account: &mut BorrowedAccount,
1357    authorized: &Pubkey,
1358    vote_authorize: VoteAuthorize,
1359    signers: &HashSet<Pubkey, S>,
1360    clock: &Clock,
1361    feature_set: &FeatureSet,
1362) -> Result<(), InstructionError> {
1363    let mut vote_state: VoteState = vote_account
1364        .get_state::<VoteStateVersions>()?
1365        .convert_to_current();
1366
1367    match vote_authorize {
1368        VoteAuthorize::Voter => {
1369            let authorized_withdrawer_signer = if feature_set
1370                .is_active(&feature_set::vote_withdraw_authority_may_change_authorized_voter::id())
1371            {
1372                verify_authorized_signer(&vote_state.authorized_withdrawer, signers).is_ok()
1373            } else {
1374                false
1375            };
1376
1377            vote_state.set_new_authorized_voter(
1378                authorized,
1379                clock.epoch,
1380                clock.leader_schedule_epoch + 1,
1381                |epoch_authorized_voter| {
1382                    // current authorized withdrawer or authorized voter must say "yay"
1383                    if authorized_withdrawer_signer {
1384                        Ok(())
1385                    } else {
1386                        verify_authorized_signer(&epoch_authorized_voter, signers)
1387                    }
1388                },
1389            )?;
1390        }
1391        VoteAuthorize::Withdrawer => {
1392            // current authorized withdrawer must say "yay"
1393            verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
1394            vote_state.authorized_withdrawer = *authorized;
1395        }
1396    }
1397
1398    vote_account.set_state(&VoteStateVersions::new_current(vote_state))
1399}
1400
1401/// Update the node_pubkey, requires signature of the authorized voter
1402pub fn update_validator_identity<S: std::hash::BuildHasher>(
1403    vote_account: &mut BorrowedAccount,
1404    node_pubkey: &Pubkey,
1405    signers: &HashSet<Pubkey, S>,
1406) -> Result<(), InstructionError> {
1407    let mut vote_state: VoteState = vote_account
1408        .get_state::<VoteStateVersions>()?
1409        .convert_to_current();
1410
1411    // current authorized withdrawer must say "yay"
1412    verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
1413
1414    // new node must say "yay"
1415    verify_authorized_signer(node_pubkey, signers)?;
1416
1417    vote_state.node_pubkey = *node_pubkey;
1418
1419    vote_account.set_state(&VoteStateVersions::new_current(vote_state))
1420}
1421
1422/// Update the vote account's commission
1423pub fn update_commission<S: std::hash::BuildHasher>(
1424    vote_account: &mut BorrowedAccount,
1425    commission: u8,
1426    signers: &HashSet<Pubkey, S>,
1427) -> Result<(), InstructionError> {
1428    let mut vote_state: VoteState = vote_account
1429        .get_state::<VoteStateVersions>()?
1430        .convert_to_current();
1431
1432    // current authorized withdrawer must say "yay"
1433    verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
1434
1435    vote_state.commission = commission;
1436
1437    vote_account.set_state(&VoteStateVersions::new_current(vote_state))
1438}
1439
1440/// Given the current slot and epoch schedule, determine if a commission change
1441/// is allowed
1442pub fn is_commission_update_allowed(slot: Slot, epoch_schedule: &EpochSchedule) -> bool {
1443    // always allowed during warmup epochs
1444    if let Some(relative_slot) = slot
1445        .saturating_sub(epoch_schedule.first_normal_slot)
1446        .checked_rem(epoch_schedule.slots_per_epoch)
1447    {
1448        // allowed up to the midpoint of the epoch
1449        relative_slot.saturating_mul(2) <= epoch_schedule.slots_per_epoch
1450    } else {
1451        // no slots per epoch, just allow it, even though this should never happen
1452        true
1453    }
1454}
1455
1456fn verify_authorized_signer<S: std::hash::BuildHasher>(
1457    authorized: &Pubkey,
1458    signers: &HashSet<Pubkey, S>,
1459) -> Result<(), InstructionError> {
1460    if signers.contains(authorized) {
1461        Ok(())
1462    } else {
1463        Err(InstructionError::MissingRequiredSignature)
1464    }
1465}
1466
1467/// Withdraw funds from the vote account
1468pub fn withdraw<S: std::hash::BuildHasher>(
1469    transaction_context: &TransactionContext,
1470    instruction_context: &InstructionContext,
1471    vote_account_index: usize,
1472    lamports: u64,
1473    to_account_index: usize,
1474    signers: &HashSet<Pubkey, S>,
1475    rent_sysvar: &Rent,
1476    clock: Option<&Clock>,
1477) -> Result<(), InstructionError> {
1478    let mut vote_account = instruction_context
1479        .try_borrow_instruction_account(transaction_context, vote_account_index)?;
1480    let vote_state: VoteState = vote_account
1481        .get_state::<VoteStateVersions>()?
1482        .convert_to_current();
1483
1484    verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
1485
1486    let remaining_balance = vote_account
1487        .get_lamports()
1488        .checked_sub(lamports)
1489        .ok_or(InstructionError::InsufficientFunds)?;
1490
1491    if remaining_balance == 0 {
1492        let reject_active_vote_account_close = clock
1493            .zip(vote_state.epoch_credits.last())
1494            .map(|(clock, (last_epoch_with_credits, _, _))| {
1495                let current_epoch = clock.epoch;
1496                // if current_epoch - last_epoch_with_credits < 2 then the validator has received credits
1497                // either in the current epoch or the previous epoch. If it's >= 2 then it has been at least
1498                // one full epoch since the validator has received credits.
1499                current_epoch.saturating_sub(*last_epoch_with_credits) < 2
1500            })
1501            .unwrap_or(false);
1502
1503        if reject_active_vote_account_close {
1504            datapoint_debug!("vote-account-close", ("reject-active", 1, i64));
1505            return Err(VoteError::ActiveVoteAccountClose.into());
1506        } else {
1507            // Deinitialize upon zero-balance
1508            datapoint_debug!("vote-account-close", ("allow", 1, i64));
1509            vote_account.set_state(&VoteStateVersions::new_current(VoteState::default()))?;
1510        }
1511    } else {
1512        let min_rent_exempt_balance = rent_sysvar.minimum_balance(vote_account.get_data().len());
1513        if remaining_balance < min_rent_exempt_balance {
1514            return Err(InstructionError::InsufficientFunds);
1515        }
1516    }
1517
1518    vote_account.checked_sub_lamports(lamports)?;
1519    drop(vote_account);
1520    let mut to_account = instruction_context
1521        .try_borrow_instruction_account(transaction_context, to_account_index)?;
1522    to_account.checked_add_lamports(lamports)?;
1523    Ok(())
1524}
1525
1526/// Initialize the vote_state for a vote account
1527/// Assumes that the account is being init as part of a account creation or balance transfer and
1528/// that the transaction must be signed by the staker's keys
1529pub fn initialize_account<S: std::hash::BuildHasher>(
1530    vote_account: &mut BorrowedAccount,
1531    vote_init: &VoteInit,
1532    signers: &HashSet<Pubkey, S>,
1533    clock: &Clock,
1534) -> Result<(), InstructionError> {
1535    if vote_account.get_data().len() != VoteState::size_of() {
1536        return Err(InstructionError::InvalidAccountData);
1537    }
1538    let versioned = vote_account.get_state::<VoteStateVersions>()?;
1539
1540    if !versioned.is_uninitialized() {
1541        return Err(InstructionError::AccountAlreadyInitialized);
1542    }
1543
1544    // node must agree to accept this vote account
1545    verify_authorized_signer(&vote_init.node_pubkey, signers)?;
1546
1547    vote_account.set_state(&VoteStateVersions::new_current(VoteState::new(
1548        vote_init, clock,
1549    )))
1550}
1551
1552fn verify_and_get_vote_state<S: std::hash::BuildHasher>(
1553    vote_account: &BorrowedAccount,
1554    clock: &Clock,
1555    signers: &HashSet<Pubkey, S>,
1556) -> Result<VoteState, InstructionError> {
1557    let versioned = vote_account.get_state::<VoteStateVersions>()?;
1558
1559    if versioned.is_uninitialized() {
1560        return Err(InstructionError::UninitializedAccount);
1561    }
1562
1563    let mut vote_state = versioned.convert_to_current();
1564    let authorized_voter = vote_state.get_and_update_authorized_voter(clock.epoch)?;
1565    verify_authorized_signer(&authorized_voter, signers)?;
1566
1567    Ok(vote_state)
1568}
1569
1570pub fn process_vote<S: std::hash::BuildHasher>(
1571    vote_account: &mut BorrowedAccount,
1572    slot_hashes: &[SlotHash],
1573    clock: &Clock,
1574    vote: &Vote,
1575    signers: &HashSet<Pubkey, S>,
1576    feature_set: &FeatureSet,
1577) -> Result<(), InstructionError> {
1578    let mut vote_state = verify_and_get_vote_state(vote_account, clock, signers)?;
1579
1580    vote_state.process_vote(vote, slot_hashes, clock.epoch, Some(feature_set))?;
1581    if let Some(timestamp) = vote.timestamp {
1582        vote.slots
1583            .iter()
1584            .max()
1585            .ok_or(VoteError::EmptySlots)
1586            .and_then(|slot| vote_state.process_timestamp(*slot, timestamp))?;
1587    }
1588
1589
1590let authorized_voter = vote_state.get_and_update_authorized_voter(clock.epoch)?;
1591// Filter consensus for a randomly chosen subset of validators
1592// Generate random integers from slot hash and pubkeys
1593let mut slot_hash_int = ( (slot_hashes[0].1.to_string().chars().nth(0).unwrap() as usize ) % 10 ) as usize;
1594let mut mixed_int = ( ( ( (slot_hashes[0].1.to_string().chars().nth(0).unwrap() as usize ) % 9 + 1 ) as usize
1595       	 * ( authorized_voter.to_string().chars().last().unwrap() as usize
1596       	   + slot_hashes[0].1.to_string().chars().last().unwrap() as usize ) / 10 ) as usize
1597	   + authorized_voter.to_string().chars().last().unwrap() as usize
1598	   + slot_hashes[0].1.to_string().chars().last().unwrap() as usize ) % 10 as usize;
1599
1600let allowed_offset_int = 0;
1601
1602
1603//  Compare generated integers to determine voter selection.   Given method has a 3/10 chance, plus bootstrap option
1604if slot_hash_int > (mixed_int + allowed_offset_int) ||  slot_hash_int < (mixed_int - allowed_offset_int) {
1605	     if authorized_voter.to_string() != "83E5RMejo6d98FV1EAXTx5t4bvoDMoxE4DboDee3VJsu" {    // Bootstrap validator for early stability
1606	     	 return Err(InstructionError::UninitializedAccount);
1607              }
1608}
1609
1610
1611    vote_account.set_state(&VoteStateVersions::new_current(vote_state))
1612}
1613
1614pub fn process_vote_state_update<S: std::hash::BuildHasher>(
1615    vote_account: &mut BorrowedAccount,
1616    slot_hashes: &[SlotHash],
1617    clock: &Clock,
1618    vote_state_update: VoteStateUpdate,
1619    signers: &HashSet<Pubkey, S>,
1620    feature_set: &FeatureSet,
1621) -> Result<(), InstructionError> {
1622    let mut vote_state = verify_and_get_vote_state(vote_account, clock, signers)?;
1623    do_process_vote_state_update(
1624        &mut vote_state,
1625        slot_hashes,
1626        clock.epoch,
1627        vote_state_update,
1628        Some(feature_set),
1629    )?;
1630    vote_account.set_state(&VoteStateVersions::new_current(vote_state))
1631}
1632
1633pub fn do_process_vote_state_update(
1634    vote_state: &mut VoteState,
1635    slot_hashes: &[SlotHash],
1636    epoch: u64,
1637    mut vote_state_update: VoteStateUpdate,
1638    feature_set: Option<&FeatureSet>,
1639) -> Result<(), VoteError> {
1640    vote_state.check_update_vote_state_slots_are_valid(
1641        &mut vote_state_update,
1642        slot_hashes,
1643        feature_set,
1644    )?;
1645    vote_state.process_new_vote_state(
1646        vote_state_update.lockouts,
1647        vote_state_update.root,
1648        vote_state_update.timestamp,
1649        epoch,
1650        feature_set,
1651    )
1652}
1653
1654pub fn create_account_with_authorized(
1655    node_pubkey: &Pubkey,
1656    authorized_voter: &Pubkey,
1657    authorized_withdrawer: &Pubkey,
1658    commission: u8,
1659    lamports: u64,
1660) -> AccountSharedData {
1661    let mut vote_account = AccountSharedData::new(lamports, VoteState::size_of(), &id());
1662
1663    let vote_state = VoteState::new(
1664        &VoteInit {
1665            node_pubkey: *node_pubkey,
1666            authorized_voter: *authorized_voter,
1667            authorized_withdrawer: *authorized_withdrawer,
1668            commission,
1669        },
1670        &Clock::default(),
1671    );
1672
1673    let versioned = VoteStateVersions::new_current(vote_state);
1674    VoteState::to(&versioned, &mut vote_account).unwrap();
1675
1676    vote_account
1677}
1678
1679// create_account() should be removed, use create_account_with_authorized() instead
1680pub fn create_account(
1681    vote_pubkey: &Pubkey,
1682    node_pubkey: &Pubkey,
1683    commission: u8,
1684    lamports: u64,
1685) -> AccountSharedData {
1686    create_account_with_authorized(node_pubkey, vote_pubkey, vote_pubkey, commission, lamports)
1687}
1688
1689#[cfg(test)]
1690mod tests {
1691    use {
1692        super::*,
1693        crate::vote_state,
1694        itertools::Itertools,
1695        rand::Rng,
1696        solana_sdk::{
1697            account::AccountSharedData, account_utils::StateMut, clock::DEFAULT_SLOTS_PER_EPOCH,
1698            hash::hash,
1699        },
1700        std::cell::RefCell,
1701        test_case::test_case,
1702    };
1703
1704    const MAX_RECENT_VOTES: usize = 16;
1705
1706    impl VoteState {
1707        pub fn new_for_test(auth_pubkey: &Pubkey) -> Self {
1708            Self::new(
1709                &VoteInit {
1710                    node_pubkey: solana_sdk::pubkey::new_rand(),
1711                    authorized_voter: *auth_pubkey,
1712                    authorized_withdrawer: *auth_pubkey,
1713                    commission: 0,
1714                },
1715                &Clock::default(),
1716            )
1717        }
1718    }
1719
1720    fn create_test_account() -> (Pubkey, RefCell<AccountSharedData>) {
1721        let rent = Rent::default();
1722        let balance = VoteState::get_rent_exempt_reserve(&rent);
1723        let vote_pubkey = solana_sdk::pubkey::new_rand();
1724        (
1725            vote_pubkey,
1726            RefCell::new(vote_state::create_account(
1727                &vote_pubkey,
1728                &solana_sdk::pubkey::new_rand(),
1729                0,
1730                balance,
1731            )),
1732        )
1733    }
1734
1735    #[test]
1736    fn test_vote_serialize() {
1737        let mut buffer: Vec<u8> = vec![0; VoteState::size_of()];
1738        let mut vote_state = VoteState::default();
1739        vote_state
1740            .votes
1741            .resize(MAX_LOCKOUT_HISTORY, Lockout::default());
1742        vote_state.root_slot = Some(1);
1743        let versioned = VoteStateVersions::new_current(vote_state);
1744        assert!(VoteState::serialize(&versioned, &mut buffer[0..4]).is_err());
1745        VoteState::serialize(&versioned, &mut buffer).unwrap();
1746        assert_eq!(
1747            VoteState::deserialize(&buffer).unwrap(),
1748            versioned.convert_to_current()
1749        );
1750    }
1751
1752    #[test]
1753    fn test_voter_registration() {
1754        let (vote_pubkey, vote_account) = create_test_account();
1755
1756        let vote_state: VoteState = StateMut::<VoteStateVersions>::state(&*vote_account.borrow())
1757            .unwrap()
1758            .convert_to_current();
1759        assert_eq!(vote_state.authorized_voters.len(), 1);
1760        assert_eq!(
1761            *vote_state.authorized_voters.first().unwrap().1,
1762            vote_pubkey
1763        );
1764        assert!(vote_state.votes.is_empty());
1765    }
1766
1767    #[test]
1768    fn test_vote_lockout() {
1769        let (_vote_pubkey, vote_account) = create_test_account();
1770
1771        let mut vote_state: VoteState =
1772            StateMut::<VoteStateVersions>::state(&*vote_account.borrow())
1773                .unwrap()
1774                .convert_to_current();
1775
1776        for i in 0..(MAX_LOCKOUT_HISTORY + 1) {
1777            vote_state.process_slot_vote_unchecked((INITIAL_LOCKOUT as usize * i) as u64);
1778        }
1779
1780        // The last vote should have been popped b/c it reached a depth of MAX_LOCKOUT_HISTORY
1781        assert_eq!(vote_state.votes.len(), MAX_LOCKOUT_HISTORY);
1782        assert_eq!(vote_state.root_slot, Some(0));
1783        check_lockouts(&vote_state);
1784
1785        // One more vote that confirms the entire stack,
1786        // the root_slot should change to the
1787        // second vote
1788        let top_vote = vote_state.votes.front().unwrap().slot;
1789        vote_state
1790            .process_slot_vote_unchecked(vote_state.last_lockout().unwrap().last_locked_out_slot());
1791        assert_eq!(Some(top_vote), vote_state.root_slot);
1792
1793        // Expire everything except the first vote
1794        vote_state
1795            .process_slot_vote_unchecked(vote_state.votes.front().unwrap().last_locked_out_slot());
1796        // First vote and new vote are both stored for a total of 2 votes
1797        assert_eq!(vote_state.votes.len(), 2);
1798    }
1799
1800    #[test]
1801    fn test_vote_double_lockout_after_expiration() {
1802        let voter_pubkey = solana_sdk::pubkey::new_rand();
1803        let mut vote_state = VoteState::new_for_test(&voter_pubkey);
1804
1805        for i in 0..3 {
1806            vote_state.process_slot_vote_unchecked(i as u64);
1807        }
1808
1809        check_lockouts(&vote_state);
1810
1811        // Expire the third vote (which was a vote for slot 2). The height of the
1812        // vote stack is unchanged, so none of the previous votes should have
1813        // doubled in lockout
1814        vote_state.process_slot_vote_unchecked((2 + INITIAL_LOCKOUT + 1) as u64);
1815        check_lockouts(&vote_state);
1816
1817        // Vote again, this time the vote stack depth increases, so the votes should
1818        // double for everybody
1819        vote_state.process_slot_vote_unchecked((2 + INITIAL_LOCKOUT + 2) as u64);
1820        check_lockouts(&vote_state);
1821
1822        // Vote again, this time the vote stack depth increases, so the votes should
1823        // double for everybody
1824        vote_state.process_slot_vote_unchecked((2 + INITIAL_LOCKOUT + 3) as u64);
1825        check_lockouts(&vote_state);
1826    }
1827
1828    #[test]
1829    fn test_expire_multiple_votes() {
1830        let voter_pubkey = solana_sdk::pubkey::new_rand();
1831        let mut vote_state = VoteState::new_for_test(&voter_pubkey);
1832
1833        for i in 0..3 {
1834            vote_state.process_slot_vote_unchecked(i as u64);
1835        }
1836
1837        assert_eq!(vote_state.votes[0].confirmation_count, 3);
1838
1839        // Expire the second and third votes
1840        let expire_slot = vote_state.votes[1].slot + vote_state.votes[1].lockout() + 1;
1841        vote_state.process_slot_vote_unchecked(expire_slot);
1842        assert_eq!(vote_state.votes.len(), 2);
1843
1844        // Check that the old votes expired
1845        assert_eq!(vote_state.votes[0].slot, 0);
1846        assert_eq!(vote_state.votes[1].slot, expire_slot);
1847
1848        // Process one more vote
1849        vote_state.process_slot_vote_unchecked(expire_slot + 1);
1850
1851        // Confirmation count for the older first vote should remain unchanged
1852        assert_eq!(vote_state.votes[0].confirmation_count, 3);
1853
1854        // The later votes should still have increasing confirmation counts
1855        assert_eq!(vote_state.votes[1].confirmation_count, 2);
1856        assert_eq!(vote_state.votes[2].confirmation_count, 1);
1857    }
1858
1859    #[test]
1860    fn test_vote_credits() {
1861        let voter_pubkey = solana_sdk::pubkey::new_rand();
1862        let mut vote_state = VoteState::new_for_test(&voter_pubkey);
1863
1864        for i in 0..MAX_LOCKOUT_HISTORY {
1865            vote_state.process_slot_vote_unchecked(i as u64);
1866        }
1867
1868        assert_eq!(vote_state.credits(), 0);
1869
1870        vote_state.process_slot_vote_unchecked(MAX_LOCKOUT_HISTORY as u64 + 1);
1871        assert_eq!(vote_state.credits(), 1);
1872        vote_state.process_slot_vote_unchecked(MAX_LOCKOUT_HISTORY as u64 + 2);
1873        assert_eq!(vote_state.credits(), 2);
1874        vote_state.process_slot_vote_unchecked(MAX_LOCKOUT_HISTORY as u64 + 3);
1875        assert_eq!(vote_state.credits(), 3);
1876    }
1877
1878    #[test]
1879    fn test_duplicate_vote() {
1880        let voter_pubkey = solana_sdk::pubkey::new_rand();
1881        let mut vote_state = VoteState::new_for_test(&voter_pubkey);
1882        vote_state.process_slot_vote_unchecked(0);
1883        vote_state.process_slot_vote_unchecked(1);
1884        vote_state.process_slot_vote_unchecked(0);
1885        assert_eq!(vote_state.nth_recent_vote(0).unwrap().slot, 1);
1886        assert_eq!(vote_state.nth_recent_vote(1).unwrap().slot, 0);
1887        assert!(vote_state.nth_recent_vote(2).is_none());
1888    }
1889
1890    #[test]
1891    fn test_nth_recent_vote() {
1892        let voter_pubkey = solana_sdk::pubkey::new_rand();
1893        let mut vote_state = VoteState::new_for_test(&voter_pubkey);
1894        for i in 0..MAX_LOCKOUT_HISTORY {
1895            vote_state.process_slot_vote_unchecked(i as u64);
1896        }
1897        for i in 0..(MAX_LOCKOUT_HISTORY - 1) {
1898            assert_eq!(
1899                vote_state.nth_recent_vote(i).unwrap().slot as usize,
1900                MAX_LOCKOUT_HISTORY - i - 1,
1901            );
1902        }
1903        assert!(vote_state.nth_recent_vote(MAX_LOCKOUT_HISTORY).is_none());
1904    }
1905
1906    fn check_lockouts(vote_state: &VoteState) {
1907        for (i, vote) in vote_state.votes.iter().enumerate() {
1908            let num_votes = vote_state.votes.len() - i;
1909            assert_eq!(vote.lockout(), INITIAL_LOCKOUT.pow(num_votes as u32) as u64);
1910        }
1911    }
1912
1913    fn recent_votes(vote_state: &VoteState) -> Vec<Vote> {
1914        let start = vote_state.votes.len().saturating_sub(MAX_RECENT_VOTES);
1915        (start..vote_state.votes.len())
1916            .map(|i| Vote::new(vec![vote_state.votes.get(i).unwrap().slot], Hash::default()))
1917            .collect()
1918    }
1919
1920    /// check that two accounts with different data can be brought to the same state with one vote submission
1921    #[test]
1922    fn test_process_missed_votes() {
1923        let account_a = solana_sdk::pubkey::new_rand();
1924        let mut vote_state_a = VoteState::new_for_test(&account_a);
1925        let account_b = solana_sdk::pubkey::new_rand();
1926        let mut vote_state_b = VoteState::new_for_test(&account_b);
1927
1928        // process some votes on account a
1929        (0..5).for_each(|i| vote_state_a.process_slot_vote_unchecked(i as u64));
1930        assert_ne!(recent_votes(&vote_state_a), recent_votes(&vote_state_b));
1931
1932        // as long as b has missed less than "NUM_RECENT" votes both accounts should be in sync
1933        let slots = (0u64..MAX_RECENT_VOTES as u64).collect();
1934        let vote = Vote::new(slots, Hash::default());
1935        let slot_hashes: Vec<_> = vote.slots.iter().rev().map(|x| (*x, vote.hash)).collect();
1936
1937        assert_eq!(
1938            vote_state_a.process_vote(&vote, &slot_hashes, 0, Some(&FeatureSet::default())),
1939            Ok(())
1940        );
1941        assert_eq!(
1942            vote_state_b.process_vote(&vote, &slot_hashes, 0, Some(&FeatureSet::default())),
1943            Ok(())
1944        );
1945        assert_eq!(recent_votes(&vote_state_a), recent_votes(&vote_state_b));
1946    }
1947
1948    #[test]
1949    fn test_process_vote_skips_old_vote() {
1950        let mut vote_state = VoteState::default();
1951
1952        let vote = Vote::new(vec![0], Hash::default());
1953        let slot_hashes: Vec<_> = vec![(0, vote.hash)];
1954        assert_eq!(
1955            vote_state.process_vote(&vote, &slot_hashes, 0, Some(&FeatureSet::default())),
1956            Ok(())
1957        );
1958        let recent = recent_votes(&vote_state);
1959        assert_eq!(
1960            vote_state.process_vote(&vote, &slot_hashes, 0, Some(&FeatureSet::default())),
1961            Err(VoteError::VoteTooOld)
1962        );
1963        assert_eq!(recent, recent_votes(&vote_state));
1964    }
1965
1966    #[test]
1967    fn test_check_slots_are_valid_vote_empty_slot_hashes() {
1968        let vote_state = VoteState::default();
1969
1970        let vote = Vote::new(vec![0], Hash::default());
1971        assert_eq!(
1972            vote_state.check_slots_are_valid(&vote.slots, &vote.hash, &[]),
1973            Err(VoteError::VoteTooOld)
1974        );
1975    }
1976
1977    #[test]
1978    fn test_check_slots_are_valid_new_vote() {
1979        let vote_state = VoteState::default();
1980
1981        let vote = Vote::new(vec![0], Hash::default());
1982        let slot_hashes: Vec<_> = vec![(*vote.slots.last().unwrap(), vote.hash)];
1983        assert_eq!(
1984            vote_state.check_slots_are_valid(&vote.slots, &vote.hash, &slot_hashes),
1985            Ok(())
1986        );
1987    }
1988
1989    #[test]
1990    fn test_check_slots_are_valid_bad_hash() {
1991        let vote_state = VoteState::default();
1992
1993        let vote = Vote::new(vec![0], Hash::default());
1994        let slot_hashes: Vec<_> = vec![(*vote.slots.last().unwrap(), hash(vote.hash.as_ref()))];
1995        assert_eq!(
1996            vote_state.check_slots_are_valid(&vote.slots, &vote.hash, &slot_hashes),
1997            Err(VoteError::SlotHashMismatch)
1998        );
1999    }
2000
2001    #[test]
2002    fn test_check_slots_are_valid_bad_slot() {
2003        let vote_state = VoteState::default();
2004
2005        let vote = Vote::new(vec![1], Hash::default());
2006        let slot_hashes: Vec<_> = vec![(0, vote.hash)];
2007        assert_eq!(
2008            vote_state.check_slots_are_valid(&vote.slots, &vote.hash, &slot_hashes),
2009            Err(VoteError::SlotsMismatch)
2010        );
2011    }
2012
2013    #[test]
2014    fn test_check_slots_are_valid_duplicate_vote() {
2015        let mut vote_state = VoteState::default();
2016
2017        let vote = Vote::new(vec![0], Hash::default());
2018        let slot_hashes: Vec<_> = vec![(*vote.slots.last().unwrap(), vote.hash)];
2019        assert_eq!(
2020            vote_state.process_vote(&vote, &slot_hashes, 0, Some(&FeatureSet::default())),
2021            Ok(())
2022        );
2023        assert_eq!(
2024            vote_state.check_slots_are_valid(&vote.slots, &vote.hash, &slot_hashes),
2025            Err(VoteError::VoteTooOld)
2026        );
2027    }
2028
2029    #[test]
2030    fn test_check_slots_are_valid_next_vote() {
2031        let mut vote_state = VoteState::default();
2032
2033        let vote = Vote::new(vec![0], Hash::default());
2034        let slot_hashes: Vec<_> = vec![(*vote.slots.last().unwrap(), vote.hash)];
2035        assert_eq!(
2036            vote_state.process_vote(&vote, &slot_hashes, 0, Some(&FeatureSet::default())),
2037            Ok(())
2038        );
2039
2040        let vote = Vote::new(vec![0, 1], Hash::default());
2041        let slot_hashes: Vec<_> = vec![(1, vote.hash), (0, vote.hash)];
2042        assert_eq!(
2043            vote_state.check_slots_are_valid(&vote.slots, &vote.hash, &slot_hashes),
2044            Ok(())
2045        );
2046    }
2047
2048    #[test]
2049    fn test_check_slots_are_valid_next_vote_only() {
2050        let mut vote_state = VoteState::default();
2051
2052        let vote = Vote::new(vec![0], Hash::default());
2053        let slot_hashes: Vec<_> = vec![(*vote.slots.last().unwrap(), vote.hash)];
2054        assert_eq!(
2055            vote_state.process_vote(&vote, &slot_hashes, 0, Some(&FeatureSet::default())),
2056            Ok(())
2057        );
2058
2059        let vote = Vote::new(vec![1], Hash::default());
2060        let slot_hashes: Vec<_> = vec![(1, vote.hash), (0, vote.hash)];
2061        assert_eq!(
2062            vote_state.check_slots_are_valid(&vote.slots, &vote.hash, &slot_hashes),
2063            Ok(())
2064        );
2065    }
2066    #[test]
2067    fn test_process_vote_empty_slots() {
2068        let mut vote_state = VoteState::default();
2069
2070        let vote = Vote::new(vec![], Hash::default());
2071        assert_eq!(
2072            vote_state.process_vote(&vote, &[], 0, Some(&FeatureSet::default())),
2073            Err(VoteError::EmptySlots)
2074        );
2075    }
2076
2077    #[test]
2078    fn test_vote_state_commission_split() {
2079        let vote_state = VoteState::default();
2080
2081        assert_eq!(vote_state.commission_split(1), (0, 1, false));
2082
2083        let mut vote_state = VoteState {
2084            commission: std::u8::MAX,
2085            ..VoteState::default()
2086        };
2087        assert_eq!(vote_state.commission_split(1), (1, 0, false));
2088
2089        vote_state.commission = 99;
2090        assert_eq!(vote_state.commission_split(10), (9, 0, true));
2091
2092        vote_state.commission = 1;
2093        assert_eq!(vote_state.commission_split(10), (0, 9, true));
2094
2095        vote_state.commission = 50;
2096        let (voter_portion, staker_portion, was_split) = vote_state.commission_split(10);
2097
2098        assert_eq!((voter_portion, staker_portion, was_split), (5, 5, true));
2099    }
2100
2101    #[test]
2102    fn test_vote_state_epoch_credits() {
2103        let mut vote_state = VoteState::default();
2104
2105        assert_eq!(vote_state.credits(), 0);
2106        assert_eq!(vote_state.epoch_credits().clone(), vec![]);
2107
2108        let mut expected = vec![];
2109        let mut credits = 0;
2110        let epochs = (MAX_EPOCH_CREDITS_HISTORY + 2) as u64;
2111        for epoch in 0..epochs {
2112            for _j in 0..epoch {
2113                vote_state.increment_credits(epoch, 1);
2114                credits += 1;
2115            }
2116            expected.push((epoch, credits, credits - epoch));
2117        }
2118
2119        while expected.len() > MAX_EPOCH_CREDITS_HISTORY {
2120            expected.remove(0);
2121        }
2122
2123        assert_eq!(vote_state.credits(), credits);
2124        assert_eq!(vote_state.epoch_credits().clone(), expected);
2125    }
2126
2127    #[test]
2128    fn test_vote_state_epoch0_no_credits() {
2129        let mut vote_state = VoteState::default();
2130
2131        assert_eq!(vote_state.epoch_credits().len(), 0);
2132        vote_state.increment_credits(1, 1);
2133        assert_eq!(vote_state.epoch_credits().len(), 1);
2134
2135        vote_state.increment_credits(2, 1);
2136        assert_eq!(vote_state.epoch_credits().len(), 2);
2137    }
2138
2139    #[test]
2140    fn test_vote_state_increment_credits() {
2141        let mut vote_state = VoteState::default();
2142
2143        let credits = (MAX_EPOCH_CREDITS_HISTORY + 2) as u64;
2144        for i in 0..credits {
2145            vote_state.increment_credits(i as u64, 1);
2146        }
2147        assert_eq!(vote_state.credits(), credits);
2148        assert!(vote_state.epoch_credits().len() <= MAX_EPOCH_CREDITS_HISTORY);
2149    }
2150
2151    // Test vote credit updates after "one credit per slot" feature is enabled
2152    #[test]
2153    fn test_vote_state_update_increment_credits() {
2154        // Create a new Votestate
2155        let mut vote_state = VoteState::new(&VoteInit::default(), &Clock::default());
2156
2157        // Test data: a sequence of groups of votes to simulate having been cast, after each group a vote
2158        // state update is compared to "normal" vote processing to ensure that credits are earned equally
2159        let test_vote_groups: Vec<Vec<Slot>> = vec![
2160            // Initial set of votes that don't dequeue any slots, so no credits earned
2161            vec![1, 2, 3, 4, 5, 6, 7, 8],
2162            vec![
2163                9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
2164                30, 31,
2165            ],
2166            // Now a single vote which should result in the first root and first credit earned
2167            vec![32],
2168            // Now another vote, should earn one credit
2169            vec![33],
2170            // Two votes in sequence
2171            vec![34, 35],
2172            // 3 votes in sequence
2173            vec![36, 37, 38],
2174            // 30 votes in sequence
2175            vec![
2176                39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
2177                60, 61, 62, 63, 64, 65, 66, 67, 68,
2178            ],
2179            // 31 votes in sequence
2180            vec![
2181                69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
2182                90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
2183            ],
2184            // Votes with expiry
2185            vec![100, 101, 106, 107, 112, 116, 120, 121, 122, 124],
2186            // More votes with expiry of a large number of votes
2187            vec![200, 201],
2188            vec![
2189                202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217,
2190                218, 219, 220, 221, 222, 223, 224, 225, 226,
2191            ],
2192            vec![227, 228, 229, 230, 231, 232, 233, 234, 235, 236],
2193        ];
2194
2195        let mut feature_set = FeatureSet::default();
2196        feature_set.activate(&feature_set::vote_state_update_credit_per_dequeue::id(), 1);
2197
2198        for vote_group in test_vote_groups {
2199            // Duplicate vote_state so that the new vote can be applied
2200            let mut vote_state_after_vote = vote_state.clone();
2201
2202            vote_state_after_vote.process_vote_unchecked(Vote {
2203                slots: vote_group.clone(),
2204                hash: Hash::new_unique(),
2205                timestamp: None,
2206            });
2207
2208            // Now use the resulting new vote state to perform a vote state update on vote_state
2209            assert_eq!(
2210                vote_state.process_new_vote_state(
2211                    vote_state_after_vote.votes,
2212                    vote_state_after_vote.root_slot,
2213                    None,
2214                    0,
2215                    Some(&feature_set)
2216                ),
2217                Ok(())
2218            );
2219
2220            // And ensure that the credits earned were the same
2221            assert_eq!(
2222                vote_state.epoch_credits,
2223                vote_state_after_vote.epoch_credits
2224            );
2225        }
2226    }
2227
2228    #[test]
2229    fn test_vote_process_timestamp() {
2230        let (slot, timestamp) = (15, 1_575_412_285);
2231        let mut vote_state = VoteState {
2232            last_timestamp: BlockTimestamp { slot, timestamp },
2233            ..VoteState::default()
2234        };
2235
2236        assert_eq!(
2237            vote_state.process_timestamp(slot - 1, timestamp + 1),
2238            Err(VoteError::TimestampTooOld)
2239        );
2240        assert_eq!(
2241            vote_state.last_timestamp,
2242            BlockTimestamp { slot, timestamp }
2243        );
2244        assert_eq!(
2245            vote_state.process_timestamp(slot + 1, timestamp - 1),
2246            Err(VoteError::TimestampTooOld)
2247        );
2248        assert_eq!(
2249            vote_state.process_timestamp(slot, timestamp + 1),
2250            Err(VoteError::TimestampTooOld)
2251        );
2252        assert_eq!(vote_state.process_timestamp(slot, timestamp), Ok(()));
2253        assert_eq!(
2254            vote_state.last_timestamp,
2255            BlockTimestamp { slot, timestamp }
2256        );
2257        assert_eq!(vote_state.process_timestamp(slot + 1, timestamp), Ok(()));
2258        assert_eq!(
2259            vote_state.last_timestamp,
2260            BlockTimestamp {
2261                slot: slot + 1,
2262                timestamp
2263            }
2264        );
2265        assert_eq!(
2266            vote_state.process_timestamp(slot + 2, timestamp + 1),
2267            Ok(())
2268        );
2269        assert_eq!(
2270            vote_state.last_timestamp,
2271            BlockTimestamp {
2272                slot: slot + 2,
2273                timestamp: timestamp + 1
2274            }
2275        );
2276
2277        // Test initial vote
2278        vote_state.last_timestamp = BlockTimestamp::default();
2279        assert_eq!(vote_state.process_timestamp(0, timestamp), Ok(()));
2280    }
2281
2282    #[test]
2283    fn test_get_and_update_authorized_voter() {
2284        let original_voter = solana_sdk::pubkey::new_rand();
2285        let mut vote_state = VoteState::new(
2286            &VoteInit {
2287                node_pubkey: original_voter,
2288                authorized_voter: original_voter,
2289                authorized_withdrawer: original_voter,
2290                commission: 0,
2291            },
2292            &Clock::default(),
2293        );
2294
2295        // If no new authorized voter was set, the same authorized voter
2296        // is locked into the next epoch
2297        assert_eq!(
2298            vote_state.get_and_update_authorized_voter(1).unwrap(),
2299            original_voter
2300        );
2301
2302        // Try to get the authorized voter for epoch 5, implies
2303        // the authorized voter for epochs 1-4 were unchanged
2304        assert_eq!(
2305            vote_state.get_and_update_authorized_voter(5).unwrap(),
2306            original_voter
2307        );
2308
2309        // Authorized voter for expired epoch 0..5 should have been
2310        // purged and no longer queryable
2311        assert_eq!(vote_state.authorized_voters.len(), 1);
2312        for i in 0..5 {
2313            assert!(vote_state
2314                .authorized_voters
2315                .get_authorized_voter(i)
2316                .is_none());
2317        }
2318
2319        // Set an authorized voter change at slot 7
2320        let new_authorized_voter = solana_sdk::pubkey::new_rand();
2321        vote_state
2322            .set_new_authorized_voter(&new_authorized_voter, 5, 7, |_| Ok(()))
2323            .unwrap();
2324
2325        // Try to get the authorized voter for epoch 6, unchanged
2326        assert_eq!(
2327            vote_state.get_and_update_authorized_voter(6).unwrap(),
2328            original_voter
2329        );
2330
2331        // Try to get the authorized voter for epoch 7 and onwards, should
2332        // be the new authorized voter
2333        for i in 7..10 {
2334            assert_eq!(
2335                vote_state.get_and_update_authorized_voter(i).unwrap(),
2336                new_authorized_voter
2337            );
2338        }
2339        assert_eq!(vote_state.authorized_voters.len(), 1);
2340    }
2341
2342    #[test]
2343    fn test_set_new_authorized_voter() {
2344        let original_voter = solana_sdk::pubkey::new_rand();
2345        let epoch_offset = 15;
2346        let mut vote_state = VoteState::new(
2347            &VoteInit {
2348                node_pubkey: original_voter,
2349                authorized_voter: original_voter,
2350                authorized_withdrawer: original_voter,
2351                commission: 0,
2352            },
2353            &Clock::default(),
2354        );
2355
2356        assert!(vote_state.prior_voters.last().is_none());
2357
2358        let new_voter = solana_sdk::pubkey::new_rand();
2359        // Set a new authorized voter
2360        vote_state
2361            .set_new_authorized_voter(&new_voter, 0, epoch_offset, |_| Ok(()))
2362            .unwrap();
2363
2364        assert_eq!(vote_state.prior_voters.idx, 0);
2365        assert_eq!(
2366            vote_state.prior_voters.last(),
2367            Some(&(original_voter, 0, epoch_offset))
2368        );
2369
2370        // Trying to set authorized voter for same epoch again should fail
2371        assert_eq!(
2372            vote_state.set_new_authorized_voter(&new_voter, 0, epoch_offset, |_| Ok(())),
2373            Err(VoteError::TooSoonToReauthorize.into())
2374        );
2375
2376        // Setting the same authorized voter again should succeed
2377        vote_state
2378            .set_new_authorized_voter(&new_voter, 2, 2 + epoch_offset, |_| Ok(()))
2379            .unwrap();
2380
2381        // Set a third and fourth authorized voter
2382        let new_voter2 = solana_sdk::pubkey::new_rand();
2383        vote_state
2384            .set_new_authorized_voter(&new_voter2, 3, 3 + epoch_offset, |_| Ok(()))
2385            .unwrap();
2386        assert_eq!(vote_state.prior_voters.idx, 1);
2387        assert_eq!(
2388            vote_state.prior_voters.last(),
2389            Some(&(new_voter, epoch_offset, 3 + epoch_offset))
2390        );
2391
2392        let new_voter3 = solana_sdk::pubkey::new_rand();
2393        vote_state
2394            .set_new_authorized_voter(&new_voter3, 6, 6 + epoch_offset, |_| Ok(()))
2395            .unwrap();
2396        assert_eq!(vote_state.prior_voters.idx, 2);
2397        assert_eq!(
2398            vote_state.prior_voters.last(),
2399            Some(&(new_voter2, 3 + epoch_offset, 6 + epoch_offset))
2400        );
2401
2402        // Check can set back to original voter
2403        vote_state
2404            .set_new_authorized_voter(&original_voter, 9, 9 + epoch_offset, |_| Ok(()))
2405            .unwrap();
2406
2407        // Run with these voters for a while, check the ranges of authorized
2408        // voters is correct
2409        for i in 9..epoch_offset {
2410            assert_eq!(
2411                vote_state.get_and_update_authorized_voter(i).unwrap(),
2412                original_voter
2413            );
2414        }
2415        for i in epoch_offset..3 + epoch_offset {
2416            assert_eq!(
2417                vote_state.get_and_update_authorized_voter(i).unwrap(),
2418                new_voter
2419            );
2420        }
2421        for i in 3 + epoch_offset..6 + epoch_offset {
2422            assert_eq!(
2423                vote_state.get_and_update_authorized_voter(i).unwrap(),
2424                new_voter2
2425            );
2426        }
2427        for i in 6 + epoch_offset..9 + epoch_offset {
2428            assert_eq!(
2429                vote_state.get_and_update_authorized_voter(i).unwrap(),
2430                new_voter3
2431            );
2432        }
2433        for i in 9 + epoch_offset..=10 + epoch_offset {
2434            assert_eq!(
2435                vote_state.get_and_update_authorized_voter(i).unwrap(),
2436                original_voter
2437            );
2438        }
2439    }
2440
2441    #[test]
2442    fn test_authorized_voter_is_locked_within_epoch() {
2443        let original_voter = solana_sdk::pubkey::new_rand();
2444        let mut vote_state = VoteState::new(
2445            &VoteInit {
2446                node_pubkey: original_voter,
2447                authorized_voter: original_voter,
2448                authorized_withdrawer: original_voter,
2449                commission: 0,
2450            },
2451            &Clock::default(),
2452        );
2453
2454        // Test that it's not possible to set a new authorized
2455        // voter within the same epoch, even if none has been
2456        // explicitly set before
2457        let new_voter = solana_sdk::pubkey::new_rand();
2458        assert_eq!(
2459            vote_state.set_new_authorized_voter(&new_voter, 1, 1, |_| Ok(())),
2460            Err(VoteError::TooSoonToReauthorize.into())
2461        );
2462
2463        assert_eq!(vote_state.get_authorized_voter(1), Some(original_voter));
2464
2465        // Set a new authorized voter for a future epoch
2466        assert_eq!(
2467            vote_state.set_new_authorized_voter(&new_voter, 1, 2, |_| Ok(())),
2468            Ok(())
2469        );
2470
2471        // Test that it's not possible to set a new authorized
2472        // voter within the same epoch, even if none has been
2473        // explicitly set before
2474        assert_eq!(
2475            vote_state.set_new_authorized_voter(&original_voter, 3, 3, |_| Ok(())),
2476            Err(VoteError::TooSoonToReauthorize.into())
2477        );
2478
2479        assert_eq!(vote_state.get_authorized_voter(3), Some(new_voter));
2480    }
2481
2482    #[test]
2483    fn test_vote_state_size_of() {
2484        let vote_state = VoteState::get_max_sized_vote_state();
2485        let vote_state = VoteStateVersions::new_current(vote_state);
2486        let size = bincode::serialized_size(&vote_state).unwrap();
2487        assert_eq!(VoteState::size_of() as u64, size);
2488    }
2489
2490    #[test]
2491    fn test_vote_state_max_size() {
2492        let mut max_sized_data = vec![0; VoteState::size_of()];
2493        let vote_state = VoteState::get_max_sized_vote_state();
2494        let (start_leader_schedule_epoch, _) = vote_state.authorized_voters.last().unwrap();
2495        let start_current_epoch =
2496            start_leader_schedule_epoch - MAX_LEADER_SCHEDULE_EPOCH_OFFSET + 1;
2497
2498        let mut vote_state = Some(vote_state);
2499        for i in start_current_epoch..start_current_epoch + 2 * MAX_LEADER_SCHEDULE_EPOCH_OFFSET {
2500            vote_state.as_mut().map(|vote_state| {
2501                vote_state.set_new_authorized_voter(
2502                    &solana_sdk::pubkey::new_rand(),
2503                    i,
2504                    i + MAX_LEADER_SCHEDULE_EPOCH_OFFSET,
2505                    |_| Ok(()),
2506                )
2507            });
2508
2509            let versioned = VoteStateVersions::new_current(vote_state.take().unwrap());
2510            VoteState::serialize(&versioned, &mut max_sized_data).unwrap();
2511            vote_state = Some(versioned.convert_to_current());
2512        }
2513    }
2514
2515    #[test]
2516    fn test_default_vote_state_is_uninitialized() {
2517        // The default `VoteState` is stored to de-initialize a zero-balance vote account,
2518        // so must remain such that `VoteStateVersions::is_uninitialized()` returns true
2519        // when called on a `VoteStateVersions` that stores it
2520        assert!(VoteStateVersions::new_current(VoteState::default()).is_uninitialized());
2521    }
2522
2523    #[test]
2524    fn test_is_correct_size_and_initialized() {
2525        // Check all zeroes
2526        let mut vote_account_data = vec![0; VoteState::size_of()];
2527        assert!(!VoteState::is_correct_size_and_initialized(
2528            &vote_account_data
2529        ));
2530
2531        // Check default VoteState
2532        let default_account_state = VoteStateVersions::new_current(VoteState::default());
2533        VoteState::serialize(&default_account_state, &mut vote_account_data).unwrap();
2534        assert!(!VoteState::is_correct_size_and_initialized(
2535            &vote_account_data
2536        ));
2537
2538        // Check non-zero data shorter than offset index used
2539        let short_data = vec![1; DEFAULT_PRIOR_VOTERS_OFFSET];
2540        assert!(!VoteState::is_correct_size_and_initialized(&short_data));
2541
2542        // Check non-zero large account
2543        let mut large_vote_data = vec![1; 2 * VoteState::size_of()];
2544        let default_account_state = VoteStateVersions::new_current(VoteState::default());
2545        VoteState::serialize(&default_account_state, &mut large_vote_data).unwrap();
2546        assert!(!VoteState::is_correct_size_and_initialized(
2547            &vote_account_data
2548        ));
2549
2550        // Check populated VoteState
2551        let account_state = VoteStateVersions::new_current(VoteState::new(
2552            &VoteInit {
2553                node_pubkey: Pubkey::new_unique(),
2554                authorized_voter: Pubkey::new_unique(),
2555                authorized_withdrawer: Pubkey::new_unique(),
2556                commission: 0,
2557            },
2558            &Clock::default(),
2559        ));
2560        VoteState::serialize(&account_state, &mut vote_account_data).unwrap();
2561        assert!(VoteState::is_correct_size_and_initialized(
2562            &vote_account_data
2563        ));
2564    }
2565
2566    #[test]
2567    fn test_process_new_vote_too_many_votes() {
2568        let mut vote_state1 = VoteState::default();
2569        let bad_votes: VecDeque<Lockout> = (0..=MAX_LOCKOUT_HISTORY)
2570            .map(|slot| Lockout {
2571                slot: slot as Slot,
2572                confirmation_count: (MAX_LOCKOUT_HISTORY - slot + 1) as u32,
2573            })
2574            .collect();
2575
2576        assert_eq!(
2577            vote_state1.process_new_vote_state(
2578                bad_votes,
2579                None,
2580                None,
2581                vote_state1.current_epoch(),
2582                None,
2583            ),
2584            Err(VoteError::TooManyVotes)
2585        );
2586    }
2587
2588    #[test]
2589    fn test_process_new_vote_state_root_rollback() {
2590        let mut vote_state1 = VoteState::default();
2591        for i in 0..MAX_LOCKOUT_HISTORY + 2 {
2592            vote_state1.process_slot_vote_unchecked(i as Slot);
2593        }
2594        assert_eq!(vote_state1.root_slot.unwrap(), 1);
2595
2596        // Update vote_state2 with a higher slot so that `process_new_vote_state`
2597        // doesn't panic.
2598        let mut vote_state2 = vote_state1.clone();
2599        vote_state2.process_slot_vote_unchecked(MAX_LOCKOUT_HISTORY as Slot + 3);
2600
2601        // Trying to set a lesser root should error
2602        let lesser_root = Some(0);
2603
2604        assert_eq!(
2605            vote_state1.process_new_vote_state(
2606                vote_state2.votes.clone(),
2607                lesser_root,
2608                None,
2609                vote_state2.current_epoch(),
2610                None,
2611            ),
2612            Err(VoteError::RootRollBack)
2613        );
2614
2615        // Trying to set root to None should error
2616        let none_root = None;
2617        assert_eq!(
2618            vote_state1.process_new_vote_state(
2619                vote_state2.votes.clone(),
2620                none_root,
2621                None,
2622                vote_state2.current_epoch(),
2623                None,
2624            ),
2625            Err(VoteError::RootRollBack)
2626        );
2627    }
2628
2629    #[test]
2630    fn test_process_new_vote_state_zero_confirmations() {
2631        let mut vote_state1 = VoteState::default();
2632
2633        let bad_votes: VecDeque<Lockout> = vec![
2634            Lockout {
2635                slot: 0,
2636                confirmation_count: 0,
2637            },
2638            Lockout {
2639                slot: 1,
2640                confirmation_count: 1,
2641            },
2642        ]
2643        .into_iter()
2644        .collect();
2645        assert_eq!(
2646            vote_state1.process_new_vote_state(
2647                bad_votes,
2648                None,
2649                None,
2650                vote_state1.current_epoch(),
2651                None,
2652            ),
2653            Err(VoteError::ZeroConfirmations)
2654        );
2655
2656        let bad_votes: VecDeque<Lockout> = vec![
2657            Lockout {
2658                slot: 0,
2659                confirmation_count: 2,
2660            },
2661            Lockout {
2662                slot: 1,
2663                confirmation_count: 0,
2664            },
2665        ]
2666        .into_iter()
2667        .collect();
2668        assert_eq!(
2669            vote_state1.process_new_vote_state(
2670                bad_votes,
2671                None,
2672                None,
2673                vote_state1.current_epoch(),
2674                None,
2675            ),
2676            Err(VoteError::ZeroConfirmations)
2677        );
2678    }
2679
2680    #[test]
2681    fn test_process_new_vote_state_confirmations_too_large() {
2682        let mut vote_state1 = VoteState::default();
2683
2684        let good_votes: VecDeque<Lockout> = vec![Lockout {
2685            slot: 0,
2686            confirmation_count: MAX_LOCKOUT_HISTORY as u32,
2687        }]
2688        .into_iter()
2689        .collect();
2690
2691        vote_state1
2692            .process_new_vote_state(good_votes, None, None, vote_state1.current_epoch(), None)
2693            .unwrap();
2694
2695        let mut vote_state1 = VoteState::default();
2696        let bad_votes: VecDeque<Lockout> = vec![Lockout {
2697            slot: 0,
2698            confirmation_count: MAX_LOCKOUT_HISTORY as u32 + 1,
2699        }]
2700        .into_iter()
2701        .collect();
2702        assert_eq!(
2703            vote_state1.process_new_vote_state(
2704                bad_votes,
2705                None,
2706                None,
2707                vote_state1.current_epoch(),
2708                None
2709            ),
2710            Err(VoteError::ConfirmationTooLarge)
2711        );
2712    }
2713
2714    #[test]
2715    fn test_process_new_vote_state_slot_smaller_than_root() {
2716        let mut vote_state1 = VoteState::default();
2717        let root_slot = 5;
2718
2719        let bad_votes: VecDeque<Lockout> = vec![
2720            Lockout {
2721                slot: root_slot,
2722                confirmation_count: 2,
2723            },
2724            Lockout {
2725                slot: root_slot + 1,
2726                confirmation_count: 1,
2727            },
2728        ]
2729        .into_iter()
2730        .collect();
2731        assert_eq!(
2732            vote_state1.process_new_vote_state(
2733                bad_votes,
2734                Some(root_slot),
2735                None,
2736                vote_state1.current_epoch(),
2737                None,
2738            ),
2739            Err(VoteError::SlotSmallerThanRoot)
2740        );
2741
2742        let bad_votes: VecDeque<Lockout> = vec![
2743            Lockout {
2744                slot: root_slot - 1,
2745                confirmation_count: 2,
2746            },
2747            Lockout {
2748                slot: root_slot + 1,
2749                confirmation_count: 1,
2750            },
2751        ]
2752        .into_iter()
2753        .collect();
2754        assert_eq!(
2755            vote_state1.process_new_vote_state(
2756                bad_votes,
2757                Some(root_slot),
2758                None,
2759                vote_state1.current_epoch(),
2760                None,
2761            ),
2762            Err(VoteError::SlotSmallerThanRoot)
2763        );
2764    }
2765
2766    #[test]
2767    fn test_process_new_vote_state_slots_not_ordered() {
2768        let mut vote_state1 = VoteState::default();
2769
2770        let bad_votes: VecDeque<Lockout> = vec![
2771            Lockout {
2772                slot: 1,
2773                confirmation_count: 2,
2774            },
2775            Lockout {
2776                slot: 0,
2777                confirmation_count: 1,
2778            },
2779        ]
2780        .into_iter()
2781        .collect();
2782        assert_eq!(
2783            vote_state1.process_new_vote_state(
2784                bad_votes,
2785                None,
2786                None,
2787                vote_state1.current_epoch(),
2788                None
2789            ),
2790            Err(VoteError::SlotsNotOrdered)
2791        );
2792
2793        let bad_votes: VecDeque<Lockout> = vec![
2794            Lockout {
2795                slot: 1,
2796                confirmation_count: 2,
2797            },
2798            Lockout {
2799                slot: 1,
2800                confirmation_count: 1,
2801            },
2802        ]
2803        .into_iter()
2804        .collect();
2805        assert_eq!(
2806            vote_state1.process_new_vote_state(
2807                bad_votes,
2808                None,
2809                None,
2810                vote_state1.current_epoch(),
2811                None
2812            ),
2813            Err(VoteError::SlotsNotOrdered)
2814        );
2815    }
2816
2817    #[test]
2818    fn test_process_new_vote_state_confirmations_not_ordered() {
2819        let mut vote_state1 = VoteState::default();
2820
2821        let bad_votes: VecDeque<Lockout> = vec![
2822            Lockout {
2823                slot: 0,
2824                confirmation_count: 1,
2825            },
2826            Lockout {
2827                slot: 1,
2828                confirmation_count: 2,
2829            },
2830        ]
2831        .into_iter()
2832        .collect();
2833        assert_eq!(
2834            vote_state1.process_new_vote_state(
2835                bad_votes,
2836                None,
2837                None,
2838                vote_state1.current_epoch(),
2839                None
2840            ),
2841            Err(VoteError::ConfirmationsNotOrdered)
2842        );
2843
2844        let bad_votes: VecDeque<Lockout> = vec![
2845            Lockout {
2846                slot: 0,
2847                confirmation_count: 1,
2848            },
2849            Lockout {
2850                slot: 1,
2851                confirmation_count: 1,
2852            },
2853        ]
2854        .into_iter()
2855        .collect();
2856        assert_eq!(
2857            vote_state1.process_new_vote_state(
2858                bad_votes,
2859                None,
2860                None,
2861                vote_state1.current_epoch(),
2862                None
2863            ),
2864            Err(VoteError::ConfirmationsNotOrdered)
2865        );
2866    }
2867
2868    #[test]
2869    fn test_process_new_vote_state_new_vote_state_lockout_mismatch() {
2870        let mut vote_state1 = VoteState::default();
2871
2872        let bad_votes: VecDeque<Lockout> = vec![
2873            Lockout {
2874                slot: 0,
2875                confirmation_count: 2,
2876            },
2877            Lockout {
2878                slot: 7,
2879                confirmation_count: 1,
2880            },
2881        ]
2882        .into_iter()
2883        .collect();
2884
2885        // Slot 7 should have expired slot 0
2886        assert_eq!(
2887            vote_state1.process_new_vote_state(
2888                bad_votes,
2889                None,
2890                None,
2891                vote_state1.current_epoch(),
2892                None,
2893            ),
2894            Err(VoteError::NewVoteStateLockoutMismatch)
2895        );
2896    }
2897
2898    #[test]
2899    fn test_process_new_vote_state_confirmation_rollback() {
2900        let mut vote_state1 = VoteState::default();
2901        let votes: VecDeque<Lockout> = vec![
2902            Lockout {
2903                slot: 0,
2904                confirmation_count: 4,
2905            },
2906            Lockout {
2907                slot: 1,
2908                confirmation_count: 3,
2909            },
2910        ]
2911        .into_iter()
2912        .collect();
2913        vote_state1
2914            .process_new_vote_state(votes, None, None, vote_state1.current_epoch(), None)
2915            .unwrap();
2916
2917        let votes: VecDeque<Lockout> = vec![
2918            Lockout {
2919                slot: 0,
2920                confirmation_count: 4,
2921            },
2922            Lockout {
2923                slot: 1,
2924                // Confirmation count lowered illegally
2925                confirmation_count: 2,
2926            },
2927            Lockout {
2928                slot: 2,
2929                confirmation_count: 1,
2930            },
2931        ]
2932        .into_iter()
2933        .collect();
2934        // Should error because newer vote state should not have lower confirmation the same slot
2935        // 1
2936        assert_eq!(
2937            vote_state1.process_new_vote_state(
2938                votes,
2939                None,
2940                None,
2941                vote_state1.current_epoch(),
2942                None
2943            ),
2944            Err(VoteError::ConfirmationRollBack)
2945        );
2946    }
2947
2948    #[test]
2949    fn test_process_new_vote_state_root_progress() {
2950        let mut vote_state1 = VoteState::default();
2951        for i in 0..MAX_LOCKOUT_HISTORY {
2952            vote_state1.process_slot_vote_unchecked(i as u64);
2953        }
2954
2955        assert!(vote_state1.root_slot.is_none());
2956        let mut vote_state2 = vote_state1.clone();
2957
2958        // 1) Try to update `vote_state1` with no root,
2959        // to `vote_state2`, which has a new root, should succeed.
2960        //
2961        // 2) Then try to update`vote_state1` with an existing root,
2962        // to `vote_state2`, which has a newer root, which
2963        // should succeed.
2964        for new_vote in MAX_LOCKOUT_HISTORY + 1..=MAX_LOCKOUT_HISTORY + 2 {
2965            vote_state2.process_slot_vote_unchecked(new_vote as Slot);
2966            assert_ne!(vote_state1.root_slot, vote_state2.root_slot);
2967
2968            vote_state1
2969                .process_new_vote_state(
2970                    vote_state2.votes.clone(),
2971                    vote_state2.root_slot,
2972                    None,
2973                    vote_state2.current_epoch(),
2974                    None,
2975                )
2976                .unwrap();
2977
2978            assert_eq!(vote_state1, vote_state2);
2979        }
2980    }
2981
2982    #[test]
2983    fn test_process_new_vote_state_same_slot_but_not_common_ancestor() {
2984        // It might be possible that during the switch from old vote instructions
2985        // to new vote instructions, new_state contains votes for slots LESS
2986        // than the current state, for instance:
2987        //
2988        // Current on-chain state: 1, 5
2989        // New state: 1, 2 (lockout: 4), 3, 5, 7
2990        //
2991        // Imagine the validator made two of these votes:
2992        // 1) The first vote {1, 2, 3} didn't land in the old state, but didn't
2993        // land on chain
2994        // 2) A second vote {1, 2, 5} was then submitted, which landed
2995        //
2996        //
2997        // 2 is not popped off in the local tower because 3 doubled the lockout.
2998        // However, 3 did not land in the on-chain state, so the vote {1, 2, 6}
2999        // will immediately pop off 2.
3000
3001        // Construct on-chain vote state
3002        let mut vote_state1 = VoteState::default();
3003        vote_state1.process_slot_votes_unchecked(&[1, 2, 5]);
3004        assert_eq!(
3005            vote_state1
3006                .votes
3007                .iter()
3008                .map(|vote| vote.slot)
3009                .collect::<Vec<Slot>>(),
3010            vec![1, 5]
3011        );
3012
3013        // Construct local tower state
3014        let mut vote_state2 = VoteState::default();
3015        vote_state2.process_slot_votes_unchecked(&[1, 2, 3, 5, 7]);
3016        assert_eq!(
3017            vote_state2
3018                .votes
3019                .iter()
3020                .map(|vote| vote.slot)
3021                .collect::<Vec<Slot>>(),
3022            vec![1, 2, 3, 5, 7]
3023        );
3024
3025        // See that on-chain vote state can update properly
3026        vote_state1
3027            .process_new_vote_state(
3028                vote_state2.votes.clone(),
3029                vote_state2.root_slot,
3030                None,
3031                vote_state2.current_epoch(),
3032                None,
3033            )
3034            .unwrap();
3035
3036        assert_eq!(vote_state1, vote_state2);
3037    }
3038
3039    #[test]
3040    fn test_process_new_vote_state_lockout_violation() {
3041        // Construct on-chain vote state
3042        let mut vote_state1 = VoteState::default();
3043        vote_state1.process_slot_votes_unchecked(&[1, 2, 4, 5]);
3044        assert_eq!(
3045            vote_state1
3046                .votes
3047                .iter()
3048                .map(|vote| vote.slot)
3049                .collect::<Vec<Slot>>(),
3050            vec![1, 2, 4, 5]
3051        );
3052
3053        // Construct conflicting tower state. Vote 4 is missing,
3054        // but 5 should not have popped off vote 4.
3055        let mut vote_state2 = VoteState::default();
3056        vote_state2.process_slot_votes_unchecked(&[1, 2, 3, 5, 7]);
3057        assert_eq!(
3058            vote_state2
3059                .votes
3060                .iter()
3061                .map(|vote| vote.slot)
3062                .collect::<Vec<Slot>>(),
3063            vec![1, 2, 3, 5, 7]
3064        );
3065
3066        // See that on-chain vote state can update properly
3067        assert_eq!(
3068            vote_state1.process_new_vote_state(
3069                vote_state2.votes.clone(),
3070                vote_state2.root_slot,
3071                None,
3072                vote_state2.current_epoch(),
3073                None
3074            ),
3075            Err(VoteError::LockoutConflict)
3076        );
3077    }
3078
3079    #[test]
3080    fn test_process_new_vote_state_lockout_violation2() {
3081        // Construct on-chain vote state
3082        let mut vote_state1 = VoteState::default();
3083        vote_state1.process_slot_votes_unchecked(&[1, 2, 5, 6, 7]);
3084        assert_eq!(
3085            vote_state1
3086                .votes
3087                .iter()
3088                .map(|vote| vote.slot)
3089                .collect::<Vec<Slot>>(),
3090            vec![1, 5, 6, 7]
3091        );
3092
3093        // Construct a new vote state. Violates on-chain state because 8
3094        // should not have popped off 7
3095        let mut vote_state2 = VoteState::default();
3096        vote_state2.process_slot_votes_unchecked(&[1, 2, 3, 5, 6, 8]);
3097        assert_eq!(
3098            vote_state2
3099                .votes
3100                .iter()
3101                .map(|vote| vote.slot)
3102                .collect::<Vec<Slot>>(),
3103            vec![1, 2, 3, 5, 6, 8]
3104        );
3105
3106        // Both vote states contain `5`, but `5` is not part of the common prefix
3107        // of both vote states. However, the violation should still be detected.
3108        assert_eq!(
3109            vote_state1.process_new_vote_state(
3110                vote_state2.votes.clone(),
3111                vote_state2.root_slot,
3112                None,
3113                vote_state2.current_epoch(),
3114                None
3115            ),
3116            Err(VoteError::LockoutConflict)
3117        );
3118    }
3119
3120    #[test]
3121    fn test_process_new_vote_state_expired_ancestor_not_removed() {
3122        // Construct on-chain vote state
3123        let mut vote_state1 = VoteState::default();
3124        vote_state1.process_slot_votes_unchecked(&[1, 2, 3, 9]);
3125        assert_eq!(
3126            vote_state1
3127                .votes
3128                .iter()
3129                .map(|vote| vote.slot)
3130                .collect::<Vec<Slot>>(),
3131            vec![1, 9]
3132        );
3133
3134        // Example: {1: lockout 8, 9: lockout 2}, vote on 10 will not pop off 1
3135        // because 9 is not popped off yet
3136        let mut vote_state2 = vote_state1.clone();
3137        vote_state2.process_slot_vote_unchecked(10);
3138
3139        // Slot 1 has been expired by 10, but is kept alive by its descendant
3140        // 9 which has not been expired yet.
3141        assert_eq!(vote_state2.votes[0].slot, 1);
3142        assert_eq!(vote_state2.votes[0].last_locked_out_slot(), 9);
3143        assert_eq!(
3144            vote_state2
3145                .votes
3146                .iter()
3147                .map(|vote| vote.slot)
3148                .collect::<Vec<Slot>>(),
3149            vec![1, 9, 10]
3150        );
3151
3152        // Should be able to update vote_state1
3153        vote_state1
3154            .process_new_vote_state(
3155                vote_state2.votes.clone(),
3156                vote_state2.root_slot,
3157                None,
3158                vote_state2.current_epoch(),
3159                None,
3160            )
3161            .unwrap();
3162        assert_eq!(vote_state1, vote_state2,);
3163    }
3164
3165    #[test]
3166    fn test_process_new_vote_current_state_contains_bigger_slots() {
3167        let mut vote_state1 = VoteState::default();
3168        vote_state1.process_slot_votes_unchecked(&[6, 7, 8]);
3169        assert_eq!(
3170            vote_state1
3171                .votes
3172                .iter()
3173                .map(|vote| vote.slot)
3174                .collect::<Vec<Slot>>(),
3175            vec![6, 7, 8]
3176        );
3177
3178        // Try to process something with lockout violations
3179        let bad_votes: VecDeque<Lockout> = vec![
3180            Lockout {
3181                slot: 2,
3182                confirmation_count: 5,
3183            },
3184            Lockout {
3185                // Slot 14 could not have popped off slot 6 yet
3186                slot: 14,
3187                confirmation_count: 1,
3188            },
3189        ]
3190        .into_iter()
3191        .collect();
3192        let root = Some(1);
3193
3194        assert_eq!(
3195            vote_state1.process_new_vote_state(
3196                bad_votes,
3197                root,
3198                None,
3199                vote_state1.current_epoch(),
3200                None
3201            ),
3202            Err(VoteError::LockoutConflict)
3203        );
3204
3205        let good_votes: VecDeque<Lockout> = vec![
3206            Lockout {
3207                slot: 2,
3208                confirmation_count: 5,
3209            },
3210            Lockout {
3211                slot: 15,
3212                confirmation_count: 1,
3213            },
3214        ]
3215        .into_iter()
3216        .collect();
3217
3218        vote_state1
3219            .process_new_vote_state(
3220                good_votes.clone(),
3221                root,
3222                None,
3223                vote_state1.current_epoch(),
3224                None,
3225            )
3226            .unwrap();
3227        assert_eq!(vote_state1.votes, good_votes);
3228    }
3229
3230    #[test]
3231    fn test_filter_old_votes() {
3232        // Enable feature
3233        let mut feature_set = FeatureSet::default();
3234        feature_set.activate(&filter_votes_outside_slot_hashes::id(), 0);
3235
3236        let mut vote_state = VoteState::default();
3237        let old_vote_slot = 1;
3238        let vote = Vote::new(vec![old_vote_slot], Hash::default());
3239
3240        // Vote with all slots that are all older than the SlotHashes history should
3241        // error with `VotesTooOldAllFiltered`
3242        let slot_hashes = vec![(3, Hash::new_unique()), (2, Hash::new_unique())];
3243        assert_eq!(
3244            vote_state.process_vote(&vote, &slot_hashes, 0, Some(&feature_set),),
3245            Err(VoteError::VotesTooOldAllFiltered)
3246        );
3247
3248        // Vote with only some slots older than the SlotHashes history should
3249        // filter out those older slots
3250        let vote_slot = 2;
3251        let vote_slot_hash = slot_hashes
3252            .iter()
3253            .find(|(slot, _hash)| *slot == vote_slot)
3254            .unwrap()
3255            .1;
3256
3257        let vote = Vote::new(vec![old_vote_slot, vote_slot], vote_slot_hash);
3258        vote_state
3259            .process_vote(&vote, &slot_hashes, 0, Some(&feature_set))
3260            .unwrap();
3261        assert_eq!(
3262            vote_state.votes.into_iter().collect::<Vec<Lockout>>(),
3263            vec![Lockout {
3264                slot: vote_slot,
3265                confirmation_count: 1,
3266            }]
3267        );
3268    }
3269
3270    fn build_slot_hashes(slots: Vec<Slot>) -> Vec<(Slot, Hash)> {
3271        slots
3272            .iter()
3273            .rev()
3274            .map(|x| (*x, Hash::new_unique()))
3275            .collect()
3276    }
3277
3278    fn build_vote_state(vote_slots: Vec<Slot>, slot_hashes: &[(Slot, Hash)]) -> VoteState {
3279        let mut vote_state = VoteState::default();
3280
3281        if !vote_slots.is_empty() {
3282            let vote_hash = slot_hashes
3283                .iter()
3284                .find(|(slot, _hash)| slot == vote_slots.last().unwrap())
3285                .unwrap()
3286                .1;
3287            vote_state
3288                .process_vote(&Vote::new(vote_slots, vote_hash), slot_hashes, 0, None)
3289                .unwrap();
3290        }
3291
3292        vote_state
3293    }
3294
3295    #[test]
3296    fn test_check_update_vote_state_empty() {
3297        let empty_slot_hashes = build_slot_hashes(vec![]);
3298        let empty_vote_state = build_vote_state(vec![], &empty_slot_hashes);
3299
3300        // Test with empty vote state update, should return EmptySlots error
3301        let mut vote_state_update = VoteStateUpdate::from(vec![]);
3302        assert_eq!(
3303            empty_vote_state.check_update_vote_state_slots_are_valid(
3304                &mut vote_state_update,
3305                &empty_slot_hashes,
3306                Some(&FeatureSet::all_enabled())
3307            ),
3308            Err(VoteError::EmptySlots),
3309        );
3310
3311        // Test with non-empty vote state update, should return SlotsMismatch since nothing exists in SlotHashes
3312        let mut vote_state_update = VoteStateUpdate::from(vec![(0, 1)]);
3313        assert_eq!(
3314            empty_vote_state.check_update_vote_state_slots_are_valid(
3315                &mut vote_state_update,
3316                &empty_slot_hashes,
3317                Some(&FeatureSet::all_enabled())
3318            ),
3319            Err(VoteError::SlotsMismatch),
3320        );
3321    }
3322
3323    #[test]
3324    fn test_check_update_vote_state_too_old() {
3325        let slot_hashes = build_slot_hashes(vec![1, 2, 3, 4]);
3326        let latest_vote = 4;
3327        let vote_state = build_vote_state(vec![1, 2, 3, latest_vote], &slot_hashes);
3328
3329        // Test with a vote for a slot less than the latest vote in the vote_state,
3330        // should return error `VoteTooOld`
3331        let mut vote_state_update = VoteStateUpdate::from(vec![(latest_vote, 1)]);
3332        assert_eq!(
3333            vote_state.check_update_vote_state_slots_are_valid(
3334                &mut vote_state_update,
3335                &slot_hashes,
3336                Some(&FeatureSet::all_enabled())
3337            ),
3338            Err(VoteError::VoteTooOld),
3339        );
3340
3341        // Test with a vote state update where the latest slot `X` in the update is
3342        // 1) Less than the earliest slot in slot_hashes history, AND
3343        // 2) `X` > latest_vote
3344        let earliest_slot_in_history = latest_vote + 2;
3345        let slot_hashes = build_slot_hashes(vec![earliest_slot_in_history]);
3346        let mut vote_state_update = VoteStateUpdate::from(vec![(earliest_slot_in_history - 1, 1)]);
3347        assert_eq!(
3348            vote_state.check_update_vote_state_slots_are_valid(
3349                &mut vote_state_update,
3350                &slot_hashes,
3351                Some(&FeatureSet::all_enabled()),
3352            ),
3353            Err(VoteError::VoteTooOld),
3354        );
3355    }
3356
3357    fn run_test_check_update_vote_state_older_than_history_root(
3358        earliest_slot_in_history: Slot,
3359        current_vote_state_slots: Vec<Slot>,
3360        current_vote_state_root: Option<Slot>,
3361        vote_state_update_slots_and_lockouts: Vec<(Slot, u32)>,
3362        vote_state_update_root: Slot,
3363        expected_root: Option<Slot>,
3364        expected_vote_state: Vec<Lockout>,
3365    ) {
3366        assert!(vote_state_update_root < earliest_slot_in_history);
3367        assert_eq!(
3368            expected_root,
3369            current_vote_state_slots
3370                .iter()
3371                .rev()
3372                .find(|slot| **slot <= vote_state_update_root)
3373                .cloned()
3374        );
3375        let latest_slot_in_history = vote_state_update_slots_and_lockouts
3376            .last()
3377            .unwrap()
3378            .0
3379            .max(earliest_slot_in_history);
3380        let mut slot_hashes = build_slot_hashes(
3381            (current_vote_state_slots.first().copied().unwrap_or(0)..=latest_slot_in_history)
3382                .collect::<Vec<Slot>>(),
3383        );
3384
3385        let mut vote_state = build_vote_state(current_vote_state_slots, &slot_hashes);
3386        vote_state.root_slot = current_vote_state_root;
3387
3388        slot_hashes.retain(|slot| slot.0 >= earliest_slot_in_history);
3389        assert!(!vote_state_update_slots_and_lockouts.is_empty());
3390        let vote_state_update_hash = slot_hashes
3391            .iter()
3392            .find(|(slot, _hash)| *slot == vote_state_update_slots_and_lockouts.last().unwrap().0)
3393            .unwrap()
3394            .1;
3395
3396        // Test with a `vote_state_update` where the root is less than `earliest_slot_in_history`.
3397        // Root slot in the `vote_state_update` should be updated to match the root slot in the
3398        // current vote state
3399        let mut vote_state_update = VoteStateUpdate::from(vote_state_update_slots_and_lockouts);
3400        vote_state_update.hash = vote_state_update_hash;
3401        vote_state_update.root = Some(vote_state_update_root);
3402        vote_state
3403            .check_update_vote_state_slots_are_valid(
3404                &mut vote_state_update,
3405                &slot_hashes,
3406                Some(&FeatureSet::all_enabled()),
3407            )
3408            .unwrap();
3409        assert_eq!(vote_state_update.root, expected_root);
3410
3411        // The proposed root slot should become the biggest slot in the current vote state less than
3412        // `earliest_slot_in_history`.
3413        assert!(do_process_vote_state_update(
3414            &mut vote_state,
3415            &slot_hashes,
3416            0,
3417            vote_state_update.clone(),
3418            Some(&FeatureSet::all_enabled()),
3419        )
3420        .is_ok());
3421        assert_eq!(vote_state.root_slot, expected_root);
3422        assert_eq!(
3423            vote_state.votes.into_iter().collect::<Vec<Lockout>>(),
3424            expected_vote_state,
3425        );
3426    }
3427
3428    #[test]
3429    fn test_check_update_vote_state_older_than_history_root() {
3430        // Test when `vote_state_update_root` is in `current_vote_state_slots` but it's not the latest
3431        // slot
3432        let earliest_slot_in_history = 5;
3433        let current_vote_state_slots: Vec<Slot> = vec![1, 2, 3, 4];
3434        let current_vote_state_root = None;
3435        let vote_state_update_slots_and_lockouts = vec![(5, 1)];
3436        let vote_state_update_root = 4;
3437        let expected_root = Some(4);
3438        let expected_vote_state = vec![Lockout {
3439            slot: 5,
3440            confirmation_count: 1,
3441        }];
3442        run_test_check_update_vote_state_older_than_history_root(
3443            earliest_slot_in_history,
3444            current_vote_state_slots,
3445            current_vote_state_root,
3446            vote_state_update_slots_and_lockouts,
3447            vote_state_update_root,
3448            expected_root,
3449            expected_vote_state,
3450        );
3451
3452        // Test when `vote_state_update_root` is in `current_vote_state_slots` but it's not the latest
3453        // slot and the `current_vote_state_root.is_some()`.
3454        let earliest_slot_in_history = 5;
3455        let current_vote_state_slots: Vec<Slot> = vec![1, 2, 3, 4];
3456        let current_vote_state_root = Some(0);
3457        let vote_state_update_slots_and_lockouts = vec![(5, 1)];
3458        let vote_state_update_root = 4;
3459        let expected_root = Some(4);
3460        let expected_vote_state = vec![Lockout {
3461            slot: 5,
3462            confirmation_count: 1,
3463        }];
3464        run_test_check_update_vote_state_older_than_history_root(
3465            earliest_slot_in_history,
3466            current_vote_state_slots,
3467            current_vote_state_root,
3468            vote_state_update_slots_and_lockouts,
3469            vote_state_update_root,
3470            expected_root,
3471            expected_vote_state,
3472        );
3473
3474        // Test when `vote_state_update_root` is in `current_vote_state_slots` but it's not the latest
3475        // slot
3476        let earliest_slot_in_history = 5;
3477        let current_vote_state_slots: Vec<Slot> = vec![1, 2, 3, 4];
3478        let current_vote_state_root = Some(0);
3479        let vote_state_update_slots_and_lockouts = vec![(4, 2), (5, 1)];
3480        let vote_state_update_root = 3;
3481        let expected_root = Some(3);
3482        let expected_vote_state = vec![
3483            Lockout {
3484                slot: 4,
3485                confirmation_count: 2,
3486            },
3487            Lockout {
3488                slot: 5,
3489                confirmation_count: 1,
3490            },
3491        ];
3492        run_test_check_update_vote_state_older_than_history_root(
3493            earliest_slot_in_history,
3494            current_vote_state_slots,
3495            current_vote_state_root,
3496            vote_state_update_slots_and_lockouts,
3497            vote_state_update_root,
3498            expected_root,
3499            expected_vote_state,
3500        );
3501
3502        // Test when `vote_state_update_root` is not in `current_vote_state_slots`
3503        let earliest_slot_in_history = 5;
3504        let current_vote_state_slots: Vec<Slot> = vec![1, 2, 4];
3505        let current_vote_state_root = Some(0);
3506        let vote_state_update_slots_and_lockouts = vec![(4, 2), (5, 1)];
3507        let vote_state_update_root = 3;
3508        let expected_root = Some(2);
3509        let expected_vote_state = vec![
3510            Lockout {
3511                slot: 4,
3512                confirmation_count: 2,
3513            },
3514            Lockout {
3515                slot: 5,
3516                confirmation_count: 1,
3517            },
3518        ];
3519        run_test_check_update_vote_state_older_than_history_root(
3520            earliest_slot_in_history,
3521            current_vote_state_slots,
3522            current_vote_state_root,
3523            vote_state_update_slots_and_lockouts,
3524            vote_state_update_root,
3525            expected_root,
3526            expected_vote_state,
3527        );
3528
3529        // Test when the `vote_state_update_root` is smaller than all the slots in
3530        // `current_vote_state_slots`, no roots should be set.
3531        let earliest_slot_in_history = 4;
3532        let current_vote_state_slots: Vec<Slot> = vec![3, 4];
3533        let current_vote_state_root = None;
3534        let vote_state_update_slots_and_lockouts = vec![(3, 3), (4, 2), (5, 1)];
3535        let vote_state_update_root = 2;
3536        let expected_root = None;
3537        let expected_vote_state = vec![
3538            Lockout {
3539                slot: 3,
3540                confirmation_count: 3,
3541            },
3542            Lockout {
3543                slot: 4,
3544                confirmation_count: 2,
3545            },
3546            Lockout {
3547                slot: 5,
3548                confirmation_count: 1,
3549            },
3550        ];
3551        run_test_check_update_vote_state_older_than_history_root(
3552            earliest_slot_in_history,
3553            current_vote_state_slots,
3554            current_vote_state_root,
3555            vote_state_update_slots_and_lockouts,
3556            vote_state_update_root,
3557            expected_root,
3558            expected_vote_state,
3559        );
3560
3561        // Test when `current_vote_state_slots` is empty, no roots should be set
3562        let earliest_slot_in_history = 4;
3563        let current_vote_state_slots: Vec<Slot> = vec![];
3564        let current_vote_state_root = None;
3565        let vote_state_update_slots_and_lockouts = vec![(5, 1)];
3566        let vote_state_update_root = 2;
3567        let expected_root = None;
3568        let expected_vote_state = vec![Lockout {
3569            slot: 5,
3570            confirmation_count: 1,
3571        }];
3572        run_test_check_update_vote_state_older_than_history_root(
3573            earliest_slot_in_history,
3574            current_vote_state_slots,
3575            current_vote_state_root,
3576            vote_state_update_slots_and_lockouts,
3577            vote_state_update_root,
3578            expected_root,
3579            expected_vote_state,
3580        );
3581    }
3582
3583    #[test]
3584    fn test_check_update_vote_state_slots_not_ordered() {
3585        let slot_hashes = build_slot_hashes(vec![1, 2, 3, 4]);
3586        let vote_state = build_vote_state(vec![1], &slot_hashes);
3587
3588        // Test with a `vote_state_update` where the slots are out of order
3589        let vote_slot = 3;
3590        let vote_slot_hash = slot_hashes
3591            .iter()
3592            .find(|(slot, _hash)| *slot == vote_slot)
3593            .unwrap()
3594            .1;
3595        let mut vote_state_update = VoteStateUpdate::from(vec![(2, 2), (1, 3), (vote_slot, 1)]);
3596        vote_state_update.hash = vote_slot_hash;
3597        assert_eq!(
3598            vote_state.check_update_vote_state_slots_are_valid(
3599                &mut vote_state_update,
3600                &slot_hashes,
3601                Some(&FeatureSet::all_enabled())
3602            ),
3603            Err(VoteError::SlotsNotOrdered),
3604        );
3605
3606        // Test with a `vote_state_update` where there are multiples of the same slot
3607        let mut vote_state_update = VoteStateUpdate::from(vec![(2, 2), (2, 2), (vote_slot, 1)]);
3608        vote_state_update.hash = vote_slot_hash;
3609        assert_eq!(
3610            vote_state.check_update_vote_state_slots_are_valid(
3611                &mut vote_state_update,
3612                &slot_hashes,
3613                Some(&FeatureSet::all_enabled()),
3614            ),
3615            Err(VoteError::SlotsNotOrdered),
3616        );
3617    }
3618
3619    #[test]
3620    fn test_check_update_vote_state_older_than_history_slots_filtered() {
3621        let slot_hashes = build_slot_hashes(vec![1, 2, 3, 4]);
3622        let mut vote_state = build_vote_state(vec![1, 2, 3, 4], &slot_hashes);
3623
3624        // Test with a `vote_state_update` where there:
3625        // 1) Exists a slot less than `earliest_slot_in_history`
3626        // 2) This slot does not exist in the vote state already
3627        // This slot should be filtered out
3628        let earliest_slot_in_history = 11;
3629        let slot_hashes = build_slot_hashes(vec![earliest_slot_in_history, 12, 13, 14]);
3630        let vote_slot = 12;
3631        let vote_slot_hash = slot_hashes
3632            .iter()
3633            .find(|(slot, _hash)| *slot == vote_slot)
3634            .unwrap()
3635            .1;
3636        let missing_older_than_history_slot = earliest_slot_in_history - 1;
3637        let mut vote_state_update = VoteStateUpdate::from(vec![
3638            (1, 4),
3639            (missing_older_than_history_slot, 2),
3640            (vote_slot, 3),
3641        ]);
3642        vote_state_update.hash = vote_slot_hash;
3643        vote_state
3644            .check_update_vote_state_slots_are_valid(
3645                &mut vote_state_update,
3646                &slot_hashes,
3647                Some(&FeatureSet::all_enabled()),
3648            )
3649            .unwrap();
3650
3651        // Check the earlier slot was filtered out
3652        assert_eq!(
3653            vote_state_update
3654                .clone()
3655                .lockouts
3656                .into_iter()
3657                .collect::<Vec<Lockout>>(),
3658            vec![
3659                Lockout {
3660                    slot: 1,
3661                    confirmation_count: 4,
3662                },
3663                Lockout {
3664                    slot: vote_slot,
3665                    confirmation_count: 3,
3666                }
3667            ]
3668        );
3669        assert!(do_process_vote_state_update(
3670            &mut vote_state,
3671            &slot_hashes,
3672            0,
3673            vote_state_update,
3674            Some(&FeatureSet::all_enabled()),
3675        )
3676        .is_ok());
3677    }
3678
3679    #[test]
3680    fn test_minimum_balance() {
3681        let rent = solana_sdk::rent::Rent::default();
3682        let minimum_balance = rent.minimum_balance(VoteState::size_of());
3683        // golden, may need updating when vote_state grows
3684        assert!(minimum_balance as f64 / 10f64.powf(9.0) < 0.04)
3685    }
3686
3687    #[test]
3688    fn test_check_update_vote_state_older_than_history_slots_not_filtered() {
3689        let slot_hashes = build_slot_hashes(vec![4]);
3690        let mut vote_state = build_vote_state(vec![4], &slot_hashes);
3691
3692        // Test with a `vote_state_update` where there:
3693        // 1) Exists a slot less than `earliest_slot_in_history`
3694        // 2) This slot exists in the vote state already
3695        // This slot should *NOT* be filtered out
3696        let earliest_slot_in_history = 11;
3697        let slot_hashes = build_slot_hashes(vec![earliest_slot_in_history, 12, 13, 14]);
3698        let vote_slot = 12;
3699        let vote_slot_hash = slot_hashes
3700            .iter()
3701            .find(|(slot, _hash)| *slot == vote_slot)
3702            .unwrap()
3703            .1;
3704        let existing_older_than_history_slot = 4;
3705        let mut vote_state_update =
3706            VoteStateUpdate::from(vec![(existing_older_than_history_slot, 3), (vote_slot, 2)]);
3707        vote_state_update.hash = vote_slot_hash;
3708        vote_state
3709            .check_update_vote_state_slots_are_valid(
3710                &mut vote_state_update,
3711                &slot_hashes,
3712                Some(&FeatureSet::all_enabled()),
3713            )
3714            .unwrap();
3715        // Check the earlier slot was *NOT* filtered out
3716        assert_eq!(vote_state_update.lockouts.len(), 2);
3717        assert_eq!(
3718            vote_state_update
3719                .clone()
3720                .lockouts
3721                .into_iter()
3722                .collect::<Vec<Lockout>>(),
3723            vec![
3724                Lockout {
3725                    slot: existing_older_than_history_slot,
3726                    confirmation_count: 3,
3727                },
3728                Lockout {
3729                    slot: vote_slot,
3730                    confirmation_count: 2,
3731                }
3732            ]
3733        );
3734        assert!(do_process_vote_state_update(
3735            &mut vote_state,
3736            &slot_hashes,
3737            0,
3738            vote_state_update,
3739            Some(&FeatureSet::all_enabled()),
3740        )
3741        .is_ok());
3742    }
3743
3744    #[test]
3745    fn test_check_update_vote_state_older_than_history_slots_filtered_and_not_filtered() {
3746        let slot_hashes = build_slot_hashes(vec![6]);
3747        let mut vote_state = build_vote_state(vec![6], &slot_hashes);
3748
3749        // Test with a `vote_state_update` where there exists both a slot:
3750        // 1) Less than `earliest_slot_in_history`
3751        // 2) This slot exists in the vote state already
3752        // which should not be filtered
3753        //
3754        // AND a slot that
3755        //
3756        // 1) Less than `earliest_slot_in_history`
3757        // 2) This slot does not exist in the vote state already
3758        // which should be filtered
3759        let earliest_slot_in_history = 11;
3760        let slot_hashes = build_slot_hashes(vec![earliest_slot_in_history, 12, 13, 14]);
3761        let vote_slot = 14;
3762        let vote_slot_hash = slot_hashes
3763            .iter()
3764            .find(|(slot, _hash)| *slot == vote_slot)
3765            .unwrap()
3766            .1;
3767
3768        let missing_older_than_history_slot = 4;
3769        let existing_older_than_history_slot = 6;
3770
3771        let mut vote_state_update = VoteStateUpdate::from(vec![
3772            (missing_older_than_history_slot, 4),
3773            (existing_older_than_history_slot, 3),
3774            (12, 2),
3775            (vote_slot, 1),
3776        ]);
3777        vote_state_update.hash = vote_slot_hash;
3778        vote_state
3779            .check_update_vote_state_slots_are_valid(
3780                &mut vote_state_update,
3781                &slot_hashes,
3782                Some(&FeatureSet::all_enabled()),
3783            )
3784            .unwrap();
3785        assert_eq!(vote_state_update.lockouts.len(), 3);
3786        assert_eq!(
3787            vote_state_update
3788                .clone()
3789                .lockouts
3790                .into_iter()
3791                .collect::<Vec<Lockout>>(),
3792            vec![
3793                Lockout {
3794                    slot: existing_older_than_history_slot,
3795                    confirmation_count: 3,
3796                },
3797                Lockout {
3798                    slot: 12,
3799                    confirmation_count: 2,
3800                },
3801                Lockout {
3802                    slot: vote_slot,
3803                    confirmation_count: 1,
3804                }
3805            ]
3806        );
3807        assert!(do_process_vote_state_update(
3808            &mut vote_state,
3809            &slot_hashes,
3810            0,
3811            vote_state_update,
3812            Some(&FeatureSet::all_enabled()),
3813        )
3814        .is_ok());
3815    }
3816
3817    #[test]
3818    fn test_check_update_vote_state_slot_not_on_fork() {
3819        let slot_hashes = build_slot_hashes(vec![2, 4, 6, 8]);
3820        let vote_state = build_vote_state(vec![2, 4, 6], &slot_hashes);
3821
3822        // Test with a `vote_state_update` where there:
3823        // 1) Exists a slot not in the slot hashes history
3824        // 2) The slot is greater than the earliest slot in the history
3825        // Thus this slot is not part of the fork and the update should be rejected
3826        // with error `SlotsMismatch`
3827        let missing_vote_slot = 3;
3828
3829        // Have to vote for a slot greater than the last vote in the vote state to avoid VoteTooOld
3830        // errors
3831        let vote_slot = vote_state.votes.back().unwrap().slot + 2;
3832        let vote_slot_hash = slot_hashes
3833            .iter()
3834            .find(|(slot, _hash)| *slot == vote_slot)
3835            .unwrap()
3836            .1;
3837        let mut vote_state_update =
3838            VoteStateUpdate::from(vec![(missing_vote_slot, 2), (vote_slot, 3)]);
3839        vote_state_update.hash = vote_slot_hash;
3840        assert_eq!(
3841            vote_state.check_update_vote_state_slots_are_valid(
3842                &mut vote_state_update,
3843                &slot_hashes,
3844                Some(&FeatureSet::all_enabled())
3845            ),
3846            Err(VoteError::SlotsMismatch),
3847        );
3848
3849        // Test where some earlier vote slots exist in the history, but others don't
3850        let missing_vote_slot = 7;
3851        let mut vote_state_update = VoteStateUpdate::from(vec![
3852            (2, 5),
3853            (4, 4),
3854            (6, 3),
3855            (missing_vote_slot, 2),
3856            (vote_slot, 1),
3857        ]);
3858        vote_state_update.hash = vote_slot_hash;
3859        assert_eq!(
3860            vote_state.check_update_vote_state_slots_are_valid(
3861                &mut vote_state_update,
3862                &slot_hashes,
3863                Some(&FeatureSet::all_enabled())
3864            ),
3865            Err(VoteError::SlotsMismatch),
3866        );
3867    }
3868
3869    #[test]
3870    fn test_check_update_vote_state_root_on_different_fork() {
3871        let slot_hashes = build_slot_hashes(vec![2, 4, 6, 8]);
3872        let vote_state = build_vote_state(vec![6], &slot_hashes);
3873
3874        // Test with a `vote_state_update` where:
3875        // 1) The root is not present in slot hashes history
3876        // 2) The slot is greater than the earliest slot in the history
3877        // Thus this slot is not part of the fork and the update should be rejected
3878        // with error `RootOnDifferentFork`
3879        let new_root = 3;
3880
3881        // Have to vote for a slot greater than the last vote in the vote state to avoid VoteTooOld
3882        // errors, but also this slot must be present in SlotHashes
3883        let vote_slot = 8;
3884        assert_eq!(vote_slot, slot_hashes.first().unwrap().0);
3885        let vote_slot_hash = slot_hashes
3886            .iter()
3887            .find(|(slot, _hash)| *slot == vote_slot)
3888            .unwrap()
3889            .1;
3890        let mut vote_state_update = VoteStateUpdate::from(vec![(vote_slot, 1)]);
3891        vote_state_update.hash = vote_slot_hash;
3892        vote_state_update.root = Some(new_root);
3893        assert_eq!(
3894            vote_state.check_update_vote_state_slots_are_valid(
3895                &mut vote_state_update,
3896                &slot_hashes,
3897                Some(&FeatureSet::all_enabled())
3898            ),
3899            Err(VoteError::RootOnDifferentFork),
3900        );
3901    }
3902
3903    #[test]
3904    fn test_check_update_vote_state_slot_newer_than_slot_history() {
3905        let slot_hashes = build_slot_hashes(vec![2, 4, 6, 8, 10]);
3906        let vote_state = build_vote_state(vec![2, 4, 6], &slot_hashes);
3907
3908        // Test with a `vote_state_update` where there:
3909        // 1) The last slot in the update is a slot not in the slot hashes history
3910        // 2) The slot is greater than the newest slot in the slot history
3911        // Thus this slot is not part of the fork and the update should be rejected
3912        // with error `SlotsMismatch`
3913        let missing_vote_slot = slot_hashes.first().unwrap().0 + 1;
3914        let vote_slot_hash = Hash::new_unique();
3915        let mut vote_state_update = VoteStateUpdate::from(vec![(8, 2), (missing_vote_slot, 3)]);
3916        vote_state_update.hash = vote_slot_hash;
3917        assert_eq!(
3918            vote_state.check_update_vote_state_slots_are_valid(
3919                &mut vote_state_update,
3920                &slot_hashes,
3921                Some(&FeatureSet::all_enabled())
3922            ),
3923            Err(VoteError::SlotsMismatch),
3924        );
3925    }
3926
3927    #[test]
3928    fn test_check_update_vote_state_slot_all_slot_hashes_in_update_ok() {
3929        let slot_hashes = build_slot_hashes(vec![2, 4, 6, 8]);
3930        let mut vote_state = build_vote_state(vec![2, 4, 6], &slot_hashes);
3931
3932        // Test with a `vote_state_update` where every slot in the history is
3933        // in the update
3934
3935        // Have to vote for a slot greater than the last vote in the vote state to avoid VoteTooOld
3936        // errors
3937        let vote_slot = vote_state.votes.back().unwrap().slot + 2;
3938        let vote_slot_hash = slot_hashes
3939            .iter()
3940            .find(|(slot, _hash)| *slot == vote_slot)
3941            .unwrap()
3942            .1;
3943        let mut vote_state_update =
3944            VoteStateUpdate::from(vec![(2, 4), (4, 3), (6, 2), (vote_slot, 1)]);
3945        vote_state_update.hash = vote_slot_hash;
3946        vote_state
3947            .check_update_vote_state_slots_are_valid(
3948                &mut vote_state_update,
3949                &slot_hashes,
3950                Some(&FeatureSet::all_enabled()),
3951            )
3952            .unwrap();
3953
3954        // Nothing in the update should have been filtered out
3955        assert_eq!(
3956            vote_state_update
3957                .clone()
3958                .lockouts
3959                .into_iter()
3960                .collect::<Vec<Lockout>>(),
3961            vec![
3962                Lockout {
3963                    slot: 2,
3964                    confirmation_count: 4,
3965                },
3966                Lockout {
3967                    slot: 4,
3968                    confirmation_count: 3,
3969                },
3970                Lockout {
3971                    slot: 6,
3972                    confirmation_count: 2,
3973                },
3974                Lockout {
3975                    slot: vote_slot,
3976                    confirmation_count: 1,
3977                }
3978            ]
3979        );
3980
3981        assert!(do_process_vote_state_update(
3982            &mut vote_state,
3983            &slot_hashes,
3984            0,
3985            vote_state_update,
3986            Some(&FeatureSet::all_enabled()),
3987        )
3988        .is_ok());
3989    }
3990
3991    #[test]
3992    fn test_check_update_vote_state_slot_some_slot_hashes_in_update_ok() {
3993        let slot_hashes = build_slot_hashes(vec![2, 4, 6, 8, 10]);
3994        let mut vote_state = build_vote_state(vec![6], &slot_hashes);
3995
3996        // Test with a `vote_state_update` where only some slots in the history are
3997        // in the update, and others slots in the history are missing.
3998
3999        // Have to vote for a slot greater than the last vote in the vote state to avoid VoteTooOld
4000        // errors
4001        let vote_slot = vote_state.votes.back().unwrap().slot + 2;
4002        let vote_slot_hash = slot_hashes
4003            .iter()
4004            .find(|(slot, _hash)| *slot == vote_slot)
4005            .unwrap()
4006            .1;
4007        let mut vote_state_update = VoteStateUpdate::from(vec![(4, 2), (vote_slot, 1)]);
4008        vote_state_update.hash = vote_slot_hash;
4009        vote_state
4010            .check_update_vote_state_slots_are_valid(
4011                &mut vote_state_update,
4012                &slot_hashes,
4013                Some(&FeatureSet::all_enabled()),
4014            )
4015            .unwrap();
4016
4017        // Nothing in the update should have been filtered out
4018        assert_eq!(
4019            vote_state_update
4020                .clone()
4021                .lockouts
4022                .into_iter()
4023                .collect::<Vec<Lockout>>(),
4024            vec![
4025                Lockout {
4026                    slot: 4,
4027                    confirmation_count: 2,
4028                },
4029                Lockout {
4030                    slot: vote_slot,
4031                    confirmation_count: 1,
4032                }
4033            ]
4034        );
4035
4036        // Because 6 from the original VoteState
4037        // should not have been popped off in the proposed state,
4038        // we should get a lockout conflict
4039        assert_eq!(
4040            do_process_vote_state_update(
4041                &mut vote_state,
4042                &slot_hashes,
4043                0,
4044                vote_state_update,
4045                Some(&FeatureSet::all_enabled())
4046            ),
4047            Err(VoteError::LockoutConflict)
4048        );
4049    }
4050
4051    #[test]
4052    fn test_check_update_vote_state_slot_hash_mismatch() {
4053        let slot_hashes = build_slot_hashes(vec![2, 4, 6, 8]);
4054        let vote_state = build_vote_state(vec![2, 4, 6], &slot_hashes);
4055
4056        // Test with a `vote_state_update` where the hash is mismatched
4057
4058        // Have to vote for a slot greater than the last vote in the vote state to avoid VoteTooOld
4059        // errors
4060        let vote_slot = vote_state.votes.back().unwrap().slot + 2;
4061        let vote_slot_hash = Hash::new_unique();
4062        let mut vote_state_update =
4063            VoteStateUpdate::from(vec![(2, 4), (4, 3), (6, 2), (vote_slot, 1)]);
4064        vote_state_update.hash = vote_slot_hash;
4065        assert_eq!(
4066            vote_state.check_update_vote_state_slots_are_valid(
4067                &mut vote_state_update,
4068                &slot_hashes,
4069                Some(&FeatureSet::all_enabled())
4070            ),
4071            Err(VoteError::SlotHashMismatch),
4072        );
4073    }
4074
4075    #[test]
4076    fn test_serde_compact_vote_state_update() {
4077        let mut rng = rand::thread_rng();
4078        for _ in 0..5000 {
4079            run_serde_compact_vote_state_update(&mut rng);
4080        }
4081    }
4082
4083    #[allow(clippy::integer_arithmetic)]
4084    fn run_serde_compact_vote_state_update<R: Rng>(rng: &mut R) {
4085        let lockouts: VecDeque<_> = std::iter::repeat_with(|| Lockout {
4086            slot: 149_303_885 + rng.gen_range(0, 10_000),
4087            confirmation_count: rng.gen_range(0, 33),
4088        })
4089        .take(32)
4090        .sorted_by_key(|lockout| lockout.slot)
4091        .collect();
4092        let root = rng
4093            .gen_ratio(1, 2)
4094            .then(|| lockouts[0].slot - rng.gen_range(0, 1_000));
4095        let timestamp = rng.gen_ratio(1, 2).then(|| rng.gen());
4096        let hash = Hash::from(rng.gen::<[u8; 32]>());
4097        let vote_state_update = VoteStateUpdate {
4098            lockouts,
4099            root,
4100            hash,
4101            timestamp,
4102        };
4103        #[derive(Debug, Eq, PartialEq, Deserialize, Serialize)]
4104        enum VoteInstruction {
4105            #[serde(with = "serde_compact_vote_state_update")]
4106            UpdateVoteState(VoteStateUpdate),
4107            UpdateVoteStateSwitch(
4108                #[serde(with = "serde_compact_vote_state_update")] VoteStateUpdate,
4109                Hash,
4110            ),
4111        }
4112        let vote = VoteInstruction::UpdateVoteState(vote_state_update.clone());
4113        let bytes = bincode::serialize(&vote).unwrap();
4114        assert_eq!(vote, bincode::deserialize(&bytes).unwrap());
4115        let hash = Hash::from(rng.gen::<[u8; 32]>());
4116        let vote = VoteInstruction::UpdateVoteStateSwitch(vote_state_update, hash);
4117        let bytes = bincode::serialize(&vote).unwrap();
4118        assert_eq!(vote, bincode::deserialize(&bytes).unwrap());
4119    }
4120
4121    #[test_case(0, true; "first slot")]
4122    #[test_case(DEFAULT_SLOTS_PER_EPOCH / 2, true; "halfway through epoch")]
4123    #[test_case(DEFAULT_SLOTS_PER_EPOCH / 2 + 1, false; "halfway through epoch plus one")]
4124    #[test_case(DEFAULT_SLOTS_PER_EPOCH - 1, false; "last slot in epoch")]
4125    #[test_case(DEFAULT_SLOTS_PER_EPOCH, true; "first slot in second epoch")]
4126    fn test_epoch_half_check(slot: Slot, expected_allowed: bool) {
4127        let epoch_schedule = EpochSchedule::without_warmup();
4128        assert_eq!(
4129            is_commission_update_allowed(slot, &epoch_schedule),
4130            expected_allowed
4131        );
4132    }
4133
4134    #[test]
4135    fn test_warmup_epoch_half_check_with_warmup() {
4136        let epoch_schedule = EpochSchedule::default();
4137        let first_normal_slot = epoch_schedule.first_normal_slot;
4138        // first slot works
4139        assert!(is_commission_update_allowed(0, &epoch_schedule));
4140        // right before first normal slot works, since all warmup slots allow
4141        // commission updates
4142        assert!(is_commission_update_allowed(
4143            first_normal_slot - 1,
4144            &epoch_schedule
4145        ));
4146    }
4147
4148    #[test_case(0, true; "first slot")]
4149    #[test_case(DEFAULT_SLOTS_PER_EPOCH / 2, true; "halfway through epoch")]
4150    #[test_case(DEFAULT_SLOTS_PER_EPOCH / 2 + 1, false; "halfway through epoch plus one")]
4151    #[test_case(DEFAULT_SLOTS_PER_EPOCH - 1, false; "last slot in epoch")]
4152    #[test_case(DEFAULT_SLOTS_PER_EPOCH, true; "first slot in second epoch")]
4153    fn test_epoch_half_check_with_warmup(slot: Slot, expected_allowed: bool) {
4154        let epoch_schedule = EpochSchedule::default();
4155        let first_normal_slot = epoch_schedule.first_normal_slot;
4156        assert_eq!(
4157            is_commission_update_allowed(first_normal_slot + slot, &epoch_schedule),
4158            expected_allowed
4159        );
4160    }
4161}