solana_vote_interface/state/
mod.rs

1//! Vote state
2
3#[cfg(feature = "dev-context-only-utils")]
4use arbitrary::Arbitrary;
5#[cfg(feature = "serde")]
6use serde_derive::{Deserialize, Serialize};
7#[cfg(feature = "frozen-abi")]
8use solana_frozen_abi_macro::AbiExample;
9use {
10    crate::authorized_voters::AuthorizedVoters,
11    solana_clock::{Epoch, Slot, UnixTimestamp},
12    solana_pubkey::Pubkey,
13    solana_rent::Rent,
14    std::{collections::VecDeque, fmt::Debug},
15};
16#[cfg(test)]
17use {arbitrary::Unstructured, solana_epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET};
18
19mod vote_state_0_23_5;
20pub mod vote_state_1_14_11;
21pub use vote_state_1_14_11::*;
22pub mod vote_state_versions;
23pub use vote_state_versions::*;
24pub mod vote_state_v3;
25pub use vote_state_v3::VoteStateV3;
26pub mod vote_state_v4;
27pub use vote_state_v4::VoteStateV4;
28mod vote_instruction_data;
29pub use vote_instruction_data::*;
30#[cfg(any(target_os = "solana", feature = "bincode"))]
31pub(crate) mod vote_state_deserialize;
32
33/// Size of a BLS public key in a compressed point representation
34pub const BLS_PUBLIC_KEY_COMPRESSED_SIZE: usize = 48;
35
36// Maximum number of votes to keep around, tightly coupled with epoch_schedule::MINIMUM_SLOTS_PER_EPOCH
37pub const MAX_LOCKOUT_HISTORY: usize = 31;
38pub const INITIAL_LOCKOUT: usize = 2;
39
40// Maximum number of credits history to keep around
41pub const MAX_EPOCH_CREDITS_HISTORY: usize = 64;
42
43// Offset of VoteState::prior_voters, for determining initialization status without deserialization
44const DEFAULT_PRIOR_VOTERS_OFFSET: usize = 114;
45
46// 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.
47pub const VOTE_CREDITS_GRACE_SLOTS: u8 = 2;
48
49// 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.
50pub const VOTE_CREDITS_MAXIMUM_PER_SLOT: u8 = 16;
51
52#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
53#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
54#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)]
55#[cfg_attr(feature = "dev-context-only-utils", derive(Arbitrary))]
56pub struct Lockout {
57    slot: Slot,
58    confirmation_count: u32,
59}
60
61impl Lockout {
62    pub fn new(slot: Slot) -> Self {
63        Self::new_with_confirmation_count(slot, 1)
64    }
65
66    pub fn new_with_confirmation_count(slot: Slot, confirmation_count: u32) -> Self {
67        Self {
68            slot,
69            confirmation_count,
70        }
71    }
72
73    // The number of slots for which this vote is locked
74    pub fn lockout(&self) -> u64 {
75        (INITIAL_LOCKOUT as u64).wrapping_pow(std::cmp::min(
76            self.confirmation_count(),
77            MAX_LOCKOUT_HISTORY as u32,
78        ))
79    }
80
81    // The last slot at which a vote is still locked out. Validators should not
82    // vote on a slot in another fork which is less than or equal to this slot
83    // to avoid having their stake slashed.
84    pub fn last_locked_out_slot(&self) -> Slot {
85        self.slot.saturating_add(self.lockout())
86    }
87
88    pub fn is_locked_out_at_slot(&self, slot: Slot) -> bool {
89        self.last_locked_out_slot() >= slot
90    }
91
92    pub fn slot(&self) -> Slot {
93        self.slot
94    }
95
96    pub fn confirmation_count(&self) -> u32 {
97        self.confirmation_count
98    }
99
100    pub fn increase_confirmation_count(&mut self, by: u32) {
101        self.confirmation_count = self.confirmation_count.saturating_add(by)
102    }
103}
104
105#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
106#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
107#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)]
108#[cfg_attr(feature = "dev-context-only-utils", derive(Arbitrary))]
109pub struct LandedVote {
110    // Latency is the difference in slot number between the slot that was voted on (lockout.slot) and the slot in
111    // which the vote that added this Lockout landed.  For votes which were cast before versions of the validator
112    // software which recorded vote latencies, latency is recorded as 0.
113    pub latency: u8,
114    pub lockout: Lockout,
115}
116
117impl LandedVote {
118    pub fn slot(&self) -> Slot {
119        self.lockout.slot
120    }
121
122    pub fn confirmation_count(&self) -> u32 {
123        self.lockout.confirmation_count
124    }
125}
126
127impl From<LandedVote> for Lockout {
128    fn from(landed_vote: LandedVote) -> Self {
129        landed_vote.lockout
130    }
131}
132
133impl From<Lockout> for LandedVote {
134    fn from(lockout: Lockout) -> Self {
135        Self {
136            latency: 0,
137            lockout,
138        }
139    }
140}
141
142#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
143#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
144#[derive(Debug, Default, PartialEq, Eq, Clone)]
145#[cfg_attr(feature = "dev-context-only-utils", derive(Arbitrary))]
146pub struct BlockTimestamp {
147    pub slot: Slot,
148    pub timestamp: UnixTimestamp,
149}
150
151// this is how many epochs a voter can be remembered for slashing
152const MAX_ITEMS: usize = 32;
153
154#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
155#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
156#[derive(Debug, PartialEq, Eq, Clone)]
157#[cfg_attr(feature = "dev-context-only-utils", derive(Arbitrary))]
158pub struct CircBuf<I> {
159    buf: [I; MAX_ITEMS],
160    /// next pointer
161    idx: usize,
162    is_empty: bool,
163}
164
165impl<I: Default + Copy> Default for CircBuf<I> {
166    fn default() -> Self {
167        Self {
168            buf: [I::default(); MAX_ITEMS],
169            idx: MAX_ITEMS
170                .checked_sub(1)
171                .expect("`MAX_ITEMS` should be positive"),
172            is_empty: true,
173        }
174    }
175}
176
177impl<I> CircBuf<I> {
178    pub fn append(&mut self, item: I) {
179        // remember prior delegate and when we switched, to support later slashing
180        self.idx = self
181            .idx
182            .checked_add(1)
183            .and_then(|idx| idx.checked_rem(MAX_ITEMS))
184            .expect("`self.idx` should be < `MAX_ITEMS` which should be non-zero");
185
186        self.buf[self.idx] = item;
187        self.is_empty = false;
188    }
189
190    pub fn buf(&self) -> &[I; MAX_ITEMS] {
191        &self.buf
192    }
193
194    pub fn last(&self) -> Option<&I> {
195        if !self.is_empty {
196            self.buf.get(self.idx)
197        } else {
198            None
199        }
200    }
201}
202
203#[cfg(feature = "serde")]
204pub mod serde_compact_vote_state_update {
205    use {
206        super::*,
207        crate::state::Lockout,
208        serde::{Deserialize, Deserializer, Serialize, Serializer},
209        solana_hash::Hash,
210        solana_serde_varint as serde_varint, solana_short_vec as short_vec,
211    };
212
213    #[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
214    #[derive(serde_derive::Deserialize, serde_derive::Serialize)]
215    struct LockoutOffset {
216        #[serde(with = "serde_varint")]
217        offset: Slot,
218        confirmation_count: u8,
219    }
220
221    #[derive(serde_derive::Deserialize, serde_derive::Serialize)]
222    struct CompactVoteStateUpdate {
223        root: Slot,
224        #[serde(with = "short_vec")]
225        lockout_offsets: Vec<LockoutOffset>,
226        hash: Hash,
227        timestamp: Option<UnixTimestamp>,
228    }
229
230    pub fn serialize<S>(
231        vote_state_update: &VoteStateUpdate,
232        serializer: S,
233    ) -> Result<S::Ok, S::Error>
234    where
235        S: Serializer,
236    {
237        let lockout_offsets = vote_state_update.lockouts.iter().scan(
238            vote_state_update.root.unwrap_or_default(),
239            |slot, lockout| {
240                let Some(offset) = lockout.slot().checked_sub(*slot) else {
241                    return Some(Err(serde::ser::Error::custom("Invalid vote lockout")));
242                };
243                let Ok(confirmation_count) = u8::try_from(lockout.confirmation_count()) else {
244                    return Some(Err(serde::ser::Error::custom("Invalid confirmation count")));
245                };
246                let lockout_offset = LockoutOffset {
247                    offset,
248                    confirmation_count,
249                };
250                *slot = lockout.slot();
251                Some(Ok(lockout_offset))
252            },
253        );
254        let compact_vote_state_update = CompactVoteStateUpdate {
255            root: vote_state_update.root.unwrap_or(Slot::MAX),
256            lockout_offsets: lockout_offsets.collect::<Result<_, _>>()?,
257            hash: vote_state_update.hash,
258            timestamp: vote_state_update.timestamp,
259        };
260        compact_vote_state_update.serialize(serializer)
261    }
262
263    pub fn deserialize<'de, D>(deserializer: D) -> Result<VoteStateUpdate, D::Error>
264    where
265        D: Deserializer<'de>,
266    {
267        let CompactVoteStateUpdate {
268            root,
269            lockout_offsets,
270            hash,
271            timestamp,
272        } = CompactVoteStateUpdate::deserialize(deserializer)?;
273        let root = (root != Slot::MAX).then_some(root);
274        let lockouts =
275            lockout_offsets
276                .iter()
277                .scan(root.unwrap_or_default(), |slot, lockout_offset| {
278                    *slot = match slot.checked_add(lockout_offset.offset) {
279                        None => {
280                            return Some(Err(serde::de::Error::custom("Invalid lockout offset")))
281                        }
282                        Some(slot) => slot,
283                    };
284                    let lockout = Lockout::new_with_confirmation_count(
285                        *slot,
286                        u32::from(lockout_offset.confirmation_count),
287                    );
288                    Some(Ok(lockout))
289                });
290        Ok(VoteStateUpdate {
291            root,
292            lockouts: lockouts.collect::<Result<_, _>>()?,
293            hash,
294            timestamp,
295        })
296    }
297}
298
299#[cfg(feature = "serde")]
300pub mod serde_tower_sync {
301    use {
302        super::*,
303        crate::state::Lockout,
304        serde::{Deserialize, Deserializer, Serialize, Serializer},
305        solana_hash::Hash,
306        solana_serde_varint as serde_varint, solana_short_vec as short_vec,
307    };
308
309    #[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
310    #[derive(serde_derive::Deserialize, serde_derive::Serialize)]
311    struct LockoutOffset {
312        #[serde(with = "serde_varint")]
313        offset: Slot,
314        confirmation_count: u8,
315    }
316
317    #[derive(serde_derive::Deserialize, serde_derive::Serialize)]
318    struct CompactTowerSync {
319        root: Slot,
320        #[serde(with = "short_vec")]
321        lockout_offsets: Vec<LockoutOffset>,
322        hash: Hash,
323        timestamp: Option<UnixTimestamp>,
324        block_id: Hash,
325    }
326
327    pub fn serialize<S>(tower_sync: &TowerSync, serializer: S) -> Result<S::Ok, S::Error>
328    where
329        S: Serializer,
330    {
331        let lockout_offsets = tower_sync.lockouts.iter().scan(
332            tower_sync.root.unwrap_or_default(),
333            |slot, lockout| {
334                let Some(offset) = lockout.slot().checked_sub(*slot) else {
335                    return Some(Err(serde::ser::Error::custom("Invalid vote lockout")));
336                };
337                let Ok(confirmation_count) = u8::try_from(lockout.confirmation_count()) else {
338                    return Some(Err(serde::ser::Error::custom("Invalid confirmation count")));
339                };
340                let lockout_offset = LockoutOffset {
341                    offset,
342                    confirmation_count,
343                };
344                *slot = lockout.slot();
345                Some(Ok(lockout_offset))
346            },
347        );
348        let compact_tower_sync = CompactTowerSync {
349            root: tower_sync.root.unwrap_or(Slot::MAX),
350            lockout_offsets: lockout_offsets.collect::<Result<_, _>>()?,
351            hash: tower_sync.hash,
352            timestamp: tower_sync.timestamp,
353            block_id: tower_sync.block_id,
354        };
355        compact_tower_sync.serialize(serializer)
356    }
357
358    pub fn deserialize<'de, D>(deserializer: D) -> Result<TowerSync, D::Error>
359    where
360        D: Deserializer<'de>,
361    {
362        let CompactTowerSync {
363            root,
364            lockout_offsets,
365            hash,
366            timestamp,
367            block_id,
368        } = CompactTowerSync::deserialize(deserializer)?;
369        let root = (root != Slot::MAX).then_some(root);
370        let lockouts =
371            lockout_offsets
372                .iter()
373                .scan(root.unwrap_or_default(), |slot, lockout_offset| {
374                    *slot = match slot.checked_add(lockout_offset.offset) {
375                        None => {
376                            return Some(Err(serde::de::Error::custom("Invalid lockout offset")))
377                        }
378                        Some(slot) => slot,
379                    };
380                    let lockout = Lockout::new_with_confirmation_count(
381                        *slot,
382                        u32::from(lockout_offset.confirmation_count),
383                    );
384                    Some(Ok(lockout))
385                });
386        Ok(TowerSync {
387            root,
388            lockouts: lockouts.collect::<Result<_, _>>()?,
389            hash,
390            timestamp,
391            block_id,
392        })
393    }
394}
395
396#[cfg(test)]
397mod tests {
398    use {
399        super::*, crate::error::VoteError, bincode::serialized_size, core::mem::MaybeUninit,
400        itertools::Itertools, rand::Rng, solana_clock::Clock, solana_hash::Hash,
401        solana_instruction_error::InstructionError,
402    };
403
404    #[test]
405    fn test_vote_serialize() {
406        let mut buffer: Vec<u8> = vec![0; VoteStateV3::size_of()];
407        let mut vote_state = VoteStateV3::default();
408        vote_state
409            .votes
410            .resize(MAX_LOCKOUT_HISTORY, LandedVote::default());
411        vote_state.root_slot = Some(1);
412        let versioned = VoteStateVersions::new_v3(vote_state);
413        assert!(VoteStateV3::serialize(&versioned, &mut buffer[0..4]).is_err());
414        VoteStateV3::serialize(&versioned, &mut buffer).unwrap();
415        assert_eq!(
416            VoteStateV3::deserialize(&buffer).unwrap(),
417            versioned.convert_to_v3()
418        );
419    }
420
421    #[test]
422    fn test_vote_deserialize_into() {
423        // base case
424        let target_vote_state = VoteStateV3::default();
425        let vote_state_buf =
426            bincode::serialize(&VoteStateVersions::new_v3(target_vote_state.clone())).unwrap();
427
428        let mut test_vote_state = VoteStateV3::default();
429        VoteStateV3::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap();
430
431        assert_eq!(target_vote_state, test_vote_state);
432
433        // variant
434        // provide 4x the minimum struct size in bytes to ensure we typically touch every field
435        let struct_bytes_x4 = std::mem::size_of::<VoteStateV3>() * 4;
436        for _ in 0..1000 {
437            let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
438            let mut unstructured = Unstructured::new(&raw_data);
439
440            let target_vote_state_versions =
441                VoteStateVersions::arbitrary(&mut unstructured).unwrap();
442            let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
443            let target_vote_state = target_vote_state_versions.convert_to_v3();
444
445            let mut test_vote_state = VoteStateV3::default();
446            VoteStateV3::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap();
447
448            assert_eq!(target_vote_state, test_vote_state);
449        }
450    }
451
452    #[test]
453    fn test_vote_deserialize_into_error() {
454        let target_vote_state = VoteStateV3::new_rand_for_tests(Pubkey::new_unique(), 42);
455        let mut vote_state_buf =
456            bincode::serialize(&VoteStateVersions::new_v3(target_vote_state.clone())).unwrap();
457        let len = vote_state_buf.len();
458        vote_state_buf.truncate(len - 1);
459
460        let mut test_vote_state = VoteStateV3::default();
461        VoteStateV3::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap_err();
462        assert_eq!(test_vote_state, VoteStateV3::default());
463    }
464
465    #[test]
466    fn test_vote_deserialize_into_uninit() {
467        // base case
468        let target_vote_state = VoteStateV3::default();
469        let vote_state_buf =
470            bincode::serialize(&VoteStateVersions::new_v3(target_vote_state.clone())).unwrap();
471
472        let mut test_vote_state = MaybeUninit::uninit();
473        VoteStateV3::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap();
474        let test_vote_state = unsafe { test_vote_state.assume_init() };
475
476        assert_eq!(target_vote_state, test_vote_state);
477
478        // variant
479        // provide 4x the minimum struct size in bytes to ensure we typically touch every field
480        let struct_bytes_x4 = std::mem::size_of::<VoteStateV3>() * 4;
481        for _ in 0..1000 {
482            let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
483            let mut unstructured = Unstructured::new(&raw_data);
484
485            let target_vote_state_versions =
486                VoteStateVersions::arbitrary(&mut unstructured).unwrap();
487            let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
488            let target_vote_state = target_vote_state_versions.convert_to_v3();
489
490            let mut test_vote_state = MaybeUninit::uninit();
491            VoteStateV3::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap();
492            let test_vote_state = unsafe { test_vote_state.assume_init() };
493
494            assert_eq!(target_vote_state, test_vote_state);
495        }
496    }
497
498    #[test]
499    fn test_vote_deserialize_into_uninit_nopanic() {
500        // base case
501        let mut test_vote_state = MaybeUninit::uninit();
502        let e = VoteStateV3::deserialize_into_uninit(&[], &mut test_vote_state).unwrap_err();
503        assert_eq!(e, InstructionError::InvalidAccountData);
504
505        // variant
506        let serialized_len_x4 = serialized_size(&VoteStateV3::default()).unwrap() * 4;
507        let mut rng = rand::thread_rng();
508        for _ in 0..1000 {
509            let raw_data_length = rng.gen_range(1..serialized_len_x4);
510            let mut raw_data: Vec<u8> = (0..raw_data_length).map(|_| rng.gen::<u8>()).collect();
511
512            // pure random data will ~never have a valid enum tag, so lets help it out
513            if raw_data_length >= 4 && rng.gen::<bool>() {
514                let tag = rng.gen::<u8>() % 3;
515                raw_data[0] = tag;
516                raw_data[1] = 0;
517                raw_data[2] = 0;
518                raw_data[3] = 0;
519            }
520
521            // it is extremely improbable, though theoretically possible, for random bytes to be syntactically valid
522            // so we only check that the parser does not panic and that it succeeds or fails exactly in line with bincode
523            let mut test_vote_state = MaybeUninit::uninit();
524            let test_res = VoteStateV3::deserialize_into_uninit(&raw_data, &mut test_vote_state);
525            let bincode_res = bincode::deserialize::<VoteStateVersions>(&raw_data)
526                .map(|versioned| versioned.convert_to_v3());
527
528            if test_res.is_err() {
529                assert!(bincode_res.is_err());
530            } else {
531                let test_vote_state = unsafe { test_vote_state.assume_init() };
532                assert_eq!(test_vote_state, bincode_res.unwrap());
533            }
534        }
535    }
536
537    #[test]
538    fn test_vote_deserialize_into_uninit_ill_sized() {
539        // provide 4x the minimum struct size in bytes to ensure we typically touch every field
540        let struct_bytes_x4 = std::mem::size_of::<VoteStateV3>() * 4;
541        for _ in 0..1000 {
542            let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
543            let mut unstructured = Unstructured::new(&raw_data);
544
545            let original_vote_state_versions =
546                VoteStateVersions::arbitrary(&mut unstructured).unwrap();
547            let original_buf = bincode::serialize(&original_vote_state_versions).unwrap();
548
549            let mut truncated_buf = original_buf.clone();
550            let mut expanded_buf = original_buf.clone();
551
552            truncated_buf.resize(original_buf.len() - 8, 0);
553            expanded_buf.resize(original_buf.len() + 8, 0);
554
555            // truncated fails
556            let mut test_vote_state = MaybeUninit::uninit();
557            let test_res =
558                VoteStateV3::deserialize_into_uninit(&truncated_buf, &mut test_vote_state);
559            let bincode_res = bincode::deserialize::<VoteStateVersions>(&truncated_buf)
560                .map(|versioned| versioned.convert_to_v3());
561
562            assert!(test_res.is_err());
563            assert!(bincode_res.is_err());
564
565            // expanded succeeds
566            let mut test_vote_state = MaybeUninit::uninit();
567            VoteStateV3::deserialize_into_uninit(&expanded_buf, &mut test_vote_state).unwrap();
568            let bincode_res = bincode::deserialize::<VoteStateVersions>(&expanded_buf)
569                .map(|versioned| versioned.convert_to_v3());
570
571            let test_vote_state = unsafe { test_vote_state.assume_init() };
572            assert_eq!(test_vote_state, bincode_res.unwrap());
573        }
574    }
575
576    #[test]
577    fn test_vote_state_epoch_credits() {
578        let mut vote_state = VoteStateV3::default();
579
580        assert_eq!(vote_state.credits(), 0);
581        assert_eq!(vote_state.epoch_credits().clone(), vec![]);
582
583        let mut expected = vec![];
584        let mut credits = 0;
585        let epochs = (MAX_EPOCH_CREDITS_HISTORY + 2) as u64;
586        for epoch in 0..epochs {
587            for _j in 0..epoch {
588                vote_state.increment_credits(epoch, 1);
589                credits += 1;
590            }
591            expected.push((epoch, credits, credits - epoch));
592        }
593
594        while expected.len() > MAX_EPOCH_CREDITS_HISTORY {
595            expected.remove(0);
596        }
597
598        assert_eq!(vote_state.credits(), credits);
599        assert_eq!(vote_state.epoch_credits().clone(), expected);
600    }
601
602    #[test]
603    fn test_vote_state_epoch0_no_credits() {
604        let mut vote_state = VoteStateV3::default();
605
606        assert_eq!(vote_state.epoch_credits().len(), 0);
607        vote_state.increment_credits(1, 1);
608        assert_eq!(vote_state.epoch_credits().len(), 1);
609
610        vote_state.increment_credits(2, 1);
611        assert_eq!(vote_state.epoch_credits().len(), 2);
612    }
613
614    #[test]
615    fn test_vote_state_increment_credits() {
616        let mut vote_state = VoteStateV3::default();
617
618        let credits = (MAX_EPOCH_CREDITS_HISTORY + 2) as u64;
619        for i in 0..credits {
620            vote_state.increment_credits(i, 1);
621        }
622        assert_eq!(vote_state.credits(), credits);
623        assert!(vote_state.epoch_credits().len() <= MAX_EPOCH_CREDITS_HISTORY);
624    }
625
626    #[test]
627    fn test_vote_process_timestamp() {
628        let (slot, timestamp) = (15, 1_575_412_285);
629        let mut vote_state = VoteStateV3 {
630            last_timestamp: BlockTimestamp { slot, timestamp },
631            ..VoteStateV3::default()
632        };
633
634        assert_eq!(
635            vote_state.process_timestamp(slot - 1, timestamp + 1),
636            Err(VoteError::TimestampTooOld)
637        );
638        assert_eq!(
639            vote_state.last_timestamp,
640            BlockTimestamp { slot, timestamp }
641        );
642        assert_eq!(
643            vote_state.process_timestamp(slot + 1, timestamp - 1),
644            Err(VoteError::TimestampTooOld)
645        );
646        assert_eq!(
647            vote_state.process_timestamp(slot, timestamp + 1),
648            Err(VoteError::TimestampTooOld)
649        );
650        assert_eq!(vote_state.process_timestamp(slot, timestamp), Ok(()));
651        assert_eq!(
652            vote_state.last_timestamp,
653            BlockTimestamp { slot, timestamp }
654        );
655        assert_eq!(vote_state.process_timestamp(slot + 1, timestamp), Ok(()));
656        assert_eq!(
657            vote_state.last_timestamp,
658            BlockTimestamp {
659                slot: slot + 1,
660                timestamp
661            }
662        );
663        assert_eq!(
664            vote_state.process_timestamp(slot + 2, timestamp + 1),
665            Ok(())
666        );
667        assert_eq!(
668            vote_state.last_timestamp,
669            BlockTimestamp {
670                slot: slot + 2,
671                timestamp: timestamp + 1
672            }
673        );
674
675        // Test initial vote
676        vote_state.last_timestamp = BlockTimestamp::default();
677        assert_eq!(vote_state.process_timestamp(0, timestamp), Ok(()));
678    }
679
680    #[test]
681    fn test_get_and_update_authorized_voter() {
682        let original_voter = Pubkey::new_unique();
683        let mut vote_state = VoteStateV3::new(
684            &VoteInit {
685                node_pubkey: original_voter,
686                authorized_voter: original_voter,
687                authorized_withdrawer: original_voter,
688                commission: 0,
689            },
690            &Clock::default(),
691        );
692
693        assert_eq!(vote_state.authorized_voters.len(), 1);
694        assert_eq!(
695            *vote_state.authorized_voters.first().unwrap().1,
696            original_voter
697        );
698
699        // If no new authorized voter was set, the same authorized voter
700        // is locked into the next epoch
701        assert_eq!(
702            vote_state.get_and_update_authorized_voter(1).unwrap(),
703            original_voter
704        );
705
706        // Try to get the authorized voter for epoch 5, implies
707        // the authorized voter for epochs 1-4 were unchanged
708        assert_eq!(
709            vote_state.get_and_update_authorized_voter(5).unwrap(),
710            original_voter
711        );
712
713        // Authorized voter for expired epoch 0..5 should have been
714        // purged and no longer queryable
715        assert_eq!(vote_state.authorized_voters.len(), 1);
716        for i in 0..5 {
717            assert!(vote_state
718                .authorized_voters
719                .get_authorized_voter(i)
720                .is_none());
721        }
722
723        // Set an authorized voter change at slot 7
724        let new_authorized_voter = Pubkey::new_unique();
725        vote_state
726            .set_new_authorized_voter(&new_authorized_voter, 5, 7, |_| Ok(()))
727            .unwrap();
728
729        // Try to get the authorized voter for epoch 6, unchanged
730        assert_eq!(
731            vote_state.get_and_update_authorized_voter(6).unwrap(),
732            original_voter
733        );
734
735        // Try to get the authorized voter for epoch 7 and onwards, should
736        // be the new authorized voter
737        for i in 7..10 {
738            assert_eq!(
739                vote_state.get_and_update_authorized_voter(i).unwrap(),
740                new_authorized_voter
741            );
742        }
743        assert_eq!(vote_state.authorized_voters.len(), 1);
744    }
745
746    #[test]
747    fn test_set_new_authorized_voter() {
748        let original_voter = Pubkey::new_unique();
749        let epoch_offset = 15;
750        let mut vote_state = VoteStateV3::new(
751            &VoteInit {
752                node_pubkey: original_voter,
753                authorized_voter: original_voter,
754                authorized_withdrawer: original_voter,
755                commission: 0,
756            },
757            &Clock::default(),
758        );
759
760        assert!(vote_state.prior_voters.last().is_none());
761
762        let new_voter = Pubkey::new_unique();
763        // Set a new authorized voter
764        vote_state
765            .set_new_authorized_voter(&new_voter, 0, epoch_offset, |_| Ok(()))
766            .unwrap();
767
768        assert_eq!(vote_state.prior_voters.idx, 0);
769        assert_eq!(
770            vote_state.prior_voters.last(),
771            Some(&(original_voter, 0, epoch_offset))
772        );
773
774        // Trying to set authorized voter for same epoch again should fail
775        assert_eq!(
776            vote_state.set_new_authorized_voter(&new_voter, 0, epoch_offset, |_| Ok(())),
777            Err(VoteError::TooSoonToReauthorize.into())
778        );
779
780        // Setting the same authorized voter again should succeed
781        vote_state
782            .set_new_authorized_voter(&new_voter, 2, 2 + epoch_offset, |_| Ok(()))
783            .unwrap();
784
785        // Set a third and fourth authorized voter
786        let new_voter2 = Pubkey::new_unique();
787        vote_state
788            .set_new_authorized_voter(&new_voter2, 3, 3 + epoch_offset, |_| Ok(()))
789            .unwrap();
790        assert_eq!(vote_state.prior_voters.idx, 1);
791        assert_eq!(
792            vote_state.prior_voters.last(),
793            Some(&(new_voter, epoch_offset, 3 + epoch_offset))
794        );
795
796        let new_voter3 = Pubkey::new_unique();
797        vote_state
798            .set_new_authorized_voter(&new_voter3, 6, 6 + epoch_offset, |_| Ok(()))
799            .unwrap();
800        assert_eq!(vote_state.prior_voters.idx, 2);
801        assert_eq!(
802            vote_state.prior_voters.last(),
803            Some(&(new_voter2, 3 + epoch_offset, 6 + epoch_offset))
804        );
805
806        // Check can set back to original voter
807        vote_state
808            .set_new_authorized_voter(&original_voter, 9, 9 + epoch_offset, |_| Ok(()))
809            .unwrap();
810
811        // Run with these voters for a while, check the ranges of authorized
812        // voters is correct
813        for i in 9..epoch_offset {
814            assert_eq!(
815                vote_state.get_and_update_authorized_voter(i).unwrap(),
816                original_voter
817            );
818        }
819        for i in epoch_offset..3 + epoch_offset {
820            assert_eq!(
821                vote_state.get_and_update_authorized_voter(i).unwrap(),
822                new_voter
823            );
824        }
825        for i in 3 + epoch_offset..6 + epoch_offset {
826            assert_eq!(
827                vote_state.get_and_update_authorized_voter(i).unwrap(),
828                new_voter2
829            );
830        }
831        for i in 6 + epoch_offset..9 + epoch_offset {
832            assert_eq!(
833                vote_state.get_and_update_authorized_voter(i).unwrap(),
834                new_voter3
835            );
836        }
837        for i in 9 + epoch_offset..=10 + epoch_offset {
838            assert_eq!(
839                vote_state.get_and_update_authorized_voter(i).unwrap(),
840                original_voter
841            );
842        }
843    }
844
845    #[test]
846    fn test_authorized_voter_is_locked_within_epoch() {
847        let original_voter = Pubkey::new_unique();
848        let mut vote_state = VoteStateV3::new(
849            &VoteInit {
850                node_pubkey: original_voter,
851                authorized_voter: original_voter,
852                authorized_withdrawer: original_voter,
853                commission: 0,
854            },
855            &Clock::default(),
856        );
857
858        // Test that it's not possible to set a new authorized
859        // voter within the same epoch, even if none has been
860        // explicitly set before
861        let new_voter = Pubkey::new_unique();
862        assert_eq!(
863            vote_state.set_new_authorized_voter(&new_voter, 1, 1, |_| Ok(())),
864            Err(VoteError::TooSoonToReauthorize.into())
865        );
866
867        assert_eq!(vote_state.get_authorized_voter(1), Some(original_voter));
868
869        // Set a new authorized voter for a future epoch
870        assert_eq!(
871            vote_state.set_new_authorized_voter(&new_voter, 1, 2, |_| Ok(())),
872            Ok(())
873        );
874
875        // Test that it's not possible to set a new authorized
876        // voter within the same epoch, even if none has been
877        // explicitly set before
878        assert_eq!(
879            vote_state.set_new_authorized_voter(&original_voter, 3, 3, |_| Ok(())),
880            Err(VoteError::TooSoonToReauthorize.into())
881        );
882
883        assert_eq!(vote_state.get_authorized_voter(3), Some(new_voter));
884    }
885
886    #[test]
887    fn test_vote_state_size_of() {
888        let vote_state = VoteStateV3::get_max_sized_vote_state();
889        let vote_state = VoteStateVersions::new_v3(vote_state);
890        let size = serialized_size(&vote_state).unwrap();
891        assert_eq!(VoteStateV3::size_of() as u64, size);
892    }
893
894    #[test]
895    fn test_vote_state_max_size() {
896        let mut max_sized_data = vec![0; VoteStateV3::size_of()];
897        let vote_state = VoteStateV3::get_max_sized_vote_state();
898        let (start_leader_schedule_epoch, _) = vote_state.authorized_voters.last().unwrap();
899        let start_current_epoch =
900            start_leader_schedule_epoch - MAX_LEADER_SCHEDULE_EPOCH_OFFSET + 1;
901
902        let mut vote_state = Some(vote_state);
903        for i in start_current_epoch..start_current_epoch + 2 * MAX_LEADER_SCHEDULE_EPOCH_OFFSET {
904            vote_state.as_mut().map(|vote_state| {
905                vote_state.set_new_authorized_voter(
906                    &Pubkey::new_unique(),
907                    i,
908                    i + MAX_LEADER_SCHEDULE_EPOCH_OFFSET,
909                    |_| Ok(()),
910                )
911            });
912
913            let versioned = VoteStateVersions::new_v3(vote_state.take().unwrap());
914            VoteStateV3::serialize(&versioned, &mut max_sized_data).unwrap();
915            vote_state = Some(versioned.convert_to_v3());
916        }
917    }
918
919    #[test]
920    fn test_default_vote_state_is_uninitialized() {
921        // The default `VoteStateV3` is stored to de-initialize a zero-balance vote account,
922        // so must remain such that `VoteStateVersions::is_uninitialized()` returns true
923        // when called on a `VoteStateVersions` that stores it
924        assert!(VoteStateVersions::new_v3(VoteStateV3::default()).is_uninitialized());
925    }
926
927    #[test]
928    fn test_is_correct_size_and_initialized() {
929        // Check all zeroes
930        let mut vote_account_data = vec![0; VoteStateVersions::vote_state_size_of(true)];
931        assert!(!VoteStateVersions::is_correct_size_and_initialized(
932            &vote_account_data
933        ));
934
935        // Check default VoteStateV3
936        let default_account_state = VoteStateVersions::new_v3(VoteStateV3::default());
937        VoteStateV3::serialize(&default_account_state, &mut vote_account_data).unwrap();
938        assert!(!VoteStateVersions::is_correct_size_and_initialized(
939            &vote_account_data
940        ));
941
942        // Check non-zero data shorter than offset index used
943        let short_data = vec![1; DEFAULT_PRIOR_VOTERS_OFFSET];
944        assert!(!VoteStateVersions::is_correct_size_and_initialized(
945            &short_data
946        ));
947
948        // Check non-zero large account
949        let mut large_vote_data = vec![1; 2 * VoteStateVersions::vote_state_size_of(true)];
950        let default_account_state = VoteStateVersions::new_v3(VoteStateV3::default());
951        VoteStateV3::serialize(&default_account_state, &mut large_vote_data).unwrap();
952        assert!(!VoteStateVersions::is_correct_size_and_initialized(
953            &vote_account_data
954        ));
955
956        // Check populated VoteStateV3
957        let vote_state = VoteStateV3::new(
958            &VoteInit {
959                node_pubkey: Pubkey::new_unique(),
960                authorized_voter: Pubkey::new_unique(),
961                authorized_withdrawer: Pubkey::new_unique(),
962                commission: 0,
963            },
964            &Clock::default(),
965        );
966        let account_state = VoteStateVersions::new_v3(vote_state.clone());
967        VoteStateV3::serialize(&account_state, &mut vote_account_data).unwrap();
968        assert!(VoteStateVersions::is_correct_size_and_initialized(
969            &vote_account_data
970        ));
971
972        // Check old VoteStateV3 that hasn't been upgraded to newest version yet
973        let old_vote_state = VoteState1_14_11::from(vote_state);
974        let account_state = VoteStateVersions::V1_14_11(Box::new(old_vote_state));
975        let mut vote_account_data = vec![0; VoteStateVersions::vote_state_size_of(false)];
976        VoteStateV3::serialize(&account_state, &mut vote_account_data).unwrap();
977        assert!(VoteStateVersions::is_correct_size_and_initialized(
978            &vote_account_data
979        ));
980    }
981
982    #[test]
983    fn test_minimum_balance() {
984        let rent = solana_rent::Rent::default();
985        let minimum_balance = rent.minimum_balance(VoteStateV3::size_of());
986        // golden, may need updating when vote_state grows
987        assert!(minimum_balance as f64 / 10f64.powf(9.0) < 0.04)
988    }
989
990    #[test]
991    fn test_serde_compact_vote_state_update() {
992        let mut rng = rand::thread_rng();
993        for _ in 0..5000 {
994            run_serde_compact_vote_state_update(&mut rng);
995        }
996    }
997
998    fn run_serde_compact_vote_state_update<R: Rng>(rng: &mut R) {
999        let lockouts: VecDeque<_> = std::iter::repeat_with(|| {
1000            let slot = 149_303_885_u64.saturating_add(rng.gen_range(0..10_000));
1001            let confirmation_count = rng.gen_range(0..33);
1002            Lockout::new_with_confirmation_count(slot, confirmation_count)
1003        })
1004        .take(32)
1005        .sorted_by_key(|lockout| lockout.slot())
1006        .collect();
1007        let root = rng.gen_ratio(1, 2).then(|| {
1008            lockouts[0]
1009                .slot()
1010                .checked_sub(rng.gen_range(0..1_000))
1011                .expect("All slots should be greater than 1_000")
1012        });
1013        let timestamp = rng.gen_ratio(1, 2).then(|| rng.gen());
1014        let hash = Hash::from(rng.gen::<[u8; 32]>());
1015        let vote_state_update = VoteStateUpdate {
1016            lockouts,
1017            root,
1018            hash,
1019            timestamp,
1020        };
1021        #[derive(Debug, Eq, PartialEq, Deserialize, Serialize)]
1022        enum VoteInstruction {
1023            #[serde(with = "serde_compact_vote_state_update")]
1024            UpdateVoteState(VoteStateUpdate),
1025            UpdateVoteStateSwitch(
1026                #[serde(with = "serde_compact_vote_state_update")] VoteStateUpdate,
1027                Hash,
1028            ),
1029        }
1030        let vote = VoteInstruction::UpdateVoteState(vote_state_update.clone());
1031        let bytes = bincode::serialize(&vote).unwrap();
1032        assert_eq!(vote, bincode::deserialize(&bytes).unwrap());
1033        let hash = Hash::from(rng.gen::<[u8; 32]>());
1034        let vote = VoteInstruction::UpdateVoteStateSwitch(vote_state_update, hash);
1035        let bytes = bincode::serialize(&vote).unwrap();
1036        assert_eq!(vote, bincode::deserialize(&bytes).unwrap());
1037    }
1038
1039    #[test]
1040    fn test_circbuf_oob() {
1041        // Craft an invalid CircBuf with out-of-bounds index
1042        let data: &[u8] = &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00];
1043        let circ_buf: CircBuf<()> = bincode::deserialize(data).unwrap();
1044        assert_eq!(circ_buf.last(), None);
1045    }
1046}