1#[cfg(not(target_os = "solana"))]
4use bincode::deserialize;
5#[cfg(test)]
6use {
7 crate::epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET,
8 arbitrary::{Arbitrary, Unstructured},
9};
10use {
11 crate::{
12 hash::Hash,
13 instruction::InstructionError,
14 pubkey::Pubkey,
15 rent::Rent,
16 serialize_utils::cursor::read_u32,
17 sysvar::clock::Clock,
18 vote::{authorized_voters::AuthorizedVoters, error::VoteError},
19 },
20 bincode::{serialize_into, ErrorKind},
21 serde_derive::{Deserialize, Serialize},
22 solana_clock::{Epoch, Slot, UnixTimestamp},
23 std::{
24 collections::VecDeque,
25 fmt::Debug,
26 io::Cursor,
27 mem::{self, MaybeUninit},
28 },
29};
30
31mod vote_state_0_23_5;
32pub mod vote_state_1_14_11;
33pub use vote_state_1_14_11::*;
34mod vote_state_deserialize;
35use vote_state_deserialize::deserialize_vote_state_into;
36pub mod vote_state_versions;
37pub use vote_state_versions::*;
38
39pub const MAX_LOCKOUT_HISTORY: usize = 31;
41pub const INITIAL_LOCKOUT: usize = 2;
42
43pub const MAX_EPOCH_CREDITS_HISTORY: usize = 64;
45
46const DEFAULT_PRIOR_VOTERS_OFFSET: usize = 114;
48
49pub const VOTE_CREDITS_GRACE_SLOTS: u8 = 2;
51
52pub const VOTE_CREDITS_MAXIMUM_PER_SLOT: u8 = 16;
54
55#[cfg_attr(
56 feature = "frozen-abi",
57 frozen_abi(digest = "GvUzgtcxhKVVxPAjSntXGPqjLZK5ovgZzCiUP1tDpB9q"),
58 derive(AbiExample)
59)]
60#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone)]
61pub struct Vote {
62 pub slots: Vec<Slot>,
64 pub hash: Hash,
66 pub timestamp: Option<UnixTimestamp>,
68}
69
70impl Vote {
71 pub fn new(slots: Vec<Slot>, hash: Hash) -> Self {
72 Self {
73 slots,
74 hash,
75 timestamp: None,
76 }
77 }
78
79 pub fn last_voted_slot(&self) -> Option<Slot> {
80 self.slots.last().copied()
81 }
82}
83
84#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
85#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Copy, Clone)]
86#[cfg_attr(test, derive(Arbitrary))]
87pub struct Lockout {
88 slot: Slot,
89 confirmation_count: u32,
90}
91
92impl Lockout {
93 pub fn new(slot: Slot) -> Self {
94 Self::new_with_confirmation_count(slot, 1)
95 }
96
97 pub fn new_with_confirmation_count(slot: Slot, confirmation_count: u32) -> Self {
98 Self {
99 slot,
100 confirmation_count,
101 }
102 }
103
104 pub fn lockout(&self) -> u64 {
106 (INITIAL_LOCKOUT as u64).pow(self.confirmation_count())
107 }
108
109 pub fn last_locked_out_slot(&self) -> Slot {
113 self.slot.saturating_add(self.lockout())
114 }
115
116 pub fn is_locked_out_at_slot(&self, slot: Slot) -> bool {
117 self.last_locked_out_slot() >= slot
118 }
119
120 pub fn slot(&self) -> Slot {
121 self.slot
122 }
123
124 pub fn confirmation_count(&self) -> u32 {
125 self.confirmation_count
126 }
127
128 pub fn increase_confirmation_count(&mut self, by: u32) {
129 self.confirmation_count = self.confirmation_count.saturating_add(by)
130 }
131}
132
133#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
134#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Copy, Clone)]
135#[cfg_attr(test, derive(Arbitrary))]
136pub struct LandedVote {
137 pub latency: u8,
141 pub lockout: Lockout,
142}
143
144impl LandedVote {
145 pub fn slot(&self) -> Slot {
146 self.lockout.slot
147 }
148
149 pub fn confirmation_count(&self) -> u32 {
150 self.lockout.confirmation_count
151 }
152}
153
154impl From<LandedVote> for Lockout {
155 fn from(landed_vote: LandedVote) -> Self {
156 landed_vote.lockout
157 }
158}
159
160impl From<Lockout> for LandedVote {
161 fn from(lockout: Lockout) -> Self {
162 Self {
163 latency: 0,
164 lockout,
165 }
166 }
167}
168
169#[cfg_attr(
170 feature = "frozen-abi",
171 frozen_abi(digest = "DRKTb72wifCUcCTSJs6PqWrQQK5Pfis4SCLEvXqWnDaL"),
172 derive(AbiExample)
173)]
174#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone)]
175pub struct VoteStateUpdate {
176 pub lockouts: VecDeque<Lockout>,
178 pub root: Option<Slot>,
180 pub hash: Hash,
182 pub timestamp: Option<UnixTimestamp>,
184}
185
186impl From<Vec<(Slot, u32)>> for VoteStateUpdate {
187 fn from(recent_slots: Vec<(Slot, u32)>) -> Self {
188 let lockouts: VecDeque<Lockout> = recent_slots
189 .into_iter()
190 .map(|(slot, confirmation_count)| {
191 Lockout::new_with_confirmation_count(slot, confirmation_count)
192 })
193 .collect();
194 Self {
195 lockouts,
196 root: None,
197 hash: Hash::default(),
198 timestamp: None,
199 }
200 }
201}
202
203impl VoteStateUpdate {
204 pub fn new(lockouts: VecDeque<Lockout>, root: Option<Slot>, hash: Hash) -> Self {
205 Self {
206 lockouts,
207 root,
208 hash,
209 timestamp: None,
210 }
211 }
212
213 pub fn slots(&self) -> Vec<Slot> {
214 self.lockouts.iter().map(|lockout| lockout.slot()).collect()
215 }
216
217 pub fn last_voted_slot(&self) -> Option<Slot> {
218 self.lockouts.back().map(|l| l.slot())
219 }
220}
221
222#[cfg_attr(
223 feature = "frozen-abi",
224 frozen_abi(digest = "5PFw9pyF1UG1DXVsw7gpjHegNyRycAAxWf2GA9wUXPs5"),
225 derive(AbiExample)
226)]
227#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone)]
228pub struct TowerSync {
229 pub lockouts: VecDeque<Lockout>,
231 pub root: Option<Slot>,
233 pub hash: Hash,
235 pub timestamp: Option<UnixTimestamp>,
237 pub block_id: Hash,
241}
242
243impl From<Vec<(Slot, u32)>> for TowerSync {
244 fn from(recent_slots: Vec<(Slot, u32)>) -> Self {
245 let lockouts: VecDeque<Lockout> = recent_slots
246 .into_iter()
247 .map(|(slot, confirmation_count)| {
248 Lockout::new_with_confirmation_count(slot, confirmation_count)
249 })
250 .collect();
251 Self {
252 lockouts,
253 root: None,
254 hash: Hash::default(),
255 timestamp: None,
256 block_id: Hash::default(),
257 }
258 }
259}
260
261impl TowerSync {
262 pub fn new(
263 lockouts: VecDeque<Lockout>,
264 root: Option<Slot>,
265 hash: Hash,
266 block_id: Hash,
267 ) -> Self {
268 Self {
269 lockouts,
270 root,
271 hash,
272 timestamp: None,
273 block_id,
274 }
275 }
276
277 pub fn new_from_slot(slot: Slot, hash: Hash) -> Self {
281 let lowest_slot = slot
282 .saturating_add(1)
283 .saturating_sub(MAX_LOCKOUT_HISTORY as u64);
284 let slots: Vec<_> = (lowest_slot..slot.saturating_add(1)).collect();
285 Self::new_from_slots(
286 slots,
287 hash,
288 (lowest_slot > 0).then(|| lowest_slot.saturating_sub(1)),
289 )
290 }
291
292 pub fn new_from_slots(slots: Vec<Slot>, hash: Hash, root: Option<Slot>) -> Self {
294 let lockouts: VecDeque<Lockout> = slots
295 .into_iter()
296 .rev()
297 .enumerate()
298 .map(|(cc, s)| Lockout::new_with_confirmation_count(s, cc.saturating_add(1) as u32))
299 .rev()
300 .collect();
301 Self {
302 lockouts,
303 hash,
304 root,
305 timestamp: None,
306 block_id: Hash::default(),
307 }
308 }
309
310 pub fn slots(&self) -> Vec<Slot> {
311 self.lockouts.iter().map(|lockout| lockout.slot()).collect()
312 }
313
314 pub fn last_voted_slot(&self) -> Option<Slot> {
315 self.lockouts.back().map(|l| l.slot())
316 }
317}
318
319#[derive(Default, Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
320pub struct VoteInit {
321 pub node_pubkey: Pubkey,
322 pub authorized_voter: Pubkey,
323 pub authorized_withdrawer: Pubkey,
324 pub commission: u8,
325}
326
327#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
328pub enum VoteAuthorize {
329 Voter,
330 Withdrawer,
331}
332
333#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
334pub struct VoteAuthorizeWithSeedArgs {
335 pub authorization_type: VoteAuthorize,
336 pub current_authority_derived_key_owner: Pubkey,
337 pub current_authority_derived_key_seed: String,
338 pub new_authority: Pubkey,
339}
340
341#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
342pub struct VoteAuthorizeCheckedWithSeedArgs {
343 pub authorization_type: VoteAuthorize,
344 pub current_authority_derived_key_owner: Pubkey,
345 pub current_authority_derived_key_seed: String,
346}
347
348#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
349#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone)]
350#[cfg_attr(test, derive(Arbitrary))]
351pub struct BlockTimestamp {
352 pub slot: Slot,
353 pub timestamp: UnixTimestamp,
354}
355
356const MAX_ITEMS: usize = 32;
358
359#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
360#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
361#[cfg_attr(test, derive(Arbitrary))]
362pub struct CircBuf<I> {
363 buf: [I; MAX_ITEMS],
364 idx: usize,
366 is_empty: bool,
367}
368
369impl<I: Default + Copy> Default for CircBuf<I> {
370 fn default() -> Self {
371 Self {
372 buf: [I::default(); MAX_ITEMS],
373 idx: MAX_ITEMS
374 .checked_sub(1)
375 .expect("`MAX_ITEMS` should be positive"),
376 is_empty: true,
377 }
378 }
379}
380
381impl<I> CircBuf<I> {
382 pub fn append(&mut self, item: I) {
383 self.idx = self
385 .idx
386 .checked_add(1)
387 .and_then(|idx| idx.checked_rem(MAX_ITEMS))
388 .expect("`self.idx` should be < `MAX_ITEMS` which should be non-zero");
389
390 self.buf[self.idx] = item;
391 self.is_empty = false;
392 }
393
394 pub fn buf(&self) -> &[I; MAX_ITEMS] {
395 &self.buf
396 }
397
398 pub fn last(&self) -> Option<&I> {
399 if !self.is_empty {
400 self.buf.get(self.idx)
401 } else {
402 None
403 }
404 }
405}
406
407#[cfg_attr(
408 feature = "frozen-abi",
409 frozen_abi(digest = "87ULMjjHnMsPmCTEyzj4KPn2u5gdX1rmgtSdycpbSaLs"),
410 derive(AbiExample)
411)]
412#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone)]
413#[cfg_attr(test, derive(Arbitrary))]
414pub struct VoteState {
415 pub node_pubkey: Pubkey,
417
418 pub authorized_withdrawer: Pubkey,
420 pub commission: u8,
423
424 pub votes: VecDeque<LandedVote>,
425
426 pub root_slot: Option<Slot>,
429
430 authorized_voters: AuthorizedVoters,
432
433 prior_voters: CircBuf<(Pubkey, Epoch, Epoch)>,
437
438 pub epoch_credits: Vec<(Epoch, u64, u64)>,
441
442 pub last_timestamp: BlockTimestamp,
444}
445
446impl VoteState {
447 pub fn new(vote_init: &VoteInit, clock: &Clock) -> Self {
448 Self {
449 node_pubkey: vote_init.node_pubkey,
450 authorized_voters: AuthorizedVoters::new(clock.epoch, vote_init.authorized_voter),
451 authorized_withdrawer: vote_init.authorized_withdrawer,
452 commission: vote_init.commission,
453 ..VoteState::default()
454 }
455 }
456
457 pub fn new_rand_for_tests(node_pubkey: Pubkey, root_slot: Slot) -> Self {
458 let votes = (1..32)
459 .map(|x| LandedVote {
460 latency: 0,
461 lockout: Lockout::new_with_confirmation_count(
462 u64::from(x).saturating_add(root_slot),
463 32_u32.saturating_sub(x),
464 ),
465 })
466 .collect();
467 Self {
468 node_pubkey,
469 root_slot: Some(root_slot),
470 votes,
471 ..VoteState::default()
472 }
473 }
474
475 pub fn get_authorized_voter(&self, epoch: Epoch) -> Option<Pubkey> {
476 self.authorized_voters.get_authorized_voter(epoch)
477 }
478
479 pub fn authorized_voters(&self) -> &AuthorizedVoters {
480 &self.authorized_voters
481 }
482
483 pub fn prior_voters(&mut self) -> &CircBuf<(Pubkey, Epoch, Epoch)> {
484 &self.prior_voters
485 }
486
487 pub fn get_rent_exempt_reserve(rent: &Rent) -> u64 {
488 rent.minimum_balance(VoteState::size_of())
489 }
490
491 pub const fn size_of() -> usize {
494 3762 }
496
497 pub fn deserialize(input: &[u8]) -> Result<Self, InstructionError> {
503 #[cfg(not(target_os = "solana"))]
504 {
505 deserialize::<VoteStateVersions>(input)
506 .map(|versioned| versioned.convert_to_current())
507 .map_err(|_| InstructionError::InvalidAccountData)
508 }
509 #[cfg(target_os = "solana")]
510 {
511 let mut vote_state = Self::default();
512 Self::deserialize_into(input, &mut vote_state)?;
513 Ok(vote_state)
514 }
515 }
516
517 pub fn deserialize_into(
525 input: &[u8],
526 vote_state: &mut VoteState,
527 ) -> Result<(), InstructionError> {
528 let vote_state = vote_state as *mut VoteState;
533
534 unsafe {
538 std::ptr::drop_in_place(vote_state);
539 }
540
541 struct DropGuard {
543 vote_state: *mut VoteState,
544 }
545
546 impl Drop for DropGuard {
547 fn drop(&mut self) {
548 unsafe {
558 self.vote_state.write(VoteState::default());
559 }
560 }
561 }
562
563 let guard = DropGuard { vote_state };
564
565 let res = VoteState::deserialize_into_ptr(input, vote_state);
566 if res.is_ok() {
567 mem::forget(guard);
568 }
569
570 res
571 }
572
573 pub fn deserialize_into_uninit(
583 input: &[u8],
584 vote_state: &mut MaybeUninit<VoteState>,
585 ) -> Result<(), InstructionError> {
586 VoteState::deserialize_into_ptr(input, vote_state.as_mut_ptr())
587 }
588
589 fn deserialize_into_ptr(
590 input: &[u8],
591 vote_state: *mut VoteState,
592 ) -> Result<(), InstructionError> {
593 let mut cursor = Cursor::new(input);
594
595 let variant = read_u32(&mut cursor)?;
596 match variant {
597 0 => {
600 #[cfg(not(target_os = "solana"))]
601 {
602 unsafe {
608 vote_state.write(
609 bincode::deserialize::<VoteStateVersions>(input)
610 .map(|versioned| versioned.convert_to_current())
611 .map_err(|_| InstructionError::InvalidAccountData)?,
612 );
613 }
614 Ok(())
615 }
616 #[cfg(target_os = "solana")]
617 Err(InstructionError::InvalidAccountData)
618 }
619 1 => deserialize_vote_state_into(&mut cursor, vote_state, false),
621 2 => deserialize_vote_state_into(&mut cursor, vote_state, true),
623 _ => Err(InstructionError::InvalidAccountData),
624 }?;
625
626 Ok(())
627 }
628
629 pub fn serialize(
630 versioned: &VoteStateVersions,
631 output: &mut [u8],
632 ) -> Result<(), InstructionError> {
633 serialize_into(output, versioned).map_err(|err| match *err {
634 ErrorKind::SizeLimit => InstructionError::AccountDataTooSmall,
635 _ => InstructionError::GenericError,
636 })
637 }
638
639 pub fn commission_split(&self, on: u64) -> (u64, u64, bool) {
644 match self.commission.min(100) {
645 0 => (0, on, false),
646 100 => (on, 0, false),
647 split => {
648 let on = u128::from(on);
649 let mine = on
655 .checked_mul(u128::from(split))
656 .expect("multiplication of a u64 and u8 should not overflow")
657 / 100u128;
658 let theirs = on
659 .checked_mul(u128::from(
660 100u8
661 .checked_sub(split)
662 .expect("commission cannot be greater than 100"),
663 ))
664 .expect("multiplication of a u64 and u8 should not overflow")
665 / 100u128;
666
667 (mine as u64, theirs as u64, true)
668 }
669 }
670 }
671
672 pub fn contains_slot(&self, candidate_slot: Slot) -> bool {
674 self.votes
675 .binary_search_by(|vote| vote.slot().cmp(&candidate_slot))
676 .is_ok()
677 }
678
679 #[cfg(test)]
680 fn get_max_sized_vote_state() -> VoteState {
681 let mut authorized_voters = AuthorizedVoters::default();
682 for i in 0..=MAX_LEADER_SCHEDULE_EPOCH_OFFSET {
683 authorized_voters.insert(i, Pubkey::new_unique());
684 }
685
686 VoteState {
687 votes: VecDeque::from(vec![LandedVote::default(); MAX_LOCKOUT_HISTORY]),
688 root_slot: Some(u64::MAX),
689 epoch_credits: vec![(0, 0, 0); MAX_EPOCH_CREDITS_HISTORY],
690 authorized_voters,
691 ..Self::default()
692 }
693 }
694
695 pub fn process_next_vote_slot(
696 &mut self,
697 next_vote_slot: Slot,
698 epoch: Epoch,
699 current_slot: Slot,
700 timely_vote_credits: bool,
701 ) {
702 if self
704 .last_voted_slot()
705 .map_or(false, |last_voted_slot| next_vote_slot <= last_voted_slot)
706 {
707 return;
708 }
709
710 self.pop_expired_votes(next_vote_slot);
711
712 let landed_vote = LandedVote {
713 latency: if timely_vote_credits {
714 Self::compute_vote_latency(next_vote_slot, current_slot)
715 } else {
716 0
717 },
718 lockout: Lockout::new(next_vote_slot),
719 };
720
721 if self.votes.len() == MAX_LOCKOUT_HISTORY {
723 let credits = self.credits_for_vote_at_index(0, timely_vote_credits);
724 let landed_vote = self.votes.pop_front().unwrap();
725 self.root_slot = Some(landed_vote.slot());
726
727 self.increment_credits(epoch, credits);
728 }
729 self.votes.push_back(landed_vote);
730 self.double_lockouts();
731 }
732
733 pub fn increment_credits(&mut self, epoch: Epoch, credits: u64) {
735 if self.epoch_credits.is_empty() {
739 self.epoch_credits.push((epoch, 0, 0));
740 } else if epoch != self.epoch_credits.last().unwrap().0 {
741 let (_, credits, prev_credits) = *self.epoch_credits.last().unwrap();
742
743 if credits != prev_credits {
744 self.epoch_credits.push((epoch, credits, credits));
747 } else {
748 self.epoch_credits.last_mut().unwrap().0 = epoch;
750 }
751
752 if self.epoch_credits.len() > MAX_EPOCH_CREDITS_HISTORY {
754 self.epoch_credits.remove(0);
755 }
756 }
757
758 self.epoch_credits.last_mut().unwrap().1 =
759 self.epoch_credits.last().unwrap().1.saturating_add(credits);
760 }
761
762 pub fn compute_vote_latency(voted_for_slot: Slot, current_slot: Slot) -> u8 {
764 std::cmp::min(current_slot.saturating_sub(voted_for_slot), u8::MAX as u64) as u8
765 }
766
767 pub fn credits_for_vote_at_index(&self, index: usize, timely_vote_credits: bool) -> u64 {
769 let latency = self
770 .votes
771 .get(index)
772 .map_or(0, |landed_vote| landed_vote.latency);
773
774 if latency == 0 || !timely_vote_credits {
777 1
778 } else {
779 match latency.checked_sub(VOTE_CREDITS_GRACE_SLOTS) {
780 None | Some(0) => {
781 VOTE_CREDITS_MAXIMUM_PER_SLOT as u64
783 }
784
785 Some(diff) => {
786 match VOTE_CREDITS_MAXIMUM_PER_SLOT.checked_sub(diff) {
789 None | Some(0) => 1,
791
792 Some(credits) => credits as u64,
793 }
794 }
795 }
796 }
797 }
798
799 pub fn nth_recent_lockout(&self, position: usize) -> Option<&Lockout> {
800 if position < self.votes.len() {
801 let pos = self
802 .votes
803 .len()
804 .checked_sub(position)
805 .and_then(|pos| pos.checked_sub(1))?;
806 self.votes.get(pos).map(|vote| &vote.lockout)
807 } else {
808 None
809 }
810 }
811
812 pub fn last_lockout(&self) -> Option<&Lockout> {
813 self.votes.back().map(|vote| &vote.lockout)
814 }
815
816 pub fn last_voted_slot(&self) -> Option<Slot> {
817 self.last_lockout().map(|v| v.slot())
818 }
819
820 pub fn tower(&self) -> Vec<Slot> {
823 self.votes.iter().map(|v| v.slot()).collect()
824 }
825
826 pub fn current_epoch(&self) -> Epoch {
827 if self.epoch_credits.is_empty() {
828 0
829 } else {
830 self.epoch_credits.last().unwrap().0
831 }
832 }
833
834 pub fn credits(&self) -> u64 {
837 if self.epoch_credits.is_empty() {
838 0
839 } else {
840 self.epoch_credits.last().unwrap().1
841 }
842 }
843
844 pub fn epoch_credits(&self) -> &Vec<(Epoch, u64, u64)> {
850 &self.epoch_credits
851 }
852
853 pub fn set_new_authorized_voter<F>(
854 &mut self,
855 authorized_pubkey: &Pubkey,
856 current_epoch: Epoch,
857 target_epoch: Epoch,
858 verify: F,
859 ) -> Result<(), InstructionError>
860 where
861 F: Fn(Pubkey) -> Result<(), InstructionError>,
862 {
863 let epoch_authorized_voter = self.get_and_update_authorized_voter(current_epoch)?;
864 verify(epoch_authorized_voter)?;
865
866 if self.authorized_voters.contains(target_epoch) {
872 return Err(VoteError::TooSoonToReauthorize.into());
873 }
874
875 let (latest_epoch, latest_authorized_pubkey) = self
877 .authorized_voters
878 .last()
879 .ok_or(InstructionError::InvalidAccountData)?;
880
881 if latest_authorized_pubkey != authorized_pubkey {
885 let epoch_of_last_authorized_switch =
887 self.prior_voters.last().map(|range| range.2).unwrap_or(0);
888
889 if target_epoch <= *latest_epoch {
896 return Err(InstructionError::InvalidAccountData);
897 }
898
899 self.prior_voters.append((
901 *latest_authorized_pubkey,
902 epoch_of_last_authorized_switch,
903 target_epoch,
904 ));
905 }
906
907 self.authorized_voters
908 .insert(target_epoch, *authorized_pubkey);
909
910 Ok(())
911 }
912
913 pub fn get_and_update_authorized_voter(
914 &mut self,
915 current_epoch: Epoch,
916 ) -> Result<Pubkey, InstructionError> {
917 let pubkey = self
918 .authorized_voters
919 .get_and_cache_authorized_voter_for_epoch(current_epoch)
920 .ok_or(InstructionError::InvalidAccountData)?;
921 self.authorized_voters
922 .purge_authorized_voters(current_epoch);
923 Ok(pubkey)
924 }
925
926 pub fn pop_expired_votes(&mut self, next_vote_slot: Slot) {
931 while let Some(vote) = self.last_lockout() {
932 if !vote.is_locked_out_at_slot(next_vote_slot) {
933 self.votes.pop_back();
934 } else {
935 break;
936 }
937 }
938 }
939
940 pub fn double_lockouts(&mut self) {
941 let stack_depth = self.votes.len();
942 for (i, v) in self.votes.iter_mut().enumerate() {
943 if stack_depth >
946 i.checked_add(v.confirmation_count() as usize)
947 .expect("`confirmation_count` and tower_size should be bounded by `MAX_LOCKOUT_HISTORY`")
948 {
949 v.lockout.increase_confirmation_count(1);
950 }
951 }
952 }
953
954 pub fn process_timestamp(
955 &mut self,
956 slot: Slot,
957 timestamp: UnixTimestamp,
958 ) -> Result<(), VoteError> {
959 if (slot < self.last_timestamp.slot || timestamp < self.last_timestamp.timestamp)
960 || (slot == self.last_timestamp.slot
961 && BlockTimestamp { slot, timestamp } != self.last_timestamp
962 && self.last_timestamp.slot != 0)
963 {
964 return Err(VoteError::TimestampTooOld);
965 }
966 self.last_timestamp = BlockTimestamp { slot, timestamp };
967 Ok(())
968 }
969
970 pub fn is_correct_size_and_initialized(data: &[u8]) -> bool {
971 const VERSION_OFFSET: usize = 4;
972 const DEFAULT_PRIOR_VOTERS_END: usize = VERSION_OFFSET + DEFAULT_PRIOR_VOTERS_OFFSET;
973 data.len() == VoteState::size_of()
974 && data[VERSION_OFFSET..DEFAULT_PRIOR_VOTERS_END] != [0; DEFAULT_PRIOR_VOTERS_OFFSET]
975 }
976}
977
978pub mod serde_compact_vote_state_update {
979 use {
980 super::*,
981 crate::vote::state::Lockout,
982 serde::{Deserialize, Deserializer, Serialize, Serializer},
983 solana_serde_varint as serde_varint, solana_short_vec as short_vec,
984 };
985
986 #[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
987 #[derive(serde_derive::Deserialize, serde_derive::Serialize)]
988 struct LockoutOffset {
989 #[serde(with = "serde_varint")]
990 offset: Slot,
991 confirmation_count: u8,
992 }
993
994 #[derive(serde_derive::Deserialize, serde_derive::Serialize)]
995 struct CompactVoteStateUpdate {
996 root: Slot,
997 #[serde(with = "short_vec")]
998 lockout_offsets: Vec<LockoutOffset>,
999 hash: Hash,
1000 timestamp: Option<UnixTimestamp>,
1001 }
1002
1003 pub fn serialize<S>(
1004 vote_state_update: &VoteStateUpdate,
1005 serializer: S,
1006 ) -> Result<S::Ok, S::Error>
1007 where
1008 S: Serializer,
1009 {
1010 let lockout_offsets = vote_state_update.lockouts.iter().scan(
1011 vote_state_update.root.unwrap_or_default(),
1012 |slot, lockout| {
1013 let Some(offset) = lockout.slot().checked_sub(*slot) else {
1014 return Some(Err(serde::ser::Error::custom("Invalid vote lockout")));
1015 };
1016 let Ok(confirmation_count) = u8::try_from(lockout.confirmation_count()) else {
1017 return Some(Err(serde::ser::Error::custom("Invalid confirmation count")));
1018 };
1019 let lockout_offset = LockoutOffset {
1020 offset,
1021 confirmation_count,
1022 };
1023 *slot = lockout.slot();
1024 Some(Ok(lockout_offset))
1025 },
1026 );
1027 let compact_vote_state_update = CompactVoteStateUpdate {
1028 root: vote_state_update.root.unwrap_or(Slot::MAX),
1029 lockout_offsets: lockout_offsets.collect::<Result<_, _>>()?,
1030 hash: vote_state_update.hash,
1031 timestamp: vote_state_update.timestamp,
1032 };
1033 compact_vote_state_update.serialize(serializer)
1034 }
1035
1036 pub fn deserialize<'de, D>(deserializer: D) -> Result<VoteStateUpdate, D::Error>
1037 where
1038 D: Deserializer<'de>,
1039 {
1040 let CompactVoteStateUpdate {
1041 root,
1042 lockout_offsets,
1043 hash,
1044 timestamp,
1045 } = CompactVoteStateUpdate::deserialize(deserializer)?;
1046 let root = (root != Slot::MAX).then_some(root);
1047 let lockouts =
1048 lockout_offsets
1049 .iter()
1050 .scan(root.unwrap_or_default(), |slot, lockout_offset| {
1051 *slot = match slot.checked_add(lockout_offset.offset) {
1052 None => {
1053 return Some(Err(serde::de::Error::custom("Invalid lockout offset")))
1054 }
1055 Some(slot) => slot,
1056 };
1057 let lockout = Lockout::new_with_confirmation_count(
1058 *slot,
1059 u32::from(lockout_offset.confirmation_count),
1060 );
1061 Some(Ok(lockout))
1062 });
1063 Ok(VoteStateUpdate {
1064 root,
1065 lockouts: lockouts.collect::<Result<_, _>>()?,
1066 hash,
1067 timestamp,
1068 })
1069 }
1070}
1071
1072pub mod serde_tower_sync {
1073 use {
1074 super::*,
1075 crate::vote::state::Lockout,
1076 serde::{Deserialize, Deserializer, Serialize, Serializer},
1077 solana_serde_varint as serde_varint, solana_short_vec as short_vec,
1078 };
1079
1080 #[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
1081 #[derive(serde_derive::Deserialize, serde_derive::Serialize)]
1082 struct LockoutOffset {
1083 #[serde(with = "serde_varint")]
1084 offset: Slot,
1085 confirmation_count: u8,
1086 }
1087
1088 #[derive(serde_derive::Deserialize, serde_derive::Serialize)]
1089 struct CompactTowerSync {
1090 root: Slot,
1091 #[serde(with = "short_vec")]
1092 lockout_offsets: Vec<LockoutOffset>,
1093 hash: Hash,
1094 timestamp: Option<UnixTimestamp>,
1095 block_id: Hash,
1096 }
1097
1098 pub fn serialize<S>(tower_sync: &TowerSync, serializer: S) -> Result<S::Ok, S::Error>
1099 where
1100 S: Serializer,
1101 {
1102 let lockout_offsets = tower_sync.lockouts.iter().scan(
1103 tower_sync.root.unwrap_or_default(),
1104 |slot, lockout| {
1105 let Some(offset) = lockout.slot().checked_sub(*slot) else {
1106 return Some(Err(serde::ser::Error::custom("Invalid vote lockout")));
1107 };
1108 let Ok(confirmation_count) = u8::try_from(lockout.confirmation_count()) else {
1109 return Some(Err(serde::ser::Error::custom("Invalid confirmation count")));
1110 };
1111 let lockout_offset = LockoutOffset {
1112 offset,
1113 confirmation_count,
1114 };
1115 *slot = lockout.slot();
1116 Some(Ok(lockout_offset))
1117 },
1118 );
1119 let compact_tower_sync = CompactTowerSync {
1120 root: tower_sync.root.unwrap_or(Slot::MAX),
1121 lockout_offsets: lockout_offsets.collect::<Result<_, _>>()?,
1122 hash: tower_sync.hash,
1123 timestamp: tower_sync.timestamp,
1124 block_id: tower_sync.block_id,
1125 };
1126 compact_tower_sync.serialize(serializer)
1127 }
1128
1129 pub fn deserialize<'de, D>(deserializer: D) -> Result<TowerSync, D::Error>
1130 where
1131 D: Deserializer<'de>,
1132 {
1133 let CompactTowerSync {
1134 root,
1135 lockout_offsets,
1136 hash,
1137 timestamp,
1138 block_id,
1139 } = CompactTowerSync::deserialize(deserializer)?;
1140 let root = (root != Slot::MAX).then_some(root);
1141 let lockouts =
1142 lockout_offsets
1143 .iter()
1144 .scan(root.unwrap_or_default(), |slot, lockout_offset| {
1145 *slot = match slot.checked_add(lockout_offset.offset) {
1146 None => {
1147 return Some(Err(serde::de::Error::custom("Invalid lockout offset")))
1148 }
1149 Some(slot) => slot,
1150 };
1151 let lockout = Lockout::new_with_confirmation_count(
1152 *slot,
1153 u32::from(lockout_offset.confirmation_count),
1154 );
1155 Some(Ok(lockout))
1156 });
1157 Ok(TowerSync {
1158 root,
1159 lockouts: lockouts.collect::<Result<_, _>>()?,
1160 hash,
1161 timestamp,
1162 block_id,
1163 })
1164 }
1165}
1166
1167#[cfg(test)]
1168mod tests {
1169 use {super::*, bincode::serialized_size, itertools::Itertools, rand::Rng};
1170
1171 #[test]
1172 fn test_vote_serialize() {
1173 let mut buffer: Vec<u8> = vec![0; VoteState::size_of()];
1174 let mut vote_state = VoteState::default();
1175 vote_state
1176 .votes
1177 .resize(MAX_LOCKOUT_HISTORY, LandedVote::default());
1178 vote_state.root_slot = Some(1);
1179 let versioned = VoteStateVersions::new_current(vote_state);
1180 assert!(VoteState::serialize(&versioned, &mut buffer[0..4]).is_err());
1181 VoteState::serialize(&versioned, &mut buffer).unwrap();
1182 assert_eq!(
1183 VoteState::deserialize(&buffer).unwrap(),
1184 versioned.convert_to_current()
1185 );
1186 }
1187
1188 #[test]
1189 fn test_vote_deserialize_into() {
1190 let target_vote_state = VoteState::default();
1192 let vote_state_buf =
1193 bincode::serialize(&VoteStateVersions::new_current(target_vote_state.clone())).unwrap();
1194
1195 let mut test_vote_state = VoteState::default();
1196 VoteState::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap();
1197
1198 assert_eq!(target_vote_state, test_vote_state);
1199
1200 let struct_bytes_x4 = std::mem::size_of::<VoteState>() * 4;
1203 for _ in 0..1000 {
1204 let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
1205 let mut unstructured = Unstructured::new(&raw_data);
1206
1207 let target_vote_state_versions =
1208 VoteStateVersions::arbitrary(&mut unstructured).unwrap();
1209 let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
1210 let target_vote_state = target_vote_state_versions.convert_to_current();
1211
1212 let mut test_vote_state = VoteState::default();
1213 VoteState::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap();
1214
1215 assert_eq!(target_vote_state, test_vote_state);
1216 }
1217 }
1218
1219 #[test]
1220 fn test_vote_deserialize_into_error() {
1221 let target_vote_state = VoteState::new_rand_for_tests(Pubkey::new_unique(), 42);
1222 let mut vote_state_buf =
1223 bincode::serialize(&VoteStateVersions::new_current(target_vote_state.clone())).unwrap();
1224 let len = vote_state_buf.len();
1225 vote_state_buf.truncate(len - 1);
1226
1227 let mut test_vote_state = VoteState::default();
1228 VoteState::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap_err();
1229 assert_eq!(test_vote_state, VoteState::default());
1230 }
1231
1232 #[test]
1233 fn test_vote_deserialize_into_uninit() {
1234 let target_vote_state = VoteState::default();
1236 let vote_state_buf =
1237 bincode::serialize(&VoteStateVersions::new_current(target_vote_state.clone())).unwrap();
1238
1239 let mut test_vote_state = MaybeUninit::uninit();
1240 VoteState::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap();
1241 let test_vote_state = unsafe { test_vote_state.assume_init() };
1242
1243 assert_eq!(target_vote_state, test_vote_state);
1244
1245 let struct_bytes_x4 = std::mem::size_of::<VoteState>() * 4;
1248 for _ in 0..1000 {
1249 let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
1250 let mut unstructured = Unstructured::new(&raw_data);
1251
1252 let target_vote_state_versions =
1253 VoteStateVersions::arbitrary(&mut unstructured).unwrap();
1254 let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
1255 let target_vote_state = target_vote_state_versions.convert_to_current();
1256
1257 let mut test_vote_state = MaybeUninit::uninit();
1258 VoteState::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap();
1259 let test_vote_state = unsafe { test_vote_state.assume_init() };
1260
1261 assert_eq!(target_vote_state, test_vote_state);
1262 }
1263 }
1264
1265 #[test]
1266 fn test_vote_deserialize_into_uninit_nopanic() {
1267 let mut test_vote_state = MaybeUninit::uninit();
1269 let e = VoteState::deserialize_into_uninit(&[], &mut test_vote_state).unwrap_err();
1270 assert_eq!(e, InstructionError::InvalidAccountData);
1271
1272 let serialized_len_x4 = serialized_size(&VoteState::default()).unwrap() * 4;
1274 let mut rng = rand::thread_rng();
1275 for _ in 0..1000 {
1276 let raw_data_length = rng.gen_range(1..serialized_len_x4);
1277 let mut raw_data: Vec<u8> = (0..raw_data_length).map(|_| rng.gen::<u8>()).collect();
1278
1279 if raw_data_length >= 4 && rng.gen::<bool>() {
1281 let tag = rng.gen::<u8>() % 3;
1282 raw_data[0] = tag;
1283 raw_data[1] = 0;
1284 raw_data[2] = 0;
1285 raw_data[3] = 0;
1286 }
1287
1288 let mut test_vote_state = MaybeUninit::uninit();
1291 let test_res = VoteState::deserialize_into_uninit(&raw_data, &mut test_vote_state);
1292 let bincode_res = bincode::deserialize::<VoteStateVersions>(&raw_data)
1293 .map(|versioned| versioned.convert_to_current());
1294
1295 if test_res.is_err() {
1296 assert!(bincode_res.is_err());
1297 } else {
1298 let test_vote_state = unsafe { test_vote_state.assume_init() };
1299 assert_eq!(test_vote_state, bincode_res.unwrap());
1300 }
1301 }
1302 }
1303
1304 #[test]
1305 fn test_vote_deserialize_into_uninit_ill_sized() {
1306 let struct_bytes_x4 = std::mem::size_of::<VoteState>() * 4;
1308 for _ in 0..1000 {
1309 let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
1310 let mut unstructured = Unstructured::new(&raw_data);
1311
1312 let original_vote_state_versions =
1313 VoteStateVersions::arbitrary(&mut unstructured).unwrap();
1314 let original_buf = bincode::serialize(&original_vote_state_versions).unwrap();
1315
1316 let mut truncated_buf = original_buf.clone();
1317 let mut expanded_buf = original_buf.clone();
1318
1319 truncated_buf.resize(original_buf.len() - 8, 0);
1320 expanded_buf.resize(original_buf.len() + 8, 0);
1321
1322 let mut test_vote_state = MaybeUninit::uninit();
1324 let test_res = VoteState::deserialize_into_uninit(&truncated_buf, &mut test_vote_state);
1325 let bincode_res = bincode::deserialize::<VoteStateVersions>(&truncated_buf)
1326 .map(|versioned| versioned.convert_to_current());
1327
1328 assert!(test_res.is_err());
1329 assert!(bincode_res.is_err());
1330
1331 let mut test_vote_state = MaybeUninit::uninit();
1333 VoteState::deserialize_into_uninit(&expanded_buf, &mut test_vote_state).unwrap();
1334 let bincode_res = bincode::deserialize::<VoteStateVersions>(&expanded_buf)
1335 .map(|versioned| versioned.convert_to_current());
1336
1337 let test_vote_state = unsafe { test_vote_state.assume_init() };
1338 assert_eq!(test_vote_state, bincode_res.unwrap());
1339 }
1340 }
1341
1342 #[test]
1343 fn test_vote_state_commission_split() {
1344 let vote_state = VoteState::default();
1345
1346 assert_eq!(vote_state.commission_split(1), (0, 1, false));
1347
1348 let mut vote_state = VoteState {
1349 commission: u8::MAX,
1350 ..VoteState::default()
1351 };
1352 assert_eq!(vote_state.commission_split(1), (1, 0, false));
1353
1354 vote_state.commission = 99;
1355 assert_eq!(vote_state.commission_split(10), (9, 0, true));
1356
1357 vote_state.commission = 1;
1358 assert_eq!(vote_state.commission_split(10), (0, 9, true));
1359
1360 vote_state.commission = 50;
1361 let (voter_portion, staker_portion, was_split) = vote_state.commission_split(10);
1362
1363 assert_eq!((voter_portion, staker_portion, was_split), (5, 5, true));
1364 }
1365
1366 #[test]
1367 fn test_vote_state_epoch_credits() {
1368 let mut vote_state = VoteState::default();
1369
1370 assert_eq!(vote_state.credits(), 0);
1371 assert_eq!(vote_state.epoch_credits().clone(), vec![]);
1372
1373 let mut expected = vec![];
1374 let mut credits = 0;
1375 let epochs = (MAX_EPOCH_CREDITS_HISTORY + 2) as u64;
1376 for epoch in 0..epochs {
1377 for _j in 0..epoch {
1378 vote_state.increment_credits(epoch, 1);
1379 credits += 1;
1380 }
1381 expected.push((epoch, credits, credits - epoch));
1382 }
1383
1384 while expected.len() > MAX_EPOCH_CREDITS_HISTORY {
1385 expected.remove(0);
1386 }
1387
1388 assert_eq!(vote_state.credits(), credits);
1389 assert_eq!(vote_state.epoch_credits().clone(), expected);
1390 }
1391
1392 #[test]
1393 fn test_vote_state_epoch0_no_credits() {
1394 let mut vote_state = VoteState::default();
1395
1396 assert_eq!(vote_state.epoch_credits().len(), 0);
1397 vote_state.increment_credits(1, 1);
1398 assert_eq!(vote_state.epoch_credits().len(), 1);
1399
1400 vote_state.increment_credits(2, 1);
1401 assert_eq!(vote_state.epoch_credits().len(), 2);
1402 }
1403
1404 #[test]
1405 fn test_vote_state_increment_credits() {
1406 let mut vote_state = VoteState::default();
1407
1408 let credits = (MAX_EPOCH_CREDITS_HISTORY + 2) as u64;
1409 for i in 0..credits {
1410 vote_state.increment_credits(i, 1);
1411 }
1412 assert_eq!(vote_state.credits(), credits);
1413 assert!(vote_state.epoch_credits().len() <= MAX_EPOCH_CREDITS_HISTORY);
1414 }
1415
1416 #[test]
1417 fn test_vote_process_timestamp() {
1418 let (slot, timestamp) = (15, 1_575_412_285);
1419 let mut vote_state = VoteState {
1420 last_timestamp: BlockTimestamp { slot, timestamp },
1421 ..VoteState::default()
1422 };
1423
1424 assert_eq!(
1425 vote_state.process_timestamp(slot - 1, timestamp + 1),
1426 Err(VoteError::TimestampTooOld)
1427 );
1428 assert_eq!(
1429 vote_state.last_timestamp,
1430 BlockTimestamp { slot, timestamp }
1431 );
1432 assert_eq!(
1433 vote_state.process_timestamp(slot + 1, timestamp - 1),
1434 Err(VoteError::TimestampTooOld)
1435 );
1436 assert_eq!(
1437 vote_state.process_timestamp(slot, timestamp + 1),
1438 Err(VoteError::TimestampTooOld)
1439 );
1440 assert_eq!(vote_state.process_timestamp(slot, timestamp), Ok(()));
1441 assert_eq!(
1442 vote_state.last_timestamp,
1443 BlockTimestamp { slot, timestamp }
1444 );
1445 assert_eq!(vote_state.process_timestamp(slot + 1, timestamp), Ok(()));
1446 assert_eq!(
1447 vote_state.last_timestamp,
1448 BlockTimestamp {
1449 slot: slot + 1,
1450 timestamp
1451 }
1452 );
1453 assert_eq!(
1454 vote_state.process_timestamp(slot + 2, timestamp + 1),
1455 Ok(())
1456 );
1457 assert_eq!(
1458 vote_state.last_timestamp,
1459 BlockTimestamp {
1460 slot: slot + 2,
1461 timestamp: timestamp + 1
1462 }
1463 );
1464
1465 vote_state.last_timestamp = BlockTimestamp::default();
1467 assert_eq!(vote_state.process_timestamp(0, timestamp), Ok(()));
1468 }
1469
1470 #[test]
1471 fn test_get_and_update_authorized_voter() {
1472 let original_voter = Pubkey::new_unique();
1473 let mut vote_state = VoteState::new(
1474 &VoteInit {
1475 node_pubkey: original_voter,
1476 authorized_voter: original_voter,
1477 authorized_withdrawer: original_voter,
1478 commission: 0,
1479 },
1480 &Clock::default(),
1481 );
1482
1483 assert_eq!(vote_state.authorized_voters.len(), 1);
1484 assert_eq!(
1485 *vote_state.authorized_voters.first().unwrap().1,
1486 original_voter
1487 );
1488
1489 assert_eq!(
1492 vote_state.get_and_update_authorized_voter(1).unwrap(),
1493 original_voter
1494 );
1495
1496 assert_eq!(
1499 vote_state.get_and_update_authorized_voter(5).unwrap(),
1500 original_voter
1501 );
1502
1503 assert_eq!(vote_state.authorized_voters.len(), 1);
1506 for i in 0..5 {
1507 assert!(vote_state
1508 .authorized_voters
1509 .get_authorized_voter(i)
1510 .is_none());
1511 }
1512
1513 let new_authorized_voter = Pubkey::new_unique();
1515 vote_state
1516 .set_new_authorized_voter(&new_authorized_voter, 5, 7, |_| Ok(()))
1517 .unwrap();
1518
1519 assert_eq!(
1521 vote_state.get_and_update_authorized_voter(6).unwrap(),
1522 original_voter
1523 );
1524
1525 for i in 7..10 {
1528 assert_eq!(
1529 vote_state.get_and_update_authorized_voter(i).unwrap(),
1530 new_authorized_voter
1531 );
1532 }
1533 assert_eq!(vote_state.authorized_voters.len(), 1);
1534 }
1535
1536 #[test]
1537 fn test_set_new_authorized_voter() {
1538 let original_voter = Pubkey::new_unique();
1539 let epoch_offset = 15;
1540 let mut vote_state = VoteState::new(
1541 &VoteInit {
1542 node_pubkey: original_voter,
1543 authorized_voter: original_voter,
1544 authorized_withdrawer: original_voter,
1545 commission: 0,
1546 },
1547 &Clock::default(),
1548 );
1549
1550 assert!(vote_state.prior_voters.last().is_none());
1551
1552 let new_voter = Pubkey::new_unique();
1553 vote_state
1555 .set_new_authorized_voter(&new_voter, 0, epoch_offset, |_| Ok(()))
1556 .unwrap();
1557
1558 assert_eq!(vote_state.prior_voters.idx, 0);
1559 assert_eq!(
1560 vote_state.prior_voters.last(),
1561 Some(&(original_voter, 0, epoch_offset))
1562 );
1563
1564 assert_eq!(
1566 vote_state.set_new_authorized_voter(&new_voter, 0, epoch_offset, |_| Ok(())),
1567 Err(VoteError::TooSoonToReauthorize.into())
1568 );
1569
1570 vote_state
1572 .set_new_authorized_voter(&new_voter, 2, 2 + epoch_offset, |_| Ok(()))
1573 .unwrap();
1574
1575 let new_voter2 = Pubkey::new_unique();
1577 vote_state
1578 .set_new_authorized_voter(&new_voter2, 3, 3 + epoch_offset, |_| Ok(()))
1579 .unwrap();
1580 assert_eq!(vote_state.prior_voters.idx, 1);
1581 assert_eq!(
1582 vote_state.prior_voters.last(),
1583 Some(&(new_voter, epoch_offset, 3 + epoch_offset))
1584 );
1585
1586 let new_voter3 = Pubkey::new_unique();
1587 vote_state
1588 .set_new_authorized_voter(&new_voter3, 6, 6 + epoch_offset, |_| Ok(()))
1589 .unwrap();
1590 assert_eq!(vote_state.prior_voters.idx, 2);
1591 assert_eq!(
1592 vote_state.prior_voters.last(),
1593 Some(&(new_voter2, 3 + epoch_offset, 6 + epoch_offset))
1594 );
1595
1596 vote_state
1598 .set_new_authorized_voter(&original_voter, 9, 9 + epoch_offset, |_| Ok(()))
1599 .unwrap();
1600
1601 for i in 9..epoch_offset {
1604 assert_eq!(
1605 vote_state.get_and_update_authorized_voter(i).unwrap(),
1606 original_voter
1607 );
1608 }
1609 for i in epoch_offset..3 + epoch_offset {
1610 assert_eq!(
1611 vote_state.get_and_update_authorized_voter(i).unwrap(),
1612 new_voter
1613 );
1614 }
1615 for i in 3 + epoch_offset..6 + epoch_offset {
1616 assert_eq!(
1617 vote_state.get_and_update_authorized_voter(i).unwrap(),
1618 new_voter2
1619 );
1620 }
1621 for i in 6 + epoch_offset..9 + epoch_offset {
1622 assert_eq!(
1623 vote_state.get_and_update_authorized_voter(i).unwrap(),
1624 new_voter3
1625 );
1626 }
1627 for i in 9 + epoch_offset..=10 + epoch_offset {
1628 assert_eq!(
1629 vote_state.get_and_update_authorized_voter(i).unwrap(),
1630 original_voter
1631 );
1632 }
1633 }
1634
1635 #[test]
1636 fn test_authorized_voter_is_locked_within_epoch() {
1637 let original_voter = Pubkey::new_unique();
1638 let mut vote_state = VoteState::new(
1639 &VoteInit {
1640 node_pubkey: original_voter,
1641 authorized_voter: original_voter,
1642 authorized_withdrawer: original_voter,
1643 commission: 0,
1644 },
1645 &Clock::default(),
1646 );
1647
1648 let new_voter = Pubkey::new_unique();
1652 assert_eq!(
1653 vote_state.set_new_authorized_voter(&new_voter, 1, 1, |_| Ok(())),
1654 Err(VoteError::TooSoonToReauthorize.into())
1655 );
1656
1657 assert_eq!(vote_state.get_authorized_voter(1), Some(original_voter));
1658
1659 assert_eq!(
1661 vote_state.set_new_authorized_voter(&new_voter, 1, 2, |_| Ok(())),
1662 Ok(())
1663 );
1664
1665 assert_eq!(
1669 vote_state.set_new_authorized_voter(&original_voter, 3, 3, |_| Ok(())),
1670 Err(VoteError::TooSoonToReauthorize.into())
1671 );
1672
1673 assert_eq!(vote_state.get_authorized_voter(3), Some(new_voter));
1674 }
1675
1676 #[test]
1677 fn test_vote_state_size_of() {
1678 let vote_state = VoteState::get_max_sized_vote_state();
1679 let vote_state = VoteStateVersions::new_current(vote_state);
1680 let size = serialized_size(&vote_state).unwrap();
1681 assert_eq!(VoteState::size_of() as u64, size);
1682 }
1683
1684 #[test]
1685 fn test_vote_state_max_size() {
1686 let mut max_sized_data = vec![0; VoteState::size_of()];
1687 let vote_state = VoteState::get_max_sized_vote_state();
1688 let (start_leader_schedule_epoch, _) = vote_state.authorized_voters.last().unwrap();
1689 let start_current_epoch =
1690 start_leader_schedule_epoch - MAX_LEADER_SCHEDULE_EPOCH_OFFSET + 1;
1691
1692 let mut vote_state = Some(vote_state);
1693 for i in start_current_epoch..start_current_epoch + 2 * MAX_LEADER_SCHEDULE_EPOCH_OFFSET {
1694 vote_state.as_mut().map(|vote_state| {
1695 vote_state.set_new_authorized_voter(
1696 &Pubkey::new_unique(),
1697 i,
1698 i + MAX_LEADER_SCHEDULE_EPOCH_OFFSET,
1699 |_| Ok(()),
1700 )
1701 });
1702
1703 let versioned = VoteStateVersions::new_current(vote_state.take().unwrap());
1704 VoteState::serialize(&versioned, &mut max_sized_data).unwrap();
1705 vote_state = Some(versioned.convert_to_current());
1706 }
1707 }
1708
1709 #[test]
1710 fn test_default_vote_state_is_uninitialized() {
1711 assert!(VoteStateVersions::new_current(VoteState::default()).is_uninitialized());
1715 }
1716
1717 #[test]
1718 fn test_is_correct_size_and_initialized() {
1719 let mut vote_account_data = vec![0; VoteStateVersions::vote_state_size_of(true)];
1721 assert!(!VoteStateVersions::is_correct_size_and_initialized(
1722 &vote_account_data
1723 ));
1724
1725 let default_account_state = VoteStateVersions::new_current(VoteState::default());
1727 VoteState::serialize(&default_account_state, &mut vote_account_data).unwrap();
1728 assert!(!VoteStateVersions::is_correct_size_and_initialized(
1729 &vote_account_data
1730 ));
1731
1732 let short_data = vec![1; DEFAULT_PRIOR_VOTERS_OFFSET];
1734 assert!(!VoteStateVersions::is_correct_size_and_initialized(
1735 &short_data
1736 ));
1737
1738 let mut large_vote_data = vec![1; 2 * VoteStateVersions::vote_state_size_of(true)];
1740 let default_account_state = VoteStateVersions::new_current(VoteState::default());
1741 VoteState::serialize(&default_account_state, &mut large_vote_data).unwrap();
1742 assert!(!VoteStateVersions::is_correct_size_and_initialized(
1743 &vote_account_data
1744 ));
1745
1746 let vote_state = VoteState::new(
1748 &VoteInit {
1749 node_pubkey: Pubkey::new_unique(),
1750 authorized_voter: Pubkey::new_unique(),
1751 authorized_withdrawer: Pubkey::new_unique(),
1752 commission: 0,
1753 },
1754 &Clock::default(),
1755 );
1756 let account_state = VoteStateVersions::new_current(vote_state.clone());
1757 VoteState::serialize(&account_state, &mut vote_account_data).unwrap();
1758 assert!(VoteStateVersions::is_correct_size_and_initialized(
1759 &vote_account_data
1760 ));
1761
1762 let old_vote_state = VoteState1_14_11::from(vote_state);
1764 let account_state = VoteStateVersions::V1_14_11(Box::new(old_vote_state));
1765 let mut vote_account_data = vec![0; VoteStateVersions::vote_state_size_of(false)];
1766 VoteState::serialize(&account_state, &mut vote_account_data).unwrap();
1767 assert!(VoteStateVersions::is_correct_size_and_initialized(
1768 &vote_account_data
1769 ));
1770 }
1771
1772 #[test]
1773 fn test_minimum_balance() {
1774 let rent = solana_program::rent::Rent::default();
1775 let minimum_balance = rent.minimum_balance(VoteState::size_of());
1776 assert!(minimum_balance as f64 / 10f64.powf(9.0) < 0.04)
1778 }
1779
1780 #[test]
1781 fn test_serde_compact_vote_state_update() {
1782 let mut rng = rand::thread_rng();
1783 for _ in 0..5000 {
1784 run_serde_compact_vote_state_update(&mut rng);
1785 }
1786 }
1787
1788 fn run_serde_compact_vote_state_update<R: Rng>(rng: &mut R) {
1789 let lockouts: VecDeque<_> = std::iter::repeat_with(|| {
1790 let slot = 149_303_885_u64.saturating_add(rng.gen_range(0..10_000));
1791 let confirmation_count = rng.gen_range(0..33);
1792 Lockout::new_with_confirmation_count(slot, confirmation_count)
1793 })
1794 .take(32)
1795 .sorted_by_key(|lockout| lockout.slot())
1796 .collect();
1797 let root = rng.gen_ratio(1, 2).then(|| {
1798 lockouts[0]
1799 .slot()
1800 .checked_sub(rng.gen_range(0..1_000))
1801 .expect("All slots should be greater than 1_000")
1802 });
1803 let timestamp = rng.gen_ratio(1, 2).then(|| rng.gen());
1804 let hash = Hash::from(rng.gen::<[u8; 32]>());
1805 let vote_state_update = VoteStateUpdate {
1806 lockouts,
1807 root,
1808 hash,
1809 timestamp,
1810 };
1811 #[derive(Debug, Eq, PartialEq, Deserialize, Serialize)]
1812 enum VoteInstruction {
1813 #[serde(with = "serde_compact_vote_state_update")]
1814 UpdateVoteState(VoteStateUpdate),
1815 UpdateVoteStateSwitch(
1816 #[serde(with = "serde_compact_vote_state_update")] VoteStateUpdate,
1817 Hash,
1818 ),
1819 }
1820 let vote = VoteInstruction::UpdateVoteState(vote_state_update.clone());
1821 let bytes = bincode::serialize(&vote).unwrap();
1822 assert_eq!(vote, bincode::deserialize(&bytes).unwrap());
1823 let hash = Hash::from(rng.gen::<[u8; 32]>());
1824 let vote = VoteInstruction::UpdateVoteStateSwitch(vote_state_update, hash);
1825 let bytes = bincode::serialize(&vote).unwrap();
1826 assert_eq!(vote, bincode::deserialize(&bytes).unwrap());
1827 }
1828
1829 #[test]
1830 fn test_circbuf_oob() {
1831 let data: &[u8] = &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00];
1833 let circ_buf: CircBuf<()> = bincode::deserialize(data).unwrap();
1834 assert_eq!(circ_buf.last(), None);
1835 }
1836}