solana_program_fork_cleon_00/vote/state/
mod.rs

1//! Vote state
2
3#[cfg(test)]
4use crate::epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET;
5#[cfg(not(target_os = "solana"))]
6use bincode::deserialize;
7use {
8    crate::{
9        clock::{Epoch, Slot, UnixTimestamp},
10        hash::Hash,
11        instruction::InstructionError,
12        pubkey::Pubkey,
13        rent::Rent,
14        sysvar::clock::Clock,
15        vote::{authorized_voters::AuthorizedVoters, error::VoteError},
16    },
17    bincode::{serialize_into, ErrorKind},
18    serde_derive::{Deserialize, Serialize},
19    std::{collections::VecDeque, fmt::Debug},
20};
21
22mod vote_state_0_23_5;
23pub mod vote_state_1_14_11;
24pub use vote_state_1_14_11::*;
25pub mod vote_state_versions;
26pub use vote_state_versions::*;
27
28// Maximum number of votes to keep around, tightly coupled with epoch_schedule::MINIMUM_SLOTS_PER_EPOCH
29pub const MAX_LOCKOUT_HISTORY: usize = 31;
30pub const INITIAL_LOCKOUT: usize = 2;
31
32// Maximum number of credits history to keep around
33pub const MAX_EPOCH_CREDITS_HISTORY: usize = 64;
34
35// Offset of VoteState::prior_voters, for determining initialization status without deserialization
36const DEFAULT_PRIOR_VOTERS_OFFSET: usize = 114;
37
38// 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.
39pub const VOTE_CREDITS_GRACE_SLOTS: u8 = 2;
40
41// 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.
42pub const VOTE_CREDITS_MAXIMUM_PER_SLOT: u8 = 16;
43
44// Previous max per slot
45pub const VOTE_CREDITS_MAXIMUM_PER_SLOT_OLD: u8 = 8;
46
47#[frozen_abi(digest = "Ch2vVEwos2EjAVqSHCyJjnN2MNX1yrpapZTGhMSCjWUH")]
48#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone, AbiExample)]
49pub struct Vote {
50    /// A stack of votes starting with the oldest vote
51    pub slots: Vec<Slot>,
52    /// signature of the bank's state at the last slot
53    pub hash: Hash,
54    /// processing timestamp of last slot
55    pub timestamp: Option<UnixTimestamp>,
56}
57
58impl Vote {
59    pub fn new(slots: Vec<Slot>, hash: Hash) -> Self {
60        Self {
61            slots,
62            hash,
63            timestamp: None,
64        }
65    }
66
67    pub fn last_voted_slot(&self) -> Option<Slot> {
68        self.slots.last().copied()
69    }
70}
71
72#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Copy, Clone, AbiExample)]
73pub struct Lockout {
74    slot: Slot,
75    confirmation_count: u32,
76}
77
78impl Lockout {
79    pub fn new(slot: Slot) -> Self {
80        Self::new_with_confirmation_count(slot, 1)
81    }
82
83    pub fn new_with_confirmation_count(slot: Slot, confirmation_count: u32) -> Self {
84        Self {
85            slot,
86            confirmation_count,
87        }
88    }
89
90    // The number of slots for which this vote is locked
91    pub fn lockout(&self) -> u64 {
92        (INITIAL_LOCKOUT as u64).pow(self.confirmation_count())
93    }
94
95    // The last slot at which a vote is still locked out. Validators should not
96    // vote on a slot in another fork which is less than or equal to this slot
97    // to avoid having their stake slashed.
98    pub fn last_locked_out_slot(&self) -> Slot {
99        self.slot.saturating_add(self.lockout())
100    }
101
102    pub fn is_locked_out_at_slot(&self, slot: Slot) -> bool {
103        self.last_locked_out_slot() >= slot
104    }
105
106    pub fn slot(&self) -> Slot {
107        self.slot
108    }
109
110    pub fn confirmation_count(&self) -> u32 {
111        self.confirmation_count
112    }
113
114    pub fn increase_confirmation_count(&mut self, by: u32) {
115        self.confirmation_count = self.confirmation_count.saturating_add(by)
116    }
117}
118
119#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Copy, Clone, AbiExample)]
120pub struct LandedVote {
121    // Latency is the difference in slot number between the slot that was voted on (lockout.slot) and the slot in
122    // which the vote that added this Lockout landed.  For votes which were cast before versions of the validator
123    // software which recorded vote latencies, latency is recorded as 0.
124    pub latency: u8,
125    pub lockout: Lockout,
126}
127
128impl LandedVote {
129    pub fn slot(&self) -> Slot {
130        self.lockout.slot
131    }
132
133    pub fn confirmation_count(&self) -> u32 {
134        self.lockout.confirmation_count
135    }
136}
137
138impl From<LandedVote> for Lockout {
139    fn from(landed_vote: LandedVote) -> Self {
140        landed_vote.lockout
141    }
142}
143
144impl From<Lockout> for LandedVote {
145    fn from(lockout: Lockout) -> Self {
146        Self {
147            latency: 0,
148            lockout,
149        }
150    }
151}
152
153#[frozen_abi(digest = "GwJfVFsATSj7nvKwtUkHYzqPRaPY6SLxPGXApuCya3x5")]
154#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone, AbiExample)]
155pub struct VoteStateUpdate {
156    /// The proposed tower
157    pub lockouts: VecDeque<Lockout>,
158    /// The proposed root
159    pub root: Option<Slot>,
160    /// signature of the bank's state at the last slot
161    pub hash: Hash,
162    /// processing timestamp of last slot
163    pub timestamp: Option<UnixTimestamp>,
164}
165
166impl From<Vec<(Slot, u32)>> for VoteStateUpdate {
167    fn from(recent_slots: Vec<(Slot, u32)>) -> Self {
168        let lockouts: VecDeque<Lockout> = recent_slots
169            .into_iter()
170            .map(|(slot, confirmation_count)| {
171                Lockout::new_with_confirmation_count(slot, confirmation_count)
172            })
173            .collect();
174        Self {
175            lockouts,
176            root: None,
177            hash: Hash::default(),
178            timestamp: None,
179        }
180    }
181}
182
183impl VoteStateUpdate {
184    pub fn new(lockouts: VecDeque<Lockout>, root: Option<Slot>, hash: Hash) -> Self {
185        Self {
186            lockouts,
187            root,
188            hash,
189            timestamp: None,
190        }
191    }
192
193    pub fn slots(&self) -> Vec<Slot> {
194        self.lockouts.iter().map(|lockout| lockout.slot()).collect()
195    }
196
197    pub fn last_voted_slot(&self) -> Option<Slot> {
198        self.lockouts.back().map(|l| l.slot())
199    }
200}
201
202#[derive(Default, Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
203pub struct VoteInit {
204    pub node_pubkey: Pubkey,
205    pub authorized_voter: Pubkey,
206    pub authorized_withdrawer: Pubkey,
207    pub commission: u8,
208}
209
210#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
211pub enum VoteAuthorize {
212    Voter,
213    Withdrawer,
214}
215
216#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
217pub struct VoteAuthorizeWithSeedArgs {
218    pub authorization_type: VoteAuthorize,
219    pub current_authority_derived_key_owner: Pubkey,
220    pub current_authority_derived_key_seed: String,
221    pub new_authority: Pubkey,
222}
223
224#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
225pub struct VoteAuthorizeCheckedWithSeedArgs {
226    pub authorization_type: VoteAuthorize,
227    pub current_authority_derived_key_owner: Pubkey,
228    pub current_authority_derived_key_seed: String,
229}
230
231#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone, AbiExample)]
232pub struct BlockTimestamp {
233    pub slot: Slot,
234    pub timestamp: UnixTimestamp,
235}
236
237// this is how many epochs a voter can be remembered for slashing
238const MAX_ITEMS: usize = 32;
239
240#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, AbiExample)]
241pub struct CircBuf<I> {
242    buf: [I; MAX_ITEMS],
243    /// next pointer
244    idx: usize,
245    is_empty: bool,
246}
247
248impl<I: Default + Copy> Default for CircBuf<I> {
249    fn default() -> Self {
250        Self {
251            buf: [I::default(); MAX_ITEMS],
252            idx: MAX_ITEMS
253                .checked_sub(1)
254                .expect("`MAX_ITEMS` should be positive"),
255            is_empty: true,
256        }
257    }
258}
259
260impl<I> CircBuf<I> {
261    pub fn append(&mut self, item: I) {
262        // remember prior delegate and when we switched, to support later slashing
263        self.idx = self
264            .idx
265            .checked_add(1)
266            .and_then(|idx| idx.checked_rem(MAX_ITEMS))
267            .expect("`self.idx` should be < `MAX_ITEMS` which should be non-zero");
268
269        self.buf[self.idx] = item;
270        self.is_empty = false;
271    }
272
273    pub fn buf(&self) -> &[I; MAX_ITEMS] {
274        &self.buf
275    }
276
277    pub fn last(&self) -> Option<&I> {
278        if !self.is_empty {
279            Some(&self.buf[self.idx])
280        } else {
281            None
282        }
283    }
284}
285
286#[frozen_abi(digest = "EeenjJaSrm9hRM39gK6raRNtzG61hnk7GciUCJJRDUSQ")]
287#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone, AbiExample)]
288pub struct VoteState {
289    /// the node that votes in this account
290    pub node_pubkey: Pubkey,
291
292    /// the signer for withdrawals
293    pub authorized_withdrawer: Pubkey,
294    /// percentage (0-100) that represents what part of a rewards
295    ///  payout should be given to this VoteAccount
296    pub commission: u8,
297
298    pub votes: VecDeque<LandedVote>,
299
300    // This usually the last Lockout which was popped from self.votes.
301    // However, it can be arbitrary slot, when being used inside Tower
302    pub root_slot: Option<Slot>,
303
304    /// the signer for vote transactions
305    authorized_voters: AuthorizedVoters,
306
307    /// history of prior authorized voters and the epochs for which
308    /// they were set, the bottom end of the range is inclusive,
309    /// the top of the range is exclusive
310    prior_voters: CircBuf<(Pubkey, Epoch, Epoch)>,
311
312    /// history of how many credits earned by the end of each epoch
313    ///  each tuple is (Epoch, credits, prev_credits)
314    pub epoch_credits: Vec<(Epoch, u64, u64)>,
315
316    /// most recent timestamp submitted with a vote
317    pub last_timestamp: BlockTimestamp,
318}
319
320impl VoteState {
321    pub fn new(vote_init: &VoteInit, clock: &Clock) -> Self {
322        Self {
323            node_pubkey: vote_init.node_pubkey,
324            authorized_voters: AuthorizedVoters::new(clock.epoch, vote_init.authorized_voter),
325            authorized_withdrawer: vote_init.authorized_withdrawer,
326            commission: vote_init.commission,
327            ..VoteState::default()
328        }
329    }
330
331    pub fn new_rand_for_tests(node_pubkey: Pubkey, root_slot: Slot) -> Self {
332        let votes = (1..32)
333            .map(|x| LandedVote {
334                latency: 0,
335                lockout: Lockout::new_with_confirmation_count(
336                    u64::from(x).saturating_add(root_slot),
337                    32_u32.saturating_sub(x),
338                ),
339            })
340            .collect();
341        Self {
342            node_pubkey,
343            root_slot: Some(root_slot),
344            votes,
345            ..VoteState::default()
346        }
347    }
348
349    pub fn get_authorized_voter(&self, epoch: Epoch) -> Option<Pubkey> {
350        self.authorized_voters.get_authorized_voter(epoch)
351    }
352
353    pub fn authorized_voters(&self) -> &AuthorizedVoters {
354        &self.authorized_voters
355    }
356
357    pub fn prior_voters(&mut self) -> &CircBuf<(Pubkey, Epoch, Epoch)> {
358        &self.prior_voters
359    }
360
361    pub fn get_rent_exempt_reserve(rent: &Rent) -> u64 {
362        rent.minimum_balance(VoteState::size_of())
363    }
364
365    /// Upper limit on the size of the Vote State
366    /// when votes.len() is MAX_LOCKOUT_HISTORY.
367    pub const fn size_of() -> usize {
368        3762 // see test_vote_state_size_of.
369    }
370
371    #[allow(clippy::used_underscore_binding)]
372    pub fn deserialize(_input: &[u8]) -> Result<Self, InstructionError> {
373        #[cfg(not(target_os = "solana"))]
374        {
375            deserialize::<VoteStateVersions>(_input)
376                .map(|versioned| versioned.convert_to_current())
377                .map_err(|_| InstructionError::InvalidAccountData)
378        }
379        #[cfg(target_os = "solana")]
380        unimplemented!();
381    }
382
383    pub fn serialize(
384        versioned: &VoteStateVersions,
385        output: &mut [u8],
386    ) -> Result<(), InstructionError> {
387        serialize_into(output, versioned).map_err(|err| match *err {
388            ErrorKind::SizeLimit => InstructionError::AccountDataTooSmall,
389            _ => InstructionError::GenericError,
390        })
391    }
392
393    /// returns commission split as (voter_portion, staker_portion, was_split) tuple
394    ///
395    ///  if commission calculation is 100% one way or other,
396    ///   indicate with false for was_split
397    pub fn commission_split(&self, on: u64) -> (u64, u64, bool) {
398        match self.commission.min(100) {
399            0 => (0, on, false),
400            100 => (on, 0, false),
401            split => {
402                let on = u128::from(on);
403                // Calculate mine and theirs independently and symmetrically instead of
404                // using the remainder of the other to treat them strictly equally.
405                // This is also to cancel the rewarding if either of the parties
406                // should receive only fractional lamports, resulting in not being rewarded at all.
407                // Thus, note that we intentionally discard any residual fractional lamports.
408                let mine = on
409                    .checked_mul(u128::from(split))
410                    .expect("multiplication of a u64 and u8 should not overflow")
411                    / 100u128;
412                let theirs = on
413                    .checked_mul(u128::from(
414                        100u8
415                            .checked_sub(split)
416                            .expect("commission cannot be greater than 100"),
417                    ))
418                    .expect("multiplication of a u64 and u8 should not overflow")
419                    / 100u128;
420
421                (mine as u64, theirs as u64, true)
422            }
423        }
424    }
425
426    /// Returns if the vote state contains a slot `candidate_slot`
427    pub fn contains_slot(&self, candidate_slot: Slot) -> bool {
428        self.votes
429            .binary_search_by(|vote| vote.slot().cmp(&candidate_slot))
430            .is_ok()
431    }
432
433    #[cfg(test)]
434    fn get_max_sized_vote_state() -> VoteState {
435        let mut authorized_voters = AuthorizedVoters::default();
436        for i in 0..=MAX_LEADER_SCHEDULE_EPOCH_OFFSET {
437            authorized_voters.insert(i, Pubkey::new_unique());
438        }
439
440        VoteState {
441            votes: VecDeque::from(vec![LandedVote::default(); MAX_LOCKOUT_HISTORY]),
442            root_slot: Some(std::u64::MAX),
443            epoch_credits: vec![(0, 0, 0); MAX_EPOCH_CREDITS_HISTORY],
444            authorized_voters,
445            ..Self::default()
446        }
447    }
448
449    pub fn process_next_vote_slot(
450        &mut self,
451        next_vote_slot: Slot,
452        epoch: Epoch,
453        current_slot: Slot,
454        timely_vote_credits: bool,
455        deprecate_unused_legacy_vote_plumbing: bool,
456    ) {
457        // Ignore votes for slots earlier than we already have votes for
458        if self
459            .last_voted_slot()
460            .map_or(false, |last_voted_slot| next_vote_slot <= last_voted_slot)
461        {
462            return;
463        }
464
465        self.pop_expired_votes(next_vote_slot);
466
467        let landed_vote = LandedVote {
468            latency: if timely_vote_credits || !deprecate_unused_legacy_vote_plumbing {
469                Self::compute_vote_latency(next_vote_slot, current_slot)
470            } else {
471                0
472            },
473            lockout: Lockout::new(next_vote_slot),
474        };
475
476        // Once the stack is full, pop the oldest lockout and distribute rewards
477        if self.votes.len() == MAX_LOCKOUT_HISTORY {
478            let credits = self.credits_for_vote_at_index(
479                0,
480                timely_vote_credits,
481                deprecate_unused_legacy_vote_plumbing,
482            );
483            let landed_vote = self.votes.pop_front().unwrap();
484            self.root_slot = Some(landed_vote.slot());
485
486            self.increment_credits(epoch, credits);
487        }
488        self.votes.push_back(landed_vote);
489        self.double_lockouts();
490    }
491
492    /// increment credits, record credits for last epoch if new epoch
493    pub fn increment_credits(&mut self, epoch: Epoch, credits: u64) {
494        // increment credits, record by epoch
495
496        // never seen a credit
497        if self.epoch_credits.is_empty() {
498            self.epoch_credits.push((epoch, 0, 0));
499        } else if epoch != self.epoch_credits.last().unwrap().0 {
500            let (_, credits, prev_credits) = *self.epoch_credits.last().unwrap();
501
502            if credits != prev_credits {
503                // if credits were earned previous epoch
504                // append entry at end of list for the new epoch
505                self.epoch_credits.push((epoch, credits, credits));
506            } else {
507                // else just move the current epoch
508                self.epoch_credits.last_mut().unwrap().0 = epoch;
509            }
510
511            // Remove too old epoch_credits
512            if self.epoch_credits.len() > MAX_EPOCH_CREDITS_HISTORY {
513                self.epoch_credits.remove(0);
514            }
515        }
516
517        self.epoch_credits.last_mut().unwrap().1 =
518            self.epoch_credits.last().unwrap().1.saturating_add(credits);
519    }
520
521    // Computes the vote latency for vote on voted_for_slot where the vote itself landed in current_slot
522    pub fn compute_vote_latency(voted_for_slot: Slot, current_slot: Slot) -> u8 {
523        std::cmp::min(current_slot.saturating_sub(voted_for_slot), u8::MAX as u64) as u8
524    }
525
526    /// Returns the credits to award for a vote at the given lockout slot index
527    pub fn credits_for_vote_at_index(
528        &self,
529        index: usize,
530        timely_vote_credits: bool,
531        deprecate_unused_legacy_vote_plumbing: bool,
532    ) -> u64 {
533        let latency = self
534            .votes
535            .get(index)
536            .map_or(0, |landed_vote| landed_vote.latency);
537        let max_credits = if deprecate_unused_legacy_vote_plumbing {
538            VOTE_CREDITS_MAXIMUM_PER_SLOT
539        } else {
540            VOTE_CREDITS_MAXIMUM_PER_SLOT_OLD
541        };
542
543        // If latency is 0, this means that the Lockout was created and stored from a software version that did not
544        // store vote latencies; in this case, 1 credit is awarded
545        if latency == 0 || (deprecate_unused_legacy_vote_plumbing && !timely_vote_credits) {
546            1
547        } else {
548            match latency.checked_sub(VOTE_CREDITS_GRACE_SLOTS) {
549                None | Some(0) => {
550                    // latency was <= VOTE_CREDITS_GRACE_SLOTS, so maximum credits are awarded
551                    max_credits as u64
552                }
553
554                Some(diff) => {
555                    // diff = latency - VOTE_CREDITS_GRACE_SLOTS, and diff > 0
556                    // Subtract diff from VOTE_CREDITS_MAXIMUM_PER_SLOT which is the number of credits to award
557                    match max_credits.checked_sub(diff) {
558                        // If diff >= VOTE_CREDITS_MAXIMUM_PER_SLOT, 1 credit is awarded
559                        None | Some(0) => 1,
560
561                        Some(credits) => credits as u64,
562                    }
563                }
564            }
565        }
566    }
567
568    pub fn nth_recent_lockout(&self, position: usize) -> Option<&Lockout> {
569        if position < self.votes.len() {
570            let pos = self
571                .votes
572                .len()
573                .checked_sub(position)
574                .and_then(|pos| pos.checked_sub(1))?;
575            self.votes.get(pos).map(|vote| &vote.lockout)
576        } else {
577            None
578        }
579    }
580
581    pub fn last_lockout(&self) -> Option<&Lockout> {
582        self.votes.back().map(|vote| &vote.lockout)
583    }
584
585    pub fn last_voted_slot(&self) -> Option<Slot> {
586        self.last_lockout().map(|v| v.slot())
587    }
588
589    // Upto MAX_LOCKOUT_HISTORY many recent unexpired
590    // vote slots pushed onto the stack.
591    pub fn tower(&self) -> Vec<Slot> {
592        self.votes.iter().map(|v| v.slot()).collect()
593    }
594
595    pub fn current_epoch(&self) -> Epoch {
596        if self.epoch_credits.is_empty() {
597            0
598        } else {
599            self.epoch_credits.last().unwrap().0
600        }
601    }
602
603    /// Number of "credits" owed to this account from the mining pool. Submit this
604    /// VoteState to the Rewards program to trade credits for lamports.
605    pub fn credits(&self) -> u64 {
606        if self.epoch_credits.is_empty() {
607            0
608        } else {
609            self.epoch_credits.last().unwrap().1
610        }
611    }
612
613    /// Number of "credits" owed to this account from the mining pool on a per-epoch basis,
614    ///  starting from credits observed.
615    /// Each tuple of (Epoch, u64, u64) is read as (epoch, credits, prev_credits), where
616    ///   credits for each epoch is credits - prev_credits; while redundant this makes
617    ///   calculating rewards over partial epochs nice and simple
618    pub fn epoch_credits(&self) -> &Vec<(Epoch, u64, u64)> {
619        &self.epoch_credits
620    }
621
622    pub fn set_new_authorized_voter<F>(
623        &mut self,
624        authorized_pubkey: &Pubkey,
625        current_epoch: Epoch,
626        target_epoch: Epoch,
627        verify: F,
628    ) -> Result<(), InstructionError>
629    where
630        F: Fn(Pubkey) -> Result<(), InstructionError>,
631    {
632        let epoch_authorized_voter = self.get_and_update_authorized_voter(current_epoch)?;
633        verify(epoch_authorized_voter)?;
634
635        // The offset in slots `n` on which the target_epoch
636        // (default value `DEFAULT_LEADER_SCHEDULE_SLOT_OFFSET`) is
637        // calculated is the number of slots available from the
638        // first slot `S` of an epoch in which to set a new voter for
639        // the epoch at `S` + `n`
640        if self.authorized_voters.contains(target_epoch) {
641            return Err(VoteError::TooSoonToReauthorize.into());
642        }
643
644        // Get the latest authorized_voter
645        let (latest_epoch, latest_authorized_pubkey) = self
646            .authorized_voters
647            .last()
648            .ok_or(InstructionError::InvalidAccountData)?;
649
650        // If we're not setting the same pubkey as authorized pubkey again,
651        // then update the list of prior voters to mark the expiration
652        // of the old authorized pubkey
653        if latest_authorized_pubkey != authorized_pubkey {
654            // Update the epoch ranges of authorized pubkeys that will be expired
655            let epoch_of_last_authorized_switch =
656                self.prior_voters.last().map(|range| range.2).unwrap_or(0);
657
658            // target_epoch must:
659            // 1) Be monotonically increasing due to the clock always
660            //    moving forward
661            // 2) not be equal to latest epoch otherwise this
662            //    function would have returned TooSoonToReauthorize error
663            //    above
664            assert!(target_epoch > *latest_epoch);
665
666            // Commit the new state
667            self.prior_voters.append((
668                *latest_authorized_pubkey,
669                epoch_of_last_authorized_switch,
670                target_epoch,
671            ));
672        }
673
674        self.authorized_voters
675            .insert(target_epoch, *authorized_pubkey);
676
677        Ok(())
678    }
679
680    pub fn get_and_update_authorized_voter(
681        &mut self,
682        current_epoch: Epoch,
683    ) -> Result<Pubkey, InstructionError> {
684        let pubkey = self
685            .authorized_voters
686            .get_and_cache_authorized_voter_for_epoch(current_epoch)
687            .ok_or(InstructionError::InvalidAccountData)?;
688        self.authorized_voters
689            .purge_authorized_voters(current_epoch);
690        Ok(pubkey)
691    }
692
693    // Pop all recent votes that are not locked out at the next vote slot.  This
694    // allows validators to switch forks once their votes for another fork have
695    // expired. This also allows validators continue voting on recent blocks in
696    // the same fork without increasing lockouts.
697    pub fn pop_expired_votes(&mut self, next_vote_slot: Slot) {
698        while let Some(vote) = self.last_lockout() {
699            if !vote.is_locked_out_at_slot(next_vote_slot) {
700                self.votes.pop_back();
701            } else {
702                break;
703            }
704        }
705    }
706
707    pub fn double_lockouts(&mut self) {
708        let stack_depth = self.votes.len();
709        for (i, v) in self.votes.iter_mut().enumerate() {
710            // Don't increase the lockout for this vote until we get more confirmations
711            // than the max number of confirmations this vote has seen
712            if stack_depth >
713                i.checked_add(v.confirmation_count() as usize)
714                    .expect("`confirmation_count` and tower_size should be bounded by `MAX_LOCKOUT_HISTORY`")
715            {
716                v.lockout.increase_confirmation_count(1);
717            }
718        }
719    }
720
721    pub fn process_timestamp(
722        &mut self,
723        slot: Slot,
724        timestamp: UnixTimestamp,
725    ) -> Result<(), VoteError> {
726        if (slot < self.last_timestamp.slot || timestamp < self.last_timestamp.timestamp)
727            || (slot == self.last_timestamp.slot
728                && BlockTimestamp { slot, timestamp } != self.last_timestamp
729                && self.last_timestamp.slot != 0)
730        {
731            return Err(VoteError::TimestampTooOld);
732        }
733        self.last_timestamp = BlockTimestamp { slot, timestamp };
734        Ok(())
735    }
736
737    pub fn is_correct_size_and_initialized(data: &[u8]) -> bool {
738        const VERSION_OFFSET: usize = 4;
739        const DEFAULT_PRIOR_VOTERS_END: usize = VERSION_OFFSET + DEFAULT_PRIOR_VOTERS_OFFSET;
740        data.len() == VoteState::size_of()
741            && data[VERSION_OFFSET..DEFAULT_PRIOR_VOTERS_END] != [0; DEFAULT_PRIOR_VOTERS_OFFSET]
742    }
743}
744
745pub mod serde_compact_vote_state_update {
746    use {
747        super::*,
748        crate::{
749            clock::{Slot, UnixTimestamp},
750            serde_varint, short_vec,
751            vote::state::Lockout,
752        },
753        serde::{Deserialize, Deserializer, Serialize, Serializer},
754    };
755
756    #[derive(Deserialize, Serialize, AbiExample)]
757    struct LockoutOffset {
758        #[serde(with = "serde_varint")]
759        offset: Slot,
760        confirmation_count: u8,
761    }
762
763    #[derive(Deserialize, Serialize)]
764    struct CompactVoteStateUpdate {
765        root: Slot,
766        #[serde(with = "short_vec")]
767        lockout_offsets: Vec<LockoutOffset>,
768        hash: Hash,
769        timestamp: Option<UnixTimestamp>,
770    }
771
772    pub fn serialize<S>(
773        vote_state_update: &VoteStateUpdate,
774        serializer: S,
775    ) -> Result<S::Ok, S::Error>
776    where
777        S: Serializer,
778    {
779        let lockout_offsets = vote_state_update.lockouts.iter().scan(
780            vote_state_update.root.unwrap_or_default(),
781            |slot, lockout| {
782                let Some(offset) = lockout.slot().checked_sub(*slot) else {
783                    return Some(Err(serde::ser::Error::custom("Invalid vote lockout")));
784                };
785                let Ok(confirmation_count) = u8::try_from(lockout.confirmation_count()) else {
786                    return Some(Err(serde::ser::Error::custom("Invalid confirmation count")));
787                };
788                let lockout_offset = LockoutOffset {
789                    offset,
790                    confirmation_count,
791                };
792                *slot = lockout.slot();
793                Some(Ok(lockout_offset))
794            },
795        );
796        let compact_vote_state_update = CompactVoteStateUpdate {
797            root: vote_state_update.root.unwrap_or(Slot::MAX),
798            lockout_offsets: lockout_offsets.collect::<Result<_, _>>()?,
799            hash: vote_state_update.hash,
800            timestamp: vote_state_update.timestamp,
801        };
802        compact_vote_state_update.serialize(serializer)
803    }
804
805    pub fn deserialize<'de, D>(deserializer: D) -> Result<VoteStateUpdate, D::Error>
806    where
807        D: Deserializer<'de>,
808    {
809        let CompactVoteStateUpdate {
810            root,
811            lockout_offsets,
812            hash,
813            timestamp,
814        } = CompactVoteStateUpdate::deserialize(deserializer)?;
815        let root = (root != Slot::MAX).then_some(root);
816        let lockouts =
817            lockout_offsets
818                .iter()
819                .scan(root.unwrap_or_default(), |slot, lockout_offset| {
820                    *slot = match slot.checked_add(lockout_offset.offset) {
821                        None => {
822                            return Some(Err(serde::de::Error::custom("Invalid lockout offset")))
823                        }
824                        Some(slot) => slot,
825                    };
826                    let lockout = Lockout::new_with_confirmation_count(
827                        *slot,
828                        u32::from(lockout_offset.confirmation_count),
829                    );
830                    Some(Ok(lockout))
831                });
832        Ok(VoteStateUpdate {
833            root,
834            lockouts: lockouts.collect::<Result<_, _>>()?,
835            hash,
836            timestamp,
837        })
838    }
839}
840
841#[cfg(test)]
842mod tests {
843    use {super::*, itertools::Itertools, rand::Rng};
844
845    #[test]
846    fn test_vote_serialize() {
847        let mut buffer: Vec<u8> = vec![0; VoteState::size_of()];
848        let mut vote_state = VoteState::default();
849        vote_state
850            .votes
851            .resize(MAX_LOCKOUT_HISTORY, LandedVote::default());
852        vote_state.root_slot = Some(1);
853        let versioned = VoteStateVersions::new_current(vote_state);
854        assert!(VoteState::serialize(&versioned, &mut buffer[0..4]).is_err());
855        VoteState::serialize(&versioned, &mut buffer).unwrap();
856        assert_eq!(
857            VoteState::deserialize(&buffer).unwrap(),
858            versioned.convert_to_current()
859        );
860    }
861
862    #[test]
863    fn test_vote_state_commission_split() {
864        let vote_state = VoteState::default();
865
866        assert_eq!(vote_state.commission_split(1), (0, 1, false));
867
868        let mut vote_state = VoteState {
869            commission: std::u8::MAX,
870            ..VoteState::default()
871        };
872        assert_eq!(vote_state.commission_split(1), (1, 0, false));
873
874        vote_state.commission = 99;
875        assert_eq!(vote_state.commission_split(10), (9, 0, true));
876
877        vote_state.commission = 1;
878        assert_eq!(vote_state.commission_split(10), (0, 9, true));
879
880        vote_state.commission = 50;
881        let (voter_portion, staker_portion, was_split) = vote_state.commission_split(10);
882
883        assert_eq!((voter_portion, staker_portion, was_split), (5, 5, true));
884    }
885
886    #[test]
887    fn test_vote_state_epoch_credits() {
888        let mut vote_state = VoteState::default();
889
890        assert_eq!(vote_state.credits(), 0);
891        assert_eq!(vote_state.epoch_credits().clone(), vec![]);
892
893        let mut expected = vec![];
894        let mut credits = 0;
895        let epochs = (MAX_EPOCH_CREDITS_HISTORY + 2) as u64;
896        for epoch in 0..epochs {
897            for _j in 0..epoch {
898                vote_state.increment_credits(epoch, 1);
899                credits += 1;
900            }
901            expected.push((epoch, credits, credits - epoch));
902        }
903
904        while expected.len() > MAX_EPOCH_CREDITS_HISTORY {
905            expected.remove(0);
906        }
907
908        assert_eq!(vote_state.credits(), credits);
909        assert_eq!(vote_state.epoch_credits().clone(), expected);
910    }
911
912    #[test]
913    fn test_vote_state_epoch0_no_credits() {
914        let mut vote_state = VoteState::default();
915
916        assert_eq!(vote_state.epoch_credits().len(), 0);
917        vote_state.increment_credits(1, 1);
918        assert_eq!(vote_state.epoch_credits().len(), 1);
919
920        vote_state.increment_credits(2, 1);
921        assert_eq!(vote_state.epoch_credits().len(), 2);
922    }
923
924    #[test]
925    fn test_vote_state_increment_credits() {
926        let mut vote_state = VoteState::default();
927
928        let credits = (MAX_EPOCH_CREDITS_HISTORY + 2) as u64;
929        for i in 0..credits {
930            vote_state.increment_credits(i, 1);
931        }
932        assert_eq!(vote_state.credits(), credits);
933        assert!(vote_state.epoch_credits().len() <= MAX_EPOCH_CREDITS_HISTORY);
934    }
935
936    #[test]
937    fn test_vote_process_timestamp() {
938        let (slot, timestamp) = (15, 1_575_412_285);
939        let mut vote_state = VoteState {
940            last_timestamp: BlockTimestamp { slot, timestamp },
941            ..VoteState::default()
942        };
943
944        assert_eq!(
945            vote_state.process_timestamp(slot - 1, timestamp + 1),
946            Err(VoteError::TimestampTooOld)
947        );
948        assert_eq!(
949            vote_state.last_timestamp,
950            BlockTimestamp { slot, timestamp }
951        );
952        assert_eq!(
953            vote_state.process_timestamp(slot + 1, timestamp - 1),
954            Err(VoteError::TimestampTooOld)
955        );
956        assert_eq!(
957            vote_state.process_timestamp(slot, timestamp + 1),
958            Err(VoteError::TimestampTooOld)
959        );
960        assert_eq!(vote_state.process_timestamp(slot, timestamp), Ok(()));
961        assert_eq!(
962            vote_state.last_timestamp,
963            BlockTimestamp { slot, timestamp }
964        );
965        assert_eq!(vote_state.process_timestamp(slot + 1, timestamp), Ok(()));
966        assert_eq!(
967            vote_state.last_timestamp,
968            BlockTimestamp {
969                slot: slot + 1,
970                timestamp
971            }
972        );
973        assert_eq!(
974            vote_state.process_timestamp(slot + 2, timestamp + 1),
975            Ok(())
976        );
977        assert_eq!(
978            vote_state.last_timestamp,
979            BlockTimestamp {
980                slot: slot + 2,
981                timestamp: timestamp + 1
982            }
983        );
984
985        // Test initial vote
986        vote_state.last_timestamp = BlockTimestamp::default();
987        assert_eq!(vote_state.process_timestamp(0, timestamp), Ok(()));
988    }
989
990    #[test]
991    fn test_get_and_update_authorized_voter() {
992        let original_voter = Pubkey::new_unique();
993        let mut vote_state = VoteState::new(
994            &VoteInit {
995                node_pubkey: original_voter,
996                authorized_voter: original_voter,
997                authorized_withdrawer: original_voter,
998                commission: 0,
999            },
1000            &Clock::default(),
1001        );
1002
1003        assert_eq!(vote_state.authorized_voters.len(), 1);
1004        assert_eq!(
1005            *vote_state.authorized_voters.first().unwrap().1,
1006            original_voter
1007        );
1008
1009        // If no new authorized voter was set, the same authorized voter
1010        // is locked into the next epoch
1011        assert_eq!(
1012            vote_state.get_and_update_authorized_voter(1).unwrap(),
1013            original_voter
1014        );
1015
1016        // Try to get the authorized voter for epoch 5, implies
1017        // the authorized voter for epochs 1-4 were unchanged
1018        assert_eq!(
1019            vote_state.get_and_update_authorized_voter(5).unwrap(),
1020            original_voter
1021        );
1022
1023        // Authorized voter for expired epoch 0..5 should have been
1024        // purged and no longer queryable
1025        assert_eq!(vote_state.authorized_voters.len(), 1);
1026        for i in 0..5 {
1027            assert!(vote_state
1028                .authorized_voters
1029                .get_authorized_voter(i)
1030                .is_none());
1031        }
1032
1033        // Set an authorized voter change at slot 7
1034        let new_authorized_voter = Pubkey::new_unique();
1035        vote_state
1036            .set_new_authorized_voter(&new_authorized_voter, 5, 7, |_| Ok(()))
1037            .unwrap();
1038
1039        // Try to get the authorized voter for epoch 6, unchanged
1040        assert_eq!(
1041            vote_state.get_and_update_authorized_voter(6).unwrap(),
1042            original_voter
1043        );
1044
1045        // Try to get the authorized voter for epoch 7 and onwards, should
1046        // be the new authorized voter
1047        for i in 7..10 {
1048            assert_eq!(
1049                vote_state.get_and_update_authorized_voter(i).unwrap(),
1050                new_authorized_voter
1051            );
1052        }
1053        assert_eq!(vote_state.authorized_voters.len(), 1);
1054    }
1055
1056    #[test]
1057    fn test_set_new_authorized_voter() {
1058        let original_voter = Pubkey::new_unique();
1059        let epoch_offset = 15;
1060        let mut vote_state = VoteState::new(
1061            &VoteInit {
1062                node_pubkey: original_voter,
1063                authorized_voter: original_voter,
1064                authorized_withdrawer: original_voter,
1065                commission: 0,
1066            },
1067            &Clock::default(),
1068        );
1069
1070        assert!(vote_state.prior_voters.last().is_none());
1071
1072        let new_voter = Pubkey::new_unique();
1073        // Set a new authorized voter
1074        vote_state
1075            .set_new_authorized_voter(&new_voter, 0, epoch_offset, |_| Ok(()))
1076            .unwrap();
1077
1078        assert_eq!(vote_state.prior_voters.idx, 0);
1079        assert_eq!(
1080            vote_state.prior_voters.last(),
1081            Some(&(original_voter, 0, epoch_offset))
1082        );
1083
1084        // Trying to set authorized voter for same epoch again should fail
1085        assert_eq!(
1086            vote_state.set_new_authorized_voter(&new_voter, 0, epoch_offset, |_| Ok(())),
1087            Err(VoteError::TooSoonToReauthorize.into())
1088        );
1089
1090        // Setting the same authorized voter again should succeed
1091        vote_state
1092            .set_new_authorized_voter(&new_voter, 2, 2 + epoch_offset, |_| Ok(()))
1093            .unwrap();
1094
1095        // Set a third and fourth authorized voter
1096        let new_voter2 = Pubkey::new_unique();
1097        vote_state
1098            .set_new_authorized_voter(&new_voter2, 3, 3 + epoch_offset, |_| Ok(()))
1099            .unwrap();
1100        assert_eq!(vote_state.prior_voters.idx, 1);
1101        assert_eq!(
1102            vote_state.prior_voters.last(),
1103            Some(&(new_voter, epoch_offset, 3 + epoch_offset))
1104        );
1105
1106        let new_voter3 = Pubkey::new_unique();
1107        vote_state
1108            .set_new_authorized_voter(&new_voter3, 6, 6 + epoch_offset, |_| Ok(()))
1109            .unwrap();
1110        assert_eq!(vote_state.prior_voters.idx, 2);
1111        assert_eq!(
1112            vote_state.prior_voters.last(),
1113            Some(&(new_voter2, 3 + epoch_offset, 6 + epoch_offset))
1114        );
1115
1116        // Check can set back to original voter
1117        vote_state
1118            .set_new_authorized_voter(&original_voter, 9, 9 + epoch_offset, |_| Ok(()))
1119            .unwrap();
1120
1121        // Run with these voters for a while, check the ranges of authorized
1122        // voters is correct
1123        for i in 9..epoch_offset {
1124            assert_eq!(
1125                vote_state.get_and_update_authorized_voter(i).unwrap(),
1126                original_voter
1127            );
1128        }
1129        for i in epoch_offset..3 + epoch_offset {
1130            assert_eq!(
1131                vote_state.get_and_update_authorized_voter(i).unwrap(),
1132                new_voter
1133            );
1134        }
1135        for i in 3 + epoch_offset..6 + epoch_offset {
1136            assert_eq!(
1137                vote_state.get_and_update_authorized_voter(i).unwrap(),
1138                new_voter2
1139            );
1140        }
1141        for i in 6 + epoch_offset..9 + epoch_offset {
1142            assert_eq!(
1143                vote_state.get_and_update_authorized_voter(i).unwrap(),
1144                new_voter3
1145            );
1146        }
1147        for i in 9 + epoch_offset..=10 + epoch_offset {
1148            assert_eq!(
1149                vote_state.get_and_update_authorized_voter(i).unwrap(),
1150                original_voter
1151            );
1152        }
1153    }
1154
1155    #[test]
1156    fn test_authorized_voter_is_locked_within_epoch() {
1157        let original_voter = Pubkey::new_unique();
1158        let mut vote_state = VoteState::new(
1159            &VoteInit {
1160                node_pubkey: original_voter,
1161                authorized_voter: original_voter,
1162                authorized_withdrawer: original_voter,
1163                commission: 0,
1164            },
1165            &Clock::default(),
1166        );
1167
1168        // Test that it's not possible to set a new authorized
1169        // voter within the same epoch, even if none has been
1170        // explicitly set before
1171        let new_voter = Pubkey::new_unique();
1172        assert_eq!(
1173            vote_state.set_new_authorized_voter(&new_voter, 1, 1, |_| Ok(())),
1174            Err(VoteError::TooSoonToReauthorize.into())
1175        );
1176
1177        assert_eq!(vote_state.get_authorized_voter(1), Some(original_voter));
1178
1179        // Set a new authorized voter for a future epoch
1180        assert_eq!(
1181            vote_state.set_new_authorized_voter(&new_voter, 1, 2, |_| Ok(())),
1182            Ok(())
1183        );
1184
1185        // Test that it's not possible to set a new authorized
1186        // voter within the same epoch, even if none has been
1187        // explicitly set before
1188        assert_eq!(
1189            vote_state.set_new_authorized_voter(&original_voter, 3, 3, |_| Ok(())),
1190            Err(VoteError::TooSoonToReauthorize.into())
1191        );
1192
1193        assert_eq!(vote_state.get_authorized_voter(3), Some(new_voter));
1194    }
1195
1196    #[test]
1197    fn test_vote_state_size_of() {
1198        let vote_state = VoteState::get_max_sized_vote_state();
1199        let vote_state = VoteStateVersions::new_current(vote_state);
1200        let size = bincode::serialized_size(&vote_state).unwrap();
1201        assert_eq!(VoteState::size_of() as u64, size);
1202    }
1203
1204    #[test]
1205    fn test_vote_state_max_size() {
1206        let mut max_sized_data = vec![0; VoteState::size_of()];
1207        let vote_state = VoteState::get_max_sized_vote_state();
1208        let (start_leader_schedule_epoch, _) = vote_state.authorized_voters.last().unwrap();
1209        let start_current_epoch =
1210            start_leader_schedule_epoch - MAX_LEADER_SCHEDULE_EPOCH_OFFSET + 1;
1211
1212        let mut vote_state = Some(vote_state);
1213        for i in start_current_epoch..start_current_epoch + 2 * MAX_LEADER_SCHEDULE_EPOCH_OFFSET {
1214            vote_state.as_mut().map(|vote_state| {
1215                vote_state.set_new_authorized_voter(
1216                    &Pubkey::new_unique(),
1217                    i,
1218                    i + MAX_LEADER_SCHEDULE_EPOCH_OFFSET,
1219                    |_| Ok(()),
1220                )
1221            });
1222
1223            let versioned = VoteStateVersions::new_current(vote_state.take().unwrap());
1224            VoteState::serialize(&versioned, &mut max_sized_data).unwrap();
1225            vote_state = Some(versioned.convert_to_current());
1226        }
1227    }
1228
1229    #[test]
1230    fn test_default_vote_state_is_uninitialized() {
1231        // The default `VoteState` is stored to de-initialize a zero-balance vote account,
1232        // so must remain such that `VoteStateVersions::is_uninitialized()` returns true
1233        // when called on a `VoteStateVersions` that stores it
1234        assert!(VoteStateVersions::new_current(VoteState::default()).is_uninitialized());
1235    }
1236
1237    #[test]
1238    fn test_is_correct_size_and_initialized() {
1239        // Check all zeroes
1240        let mut vote_account_data = vec![0; VoteStateVersions::vote_state_size_of(true)];
1241        assert!(!VoteStateVersions::is_correct_size_and_initialized(
1242            &vote_account_data
1243        ));
1244
1245        // Check default VoteState
1246        let default_account_state = VoteStateVersions::new_current(VoteState::default());
1247        VoteState::serialize(&default_account_state, &mut vote_account_data).unwrap();
1248        assert!(!VoteStateVersions::is_correct_size_and_initialized(
1249            &vote_account_data
1250        ));
1251
1252        // Check non-zero data shorter than offset index used
1253        let short_data = vec![1; DEFAULT_PRIOR_VOTERS_OFFSET];
1254        assert!(!VoteStateVersions::is_correct_size_and_initialized(
1255            &short_data
1256        ));
1257
1258        // Check non-zero large account
1259        let mut large_vote_data = vec![1; 2 * VoteStateVersions::vote_state_size_of(true)];
1260        let default_account_state = VoteStateVersions::new_current(VoteState::default());
1261        VoteState::serialize(&default_account_state, &mut large_vote_data).unwrap();
1262        assert!(!VoteStateVersions::is_correct_size_and_initialized(
1263            &vote_account_data
1264        ));
1265
1266        // Check populated VoteState
1267        let vote_state = VoteState::new(
1268            &VoteInit {
1269                node_pubkey: Pubkey::new_unique(),
1270                authorized_voter: Pubkey::new_unique(),
1271                authorized_withdrawer: Pubkey::new_unique(),
1272                commission: 0,
1273            },
1274            &Clock::default(),
1275        );
1276        let account_state = VoteStateVersions::new_current(vote_state.clone());
1277        VoteState::serialize(&account_state, &mut vote_account_data).unwrap();
1278        assert!(VoteStateVersions::is_correct_size_and_initialized(
1279            &vote_account_data
1280        ));
1281
1282        // Check old VoteState that hasn't been upgraded to newest version yet
1283        let old_vote_state = VoteState1_14_11::from(vote_state);
1284        let account_state = VoteStateVersions::V1_14_11(Box::new(old_vote_state));
1285        let mut vote_account_data = vec![0; VoteStateVersions::vote_state_size_of(false)];
1286        VoteState::serialize(&account_state, &mut vote_account_data).unwrap();
1287        assert!(VoteStateVersions::is_correct_size_and_initialized(
1288            &vote_account_data
1289        ));
1290    }
1291
1292    #[test]
1293    fn test_minimum_balance() {
1294        let rent = solana_program::rent::Rent::default();
1295        let minimum_balance = rent.minimum_balance(VoteState::size_of());
1296        // golden, may need updating when vote_state grows
1297        assert!(minimum_balance as f64 / 10f64.powf(9.0) < 0.04)
1298    }
1299
1300    #[test]
1301    fn test_serde_compact_vote_state_update() {
1302        let mut rng = rand::thread_rng();
1303        for _ in 0..5000 {
1304            run_serde_compact_vote_state_update(&mut rng);
1305        }
1306    }
1307
1308    fn run_serde_compact_vote_state_update<R: Rng>(rng: &mut R) {
1309        let lockouts: VecDeque<_> = std::iter::repeat_with(|| {
1310            let slot = 149_303_885_u64.saturating_add(rng.gen_range(0..10_000));
1311            let confirmation_count = rng.gen_range(0..33);
1312            Lockout::new_with_confirmation_count(slot, confirmation_count)
1313        })
1314        .take(32)
1315        .sorted_by_key(|lockout| lockout.slot())
1316        .collect();
1317        let root = rng.gen_ratio(1, 2).then(|| {
1318            lockouts[0]
1319                .slot()
1320                .checked_sub(rng.gen_range(0..1_000))
1321                .expect("All slots should be greater than 1_000")
1322        });
1323        let timestamp = rng.gen_ratio(1, 2).then(|| rng.gen());
1324        let hash = Hash::from(rng.gen::<[u8; 32]>());
1325        let vote_state_update = VoteStateUpdate {
1326            lockouts,
1327            root,
1328            hash,
1329            timestamp,
1330        };
1331        #[derive(Debug, Eq, PartialEq, Deserialize, Serialize)]
1332        enum VoteInstruction {
1333            #[serde(with = "serde_compact_vote_state_update")]
1334            UpdateVoteState(VoteStateUpdate),
1335            UpdateVoteStateSwitch(
1336                #[serde(with = "serde_compact_vote_state_update")] VoteStateUpdate,
1337                Hash,
1338            ),
1339        }
1340        let vote = VoteInstruction::UpdateVoteState(vote_state_update.clone());
1341        let bytes = bincode::serialize(&vote).unwrap();
1342        assert_eq!(vote, bincode::deserialize(&bytes).unwrap());
1343        let hash = Hash::from(rng.gen::<[u8; 32]>());
1344        let vote = VoteInstruction::UpdateVoteStateSwitch(vote_state_update, hash);
1345        let bytes = bincode::serialize(&vote).unwrap();
1346        assert_eq!(vote, bincode::deserialize(&bytes).unwrap());
1347    }
1348}