atlas_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 atlas_frozen_abi_macro::AbiExample;
9use {
10    crate::authorized_voters::AuthorizedVoters,
11    atlas_clock::{Epoch, Slot, UnixTimestamp},
12    atlas_pubkey::Pubkey,
13    atlas_rent::Rent,
14    std::{collections::VecDeque, fmt::Debug},
15};
16#[cfg(test)]
17use {arbitrary::Unstructured, atlas_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 = "atlas", 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        atlas_hash::Hash,
210        atlas_serde_varint as serde_varint, atlas_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        atlas_hash::Hash,
306        atlas_serde_varint as serde_varint, atlas_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::*,
400        crate::{error::VoteError, state::vote_state_0_23_5::VoteState0_23_5},
401        bincode::serialized_size,
402        core::mem::MaybeUninit,
403        itertools::Itertools,
404        rand::Rng,
405        atlas_clock::Clock,
406        atlas_hash::Hash,
407        atlas_instruction::error::InstructionError,
408    };
409
410    // Test helper to create a VoteStateV4 with random data for testing
411    fn create_test_vote_state_v4(node_pubkey: Pubkey, root_slot: Slot) -> VoteStateV4 {
412        let votes = (1..32)
413            .map(|x| LandedVote {
414                latency: 0,
415                lockout: Lockout::new_with_confirmation_count(
416                    u64::from(x).saturating_add(root_slot),
417                    32_u32.saturating_sub(x),
418                ),
419            })
420            .collect();
421        VoteStateV4 {
422            node_pubkey,
423            root_slot: Some(root_slot),
424            votes,
425            ..VoteStateV4::default()
426        }
427    }
428
429    #[test]
430    fn test_vote_serialize_v3() {
431        let mut buffer: Vec<u8> = vec![0; VoteStateV3::size_of()];
432        let mut vote_state = VoteStateV3::default();
433        vote_state
434            .votes
435            .resize(MAX_LOCKOUT_HISTORY, LandedVote::default());
436        vote_state.root_slot = Some(1);
437        let versioned = VoteStateVersions::new_v3(vote_state);
438        assert!(VoteStateV3::serialize(&versioned, &mut buffer[0..4]).is_err());
439        VoteStateV3::serialize(&versioned, &mut buffer).unwrap();
440        assert_eq!(
441            VoteStateV3::deserialize(&buffer).unwrap(),
442            versioned.try_convert_to_v3().unwrap()
443        );
444    }
445
446    #[test]
447    fn test_vote_serialize_v4() {
448        // Use two different pubkeys to demonstrate that v4 ignores the
449        // `vote_pubkey` parameter.
450        let vote_pubkey_for_deserialize = Pubkey::new_unique();
451        let vote_pubkey_for_convert = Pubkey::new_unique();
452
453        let mut buffer: Vec<u8> = vec![0; VoteStateV4::size_of()];
454        let mut vote_state = VoteStateV4::default();
455        vote_state
456            .votes
457            .resize(MAX_LOCKOUT_HISTORY, LandedVote::default());
458        vote_state.root_slot = Some(1);
459        let versioned = VoteStateVersions::new_v4(vote_state);
460        assert!(VoteStateV4::serialize(&versioned, &mut buffer[0..4]).is_err());
461        VoteStateV4::serialize(&versioned, &mut buffer).unwrap();
462        assert_eq!(
463            VoteStateV4::deserialize(&buffer, &vote_pubkey_for_deserialize).unwrap(),
464            versioned
465                .try_convert_to_v4(&vote_pubkey_for_convert)
466                .unwrap()
467        );
468    }
469
470    #[test]
471    fn test_vote_deserialize_into_v3() {
472        // base case
473        let target_vote_state = VoteStateV3::default();
474        let vote_state_buf =
475            bincode::serialize(&VoteStateVersions::new_v3(target_vote_state.clone())).unwrap();
476
477        let mut test_vote_state = VoteStateV3::default();
478        VoteStateV3::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap();
479
480        assert_eq!(target_vote_state, test_vote_state);
481
482        // variant
483        // provide 4x the minimum struct size in bytes to ensure we typically touch every field
484        let struct_bytes_x4 = std::mem::size_of::<VoteStateV3>() * 4;
485        for _ in 0..1000 {
486            let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
487            let mut unstructured = Unstructured::new(&raw_data);
488
489            let target_vote_state_versions =
490                VoteStateVersions::arbitrary(&mut unstructured).unwrap();
491            let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
492
493            // Skip any v4 since they can't convert to v3.
494            if let Ok(target_vote_state) = target_vote_state_versions.try_convert_to_v3() {
495                let mut test_vote_state = VoteStateV3::default();
496                VoteStateV3::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap();
497
498                assert_eq!(target_vote_state, test_vote_state);
499            }
500        }
501    }
502
503    #[test]
504    fn test_vote_deserialize_into_v4() {
505        let vote_pubkey = Pubkey::new_unique();
506
507        // base case
508        let target_vote_state = VoteStateV4::default();
509        let vote_state_buf =
510            bincode::serialize(&VoteStateVersions::new_v4(target_vote_state.clone())).unwrap();
511
512        let mut test_vote_state = VoteStateV4::default();
513        VoteStateV4::deserialize_into(&vote_state_buf, &mut test_vote_state, &vote_pubkey).unwrap();
514
515        assert_eq!(target_vote_state, test_vote_state);
516
517        // variant
518        // provide 4x the minimum struct size in bytes to ensure we typically touch every field
519        let struct_bytes_x4 = std::mem::size_of::<VoteStateV4>() * 4;
520        for _ in 0..1000 {
521            let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
522            let mut unstructured = Unstructured::new(&raw_data);
523
524            let target_vote_state_versions =
525                VoteStateVersions::arbitrary(&mut unstructured).unwrap();
526            let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
527            let target_vote_state = target_vote_state_versions
528                .try_convert_to_v4(&vote_pubkey)
529                .unwrap();
530
531            let mut test_vote_state = VoteStateV4::default();
532            VoteStateV4::deserialize_into(&vote_state_buf, &mut test_vote_state, &vote_pubkey)
533                .unwrap();
534
535            assert_eq!(target_vote_state, test_vote_state);
536        }
537    }
538
539    #[test]
540    fn test_vote_deserialize_into_error_v3() {
541        let target_vote_state = VoteStateV3::new_rand_for_tests(Pubkey::new_unique(), 42);
542        let mut vote_state_buf =
543            bincode::serialize(&VoteStateVersions::new_v3(target_vote_state.clone())).unwrap();
544        let len = vote_state_buf.len();
545        vote_state_buf.truncate(len - 1);
546
547        let mut test_vote_state = VoteStateV3::default();
548        VoteStateV3::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap_err();
549        assert_eq!(test_vote_state, VoteStateV3::default());
550    }
551
552    #[test]
553    fn test_vote_deserialize_into_error_v4() {
554        let vote_pubkey = Pubkey::new_unique();
555
556        let target_vote_state = create_test_vote_state_v4(Pubkey::new_unique(), 42);
557        let mut vote_state_buf =
558            bincode::serialize(&VoteStateVersions::new_v4(target_vote_state.clone())).unwrap();
559        let len = vote_state_buf.len();
560        vote_state_buf.truncate(len - 1);
561
562        let mut test_vote_state = VoteStateV4::default();
563        VoteStateV4::deserialize_into(&vote_state_buf, &mut test_vote_state, &vote_pubkey)
564            .unwrap_err();
565        assert_eq!(test_vote_state, VoteStateV4::default());
566    }
567
568    #[test]
569    fn test_vote_deserialize_into_uninit_v3() {
570        // base case
571        let target_vote_state = VoteStateV3::default();
572        let vote_state_buf =
573            bincode::serialize(&VoteStateVersions::new_v3(target_vote_state.clone())).unwrap();
574
575        let mut test_vote_state = MaybeUninit::uninit();
576        VoteStateV3::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap();
577        let test_vote_state = unsafe { test_vote_state.assume_init() };
578
579        assert_eq!(target_vote_state, test_vote_state);
580
581        // variant
582        // provide 4x the minimum struct size in bytes to ensure we typically touch every field
583        let struct_bytes_x4 = std::mem::size_of::<VoteStateV3>() * 4;
584        for _ in 0..1000 {
585            let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
586            let mut unstructured = Unstructured::new(&raw_data);
587
588            let target_vote_state_versions =
589                VoteStateVersions::arbitrary(&mut unstructured).unwrap();
590            let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
591
592            // Skip any v4 since they can't convert to v3.
593            if let Ok(target_vote_state) = target_vote_state_versions.try_convert_to_v3() {
594                let mut test_vote_state = MaybeUninit::uninit();
595                VoteStateV3::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state)
596                    .unwrap();
597                let test_vote_state = unsafe { test_vote_state.assume_init() };
598
599                assert_eq!(target_vote_state, test_vote_state);
600            }
601        }
602    }
603
604    #[test]
605    fn test_vote_deserialize_into_uninit_v4() {
606        let vote_pubkey = Pubkey::new_unique();
607
608        // base case
609        let target_vote_state = VoteStateV4::default();
610        let vote_state_buf =
611            bincode::serialize(&VoteStateVersions::new_v4(target_vote_state.clone())).unwrap();
612
613        let mut test_vote_state = MaybeUninit::uninit();
614        VoteStateV4::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state, &vote_pubkey)
615            .unwrap();
616        let test_vote_state = unsafe { test_vote_state.assume_init() };
617
618        assert_eq!(target_vote_state, test_vote_state);
619
620        // variant
621        // provide 4x the minimum struct size in bytes to ensure we typically touch every field
622        let struct_bytes_x4 = std::mem::size_of::<VoteStateV4>() * 4;
623        for _ in 0..1000 {
624            let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
625            let mut unstructured = Unstructured::new(&raw_data);
626
627            let target_vote_state_versions =
628                VoteStateVersions::arbitrary(&mut unstructured).unwrap();
629            let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
630            let target_vote_state = target_vote_state_versions
631                .try_convert_to_v4(&Pubkey::default())
632                .unwrap();
633
634            let mut test_vote_state = MaybeUninit::uninit();
635            VoteStateV4::deserialize_into_uninit(
636                &vote_state_buf,
637                &mut test_vote_state,
638                &Pubkey::default(),
639            )
640            .unwrap();
641            let test_vote_state = unsafe { test_vote_state.assume_init() };
642
643            assert_eq!(target_vote_state, test_vote_state);
644        }
645    }
646
647    #[test]
648    fn test_vote_deserialize_into_uninit_nopanic_v3() {
649        // base case
650        let mut test_vote_state = MaybeUninit::uninit();
651        let e = VoteStateV3::deserialize_into_uninit(&[], &mut test_vote_state).unwrap_err();
652        assert_eq!(e, InstructionError::InvalidAccountData);
653
654        // variant
655        let serialized_len_x4 = serialized_size(&VoteStateV3::default()).unwrap() * 4;
656        let mut rng = rand::thread_rng();
657        for _ in 0..1000 {
658            let raw_data_length = rng.gen_range(1..serialized_len_x4);
659            let mut raw_data: Vec<u8> = (0..raw_data_length).map(|_| rng.gen::<u8>()).collect();
660
661            // pure random data will ~never have a valid enum tag, so lets help it out
662            if raw_data_length >= 4 && rng.gen::<bool>() {
663                let tag = rng.gen::<u8>() % 4;
664                raw_data[0] = tag;
665                raw_data[1] = 0;
666                raw_data[2] = 0;
667                raw_data[3] = 0;
668            }
669
670            // it is extremely improbable, though theoretically possible, for random bytes to be syntactically valid
671            // so we only check that the parser does not panic and that it succeeds or fails exactly in line with bincode
672            let mut test_vote_state = MaybeUninit::uninit();
673            let test_res = VoteStateV3::deserialize_into_uninit(&raw_data, &mut test_vote_state);
674
675            // Test with bincode for consistency.
676            let bincode_res = bincode::deserialize::<VoteStateVersions>(&raw_data)
677                .map_err(|_| InstructionError::InvalidAccountData)
678                .and_then(|versioned| versioned.try_convert_to_v3());
679
680            if test_res.is_err() {
681                assert!(bincode_res.is_err());
682            } else {
683                let test_vote_state = unsafe { test_vote_state.assume_init() };
684                assert_eq!(test_vote_state, bincode_res.unwrap());
685            }
686        }
687    }
688
689    #[test]
690    fn test_vote_deserialize_into_uninit_nopanic_v4() {
691        let vote_pubkey = Pubkey::new_unique();
692
693        // base case
694        let mut test_vote_state = MaybeUninit::uninit();
695        let e = VoteStateV4::deserialize_into_uninit(&[], &mut test_vote_state, &vote_pubkey)
696            .unwrap_err();
697        assert_eq!(e, InstructionError::InvalidAccountData);
698
699        // variant
700        let serialized_len_x4 = serialized_size(&VoteStateV4::default()).unwrap() * 4;
701        let mut rng = rand::thread_rng();
702        for _ in 0..1000 {
703            let raw_data_length = rng.gen_range(1..serialized_len_x4);
704            let mut raw_data: Vec<u8> = (0..raw_data_length).map(|_| rng.gen::<u8>()).collect();
705
706            // pure random data will ~never have a valid enum tag, so lets help it out
707            if raw_data_length >= 4 && rng.gen::<bool>() {
708                let tag = rng.gen::<u8>() % 4;
709                raw_data[0] = tag;
710                raw_data[1] = 0;
711                raw_data[2] = 0;
712                raw_data[3] = 0;
713            }
714
715            // it is extremely improbable, though theoretically possible, for random bytes to be syntactically valid
716            // so we only check that the parser does not panic and that it succeeds or fails exactly in line with bincode
717            let mut test_vote_state = MaybeUninit::uninit();
718            let test_res =
719                VoteStateV4::deserialize_into_uninit(&raw_data, &mut test_vote_state, &vote_pubkey);
720            let bincode_res = bincode::deserialize::<VoteStateVersions>(&raw_data)
721                .map(|versioned| versioned.try_convert_to_v4(&vote_pubkey).unwrap());
722
723            if test_res.is_err() {
724                assert!(bincode_res.is_err());
725            } else {
726                let test_vote_state = unsafe { test_vote_state.assume_init() };
727                assert_eq!(test_vote_state, bincode_res.unwrap());
728            }
729        }
730    }
731
732    #[test]
733    fn test_vote_deserialize_into_uninit_ill_sized_v3() {
734        // provide 4x the minimum struct size in bytes to ensure we typically touch every field
735        let struct_bytes_x4 = std::mem::size_of::<VoteStateV3>() * 4;
736        for _ in 0..1000 {
737            let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
738            let mut unstructured = Unstructured::new(&raw_data);
739
740            let original_vote_state_versions =
741                VoteStateVersions::arbitrary(&mut unstructured).unwrap();
742            let original_buf = bincode::serialize(&original_vote_state_versions).unwrap();
743
744            // Skip any v4 since they can't convert to v3.
745            if !matches!(original_vote_state_versions, VoteStateVersions::V4(_)) {
746                let mut truncated_buf = original_buf.clone();
747                let mut expanded_buf = original_buf.clone();
748
749                truncated_buf.resize(original_buf.len() - 8, 0);
750                expanded_buf.resize(original_buf.len() + 8, 0);
751
752                // truncated fails
753                let mut test_vote_state = MaybeUninit::uninit();
754                let test_res =
755                    VoteStateV3::deserialize_into_uninit(&truncated_buf, &mut test_vote_state);
756                // `deserialize_into_uninit` will eventually call into
757                // `try_convert_to_v3`, so we have alignment in the following map.
758                let bincode_res = bincode::deserialize::<VoteStateVersions>(&truncated_buf)
759                    .map_err(|_| InstructionError::InvalidAccountData)
760                    .and_then(|versioned| versioned.try_convert_to_v3());
761
762                assert!(test_res.is_err());
763                assert!(bincode_res.is_err());
764
765                // expanded succeeds
766                let mut test_vote_state = MaybeUninit::uninit();
767                VoteStateV3::deserialize_into_uninit(&expanded_buf, &mut test_vote_state).unwrap();
768                // `deserialize_into_uninit` will eventually call into
769                // `try_convert_to_v3`, so we have alignment in the following map.
770                let bincode_res = bincode::deserialize::<VoteStateVersions>(&expanded_buf)
771                    .map_err(|_| InstructionError::InvalidAccountData)
772                    .and_then(|versioned| versioned.try_convert_to_v3());
773
774                let test_vote_state = unsafe { test_vote_state.assume_init() };
775                assert_eq!(test_vote_state, bincode_res.unwrap());
776            }
777        }
778    }
779
780    #[test]
781    fn test_vote_deserialize_into_uninit_ill_sized_v4() {
782        let vote_pubkey = Pubkey::new_unique();
783
784        // provide 4x the minimum struct size in bytes to ensure we typically touch every field
785        let struct_bytes_x4 = std::mem::size_of::<VoteStateV4>() * 4;
786        for _ in 0..1000 {
787            let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
788            let mut unstructured = Unstructured::new(&raw_data);
789
790            let original_vote_state_versions =
791                VoteStateVersions::arbitrary(&mut unstructured).unwrap();
792            let original_buf = bincode::serialize(&original_vote_state_versions).unwrap();
793
794            let mut truncated_buf = original_buf.clone();
795            let mut expanded_buf = original_buf.clone();
796
797            truncated_buf.resize(original_buf.len() - 8, 0);
798            expanded_buf.resize(original_buf.len() + 8, 0);
799
800            // truncated fails
801            let mut test_vote_state = MaybeUninit::uninit();
802            let test_res = VoteStateV4::deserialize_into_uninit(
803                &truncated_buf,
804                &mut test_vote_state,
805                &vote_pubkey,
806            );
807            let bincode_res = bincode::deserialize::<VoteStateVersions>(&truncated_buf)
808                .map(|versioned| versioned.try_convert_to_v4(&vote_pubkey).unwrap());
809
810            assert!(test_res.is_err());
811            assert!(bincode_res.is_err());
812
813            // expanded succeeds
814            let mut test_vote_state = MaybeUninit::uninit();
815            VoteStateV4::deserialize_into_uninit(&expanded_buf, &mut test_vote_state, &vote_pubkey)
816                .unwrap();
817            let bincode_res = bincode::deserialize::<VoteStateVersions>(&expanded_buf)
818                .map(|versioned| versioned.try_convert_to_v4(&vote_pubkey).unwrap());
819
820            let test_vote_state = unsafe { test_vote_state.assume_init() };
821            assert_eq!(test_vote_state, bincode_res.unwrap());
822        }
823    }
824
825    #[test]
826    fn test_vote_state_epoch_credits() {
827        let mut vote_state = VoteStateV3::default();
828
829        assert_eq!(vote_state.credits(), 0);
830        assert_eq!(vote_state.epoch_credits().clone(), vec![]);
831
832        let mut expected = vec![];
833        let mut credits = 0;
834        let epochs = (MAX_EPOCH_CREDITS_HISTORY + 2) as u64;
835        for epoch in 0..epochs {
836            for _j in 0..epoch {
837                vote_state.increment_credits(epoch, 1);
838                credits += 1;
839            }
840            expected.push((epoch, credits, credits - epoch));
841        }
842
843        while expected.len() > MAX_EPOCH_CREDITS_HISTORY {
844            expected.remove(0);
845        }
846
847        assert_eq!(vote_state.credits(), credits);
848        assert_eq!(vote_state.epoch_credits().clone(), expected);
849    }
850
851    #[test]
852    fn test_vote_state_epoch0_no_credits() {
853        let mut vote_state = VoteStateV3::default();
854
855        assert_eq!(vote_state.epoch_credits().len(), 0);
856        vote_state.increment_credits(1, 1);
857        assert_eq!(vote_state.epoch_credits().len(), 1);
858
859        vote_state.increment_credits(2, 1);
860        assert_eq!(vote_state.epoch_credits().len(), 2);
861    }
862
863    #[test]
864    fn test_vote_state_increment_credits() {
865        let mut vote_state = VoteStateV3::default();
866
867        let credits = (MAX_EPOCH_CREDITS_HISTORY + 2) as u64;
868        for i in 0..credits {
869            vote_state.increment_credits(i, 1);
870        }
871        assert_eq!(vote_state.credits(), credits);
872        assert!(vote_state.epoch_credits().len() <= MAX_EPOCH_CREDITS_HISTORY);
873    }
874
875    #[test]
876    fn test_vote_process_timestamp() {
877        let (slot, timestamp) = (15, 1_575_412_285);
878        let mut vote_state = VoteStateV3 {
879            last_timestamp: BlockTimestamp { slot, timestamp },
880            ..VoteStateV3::default()
881        };
882
883        assert_eq!(
884            vote_state.process_timestamp(slot - 1, timestamp + 1),
885            Err(VoteError::TimestampTooOld)
886        );
887        assert_eq!(
888            vote_state.last_timestamp,
889            BlockTimestamp { slot, timestamp }
890        );
891        assert_eq!(
892            vote_state.process_timestamp(slot + 1, timestamp - 1),
893            Err(VoteError::TimestampTooOld)
894        );
895        assert_eq!(
896            vote_state.process_timestamp(slot, timestamp + 1),
897            Err(VoteError::TimestampTooOld)
898        );
899        assert_eq!(vote_state.process_timestamp(slot, timestamp), Ok(()));
900        assert_eq!(
901            vote_state.last_timestamp,
902            BlockTimestamp { slot, timestamp }
903        );
904        assert_eq!(vote_state.process_timestamp(slot + 1, timestamp), Ok(()));
905        assert_eq!(
906            vote_state.last_timestamp,
907            BlockTimestamp {
908                slot: slot + 1,
909                timestamp
910            }
911        );
912        assert_eq!(
913            vote_state.process_timestamp(slot + 2, timestamp + 1),
914            Ok(())
915        );
916        assert_eq!(
917            vote_state.last_timestamp,
918            BlockTimestamp {
919                slot: slot + 2,
920                timestamp: timestamp + 1
921            }
922        );
923
924        // Test initial vote
925        vote_state.last_timestamp = BlockTimestamp::default();
926        assert_eq!(vote_state.process_timestamp(0, timestamp), Ok(()));
927    }
928
929    #[test]
930    fn test_get_and_update_authorized_voter() {
931        let original_voter = Pubkey::new_unique();
932        let mut vote_state = VoteStateV3::new(
933            &VoteInit {
934                node_pubkey: original_voter,
935                authorized_voter: original_voter,
936                authorized_withdrawer: original_voter,
937                commission: 0,
938            },
939            &Clock::default(),
940        );
941
942        assert_eq!(vote_state.authorized_voters.len(), 1);
943        assert_eq!(
944            *vote_state.authorized_voters.first().unwrap().1,
945            original_voter
946        );
947
948        // If no new authorized voter was set, the same authorized voter
949        // is locked into the next epoch
950        assert_eq!(
951            vote_state.get_and_update_authorized_voter(1).unwrap(),
952            original_voter
953        );
954
955        // Try to get the authorized voter for epoch 5, implies
956        // the authorized voter for epochs 1-4 were unchanged
957        assert_eq!(
958            vote_state.get_and_update_authorized_voter(5).unwrap(),
959            original_voter
960        );
961
962        // Authorized voter for expired epoch 0..5 should have been
963        // purged and no longer queryable
964        assert_eq!(vote_state.authorized_voters.len(), 1);
965        for i in 0..5 {
966            assert!(vote_state
967                .authorized_voters
968                .get_authorized_voter(i)
969                .is_none());
970        }
971
972        // Set an authorized voter change at slot 7
973        let new_authorized_voter = Pubkey::new_unique();
974        vote_state
975            .set_new_authorized_voter(&new_authorized_voter, 5, 7, |_| Ok(()))
976            .unwrap();
977
978        // Try to get the authorized voter for epoch 6, unchanged
979        assert_eq!(
980            vote_state.get_and_update_authorized_voter(6).unwrap(),
981            original_voter
982        );
983
984        // Try to get the authorized voter for epoch 7 and onwards, should
985        // be the new authorized voter
986        for i in 7..10 {
987            assert_eq!(
988                vote_state.get_and_update_authorized_voter(i).unwrap(),
989                new_authorized_voter
990            );
991        }
992        assert_eq!(vote_state.authorized_voters.len(), 1);
993    }
994
995    #[test]
996    fn test_set_new_authorized_voter() {
997        let original_voter = Pubkey::new_unique();
998        let epoch_offset = 15;
999        let mut vote_state = VoteStateV3::new(
1000            &VoteInit {
1001                node_pubkey: original_voter,
1002                authorized_voter: original_voter,
1003                authorized_withdrawer: original_voter,
1004                commission: 0,
1005            },
1006            &Clock::default(),
1007        );
1008
1009        assert!(vote_state.prior_voters.last().is_none());
1010
1011        let new_voter = Pubkey::new_unique();
1012        // Set a new authorized voter
1013        vote_state
1014            .set_new_authorized_voter(&new_voter, 0, epoch_offset, |_| Ok(()))
1015            .unwrap();
1016
1017        assert_eq!(vote_state.prior_voters.idx, 0);
1018        assert_eq!(
1019            vote_state.prior_voters.last(),
1020            Some(&(original_voter, 0, epoch_offset))
1021        );
1022
1023        // Trying to set authorized voter for same epoch again should fail
1024        assert_eq!(
1025            vote_state.set_new_authorized_voter(&new_voter, 0, epoch_offset, |_| Ok(())),
1026            Err(VoteError::TooSoonToReauthorize.into())
1027        );
1028
1029        // Setting the same authorized voter again should succeed
1030        vote_state
1031            .set_new_authorized_voter(&new_voter, 2, 2 + epoch_offset, |_| Ok(()))
1032            .unwrap();
1033
1034        // Set a third and fourth authorized voter
1035        let new_voter2 = Pubkey::new_unique();
1036        vote_state
1037            .set_new_authorized_voter(&new_voter2, 3, 3 + epoch_offset, |_| Ok(()))
1038            .unwrap();
1039        assert_eq!(vote_state.prior_voters.idx, 1);
1040        assert_eq!(
1041            vote_state.prior_voters.last(),
1042            Some(&(new_voter, epoch_offset, 3 + epoch_offset))
1043        );
1044
1045        let new_voter3 = Pubkey::new_unique();
1046        vote_state
1047            .set_new_authorized_voter(&new_voter3, 6, 6 + epoch_offset, |_| Ok(()))
1048            .unwrap();
1049        assert_eq!(vote_state.prior_voters.idx, 2);
1050        assert_eq!(
1051            vote_state.prior_voters.last(),
1052            Some(&(new_voter2, 3 + epoch_offset, 6 + epoch_offset))
1053        );
1054
1055        // Check can set back to original voter
1056        vote_state
1057            .set_new_authorized_voter(&original_voter, 9, 9 + epoch_offset, |_| Ok(()))
1058            .unwrap();
1059
1060        // Run with these voters for a while, check the ranges of authorized
1061        // voters is correct
1062        for i in 9..epoch_offset {
1063            assert_eq!(
1064                vote_state.get_and_update_authorized_voter(i).unwrap(),
1065                original_voter
1066            );
1067        }
1068        for i in epoch_offset..3 + epoch_offset {
1069            assert_eq!(
1070                vote_state.get_and_update_authorized_voter(i).unwrap(),
1071                new_voter
1072            );
1073        }
1074        for i in 3 + epoch_offset..6 + epoch_offset {
1075            assert_eq!(
1076                vote_state.get_and_update_authorized_voter(i).unwrap(),
1077                new_voter2
1078            );
1079        }
1080        for i in 6 + epoch_offset..9 + epoch_offset {
1081            assert_eq!(
1082                vote_state.get_and_update_authorized_voter(i).unwrap(),
1083                new_voter3
1084            );
1085        }
1086        for i in 9 + epoch_offset..=10 + epoch_offset {
1087            assert_eq!(
1088                vote_state.get_and_update_authorized_voter(i).unwrap(),
1089                original_voter
1090            );
1091        }
1092    }
1093
1094    #[test]
1095    fn test_authorized_voter_is_locked_within_epoch() {
1096        let original_voter = Pubkey::new_unique();
1097        let mut vote_state = VoteStateV3::new(
1098            &VoteInit {
1099                node_pubkey: original_voter,
1100                authorized_voter: original_voter,
1101                authorized_withdrawer: original_voter,
1102                commission: 0,
1103            },
1104            &Clock::default(),
1105        );
1106
1107        // Test that it's not possible to set a new authorized
1108        // voter within the same epoch, even if none has been
1109        // explicitly set before
1110        let new_voter = Pubkey::new_unique();
1111        assert_eq!(
1112            vote_state.set_new_authorized_voter(&new_voter, 1, 1, |_| Ok(())),
1113            Err(VoteError::TooSoonToReauthorize.into())
1114        );
1115
1116        assert_eq!(vote_state.get_authorized_voter(1), Some(original_voter));
1117
1118        // Set a new authorized voter for a future epoch
1119        assert_eq!(
1120            vote_state.set_new_authorized_voter(&new_voter, 1, 2, |_| Ok(())),
1121            Ok(())
1122        );
1123
1124        // Test that it's not possible to set a new authorized
1125        // voter within the same epoch, even if none has been
1126        // explicitly set before
1127        assert_eq!(
1128            vote_state.set_new_authorized_voter(&original_voter, 3, 3, |_| Ok(())),
1129            Err(VoteError::TooSoonToReauthorize.into())
1130        );
1131
1132        assert_eq!(vote_state.get_authorized_voter(3), Some(new_voter));
1133    }
1134
1135    #[test]
1136    fn test_vote_state_v3_size_of() {
1137        let vote_state = VoteStateV3::get_max_sized_vote_state();
1138        let vote_state = VoteStateVersions::new_v3(vote_state);
1139        let size = serialized_size(&vote_state).unwrap();
1140        assert_eq!(VoteStateV3::size_of() as u64, size);
1141    }
1142
1143    #[test]
1144    fn test_vote_state_v4_size_of() {
1145        let vote_state = VoteStateV4::get_max_sized_vote_state();
1146        let vote_state = VoteStateVersions::new_v4(vote_state);
1147        let size = serialized_size(&vote_state).unwrap();
1148        assert!(size < VoteStateV4::size_of() as u64); // v4 is smaller than the max size
1149    }
1150
1151    #[test]
1152    fn test_vote_state_max_size() {
1153        let mut max_sized_data = vec![0; VoteStateV3::size_of()];
1154        let vote_state = VoteStateV3::get_max_sized_vote_state();
1155        let (start_leader_schedule_epoch, _) = vote_state.authorized_voters.last().unwrap();
1156        let start_current_epoch =
1157            start_leader_schedule_epoch - MAX_LEADER_SCHEDULE_EPOCH_OFFSET + 1;
1158
1159        let mut vote_state = Some(vote_state);
1160        for i in start_current_epoch..start_current_epoch + 2 * MAX_LEADER_SCHEDULE_EPOCH_OFFSET {
1161            vote_state.as_mut().map(|vote_state| {
1162                vote_state.set_new_authorized_voter(
1163                    &Pubkey::new_unique(),
1164                    i,
1165                    i + MAX_LEADER_SCHEDULE_EPOCH_OFFSET,
1166                    |_| Ok(()),
1167                )
1168            });
1169
1170            let versioned = VoteStateVersions::new_v3(vote_state.take().unwrap());
1171            VoteStateV3::serialize(&versioned, &mut max_sized_data).unwrap();
1172            vote_state = Some(versioned.try_convert_to_v3().unwrap());
1173        }
1174    }
1175
1176    #[test]
1177    fn test_default_vote_state_is_uninitialized() {
1178        // The default `VoteStateV3` is stored to de-initialize a zero-balance vote account,
1179        // so must remain such that `VoteStateVersions::is_uninitialized()` returns true
1180        // when called on a `VoteStateVersions` that stores it
1181        assert!(VoteStateVersions::new_v3(VoteStateV3::default()).is_uninitialized());
1182    }
1183
1184    #[test]
1185    fn test_is_correct_size_and_initialized() {
1186        // Check all zeroes
1187        let mut vote_account_data = vec![0; VoteStateV3::size_of()];
1188        assert!(!VoteStateVersions::is_correct_size_and_initialized(
1189            &vote_account_data
1190        ));
1191
1192        // Check default VoteStateV3
1193        let default_account_state = VoteStateVersions::new_v3(VoteStateV3::default());
1194        VoteStateV3::serialize(&default_account_state, &mut vote_account_data).unwrap();
1195        assert!(!VoteStateVersions::is_correct_size_and_initialized(
1196            &vote_account_data
1197        ));
1198
1199        // Check non-zero data shorter than offset index used
1200        let short_data = vec![1; DEFAULT_PRIOR_VOTERS_OFFSET];
1201        assert!(!VoteStateVersions::is_correct_size_and_initialized(
1202            &short_data
1203        ));
1204
1205        // Check non-zero large account
1206        let mut large_vote_data = vec![1; 2 * VoteStateV3::size_of()];
1207        let default_account_state = VoteStateVersions::new_v3(VoteStateV3::default());
1208        VoteStateV3::serialize(&default_account_state, &mut large_vote_data).unwrap();
1209        assert!(!VoteStateVersions::is_correct_size_and_initialized(
1210            &vote_account_data
1211        ));
1212
1213        // Check populated VoteStateV3
1214        let vote_state = VoteStateV3::new(
1215            &VoteInit {
1216                node_pubkey: Pubkey::new_unique(),
1217                authorized_voter: Pubkey::new_unique(),
1218                authorized_withdrawer: Pubkey::new_unique(),
1219                commission: 0,
1220            },
1221            &Clock::default(),
1222        );
1223        let account_state = VoteStateVersions::new_v3(vote_state.clone());
1224        VoteStateV3::serialize(&account_state, &mut vote_account_data).unwrap();
1225        assert!(VoteStateVersions::is_correct_size_and_initialized(
1226            &vote_account_data
1227        ));
1228
1229        // Check old VoteStateV3 that hasn't been upgraded to newest version yet
1230        let old_vote_state = VoteState1_14_11::from(vote_state);
1231        let account_state = VoteStateVersions::V1_14_11(Box::new(old_vote_state));
1232        let mut vote_account_data = vec![0; VoteState1_14_11::size_of()];
1233        VoteStateV3::serialize(&account_state, &mut vote_account_data).unwrap();
1234        assert!(VoteStateVersions::is_correct_size_and_initialized(
1235            &vote_account_data
1236        ));
1237    }
1238
1239    #[test]
1240    fn test_minimum_balance() {
1241        let rent = atlas_rent::Rent::default();
1242        let minimum_balance = rent.minimum_balance(VoteStateV3::size_of());
1243        // golden, may need updating when vote_state grows
1244        assert!(minimum_balance as f64 / 10f64.powf(9.0) < 0.04)
1245    }
1246
1247    #[test]
1248    fn test_serde_compact_vote_state_update() {
1249        let mut rng = rand::thread_rng();
1250        for _ in 0..5000 {
1251            run_serde_compact_vote_state_update(&mut rng);
1252        }
1253    }
1254
1255    fn run_serde_compact_vote_state_update<R: Rng>(rng: &mut R) {
1256        let lockouts: VecDeque<_> = std::iter::repeat_with(|| {
1257            let slot = 149_303_885_u64.saturating_add(rng.gen_range(0..10_000));
1258            let confirmation_count = rng.gen_range(0..33);
1259            Lockout::new_with_confirmation_count(slot, confirmation_count)
1260        })
1261        .take(32)
1262        .sorted_by_key(|lockout| lockout.slot())
1263        .collect();
1264        let root = rng.gen_ratio(1, 2).then(|| {
1265            lockouts[0]
1266                .slot()
1267                .checked_sub(rng.gen_range(0..1_000))
1268                .expect("All slots should be greater than 1_000")
1269        });
1270        let timestamp = rng.gen_ratio(1, 2).then(|| rng.gen());
1271        let hash = Hash::from(rng.gen::<[u8; 32]>());
1272        let vote_state_update = VoteStateUpdate {
1273            lockouts,
1274            root,
1275            hash,
1276            timestamp,
1277        };
1278        #[derive(Debug, Eq, PartialEq, Deserialize, Serialize)]
1279        enum VoteInstruction {
1280            #[serde(with = "serde_compact_vote_state_update")]
1281            UpdateVoteState(VoteStateUpdate),
1282            UpdateVoteStateSwitch(
1283                #[serde(with = "serde_compact_vote_state_update")] VoteStateUpdate,
1284                Hash,
1285            ),
1286        }
1287        let vote = VoteInstruction::UpdateVoteState(vote_state_update.clone());
1288        let bytes = bincode::serialize(&vote).unwrap();
1289        assert_eq!(vote, bincode::deserialize(&bytes).unwrap());
1290        let hash = Hash::from(rng.gen::<[u8; 32]>());
1291        let vote = VoteInstruction::UpdateVoteStateSwitch(vote_state_update, hash);
1292        let bytes = bincode::serialize(&vote).unwrap();
1293        assert_eq!(vote, bincode::deserialize(&bytes).unwrap());
1294    }
1295
1296    #[test]
1297    fn test_circbuf_oob() {
1298        // Craft an invalid CircBuf with out-of-bounds index
1299        let data: &[u8] = &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00];
1300        let circ_buf: CircBuf<()> = bincode::deserialize(data).unwrap();
1301        assert_eq!(circ_buf.last(), None);
1302    }
1303
1304    #[test]
1305    fn test_vote_state_v4_bls_pubkey_compressed() {
1306        let vote_pubkey = Pubkey::new_unique();
1307
1308        let run_test = |start, expected| {
1309            let versioned = VoteStateVersions::new_v4(start);
1310            let serialized = bincode::serialize(&versioned).unwrap();
1311            let deserialized = VoteStateV4::deserialize(&serialized, &vote_pubkey).unwrap();
1312            assert_eq!(deserialized.bls_pubkey_compressed, expected);
1313        };
1314
1315        // First try `None`.
1316        let vote_state_none = VoteStateV4::default();
1317        assert_eq!(vote_state_none.bls_pubkey_compressed, None);
1318        run_test(vote_state_none, None);
1319
1320        // Now try `Some`.
1321        let test_bls_key = [42u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE];
1322        let vote_state_some = VoteStateV4 {
1323            bls_pubkey_compressed: Some(test_bls_key),
1324            ..VoteStateV4::default()
1325        };
1326        assert_eq!(vote_state_some.bls_pubkey_compressed, Some(test_bls_key));
1327        run_test(vote_state_some, Some(test_bls_key));
1328    }
1329
1330    #[test]
1331    fn test_vote_state_version_conversion_bls_pubkey() {
1332        let vote_pubkey = Pubkey::new_unique();
1333
1334        // All versions before v4 should result in `None` for BLS pubkey.
1335        let v0_23_5_state = VoteState0_23_5::default();
1336        let v0_23_5_versioned = VoteStateVersions::V0_23_5(Box::new(v0_23_5_state));
1337
1338        let v1_14_11_state = VoteState1_14_11::default();
1339        let v1_14_11_versioned = VoteStateVersions::V1_14_11(Box::new(v1_14_11_state));
1340
1341        let v3_state = VoteStateV3::default();
1342        let v3_versioned = VoteStateVersions::V3(Box::new(v3_state));
1343
1344        for versioned in [v0_23_5_versioned, v1_14_11_versioned, v3_versioned] {
1345            let converted = versioned.try_convert_to_v4(&vote_pubkey).unwrap();
1346            assert_eq!(converted.bls_pubkey_compressed, None);
1347        }
1348
1349        // v4 to v4 conversion should preserve the BLS pubkey.
1350        let test_bls_key = [128u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE];
1351        let v4_state = VoteStateV4 {
1352            bls_pubkey_compressed: Some(test_bls_key),
1353            ..VoteStateV4::default()
1354        };
1355        let v4_versioned = VoteStateVersions::V4(Box::new(v4_state));
1356        let converted = v4_versioned.try_convert_to_v4(&vote_pubkey).unwrap();
1357        assert_eq!(converted.bls_pubkey_compressed, Some(test_bls_key));
1358    }
1359}