solana_program/vote/state/
mod.rs

1//! Vote state
2
3#[cfg(not(target_os = "solana"))]
4use bincode::deserialize;
5#[cfg(test)]
6use {
7    crate::epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET,
8    arbitrary::{Arbitrary, Unstructured},
9};
10use {
11    crate::{
12        hash::Hash,
13        instruction::InstructionError,
14        pubkey::Pubkey,
15        rent::Rent,
16        serialize_utils::cursor::read_u32,
17        sysvar::clock::Clock,
18        vote::{authorized_voters::AuthorizedVoters, error::VoteError},
19    },
20    bincode::{serialize_into, ErrorKind},
21    serde_derive::{Deserialize, Serialize},
22    solana_clock::{Epoch, Slot, UnixTimestamp},
23    std::{
24        collections::VecDeque,
25        fmt::Debug,
26        io::Cursor,
27        mem::{self, MaybeUninit},
28    },
29};
30
31mod vote_state_0_23_5;
32pub mod vote_state_1_14_11;
33pub use vote_state_1_14_11::*;
34mod vote_state_deserialize;
35use vote_state_deserialize::deserialize_vote_state_into;
36pub mod vote_state_versions;
37pub use vote_state_versions::*;
38
39// Maximum number of votes to keep around, tightly coupled with epoch_schedule::MINIMUM_SLOTS_PER_EPOCH
40pub const MAX_LOCKOUT_HISTORY: usize = 31;
41pub const INITIAL_LOCKOUT: usize = 2;
42
43// Maximum number of credits history to keep around
44pub const MAX_EPOCH_CREDITS_HISTORY: usize = 64;
45
46// Offset of VoteState::prior_voters, for determining initialization status without deserialization
47const DEFAULT_PRIOR_VOTERS_OFFSET: usize = 114;
48
49// Number of slots of grace period for which maximum vote credits are awarded - votes landing within this number of slots of the slot that is being voted on are awarded full credits.
50pub const VOTE_CREDITS_GRACE_SLOTS: u8 = 2;
51
52// Maximum number of credits to award for a vote; this number of credits is awarded to votes on slots that land within the grace period. After that grace period, vote credits are reduced.
53pub const VOTE_CREDITS_MAXIMUM_PER_SLOT: u8 = 16;
54
55#[cfg_attr(
56    feature = "frozen-abi",
57    frozen_abi(digest = "GvUzgtcxhKVVxPAjSntXGPqjLZK5ovgZzCiUP1tDpB9q"),
58    derive(AbiExample)
59)]
60#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone)]
61pub struct Vote {
62    /// A stack of votes starting with the oldest vote
63    pub slots: Vec<Slot>,
64    /// signature of the bank's state at the last slot
65    pub hash: Hash,
66    /// processing timestamp of last slot
67    pub timestamp: Option<UnixTimestamp>,
68}
69
70impl Vote {
71    pub fn new(slots: Vec<Slot>, hash: Hash) -> Self {
72        Self {
73            slots,
74            hash,
75            timestamp: None,
76        }
77    }
78
79    pub fn last_voted_slot(&self) -> Option<Slot> {
80        self.slots.last().copied()
81    }
82}
83
84#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
85#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Copy, Clone)]
86#[cfg_attr(test, derive(Arbitrary))]
87pub struct Lockout {
88    slot: Slot,
89    confirmation_count: u32,
90}
91
92impl Lockout {
93    pub fn new(slot: Slot) -> Self {
94        Self::new_with_confirmation_count(slot, 1)
95    }
96
97    pub fn new_with_confirmation_count(slot: Slot, confirmation_count: u32) -> Self {
98        Self {
99            slot,
100            confirmation_count,
101        }
102    }
103
104    // The number of slots for which this vote is locked
105    pub fn lockout(&self) -> u64 {
106        (INITIAL_LOCKOUT as u64).pow(self.confirmation_count())
107    }
108
109    // The last slot at which a vote is still locked out. Validators should not
110    // vote on a slot in another fork which is less than or equal to this slot
111    // to avoid having their stake slashed.
112    pub fn last_locked_out_slot(&self) -> Slot {
113        self.slot.saturating_add(self.lockout())
114    }
115
116    pub fn is_locked_out_at_slot(&self, slot: Slot) -> bool {
117        self.last_locked_out_slot() >= slot
118    }
119
120    pub fn slot(&self) -> Slot {
121        self.slot
122    }
123
124    pub fn confirmation_count(&self) -> u32 {
125        self.confirmation_count
126    }
127
128    pub fn increase_confirmation_count(&mut self, by: u32) {
129        self.confirmation_count = self.confirmation_count.saturating_add(by)
130    }
131}
132
133#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
134#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Copy, Clone)]
135#[cfg_attr(test, derive(Arbitrary))]
136pub struct LandedVote {
137    // Latency is the difference in slot number between the slot that was voted on (lockout.slot) and the slot in
138    // which the vote that added this Lockout landed.  For votes which were cast before versions of the validator
139    // software which recorded vote latencies, latency is recorded as 0.
140    pub latency: u8,
141    pub lockout: Lockout,
142}
143
144impl LandedVote {
145    pub fn slot(&self) -> Slot {
146        self.lockout.slot
147    }
148
149    pub fn confirmation_count(&self) -> u32 {
150        self.lockout.confirmation_count
151    }
152}
153
154impl From<LandedVote> for Lockout {
155    fn from(landed_vote: LandedVote) -> Self {
156        landed_vote.lockout
157    }
158}
159
160impl From<Lockout> for LandedVote {
161    fn from(lockout: Lockout) -> Self {
162        Self {
163            latency: 0,
164            lockout,
165        }
166    }
167}
168
169#[cfg_attr(
170    feature = "frozen-abi",
171    frozen_abi(digest = "DRKTb72wifCUcCTSJs6PqWrQQK5Pfis4SCLEvXqWnDaL"),
172    derive(AbiExample)
173)]
174#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone)]
175pub struct VoteStateUpdate {
176    /// The proposed tower
177    pub lockouts: VecDeque<Lockout>,
178    /// The proposed root
179    pub root: Option<Slot>,
180    /// signature of the bank's state at the last slot
181    pub hash: Hash,
182    /// processing timestamp of last slot
183    pub timestamp: Option<UnixTimestamp>,
184}
185
186impl From<Vec<(Slot, u32)>> for VoteStateUpdate {
187    fn from(recent_slots: Vec<(Slot, u32)>) -> Self {
188        let lockouts: VecDeque<Lockout> = recent_slots
189            .into_iter()
190            .map(|(slot, confirmation_count)| {
191                Lockout::new_with_confirmation_count(slot, confirmation_count)
192            })
193            .collect();
194        Self {
195            lockouts,
196            root: None,
197            hash: Hash::default(),
198            timestamp: None,
199        }
200    }
201}
202
203impl VoteStateUpdate {
204    pub fn new(lockouts: VecDeque<Lockout>, root: Option<Slot>, hash: Hash) -> Self {
205        Self {
206            lockouts,
207            root,
208            hash,
209            timestamp: None,
210        }
211    }
212
213    pub fn slots(&self) -> Vec<Slot> {
214        self.lockouts.iter().map(|lockout| lockout.slot()).collect()
215    }
216
217    pub fn last_voted_slot(&self) -> Option<Slot> {
218        self.lockouts.back().map(|l| l.slot())
219    }
220}
221
222#[cfg_attr(
223    feature = "frozen-abi",
224    frozen_abi(digest = "5PFw9pyF1UG1DXVsw7gpjHegNyRycAAxWf2GA9wUXPs5"),
225    derive(AbiExample)
226)]
227#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone)]
228pub struct TowerSync {
229    /// The proposed tower
230    pub lockouts: VecDeque<Lockout>,
231    /// The proposed root
232    pub root: Option<Slot>,
233    /// signature of the bank's state at the last slot
234    pub hash: Hash,
235    /// processing timestamp of last slot
236    pub timestamp: Option<UnixTimestamp>,
237    /// the unique identifier for the chain up to and
238    /// including this block. Does not require replaying
239    /// in order to compute.
240    pub block_id: Hash,
241}
242
243impl From<Vec<(Slot, u32)>> for TowerSync {
244    fn from(recent_slots: Vec<(Slot, u32)>) -> Self {
245        let lockouts: VecDeque<Lockout> = recent_slots
246            .into_iter()
247            .map(|(slot, confirmation_count)| {
248                Lockout::new_with_confirmation_count(slot, confirmation_count)
249            })
250            .collect();
251        Self {
252            lockouts,
253            root: None,
254            hash: Hash::default(),
255            timestamp: None,
256            block_id: Hash::default(),
257        }
258    }
259}
260
261impl TowerSync {
262    pub fn new(
263        lockouts: VecDeque<Lockout>,
264        root: Option<Slot>,
265        hash: Hash,
266        block_id: Hash,
267    ) -> Self {
268        Self {
269            lockouts,
270            root,
271            hash,
272            timestamp: None,
273            block_id,
274        }
275    }
276
277    /// Creates a tower with consecutive votes for `slot - MAX_LOCKOUT_HISTORY + 1` to `slot` inclusive.
278    /// If `slot >= MAX_LOCKOUT_HISTORY`, sets the root to `(slot - MAX_LOCKOUT_HISTORY)`
279    /// Sets the hash to `hash` and leaves `block_id` unset.
280    pub fn new_from_slot(slot: Slot, hash: Hash) -> Self {
281        let lowest_slot = slot
282            .saturating_add(1)
283            .saturating_sub(MAX_LOCKOUT_HISTORY as u64);
284        let slots: Vec<_> = (lowest_slot..slot.saturating_add(1)).collect();
285        Self::new_from_slots(
286            slots,
287            hash,
288            (lowest_slot > 0).then(|| lowest_slot.saturating_sub(1)),
289        )
290    }
291
292    /// Creates a tower with consecutive confirmation for `slots`
293    pub fn new_from_slots(slots: Vec<Slot>, hash: Hash, root: Option<Slot>) -> Self {
294        let lockouts: VecDeque<Lockout> = slots
295            .into_iter()
296            .rev()
297            .enumerate()
298            .map(|(cc, s)| Lockout::new_with_confirmation_count(s, cc.saturating_add(1) as u32))
299            .rev()
300            .collect();
301        Self {
302            lockouts,
303            hash,
304            root,
305            timestamp: None,
306            block_id: Hash::default(),
307        }
308    }
309
310    pub fn slots(&self) -> Vec<Slot> {
311        self.lockouts.iter().map(|lockout| lockout.slot()).collect()
312    }
313
314    pub fn last_voted_slot(&self) -> Option<Slot> {
315        self.lockouts.back().map(|l| l.slot())
316    }
317}
318
319#[derive(Default, Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
320pub struct VoteInit {
321    pub node_pubkey: Pubkey,
322    pub authorized_voter: Pubkey,
323    pub authorized_withdrawer: Pubkey,
324    pub commission: u8,
325}
326
327#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
328pub enum VoteAuthorize {
329    Voter,
330    Withdrawer,
331}
332
333#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
334pub struct VoteAuthorizeWithSeedArgs {
335    pub authorization_type: VoteAuthorize,
336    pub current_authority_derived_key_owner: Pubkey,
337    pub current_authority_derived_key_seed: String,
338    pub new_authority: Pubkey,
339}
340
341#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
342pub struct VoteAuthorizeCheckedWithSeedArgs {
343    pub authorization_type: VoteAuthorize,
344    pub current_authority_derived_key_owner: Pubkey,
345    pub current_authority_derived_key_seed: String,
346}
347
348#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
349#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone)]
350#[cfg_attr(test, derive(Arbitrary))]
351pub struct BlockTimestamp {
352    pub slot: Slot,
353    pub timestamp: UnixTimestamp,
354}
355
356// this is how many epochs a voter can be remembered for slashing
357const MAX_ITEMS: usize = 32;
358
359#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
360#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
361#[cfg_attr(test, derive(Arbitrary))]
362pub struct CircBuf<I> {
363    buf: [I; MAX_ITEMS],
364    /// next pointer
365    idx: usize,
366    is_empty: bool,
367}
368
369impl<I: Default + Copy> Default for CircBuf<I> {
370    fn default() -> Self {
371        Self {
372            buf: [I::default(); MAX_ITEMS],
373            idx: MAX_ITEMS
374                .checked_sub(1)
375                .expect("`MAX_ITEMS` should be positive"),
376            is_empty: true,
377        }
378    }
379}
380
381impl<I> CircBuf<I> {
382    pub fn append(&mut self, item: I) {
383        // remember prior delegate and when we switched, to support later slashing
384        self.idx = self
385            .idx
386            .checked_add(1)
387            .and_then(|idx| idx.checked_rem(MAX_ITEMS))
388            .expect("`self.idx` should be < `MAX_ITEMS` which should be non-zero");
389
390        self.buf[self.idx] = item;
391        self.is_empty = false;
392    }
393
394    pub fn buf(&self) -> &[I; MAX_ITEMS] {
395        &self.buf
396    }
397
398    pub fn last(&self) -> Option<&I> {
399        if !self.is_empty {
400            self.buf.get(self.idx)
401        } else {
402            None
403        }
404    }
405}
406
407#[cfg_attr(
408    feature = "frozen-abi",
409    frozen_abi(digest = "87ULMjjHnMsPmCTEyzj4KPn2u5gdX1rmgtSdycpbSaLs"),
410    derive(AbiExample)
411)]
412#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone)]
413#[cfg_attr(test, derive(Arbitrary))]
414pub struct VoteState {
415    /// the node that votes in this account
416    pub node_pubkey: Pubkey,
417
418    /// the signer for withdrawals
419    pub authorized_withdrawer: Pubkey,
420    /// percentage (0-100) that represents what part of a rewards
421    ///  payout should be given to this VoteAccount
422    pub commission: u8,
423
424    pub votes: VecDeque<LandedVote>,
425
426    // This usually the last Lockout which was popped from self.votes.
427    // However, it can be arbitrary slot, when being used inside Tower
428    pub root_slot: Option<Slot>,
429
430    /// the signer for vote transactions
431    authorized_voters: AuthorizedVoters,
432
433    /// history of prior authorized voters and the epochs for which
434    /// they were set, the bottom end of the range is inclusive,
435    /// the top of the range is exclusive
436    prior_voters: CircBuf<(Pubkey, Epoch, Epoch)>,
437
438    /// history of how many credits earned by the end of each epoch
439    ///  each tuple is (Epoch, credits, prev_credits)
440    pub epoch_credits: Vec<(Epoch, u64, u64)>,
441
442    /// most recent timestamp submitted with a vote
443    pub last_timestamp: BlockTimestamp,
444}
445
446impl VoteState {
447    pub fn new(vote_init: &VoteInit, clock: &Clock) -> Self {
448        Self {
449            node_pubkey: vote_init.node_pubkey,
450            authorized_voters: AuthorizedVoters::new(clock.epoch, vote_init.authorized_voter),
451            authorized_withdrawer: vote_init.authorized_withdrawer,
452            commission: vote_init.commission,
453            ..VoteState::default()
454        }
455    }
456
457    pub fn new_rand_for_tests(node_pubkey: Pubkey, root_slot: Slot) -> Self {
458        let votes = (1..32)
459            .map(|x| LandedVote {
460                latency: 0,
461                lockout: Lockout::new_with_confirmation_count(
462                    u64::from(x).saturating_add(root_slot),
463                    32_u32.saturating_sub(x),
464                ),
465            })
466            .collect();
467        Self {
468            node_pubkey,
469            root_slot: Some(root_slot),
470            votes,
471            ..VoteState::default()
472        }
473    }
474
475    pub fn get_authorized_voter(&self, epoch: Epoch) -> Option<Pubkey> {
476        self.authorized_voters.get_authorized_voter(epoch)
477    }
478
479    pub fn authorized_voters(&self) -> &AuthorizedVoters {
480        &self.authorized_voters
481    }
482
483    pub fn prior_voters(&mut self) -> &CircBuf<(Pubkey, Epoch, Epoch)> {
484        &self.prior_voters
485    }
486
487    pub fn get_rent_exempt_reserve(rent: &Rent) -> u64 {
488        rent.minimum_balance(VoteState::size_of())
489    }
490
491    /// Upper limit on the size of the Vote State
492    /// when votes.len() is MAX_LOCKOUT_HISTORY.
493    pub const fn size_of() -> usize {
494        3762 // see test_vote_state_size_of.
495    }
496
497    // NOTE we retain `bincode::deserialize` for `not(target_os = "solana")` pending testing on mainnet-beta
498    // once that testing is done, `VoteState::deserialize_into` may be used for all targets
499    // conversion of V0_23_5 to current must be handled specially, however
500    // because it inserts a null voter into `authorized_voters`
501    // which `VoteStateVersions::is_uninitialized` erroneously reports as initialized
502    pub fn deserialize(input: &[u8]) -> Result<Self, InstructionError> {
503        #[cfg(not(target_os = "solana"))]
504        {
505            deserialize::<VoteStateVersions>(input)
506                .map(|versioned| versioned.convert_to_current())
507                .map_err(|_| InstructionError::InvalidAccountData)
508        }
509        #[cfg(target_os = "solana")]
510        {
511            let mut vote_state = Self::default();
512            Self::deserialize_into(input, &mut vote_state)?;
513            Ok(vote_state)
514        }
515    }
516
517    /// Deserializes the input `VoteStateVersions` buffer directly into the provided `VoteState`.
518    ///
519    /// In a SBPF context, V0_23_5 is not supported, but in non-SBPF, all versions are supported for
520    /// compatibility with `bincode::deserialize`.
521    ///
522    /// On success, `vote_state` reflects the state of the input data. On failure, `vote_state` is
523    /// reset to `VoteState::default()`.
524    pub fn deserialize_into(
525        input: &[u8],
526        vote_state: &mut VoteState,
527    ) -> Result<(), InstructionError> {
528        // Rebind vote_state to *mut VoteState so that the &mut binding isn't
529        // accessible anymore, preventing accidental use after this point.
530        //
531        // NOTE: switch to ptr::from_mut() once platform-tools moves to rustc >= 1.76
532        let vote_state = vote_state as *mut VoteState;
533
534        // Safety: vote_state is valid to_drop (see drop_in_place() docs). After
535        // dropping, the pointer is treated as uninitialized and only accessed
536        // through ptr::write, which is safe as per drop_in_place docs.
537        unsafe {
538            std::ptr::drop_in_place(vote_state);
539        }
540
541        // This is to reset vote_state to VoteState::default() if deserialize fails or panics.
542        struct DropGuard {
543            vote_state: *mut VoteState,
544        }
545
546        impl Drop for DropGuard {
547            fn drop(&mut self) {
548                // Safety:
549                //
550                // Deserialize failed or panicked so at this point vote_state is uninitialized. We
551                // must write a new _valid_ value into it or after returning (or unwinding) from
552                // this function the caller is left with an uninitialized `&mut VoteState`, which is
553                // UB (references must always be valid).
554                //
555                // This is always safe and doesn't leak memory because deserialize_into_ptr() writes
556                // into the fields that heap alloc only when it returns Ok().
557                unsafe {
558                    self.vote_state.write(VoteState::default());
559                }
560            }
561        }
562
563        let guard = DropGuard { vote_state };
564
565        let res = VoteState::deserialize_into_ptr(input, vote_state);
566        if res.is_ok() {
567            mem::forget(guard);
568        }
569
570        res
571    }
572
573    /// Deserializes the input `VoteStateVersions` buffer directly into the provided
574    /// `MaybeUninit<VoteState>`.
575    ///
576    /// In a SBPF context, V0_23_5 is not supported, but in non-SBPF, all versions are supported for
577    /// compatibility with `bincode::deserialize`.
578    ///
579    /// On success, `vote_state` is fully initialized and can be converted to `VoteState` using
580    /// [MaybeUninit::assume_init]. On failure, `vote_state` may still be uninitialized and must not
581    /// be converted to `VoteState`.
582    pub fn deserialize_into_uninit(
583        input: &[u8],
584        vote_state: &mut MaybeUninit<VoteState>,
585    ) -> Result<(), InstructionError> {
586        VoteState::deserialize_into_ptr(input, vote_state.as_mut_ptr())
587    }
588
589    fn deserialize_into_ptr(
590        input: &[u8],
591        vote_state: *mut VoteState,
592    ) -> Result<(), InstructionError> {
593        let mut cursor = Cursor::new(input);
594
595        let variant = read_u32(&mut cursor)?;
596        match variant {
597            // V0_23_5. not supported for bpf targets; these should not exist on mainnet
598            // supported for non-bpf targets for backwards compatibility
599            0 => {
600                #[cfg(not(target_os = "solana"))]
601                {
602                    // Safety: vote_state is valid as it comes from `&mut MaybeUninit<VoteState>` or
603                    // `&mut VoteState`. In the first case, the value is uninitialized so we write()
604                    // to avoid dropping invalid data; in the latter case, we `drop_in_place()`
605                    // before writing so the value has already been dropped and we just write a new
606                    // one in place.
607                    unsafe {
608                        vote_state.write(
609                            bincode::deserialize::<VoteStateVersions>(input)
610                                .map(|versioned| versioned.convert_to_current())
611                                .map_err(|_| InstructionError::InvalidAccountData)?,
612                        );
613                    }
614                    Ok(())
615                }
616                #[cfg(target_os = "solana")]
617                Err(InstructionError::InvalidAccountData)
618            }
619            // V1_14_11. substantially different layout and data from V0_23_5
620            1 => deserialize_vote_state_into(&mut cursor, vote_state, false),
621            // Current. the only difference from V1_14_11 is the addition of a slot-latency to each vote
622            2 => deserialize_vote_state_into(&mut cursor, vote_state, true),
623            _ => Err(InstructionError::InvalidAccountData),
624        }?;
625
626        Ok(())
627    }
628
629    pub fn serialize(
630        versioned: &VoteStateVersions,
631        output: &mut [u8],
632    ) -> Result<(), InstructionError> {
633        serialize_into(output, versioned).map_err(|err| match *err {
634            ErrorKind::SizeLimit => InstructionError::AccountDataTooSmall,
635            _ => InstructionError::GenericError,
636        })
637    }
638
639    /// returns commission split as (voter_portion, staker_portion, was_split) tuple
640    ///
641    ///  if commission calculation is 100% one way or other,
642    ///   indicate with false for was_split
643    pub fn commission_split(&self, on: u64) -> (u64, u64, bool) {
644        match self.commission.min(100) {
645            0 => (0, on, false),
646            100 => (on, 0, false),
647            split => {
648                let on = u128::from(on);
649                // Calculate mine and theirs independently and symmetrically instead of
650                // using the remainder of the other to treat them strictly equally.
651                // This is also to cancel the rewarding if either of the parties
652                // should receive only fractional lamports, resulting in not being rewarded at all.
653                // Thus, note that we intentionally discard any residual fractional lamports.
654                let mine = on
655                    .checked_mul(u128::from(split))
656                    .expect("multiplication of a u64 and u8 should not overflow")
657                    / 100u128;
658                let theirs = on
659                    .checked_mul(u128::from(
660                        100u8
661                            .checked_sub(split)
662                            .expect("commission cannot be greater than 100"),
663                    ))
664                    .expect("multiplication of a u64 and u8 should not overflow")
665                    / 100u128;
666
667                (mine as u64, theirs as u64, true)
668            }
669        }
670    }
671
672    /// Returns if the vote state contains a slot `candidate_slot`
673    pub fn contains_slot(&self, candidate_slot: Slot) -> bool {
674        self.votes
675            .binary_search_by(|vote| vote.slot().cmp(&candidate_slot))
676            .is_ok()
677    }
678
679    #[cfg(test)]
680    fn get_max_sized_vote_state() -> VoteState {
681        let mut authorized_voters = AuthorizedVoters::default();
682        for i in 0..=MAX_LEADER_SCHEDULE_EPOCH_OFFSET {
683            authorized_voters.insert(i, Pubkey::new_unique());
684        }
685
686        VoteState {
687            votes: VecDeque::from(vec![LandedVote::default(); MAX_LOCKOUT_HISTORY]),
688            root_slot: Some(u64::MAX),
689            epoch_credits: vec![(0, 0, 0); MAX_EPOCH_CREDITS_HISTORY],
690            authorized_voters,
691            ..Self::default()
692        }
693    }
694
695    pub fn process_next_vote_slot(
696        &mut self,
697        next_vote_slot: Slot,
698        epoch: Epoch,
699        current_slot: Slot,
700        timely_vote_credits: bool,
701    ) {
702        // Ignore votes for slots earlier than we already have votes for
703        if self
704            .last_voted_slot()
705            .map_or(false, |last_voted_slot| next_vote_slot <= last_voted_slot)
706        {
707            return;
708        }
709
710        self.pop_expired_votes(next_vote_slot);
711
712        let landed_vote = LandedVote {
713            latency: if timely_vote_credits {
714                Self::compute_vote_latency(next_vote_slot, current_slot)
715            } else {
716                0
717            },
718            lockout: Lockout::new(next_vote_slot),
719        };
720
721        // Once the stack is full, pop the oldest lockout and distribute rewards
722        if self.votes.len() == MAX_LOCKOUT_HISTORY {
723            let credits = self.credits_for_vote_at_index(0, timely_vote_credits);
724            let landed_vote = self.votes.pop_front().unwrap();
725            self.root_slot = Some(landed_vote.slot());
726
727            self.increment_credits(epoch, credits);
728        }
729        self.votes.push_back(landed_vote);
730        self.double_lockouts();
731    }
732
733    /// increment credits, record credits for last epoch if new epoch
734    pub fn increment_credits(&mut self, epoch: Epoch, credits: u64) {
735        // increment credits, record by epoch
736
737        // never seen a credit
738        if self.epoch_credits.is_empty() {
739            self.epoch_credits.push((epoch, 0, 0));
740        } else if epoch != self.epoch_credits.last().unwrap().0 {
741            let (_, credits, prev_credits) = *self.epoch_credits.last().unwrap();
742
743            if credits != prev_credits {
744                // if credits were earned previous epoch
745                // append entry at end of list for the new epoch
746                self.epoch_credits.push((epoch, credits, credits));
747            } else {
748                // else just move the current epoch
749                self.epoch_credits.last_mut().unwrap().0 = epoch;
750            }
751
752            // Remove too old epoch_credits
753            if self.epoch_credits.len() > MAX_EPOCH_CREDITS_HISTORY {
754                self.epoch_credits.remove(0);
755            }
756        }
757
758        self.epoch_credits.last_mut().unwrap().1 =
759            self.epoch_credits.last().unwrap().1.saturating_add(credits);
760    }
761
762    // Computes the vote latency for vote on voted_for_slot where the vote itself landed in current_slot
763    pub fn compute_vote_latency(voted_for_slot: Slot, current_slot: Slot) -> u8 {
764        std::cmp::min(current_slot.saturating_sub(voted_for_slot), u8::MAX as u64) as u8
765    }
766
767    /// Returns the credits to award for a vote at the given lockout slot index
768    pub fn credits_for_vote_at_index(&self, index: usize, timely_vote_credits: bool) -> u64 {
769        let latency = self
770            .votes
771            .get(index)
772            .map_or(0, |landed_vote| landed_vote.latency);
773
774        // If latency is 0, this means that the Lockout was created and stored from a software version that did not
775        // store vote latencies; in this case, 1 credit is awarded
776        if latency == 0 || !timely_vote_credits {
777            1
778        } else {
779            match latency.checked_sub(VOTE_CREDITS_GRACE_SLOTS) {
780                None | Some(0) => {
781                    // latency was <= VOTE_CREDITS_GRACE_SLOTS, so maximum credits are awarded
782                    VOTE_CREDITS_MAXIMUM_PER_SLOT as u64
783                }
784
785                Some(diff) => {
786                    // diff = latency - VOTE_CREDITS_GRACE_SLOTS, and diff > 0
787                    // Subtract diff from VOTE_CREDITS_MAXIMUM_PER_SLOT which is the number of credits to award
788                    match VOTE_CREDITS_MAXIMUM_PER_SLOT.checked_sub(diff) {
789                        // If diff >= VOTE_CREDITS_MAXIMUM_PER_SLOT, 1 credit is awarded
790                        None | Some(0) => 1,
791
792                        Some(credits) => credits as u64,
793                    }
794                }
795            }
796        }
797    }
798
799    pub fn nth_recent_lockout(&self, position: usize) -> Option<&Lockout> {
800        if position < self.votes.len() {
801            let pos = self
802                .votes
803                .len()
804                .checked_sub(position)
805                .and_then(|pos| pos.checked_sub(1))?;
806            self.votes.get(pos).map(|vote| &vote.lockout)
807        } else {
808            None
809        }
810    }
811
812    pub fn last_lockout(&self) -> Option<&Lockout> {
813        self.votes.back().map(|vote| &vote.lockout)
814    }
815
816    pub fn last_voted_slot(&self) -> Option<Slot> {
817        self.last_lockout().map(|v| v.slot())
818    }
819
820    // Upto MAX_LOCKOUT_HISTORY many recent unexpired
821    // vote slots pushed onto the stack.
822    pub fn tower(&self) -> Vec<Slot> {
823        self.votes.iter().map(|v| v.slot()).collect()
824    }
825
826    pub fn current_epoch(&self) -> Epoch {
827        if self.epoch_credits.is_empty() {
828            0
829        } else {
830            self.epoch_credits.last().unwrap().0
831        }
832    }
833
834    /// Number of "credits" owed to this account from the mining pool. Submit this
835    /// VoteState to the Rewards program to trade credits for lamports.
836    pub fn credits(&self) -> u64 {
837        if self.epoch_credits.is_empty() {
838            0
839        } else {
840            self.epoch_credits.last().unwrap().1
841        }
842    }
843
844    /// Number of "credits" owed to this account from the mining pool on a per-epoch basis,
845    ///  starting from credits observed.
846    /// Each tuple of (Epoch, u64, u64) is read as (epoch, credits, prev_credits), where
847    ///   credits for each epoch is credits - prev_credits; while redundant this makes
848    ///   calculating rewards over partial epochs nice and simple
849    pub fn epoch_credits(&self) -> &Vec<(Epoch, u64, u64)> {
850        &self.epoch_credits
851    }
852
853    pub fn set_new_authorized_voter<F>(
854        &mut self,
855        authorized_pubkey: &Pubkey,
856        current_epoch: Epoch,
857        target_epoch: Epoch,
858        verify: F,
859    ) -> Result<(), InstructionError>
860    where
861        F: Fn(Pubkey) -> Result<(), InstructionError>,
862    {
863        let epoch_authorized_voter = self.get_and_update_authorized_voter(current_epoch)?;
864        verify(epoch_authorized_voter)?;
865
866        // The offset in slots `n` on which the target_epoch
867        // (default value `DEFAULT_LEADER_SCHEDULE_SLOT_OFFSET`) is
868        // calculated is the number of slots available from the
869        // first slot `S` of an epoch in which to set a new voter for
870        // the epoch at `S` + `n`
871        if self.authorized_voters.contains(target_epoch) {
872            return Err(VoteError::TooSoonToReauthorize.into());
873        }
874
875        // Get the latest authorized_voter
876        let (latest_epoch, latest_authorized_pubkey) = self
877            .authorized_voters
878            .last()
879            .ok_or(InstructionError::InvalidAccountData)?;
880
881        // If we're not setting the same pubkey as authorized pubkey again,
882        // then update the list of prior voters to mark the expiration
883        // of the old authorized pubkey
884        if latest_authorized_pubkey != authorized_pubkey {
885            // Update the epoch ranges of authorized pubkeys that will be expired
886            let epoch_of_last_authorized_switch =
887                self.prior_voters.last().map(|range| range.2).unwrap_or(0);
888
889            // target_epoch must:
890            // 1) Be monotonically increasing due to the clock always
891            //    moving forward
892            // 2) not be equal to latest epoch otherwise this
893            //    function would have returned TooSoonToReauthorize error
894            //    above
895            if target_epoch <= *latest_epoch {
896                return Err(InstructionError::InvalidAccountData);
897            }
898
899            // Commit the new state
900            self.prior_voters.append((
901                *latest_authorized_pubkey,
902                epoch_of_last_authorized_switch,
903                target_epoch,
904            ));
905        }
906
907        self.authorized_voters
908            .insert(target_epoch, *authorized_pubkey);
909
910        Ok(())
911    }
912
913    pub fn get_and_update_authorized_voter(
914        &mut self,
915        current_epoch: Epoch,
916    ) -> Result<Pubkey, InstructionError> {
917        let pubkey = self
918            .authorized_voters
919            .get_and_cache_authorized_voter_for_epoch(current_epoch)
920            .ok_or(InstructionError::InvalidAccountData)?;
921        self.authorized_voters
922            .purge_authorized_voters(current_epoch);
923        Ok(pubkey)
924    }
925
926    // Pop all recent votes that are not locked out at the next vote slot.  This
927    // allows validators to switch forks once their votes for another fork have
928    // expired. This also allows validators continue voting on recent blocks in
929    // the same fork without increasing lockouts.
930    pub fn pop_expired_votes(&mut self, next_vote_slot: Slot) {
931        while let Some(vote) = self.last_lockout() {
932            if !vote.is_locked_out_at_slot(next_vote_slot) {
933                self.votes.pop_back();
934            } else {
935                break;
936            }
937        }
938    }
939
940    pub fn double_lockouts(&mut self) {
941        let stack_depth = self.votes.len();
942        for (i, v) in self.votes.iter_mut().enumerate() {
943            // Don't increase the lockout for this vote until we get more confirmations
944            // than the max number of confirmations this vote has seen
945            if stack_depth >
946                i.checked_add(v.confirmation_count() as usize)
947                    .expect("`confirmation_count` and tower_size should be bounded by `MAX_LOCKOUT_HISTORY`")
948            {
949                v.lockout.increase_confirmation_count(1);
950            }
951        }
952    }
953
954    pub fn process_timestamp(
955        &mut self,
956        slot: Slot,
957        timestamp: UnixTimestamp,
958    ) -> Result<(), VoteError> {
959        if (slot < self.last_timestamp.slot || timestamp < self.last_timestamp.timestamp)
960            || (slot == self.last_timestamp.slot
961                && BlockTimestamp { slot, timestamp } != self.last_timestamp
962                && self.last_timestamp.slot != 0)
963        {
964            return Err(VoteError::TimestampTooOld);
965        }
966        self.last_timestamp = BlockTimestamp { slot, timestamp };
967        Ok(())
968    }
969
970    pub fn is_correct_size_and_initialized(data: &[u8]) -> bool {
971        const VERSION_OFFSET: usize = 4;
972        const DEFAULT_PRIOR_VOTERS_END: usize = VERSION_OFFSET + DEFAULT_PRIOR_VOTERS_OFFSET;
973        data.len() == VoteState::size_of()
974            && data[VERSION_OFFSET..DEFAULT_PRIOR_VOTERS_END] != [0; DEFAULT_PRIOR_VOTERS_OFFSET]
975    }
976}
977
978pub mod serde_compact_vote_state_update {
979    use {
980        super::*,
981        crate::vote::state::Lockout,
982        serde::{Deserialize, Deserializer, Serialize, Serializer},
983        solana_serde_varint as serde_varint, solana_short_vec as short_vec,
984    };
985
986    #[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
987    #[derive(serde_derive::Deserialize, serde_derive::Serialize)]
988    struct LockoutOffset {
989        #[serde(with = "serde_varint")]
990        offset: Slot,
991        confirmation_count: u8,
992    }
993
994    #[derive(serde_derive::Deserialize, serde_derive::Serialize)]
995    struct CompactVoteStateUpdate {
996        root: Slot,
997        #[serde(with = "short_vec")]
998        lockout_offsets: Vec<LockoutOffset>,
999        hash: Hash,
1000        timestamp: Option<UnixTimestamp>,
1001    }
1002
1003    pub fn serialize<S>(
1004        vote_state_update: &VoteStateUpdate,
1005        serializer: S,
1006    ) -> Result<S::Ok, S::Error>
1007    where
1008        S: Serializer,
1009    {
1010        let lockout_offsets = vote_state_update.lockouts.iter().scan(
1011            vote_state_update.root.unwrap_or_default(),
1012            |slot, lockout| {
1013                let Some(offset) = lockout.slot().checked_sub(*slot) else {
1014                    return Some(Err(serde::ser::Error::custom("Invalid vote lockout")));
1015                };
1016                let Ok(confirmation_count) = u8::try_from(lockout.confirmation_count()) else {
1017                    return Some(Err(serde::ser::Error::custom("Invalid confirmation count")));
1018                };
1019                let lockout_offset = LockoutOffset {
1020                    offset,
1021                    confirmation_count,
1022                };
1023                *slot = lockout.slot();
1024                Some(Ok(lockout_offset))
1025            },
1026        );
1027        let compact_vote_state_update = CompactVoteStateUpdate {
1028            root: vote_state_update.root.unwrap_or(Slot::MAX),
1029            lockout_offsets: lockout_offsets.collect::<Result<_, _>>()?,
1030            hash: vote_state_update.hash,
1031            timestamp: vote_state_update.timestamp,
1032        };
1033        compact_vote_state_update.serialize(serializer)
1034    }
1035
1036    pub fn deserialize<'de, D>(deserializer: D) -> Result<VoteStateUpdate, D::Error>
1037    where
1038        D: Deserializer<'de>,
1039    {
1040        let CompactVoteStateUpdate {
1041            root,
1042            lockout_offsets,
1043            hash,
1044            timestamp,
1045        } = CompactVoteStateUpdate::deserialize(deserializer)?;
1046        let root = (root != Slot::MAX).then_some(root);
1047        let lockouts =
1048            lockout_offsets
1049                .iter()
1050                .scan(root.unwrap_or_default(), |slot, lockout_offset| {
1051                    *slot = match slot.checked_add(lockout_offset.offset) {
1052                        None => {
1053                            return Some(Err(serde::de::Error::custom("Invalid lockout offset")))
1054                        }
1055                        Some(slot) => slot,
1056                    };
1057                    let lockout = Lockout::new_with_confirmation_count(
1058                        *slot,
1059                        u32::from(lockout_offset.confirmation_count),
1060                    );
1061                    Some(Ok(lockout))
1062                });
1063        Ok(VoteStateUpdate {
1064            root,
1065            lockouts: lockouts.collect::<Result<_, _>>()?,
1066            hash,
1067            timestamp,
1068        })
1069    }
1070}
1071
1072pub mod serde_tower_sync {
1073    use {
1074        super::*,
1075        crate::vote::state::Lockout,
1076        serde::{Deserialize, Deserializer, Serialize, Serializer},
1077        solana_serde_varint as serde_varint, solana_short_vec as short_vec,
1078    };
1079
1080    #[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
1081    #[derive(serde_derive::Deserialize, serde_derive::Serialize)]
1082    struct LockoutOffset {
1083        #[serde(with = "serde_varint")]
1084        offset: Slot,
1085        confirmation_count: u8,
1086    }
1087
1088    #[derive(serde_derive::Deserialize, serde_derive::Serialize)]
1089    struct CompactTowerSync {
1090        root: Slot,
1091        #[serde(with = "short_vec")]
1092        lockout_offsets: Vec<LockoutOffset>,
1093        hash: Hash,
1094        timestamp: Option<UnixTimestamp>,
1095        block_id: Hash,
1096    }
1097
1098    pub fn serialize<S>(tower_sync: &TowerSync, serializer: S) -> Result<S::Ok, S::Error>
1099    where
1100        S: Serializer,
1101    {
1102        let lockout_offsets = tower_sync.lockouts.iter().scan(
1103            tower_sync.root.unwrap_or_default(),
1104            |slot, lockout| {
1105                let Some(offset) = lockout.slot().checked_sub(*slot) else {
1106                    return Some(Err(serde::ser::Error::custom("Invalid vote lockout")));
1107                };
1108                let Ok(confirmation_count) = u8::try_from(lockout.confirmation_count()) else {
1109                    return Some(Err(serde::ser::Error::custom("Invalid confirmation count")));
1110                };
1111                let lockout_offset = LockoutOffset {
1112                    offset,
1113                    confirmation_count,
1114                };
1115                *slot = lockout.slot();
1116                Some(Ok(lockout_offset))
1117            },
1118        );
1119        let compact_tower_sync = CompactTowerSync {
1120            root: tower_sync.root.unwrap_or(Slot::MAX),
1121            lockout_offsets: lockout_offsets.collect::<Result<_, _>>()?,
1122            hash: tower_sync.hash,
1123            timestamp: tower_sync.timestamp,
1124            block_id: tower_sync.block_id,
1125        };
1126        compact_tower_sync.serialize(serializer)
1127    }
1128
1129    pub fn deserialize<'de, D>(deserializer: D) -> Result<TowerSync, D::Error>
1130    where
1131        D: Deserializer<'de>,
1132    {
1133        let CompactTowerSync {
1134            root,
1135            lockout_offsets,
1136            hash,
1137            timestamp,
1138            block_id,
1139        } = CompactTowerSync::deserialize(deserializer)?;
1140        let root = (root != Slot::MAX).then_some(root);
1141        let lockouts =
1142            lockout_offsets
1143                .iter()
1144                .scan(root.unwrap_or_default(), |slot, lockout_offset| {
1145                    *slot = match slot.checked_add(lockout_offset.offset) {
1146                        None => {
1147                            return Some(Err(serde::de::Error::custom("Invalid lockout offset")))
1148                        }
1149                        Some(slot) => slot,
1150                    };
1151                    let lockout = Lockout::new_with_confirmation_count(
1152                        *slot,
1153                        u32::from(lockout_offset.confirmation_count),
1154                    );
1155                    Some(Ok(lockout))
1156                });
1157        Ok(TowerSync {
1158            root,
1159            lockouts: lockouts.collect::<Result<_, _>>()?,
1160            hash,
1161            timestamp,
1162            block_id,
1163        })
1164    }
1165}
1166
1167#[cfg(test)]
1168mod tests {
1169    use {super::*, bincode::serialized_size, itertools::Itertools, rand::Rng};
1170
1171    #[test]
1172    fn test_vote_serialize() {
1173        let mut buffer: Vec<u8> = vec![0; VoteState::size_of()];
1174        let mut vote_state = VoteState::default();
1175        vote_state
1176            .votes
1177            .resize(MAX_LOCKOUT_HISTORY, LandedVote::default());
1178        vote_state.root_slot = Some(1);
1179        let versioned = VoteStateVersions::new_current(vote_state);
1180        assert!(VoteState::serialize(&versioned, &mut buffer[0..4]).is_err());
1181        VoteState::serialize(&versioned, &mut buffer).unwrap();
1182        assert_eq!(
1183            VoteState::deserialize(&buffer).unwrap(),
1184            versioned.convert_to_current()
1185        );
1186    }
1187
1188    #[test]
1189    fn test_vote_deserialize_into() {
1190        // base case
1191        let target_vote_state = VoteState::default();
1192        let vote_state_buf =
1193            bincode::serialize(&VoteStateVersions::new_current(target_vote_state.clone())).unwrap();
1194
1195        let mut test_vote_state = VoteState::default();
1196        VoteState::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap();
1197
1198        assert_eq!(target_vote_state, test_vote_state);
1199
1200        // variant
1201        // provide 4x the minimum struct size in bytes to ensure we typically touch every field
1202        let struct_bytes_x4 = std::mem::size_of::<VoteState>() * 4;
1203        for _ in 0..1000 {
1204            let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
1205            let mut unstructured = Unstructured::new(&raw_data);
1206
1207            let target_vote_state_versions =
1208                VoteStateVersions::arbitrary(&mut unstructured).unwrap();
1209            let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
1210            let target_vote_state = target_vote_state_versions.convert_to_current();
1211
1212            let mut test_vote_state = VoteState::default();
1213            VoteState::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap();
1214
1215            assert_eq!(target_vote_state, test_vote_state);
1216        }
1217    }
1218
1219    #[test]
1220    fn test_vote_deserialize_into_error() {
1221        let target_vote_state = VoteState::new_rand_for_tests(Pubkey::new_unique(), 42);
1222        let mut vote_state_buf =
1223            bincode::serialize(&VoteStateVersions::new_current(target_vote_state.clone())).unwrap();
1224        let len = vote_state_buf.len();
1225        vote_state_buf.truncate(len - 1);
1226
1227        let mut test_vote_state = VoteState::default();
1228        VoteState::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap_err();
1229        assert_eq!(test_vote_state, VoteState::default());
1230    }
1231
1232    #[test]
1233    fn test_vote_deserialize_into_uninit() {
1234        // base case
1235        let target_vote_state = VoteState::default();
1236        let vote_state_buf =
1237            bincode::serialize(&VoteStateVersions::new_current(target_vote_state.clone())).unwrap();
1238
1239        let mut test_vote_state = MaybeUninit::uninit();
1240        VoteState::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap();
1241        let test_vote_state = unsafe { test_vote_state.assume_init() };
1242
1243        assert_eq!(target_vote_state, test_vote_state);
1244
1245        // variant
1246        // provide 4x the minimum struct size in bytes to ensure we typically touch every field
1247        let struct_bytes_x4 = std::mem::size_of::<VoteState>() * 4;
1248        for _ in 0..1000 {
1249            let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
1250            let mut unstructured = Unstructured::new(&raw_data);
1251
1252            let target_vote_state_versions =
1253                VoteStateVersions::arbitrary(&mut unstructured).unwrap();
1254            let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
1255            let target_vote_state = target_vote_state_versions.convert_to_current();
1256
1257            let mut test_vote_state = MaybeUninit::uninit();
1258            VoteState::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap();
1259            let test_vote_state = unsafe { test_vote_state.assume_init() };
1260
1261            assert_eq!(target_vote_state, test_vote_state);
1262        }
1263    }
1264
1265    #[test]
1266    fn test_vote_deserialize_into_uninit_nopanic() {
1267        // base case
1268        let mut test_vote_state = MaybeUninit::uninit();
1269        let e = VoteState::deserialize_into_uninit(&[], &mut test_vote_state).unwrap_err();
1270        assert_eq!(e, InstructionError::InvalidAccountData);
1271
1272        // variant
1273        let serialized_len_x4 = serialized_size(&VoteState::default()).unwrap() * 4;
1274        let mut rng = rand::thread_rng();
1275        for _ in 0..1000 {
1276            let raw_data_length = rng.gen_range(1..serialized_len_x4);
1277            let mut raw_data: Vec<u8> = (0..raw_data_length).map(|_| rng.gen::<u8>()).collect();
1278
1279            // pure random data will ~never have a valid enum tag, so lets help it out
1280            if raw_data_length >= 4 && rng.gen::<bool>() {
1281                let tag = rng.gen::<u8>() % 3;
1282                raw_data[0] = tag;
1283                raw_data[1] = 0;
1284                raw_data[2] = 0;
1285                raw_data[3] = 0;
1286            }
1287
1288            // it is extremely improbable, though theoretically possible, for random bytes to be syntactically valid
1289            // so we only check that the parser does not panic and that it succeeds or fails exactly in line with bincode
1290            let mut test_vote_state = MaybeUninit::uninit();
1291            let test_res = VoteState::deserialize_into_uninit(&raw_data, &mut test_vote_state);
1292            let bincode_res = bincode::deserialize::<VoteStateVersions>(&raw_data)
1293                .map(|versioned| versioned.convert_to_current());
1294
1295            if test_res.is_err() {
1296                assert!(bincode_res.is_err());
1297            } else {
1298                let test_vote_state = unsafe { test_vote_state.assume_init() };
1299                assert_eq!(test_vote_state, bincode_res.unwrap());
1300            }
1301        }
1302    }
1303
1304    #[test]
1305    fn test_vote_deserialize_into_uninit_ill_sized() {
1306        // provide 4x the minimum struct size in bytes to ensure we typically touch every field
1307        let struct_bytes_x4 = std::mem::size_of::<VoteState>() * 4;
1308        for _ in 0..1000 {
1309            let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
1310            let mut unstructured = Unstructured::new(&raw_data);
1311
1312            let original_vote_state_versions =
1313                VoteStateVersions::arbitrary(&mut unstructured).unwrap();
1314            let original_buf = bincode::serialize(&original_vote_state_versions).unwrap();
1315
1316            let mut truncated_buf = original_buf.clone();
1317            let mut expanded_buf = original_buf.clone();
1318
1319            truncated_buf.resize(original_buf.len() - 8, 0);
1320            expanded_buf.resize(original_buf.len() + 8, 0);
1321
1322            // truncated fails
1323            let mut test_vote_state = MaybeUninit::uninit();
1324            let test_res = VoteState::deserialize_into_uninit(&truncated_buf, &mut test_vote_state);
1325            let bincode_res = bincode::deserialize::<VoteStateVersions>(&truncated_buf)
1326                .map(|versioned| versioned.convert_to_current());
1327
1328            assert!(test_res.is_err());
1329            assert!(bincode_res.is_err());
1330
1331            // expanded succeeds
1332            let mut test_vote_state = MaybeUninit::uninit();
1333            VoteState::deserialize_into_uninit(&expanded_buf, &mut test_vote_state).unwrap();
1334            let bincode_res = bincode::deserialize::<VoteStateVersions>(&expanded_buf)
1335                .map(|versioned| versioned.convert_to_current());
1336
1337            let test_vote_state = unsafe { test_vote_state.assume_init() };
1338            assert_eq!(test_vote_state, bincode_res.unwrap());
1339        }
1340    }
1341
1342    #[test]
1343    fn test_vote_state_commission_split() {
1344        let vote_state = VoteState::default();
1345
1346        assert_eq!(vote_state.commission_split(1), (0, 1, false));
1347
1348        let mut vote_state = VoteState {
1349            commission: u8::MAX,
1350            ..VoteState::default()
1351        };
1352        assert_eq!(vote_state.commission_split(1), (1, 0, false));
1353
1354        vote_state.commission = 99;
1355        assert_eq!(vote_state.commission_split(10), (9, 0, true));
1356
1357        vote_state.commission = 1;
1358        assert_eq!(vote_state.commission_split(10), (0, 9, true));
1359
1360        vote_state.commission = 50;
1361        let (voter_portion, staker_portion, was_split) = vote_state.commission_split(10);
1362
1363        assert_eq!((voter_portion, staker_portion, was_split), (5, 5, true));
1364    }
1365
1366    #[test]
1367    fn test_vote_state_epoch_credits() {
1368        let mut vote_state = VoteState::default();
1369
1370        assert_eq!(vote_state.credits(), 0);
1371        assert_eq!(vote_state.epoch_credits().clone(), vec![]);
1372
1373        let mut expected = vec![];
1374        let mut credits = 0;
1375        let epochs = (MAX_EPOCH_CREDITS_HISTORY + 2) as u64;
1376        for epoch in 0..epochs {
1377            for _j in 0..epoch {
1378                vote_state.increment_credits(epoch, 1);
1379                credits += 1;
1380            }
1381            expected.push((epoch, credits, credits - epoch));
1382        }
1383
1384        while expected.len() > MAX_EPOCH_CREDITS_HISTORY {
1385            expected.remove(0);
1386        }
1387
1388        assert_eq!(vote_state.credits(), credits);
1389        assert_eq!(vote_state.epoch_credits().clone(), expected);
1390    }
1391
1392    #[test]
1393    fn test_vote_state_epoch0_no_credits() {
1394        let mut vote_state = VoteState::default();
1395
1396        assert_eq!(vote_state.epoch_credits().len(), 0);
1397        vote_state.increment_credits(1, 1);
1398        assert_eq!(vote_state.epoch_credits().len(), 1);
1399
1400        vote_state.increment_credits(2, 1);
1401        assert_eq!(vote_state.epoch_credits().len(), 2);
1402    }
1403
1404    #[test]
1405    fn test_vote_state_increment_credits() {
1406        let mut vote_state = VoteState::default();
1407
1408        let credits = (MAX_EPOCH_CREDITS_HISTORY + 2) as u64;
1409        for i in 0..credits {
1410            vote_state.increment_credits(i, 1);
1411        }
1412        assert_eq!(vote_state.credits(), credits);
1413        assert!(vote_state.epoch_credits().len() <= MAX_EPOCH_CREDITS_HISTORY);
1414    }
1415
1416    #[test]
1417    fn test_vote_process_timestamp() {
1418        let (slot, timestamp) = (15, 1_575_412_285);
1419        let mut vote_state = VoteState {
1420            last_timestamp: BlockTimestamp { slot, timestamp },
1421            ..VoteState::default()
1422        };
1423
1424        assert_eq!(
1425            vote_state.process_timestamp(slot - 1, timestamp + 1),
1426            Err(VoteError::TimestampTooOld)
1427        );
1428        assert_eq!(
1429            vote_state.last_timestamp,
1430            BlockTimestamp { slot, timestamp }
1431        );
1432        assert_eq!(
1433            vote_state.process_timestamp(slot + 1, timestamp - 1),
1434            Err(VoteError::TimestampTooOld)
1435        );
1436        assert_eq!(
1437            vote_state.process_timestamp(slot, timestamp + 1),
1438            Err(VoteError::TimestampTooOld)
1439        );
1440        assert_eq!(vote_state.process_timestamp(slot, timestamp), Ok(()));
1441        assert_eq!(
1442            vote_state.last_timestamp,
1443            BlockTimestamp { slot, timestamp }
1444        );
1445        assert_eq!(vote_state.process_timestamp(slot + 1, timestamp), Ok(()));
1446        assert_eq!(
1447            vote_state.last_timestamp,
1448            BlockTimestamp {
1449                slot: slot + 1,
1450                timestamp
1451            }
1452        );
1453        assert_eq!(
1454            vote_state.process_timestamp(slot + 2, timestamp + 1),
1455            Ok(())
1456        );
1457        assert_eq!(
1458            vote_state.last_timestamp,
1459            BlockTimestamp {
1460                slot: slot + 2,
1461                timestamp: timestamp + 1
1462            }
1463        );
1464
1465        // Test initial vote
1466        vote_state.last_timestamp = BlockTimestamp::default();
1467        assert_eq!(vote_state.process_timestamp(0, timestamp), Ok(()));
1468    }
1469
1470    #[test]
1471    fn test_get_and_update_authorized_voter() {
1472        let original_voter = Pubkey::new_unique();
1473        let mut vote_state = VoteState::new(
1474            &VoteInit {
1475                node_pubkey: original_voter,
1476                authorized_voter: original_voter,
1477                authorized_withdrawer: original_voter,
1478                commission: 0,
1479            },
1480            &Clock::default(),
1481        );
1482
1483        assert_eq!(vote_state.authorized_voters.len(), 1);
1484        assert_eq!(
1485            *vote_state.authorized_voters.first().unwrap().1,
1486            original_voter
1487        );
1488
1489        // If no new authorized voter was set, the same authorized voter
1490        // is locked into the next epoch
1491        assert_eq!(
1492            vote_state.get_and_update_authorized_voter(1).unwrap(),
1493            original_voter
1494        );
1495
1496        // Try to get the authorized voter for epoch 5, implies
1497        // the authorized voter for epochs 1-4 were unchanged
1498        assert_eq!(
1499            vote_state.get_and_update_authorized_voter(5).unwrap(),
1500            original_voter
1501        );
1502
1503        // Authorized voter for expired epoch 0..5 should have been
1504        // purged and no longer queryable
1505        assert_eq!(vote_state.authorized_voters.len(), 1);
1506        for i in 0..5 {
1507            assert!(vote_state
1508                .authorized_voters
1509                .get_authorized_voter(i)
1510                .is_none());
1511        }
1512
1513        // Set an authorized voter change at slot 7
1514        let new_authorized_voter = Pubkey::new_unique();
1515        vote_state
1516            .set_new_authorized_voter(&new_authorized_voter, 5, 7, |_| Ok(()))
1517            .unwrap();
1518
1519        // Try to get the authorized voter for epoch 6, unchanged
1520        assert_eq!(
1521            vote_state.get_and_update_authorized_voter(6).unwrap(),
1522            original_voter
1523        );
1524
1525        // Try to get the authorized voter for epoch 7 and onwards, should
1526        // be the new authorized voter
1527        for i in 7..10 {
1528            assert_eq!(
1529                vote_state.get_and_update_authorized_voter(i).unwrap(),
1530                new_authorized_voter
1531            );
1532        }
1533        assert_eq!(vote_state.authorized_voters.len(), 1);
1534    }
1535
1536    #[test]
1537    fn test_set_new_authorized_voter() {
1538        let original_voter = Pubkey::new_unique();
1539        let epoch_offset = 15;
1540        let mut vote_state = VoteState::new(
1541            &VoteInit {
1542                node_pubkey: original_voter,
1543                authorized_voter: original_voter,
1544                authorized_withdrawer: original_voter,
1545                commission: 0,
1546            },
1547            &Clock::default(),
1548        );
1549
1550        assert!(vote_state.prior_voters.last().is_none());
1551
1552        let new_voter = Pubkey::new_unique();
1553        // Set a new authorized voter
1554        vote_state
1555            .set_new_authorized_voter(&new_voter, 0, epoch_offset, |_| Ok(()))
1556            .unwrap();
1557
1558        assert_eq!(vote_state.prior_voters.idx, 0);
1559        assert_eq!(
1560            vote_state.prior_voters.last(),
1561            Some(&(original_voter, 0, epoch_offset))
1562        );
1563
1564        // Trying to set authorized voter for same epoch again should fail
1565        assert_eq!(
1566            vote_state.set_new_authorized_voter(&new_voter, 0, epoch_offset, |_| Ok(())),
1567            Err(VoteError::TooSoonToReauthorize.into())
1568        );
1569
1570        // Setting the same authorized voter again should succeed
1571        vote_state
1572            .set_new_authorized_voter(&new_voter, 2, 2 + epoch_offset, |_| Ok(()))
1573            .unwrap();
1574
1575        // Set a third and fourth authorized voter
1576        let new_voter2 = Pubkey::new_unique();
1577        vote_state
1578            .set_new_authorized_voter(&new_voter2, 3, 3 + epoch_offset, |_| Ok(()))
1579            .unwrap();
1580        assert_eq!(vote_state.prior_voters.idx, 1);
1581        assert_eq!(
1582            vote_state.prior_voters.last(),
1583            Some(&(new_voter, epoch_offset, 3 + epoch_offset))
1584        );
1585
1586        let new_voter3 = Pubkey::new_unique();
1587        vote_state
1588            .set_new_authorized_voter(&new_voter3, 6, 6 + epoch_offset, |_| Ok(()))
1589            .unwrap();
1590        assert_eq!(vote_state.prior_voters.idx, 2);
1591        assert_eq!(
1592            vote_state.prior_voters.last(),
1593            Some(&(new_voter2, 3 + epoch_offset, 6 + epoch_offset))
1594        );
1595
1596        // Check can set back to original voter
1597        vote_state
1598            .set_new_authorized_voter(&original_voter, 9, 9 + epoch_offset, |_| Ok(()))
1599            .unwrap();
1600
1601        // Run with these voters for a while, check the ranges of authorized
1602        // voters is correct
1603        for i in 9..epoch_offset {
1604            assert_eq!(
1605                vote_state.get_and_update_authorized_voter(i).unwrap(),
1606                original_voter
1607            );
1608        }
1609        for i in epoch_offset..3 + epoch_offset {
1610            assert_eq!(
1611                vote_state.get_and_update_authorized_voter(i).unwrap(),
1612                new_voter
1613            );
1614        }
1615        for i in 3 + epoch_offset..6 + epoch_offset {
1616            assert_eq!(
1617                vote_state.get_and_update_authorized_voter(i).unwrap(),
1618                new_voter2
1619            );
1620        }
1621        for i in 6 + epoch_offset..9 + epoch_offset {
1622            assert_eq!(
1623                vote_state.get_and_update_authorized_voter(i).unwrap(),
1624                new_voter3
1625            );
1626        }
1627        for i in 9 + epoch_offset..=10 + epoch_offset {
1628            assert_eq!(
1629                vote_state.get_and_update_authorized_voter(i).unwrap(),
1630                original_voter
1631            );
1632        }
1633    }
1634
1635    #[test]
1636    fn test_authorized_voter_is_locked_within_epoch() {
1637        let original_voter = Pubkey::new_unique();
1638        let mut vote_state = VoteState::new(
1639            &VoteInit {
1640                node_pubkey: original_voter,
1641                authorized_voter: original_voter,
1642                authorized_withdrawer: original_voter,
1643                commission: 0,
1644            },
1645            &Clock::default(),
1646        );
1647
1648        // Test that it's not possible to set a new authorized
1649        // voter within the same epoch, even if none has been
1650        // explicitly set before
1651        let new_voter = Pubkey::new_unique();
1652        assert_eq!(
1653            vote_state.set_new_authorized_voter(&new_voter, 1, 1, |_| Ok(())),
1654            Err(VoteError::TooSoonToReauthorize.into())
1655        );
1656
1657        assert_eq!(vote_state.get_authorized_voter(1), Some(original_voter));
1658
1659        // Set a new authorized voter for a future epoch
1660        assert_eq!(
1661            vote_state.set_new_authorized_voter(&new_voter, 1, 2, |_| Ok(())),
1662            Ok(())
1663        );
1664
1665        // Test that it's not possible to set a new authorized
1666        // voter within the same epoch, even if none has been
1667        // explicitly set before
1668        assert_eq!(
1669            vote_state.set_new_authorized_voter(&original_voter, 3, 3, |_| Ok(())),
1670            Err(VoteError::TooSoonToReauthorize.into())
1671        );
1672
1673        assert_eq!(vote_state.get_authorized_voter(3), Some(new_voter));
1674    }
1675
1676    #[test]
1677    fn test_vote_state_size_of() {
1678        let vote_state = VoteState::get_max_sized_vote_state();
1679        let vote_state = VoteStateVersions::new_current(vote_state);
1680        let size = serialized_size(&vote_state).unwrap();
1681        assert_eq!(VoteState::size_of() as u64, size);
1682    }
1683
1684    #[test]
1685    fn test_vote_state_max_size() {
1686        let mut max_sized_data = vec![0; VoteState::size_of()];
1687        let vote_state = VoteState::get_max_sized_vote_state();
1688        let (start_leader_schedule_epoch, _) = vote_state.authorized_voters.last().unwrap();
1689        let start_current_epoch =
1690            start_leader_schedule_epoch - MAX_LEADER_SCHEDULE_EPOCH_OFFSET + 1;
1691
1692        let mut vote_state = Some(vote_state);
1693        for i in start_current_epoch..start_current_epoch + 2 * MAX_LEADER_SCHEDULE_EPOCH_OFFSET {
1694            vote_state.as_mut().map(|vote_state| {
1695                vote_state.set_new_authorized_voter(
1696                    &Pubkey::new_unique(),
1697                    i,
1698                    i + MAX_LEADER_SCHEDULE_EPOCH_OFFSET,
1699                    |_| Ok(()),
1700                )
1701            });
1702
1703            let versioned = VoteStateVersions::new_current(vote_state.take().unwrap());
1704            VoteState::serialize(&versioned, &mut max_sized_data).unwrap();
1705            vote_state = Some(versioned.convert_to_current());
1706        }
1707    }
1708
1709    #[test]
1710    fn test_default_vote_state_is_uninitialized() {
1711        // The default `VoteState` is stored to de-initialize a zero-balance vote account,
1712        // so must remain such that `VoteStateVersions::is_uninitialized()` returns true
1713        // when called on a `VoteStateVersions` that stores it
1714        assert!(VoteStateVersions::new_current(VoteState::default()).is_uninitialized());
1715    }
1716
1717    #[test]
1718    fn test_is_correct_size_and_initialized() {
1719        // Check all zeroes
1720        let mut vote_account_data = vec![0; VoteStateVersions::vote_state_size_of(true)];
1721        assert!(!VoteStateVersions::is_correct_size_and_initialized(
1722            &vote_account_data
1723        ));
1724
1725        // Check default VoteState
1726        let default_account_state = VoteStateVersions::new_current(VoteState::default());
1727        VoteState::serialize(&default_account_state, &mut vote_account_data).unwrap();
1728        assert!(!VoteStateVersions::is_correct_size_and_initialized(
1729            &vote_account_data
1730        ));
1731
1732        // Check non-zero data shorter than offset index used
1733        let short_data = vec![1; DEFAULT_PRIOR_VOTERS_OFFSET];
1734        assert!(!VoteStateVersions::is_correct_size_and_initialized(
1735            &short_data
1736        ));
1737
1738        // Check non-zero large account
1739        let mut large_vote_data = vec![1; 2 * VoteStateVersions::vote_state_size_of(true)];
1740        let default_account_state = VoteStateVersions::new_current(VoteState::default());
1741        VoteState::serialize(&default_account_state, &mut large_vote_data).unwrap();
1742        assert!(!VoteStateVersions::is_correct_size_and_initialized(
1743            &vote_account_data
1744        ));
1745
1746        // Check populated VoteState
1747        let vote_state = VoteState::new(
1748            &VoteInit {
1749                node_pubkey: Pubkey::new_unique(),
1750                authorized_voter: Pubkey::new_unique(),
1751                authorized_withdrawer: Pubkey::new_unique(),
1752                commission: 0,
1753            },
1754            &Clock::default(),
1755        );
1756        let account_state = VoteStateVersions::new_current(vote_state.clone());
1757        VoteState::serialize(&account_state, &mut vote_account_data).unwrap();
1758        assert!(VoteStateVersions::is_correct_size_and_initialized(
1759            &vote_account_data
1760        ));
1761
1762        // Check old VoteState that hasn't been upgraded to newest version yet
1763        let old_vote_state = VoteState1_14_11::from(vote_state);
1764        let account_state = VoteStateVersions::V1_14_11(Box::new(old_vote_state));
1765        let mut vote_account_data = vec![0; VoteStateVersions::vote_state_size_of(false)];
1766        VoteState::serialize(&account_state, &mut vote_account_data).unwrap();
1767        assert!(VoteStateVersions::is_correct_size_and_initialized(
1768            &vote_account_data
1769        ));
1770    }
1771
1772    #[test]
1773    fn test_minimum_balance() {
1774        let rent = solana_program::rent::Rent::default();
1775        let minimum_balance = rent.minimum_balance(VoteState::size_of());
1776        // golden, may need updating when vote_state grows
1777        assert!(minimum_balance as f64 / 10f64.powf(9.0) < 0.04)
1778    }
1779
1780    #[test]
1781    fn test_serde_compact_vote_state_update() {
1782        let mut rng = rand::thread_rng();
1783        for _ in 0..5000 {
1784            run_serde_compact_vote_state_update(&mut rng);
1785        }
1786    }
1787
1788    fn run_serde_compact_vote_state_update<R: Rng>(rng: &mut R) {
1789        let lockouts: VecDeque<_> = std::iter::repeat_with(|| {
1790            let slot = 149_303_885_u64.saturating_add(rng.gen_range(0..10_000));
1791            let confirmation_count = rng.gen_range(0..33);
1792            Lockout::new_with_confirmation_count(slot, confirmation_count)
1793        })
1794        .take(32)
1795        .sorted_by_key(|lockout| lockout.slot())
1796        .collect();
1797        let root = rng.gen_ratio(1, 2).then(|| {
1798            lockouts[0]
1799                .slot()
1800                .checked_sub(rng.gen_range(0..1_000))
1801                .expect("All slots should be greater than 1_000")
1802        });
1803        let timestamp = rng.gen_ratio(1, 2).then(|| rng.gen());
1804        let hash = Hash::from(rng.gen::<[u8; 32]>());
1805        let vote_state_update = VoteStateUpdate {
1806            lockouts,
1807            root,
1808            hash,
1809            timestamp,
1810        };
1811        #[derive(Debug, Eq, PartialEq, Deserialize, Serialize)]
1812        enum VoteInstruction {
1813            #[serde(with = "serde_compact_vote_state_update")]
1814            UpdateVoteState(VoteStateUpdate),
1815            UpdateVoteStateSwitch(
1816                #[serde(with = "serde_compact_vote_state_update")] VoteStateUpdate,
1817                Hash,
1818            ),
1819        }
1820        let vote = VoteInstruction::UpdateVoteState(vote_state_update.clone());
1821        let bytes = bincode::serialize(&vote).unwrap();
1822        assert_eq!(vote, bincode::deserialize(&bytes).unwrap());
1823        let hash = Hash::from(rng.gen::<[u8; 32]>());
1824        let vote = VoteInstruction::UpdateVoteStateSwitch(vote_state_update, hash);
1825        let bytes = bincode::serialize(&vote).unwrap();
1826        assert_eq!(vote, bincode::deserialize(&bytes).unwrap());
1827    }
1828
1829    #[test]
1830    fn test_circbuf_oob() {
1831        // Craft an invalid CircBuf with out-of-bounds index
1832        let data: &[u8] = &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00];
1833        let circ_buf: CircBuf<()> = bincode::deserialize(data).unwrap();
1834        assert_eq!(circ_buf.last(), None);
1835    }
1836}