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 clock::{Epoch, Slot, UnixTimestamp},
13 hash::Hash,
14 instruction::InstructionError,
15 pubkey::Pubkey,
16 rent::Rent,
17 serialize_utils::cursor::read_u32,
18 sysvar::clock::Clock,
19 vote::{authorized_voters::AuthorizedVoters, error::VoteError},
20 },
21 bincode::{serialize_into, serialized_size, ErrorKind},
22 serde_derive::{Deserialize, Serialize},
23 std::{collections::VecDeque, fmt::Debug, io::Cursor},
24};
25
26mod vote_state_0_23_5;
27pub mod vote_state_1_14_11;
28pub use vote_state_1_14_11::*;
29mod vote_state_deserialize;
30use vote_state_deserialize::deserialize_vote_state_into;
31pub mod vote_state_versions;
32pub use vote_state_versions::*;
33
34pub const MAX_LOCKOUT_HISTORY: usize = 31;
36pub const INITIAL_LOCKOUT: usize = 2;
37
38pub const MAX_EPOCH_CREDITS_HISTORY: usize = 64;
40
41const DEFAULT_PRIOR_VOTERS_OFFSET: usize = 114;
43
44pub const VOTE_CREDITS_GRACE_SLOTS: u8 = 2;
46
47pub const VOTE_CREDITS_MAXIMUM_PER_SLOT: u8 = 8;
49
50#[frozen_abi(digest = "Ch2vVEwos2EjAVqSHCyJjnN2MNX1yrpapZTGhMSCjWUH")]
51#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone, AbiExample)]
52pub struct Vote {
53 pub slots: Vec<Slot>,
55 pub hash: Hash,
57 pub timestamp: Option<UnixTimestamp>,
59}
60
61impl Vote {
62 pub fn new(slots: Vec<Slot>, hash: Hash) -> Self {
63 Self {
64 slots,
65 hash,
66 timestamp: None,
67 }
68 }
69
70 pub fn last_voted_slot(&self) -> Option<Slot> {
71 self.slots.last().copied()
72 }
73}
74
75#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Copy, Clone, AbiExample)]
76#[cfg_attr(test, derive(Arbitrary))]
77pub struct Lockout {
78 slot: Slot,
79 confirmation_count: u32,
80}
81
82impl Lockout {
83 pub fn new(slot: Slot) -> Self {
84 Self::new_with_confirmation_count(slot, 1)
85 }
86
87 pub fn new_with_confirmation_count(slot: Slot, confirmation_count: u32) -> Self {
88 Self {
89 slot,
90 confirmation_count,
91 }
92 }
93
94 pub fn lockout(&self) -> u64 {
96 (INITIAL_LOCKOUT as u64).pow(self.confirmation_count())
97 }
98
99 pub fn last_locked_out_slot(&self) -> Slot {
103 self.slot.saturating_add(self.lockout())
104 }
105
106 pub fn is_locked_out_at_slot(&self, slot: Slot) -> bool {
107 self.last_locked_out_slot() >= slot
108 }
109
110 pub fn slot(&self) -> Slot {
111 self.slot
112 }
113
114 pub fn confirmation_count(&self) -> u32 {
115 self.confirmation_count
116 }
117
118 pub fn increase_confirmation_count(&mut self, by: u32) {
119 self.confirmation_count = self.confirmation_count.saturating_add(by)
120 }
121}
122
123#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Copy, Clone, AbiExample)]
124#[cfg_attr(test, derive(Arbitrary))]
125pub struct LandedVote {
126 pub latency: u8,
130 pub lockout: Lockout,
131}
132
133impl LandedVote {
134 pub fn slot(&self) -> Slot {
135 self.lockout.slot
136 }
137
138 pub fn confirmation_count(&self) -> u32 {
139 self.lockout.confirmation_count
140 }
141}
142
143impl From<LandedVote> for Lockout {
144 fn from(landed_vote: LandedVote) -> Self {
145 landed_vote.lockout
146 }
147}
148
149impl From<Lockout> for LandedVote {
150 fn from(lockout: Lockout) -> Self {
151 Self {
152 latency: 0,
153 lockout,
154 }
155 }
156}
157
158#[frozen_abi(digest = "GwJfVFsATSj7nvKwtUkHYzqPRaPY6SLxPGXApuCya3x5")]
159#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone, AbiExample)]
160pub struct VoteStateUpdate {
161 pub lockouts: VecDeque<Lockout>,
163 pub root: Option<Slot>,
165 pub hash: Hash,
167 pub timestamp: Option<UnixTimestamp>,
169}
170
171impl From<Vec<(Slot, u32)>> for VoteStateUpdate {
172 fn from(recent_slots: Vec<(Slot, u32)>) -> Self {
173 let lockouts: VecDeque<Lockout> = recent_slots
174 .into_iter()
175 .map(|(slot, confirmation_count)| {
176 Lockout::new_with_confirmation_count(slot, confirmation_count)
177 })
178 .collect();
179 Self {
180 lockouts,
181 root: None,
182 hash: Hash::default(),
183 timestamp: None,
184 }
185 }
186}
187
188impl VoteStateUpdate {
189 pub fn new(lockouts: VecDeque<Lockout>, root: Option<Slot>, hash: Hash) -> Self {
190 Self {
191 lockouts,
192 root,
193 hash,
194 timestamp: None,
195 }
196 }
197
198 pub fn slots(&self) -> Vec<Slot> {
199 self.lockouts.iter().map(|lockout| lockout.slot()).collect()
200 }
201
202 pub fn last_voted_slot(&self) -> Option<Slot> {
203 self.lockouts.back().map(|l| l.slot())
204 }
205}
206
207#[derive(Default, Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
208pub struct VoteInit {
209 pub node_pubkey: Pubkey,
210 pub authorized_voter: Pubkey,
211 pub authorized_withdrawer: Pubkey,
212 pub commission: u8,
213}
214
215#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
216pub enum VoteAuthorize {
217 Voter,
218 Withdrawer,
219}
220
221#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
222pub struct VoteAuthorizeWithSeedArgs {
223 pub authorization_type: VoteAuthorize,
224 pub current_authority_derived_key_owner: Pubkey,
225 pub current_authority_derived_key_seed: String,
226 pub new_authority: Pubkey,
227}
228
229#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
230pub struct VoteAuthorizeCheckedWithSeedArgs {
231 pub authorization_type: VoteAuthorize,
232 pub current_authority_derived_key_owner: Pubkey,
233 pub current_authority_derived_key_seed: String,
234}
235
236#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone, AbiExample)]
237#[cfg_attr(test, derive(Arbitrary))]
238pub struct BlockTimestamp {
239 pub slot: Slot,
240 pub timestamp: UnixTimestamp,
241}
242
243const MAX_ITEMS: usize = 32;
245
246#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, AbiExample)]
247pub struct CircBuf<I> {
248 buf: [I; MAX_ITEMS],
249 idx: usize,
251 is_empty: bool,
252}
253
254impl<I: Default + Copy> Default for CircBuf<I> {
255 fn default() -> Self {
256 Self {
257 buf: [I::default(); MAX_ITEMS],
258 idx: MAX_ITEMS
259 .checked_sub(1)
260 .expect("`MAX_ITEMS` should be positive"),
261 is_empty: true,
262 }
263 }
264}
265
266impl<I> CircBuf<I> {
267 pub fn append(&mut self, item: I) {
268 self.idx = self
270 .idx
271 .checked_add(1)
272 .and_then(|idx| idx.checked_rem(MAX_ITEMS))
273 .expect("`self.idx` should be < `MAX_ITEMS` which should be non-zero");
274
275 self.buf[self.idx] = item;
276 self.is_empty = false;
277 }
278
279 pub fn buf(&self) -> &[I; MAX_ITEMS] {
280 &self.buf
281 }
282
283 pub fn last(&self) -> Option<&I> {
284 if !self.is_empty {
285 Some(&self.buf[self.idx])
286 } else {
287 None
288 }
289 }
290}
291
292#[cfg(test)]
293impl<'a, I: Default + Copy> Arbitrary<'a> for CircBuf<I>
294where
295 I: Arbitrary<'a>,
296{
297 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
298 let mut circbuf = Self::default();
299
300 let len = u.arbitrary_len::<I>()?;
301 for _ in 0..len {
302 circbuf.append(I::arbitrary(u)?);
303 }
304
305 Ok(circbuf)
306 }
307}
308
309#[frozen_abi(digest = "EeenjJaSrm9hRM39gK6raRNtzG61hnk7GciUCJJRDUSQ")]
310#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone, AbiExample)]
311#[cfg_attr(test, derive(Arbitrary))]
312pub struct VoteState {
313 pub node_pubkey: Pubkey,
315
316 pub authorized_withdrawer: Pubkey,
318 pub commission: u8,
321
322 pub votes: VecDeque<LandedVote>,
323
324 pub root_slot: Option<Slot>,
327
328 authorized_voters: AuthorizedVoters,
330
331 prior_voters: CircBuf<(Pubkey, Epoch, Epoch)>,
335
336 pub epoch_credits: Vec<(Epoch, u64, u64)>,
339
340 pub last_timestamp: BlockTimestamp,
342}
343
344impl VoteState {
345 pub fn new(vote_init: &VoteInit, clock: &Clock) -> Self {
346 Self {
347 node_pubkey: vote_init.node_pubkey,
348 authorized_voters: AuthorizedVoters::new(clock.epoch, vote_init.authorized_voter),
349 authorized_withdrawer: vote_init.authorized_withdrawer,
350 commission: vote_init.commission,
351 ..VoteState::default()
352 }
353 }
354
355 pub fn new_rand_for_tests(node_pubkey: Pubkey, root_slot: Slot) -> Self {
356 let votes = (1..32)
357 .map(|x| LandedVote {
358 latency: 0,
359 lockout: Lockout::new_with_confirmation_count(
360 u64::from(x).saturating_add(root_slot),
361 32_u32.saturating_sub(x),
362 ),
363 })
364 .collect();
365 Self {
366 node_pubkey,
367 root_slot: Some(root_slot),
368 votes,
369 ..VoteState::default()
370 }
371 }
372
373 pub fn get_authorized_voter(&self, epoch: Epoch) -> Option<Pubkey> {
374 self.authorized_voters.get_authorized_voter(epoch)
375 }
376
377 pub fn authorized_voters(&self) -> &AuthorizedVoters {
378 &self.authorized_voters
379 }
380
381 pub fn prior_voters(&mut self) -> &CircBuf<(Pubkey, Epoch, Epoch)> {
382 &self.prior_voters
383 }
384
385 pub fn get_rent_exempt_reserve(rent: &Rent) -> u64 {
386 rent.minimum_balance(VoteState::size_of())
387 }
388
389 pub const fn size_of() -> usize {
392 3762 }
394
395 pub fn deserialize(input: &[u8]) -> Result<Self, InstructionError> {
398 #[cfg(not(target_os = "solana"))]
399 {
400 deserialize::<VoteStateVersions>(input)
401 .map(|versioned| versioned.convert_to_current())
402 .map_err(|_| InstructionError::InvalidAccountData)
403 }
404 #[cfg(target_os = "solana")]
405 {
406 let mut vote_state = Self::default();
407 Self::deserialize_into(input, &mut vote_state)?;
408 Ok(vote_state)
409 }
410 }
411
412 pub fn deserialize_into(
417 input: &[u8],
418 vote_state: &mut VoteState,
419 ) -> Result<(), InstructionError> {
420 let minimum_size =
421 serialized_size(vote_state).map_err(|_| InstructionError::InvalidAccountData)?;
422 if (input.len() as u64) < minimum_size {
423 return Err(InstructionError::InvalidAccountData);
424 }
425
426 let mut cursor = Cursor::new(input);
427
428 let variant = read_u32(&mut cursor)?;
429 match variant {
430 0 => Err(InstructionError::InvalidAccountData),
432 1 => deserialize_vote_state_into(&mut cursor, vote_state, false),
434 2 => deserialize_vote_state_into(&mut cursor, vote_state, true),
436 _ => Err(InstructionError::InvalidAccountData),
437 }?;
438
439 if cursor.position() > input.len() as u64 {
440 return Err(InstructionError::InvalidAccountData);
441 }
442
443 Ok(())
444 }
445
446 pub fn serialize(
447 versioned: &VoteStateVersions,
448 output: &mut [u8],
449 ) -> Result<(), InstructionError> {
450 serialize_into(output, versioned).map_err(|err| match *err {
451 ErrorKind::SizeLimit => InstructionError::AccountDataTooSmall,
452 _ => InstructionError::GenericError,
453 })
454 }
455
456 pub fn commission_split(&self, on: u64) -> (u64, u64, bool) {
461 match self.commission.min(100) {
462 0 => (0, on, false),
463 100 => (on, 0, false),
464 split => {
465 let on = u128::from(on);
466 let mine = on
472 .checked_mul(u128::from(split))
473 .expect("multiplication of a u64 and u8 should not overflow")
474 / 100u128;
475 let theirs = on
476 .checked_mul(u128::from(
477 100u8
478 .checked_sub(split)
479 .expect("commission cannot be greater than 100"),
480 ))
481 .expect("multiplication of a u64 and u8 should not overflow")
482 / 100u128;
483
484 (mine as u64, theirs as u64, true)
485 }
486 }
487 }
488
489 pub fn contains_slot(&self, candidate_slot: Slot) -> bool {
491 self.votes
492 .binary_search_by(|vote| vote.slot().cmp(&candidate_slot))
493 .is_ok()
494 }
495
496 #[cfg(test)]
497 fn get_max_sized_vote_state() -> VoteState {
498 let mut authorized_voters = AuthorizedVoters::default();
499 for i in 0..=MAX_LEADER_SCHEDULE_EPOCH_OFFSET {
500 authorized_voters.insert(i, Pubkey::new_unique());
501 }
502
503 VoteState {
504 votes: VecDeque::from(vec![LandedVote::default(); MAX_LOCKOUT_HISTORY]),
505 root_slot: Some(std::u64::MAX),
506 epoch_credits: vec![(0, 0, 0); MAX_EPOCH_CREDITS_HISTORY],
507 authorized_voters,
508 ..Self::default()
509 }
510 }
511
512 pub fn process_next_vote_slot(
513 &mut self,
514 next_vote_slot: Slot,
515 epoch: Epoch,
516 current_slot: Slot,
517 ) {
518 if self
520 .last_voted_slot()
521 .map_or(false, |last_voted_slot| next_vote_slot <= last_voted_slot)
522 {
523 return;
524 }
525
526 self.pop_expired_votes(next_vote_slot);
527
528 let landed_vote = LandedVote {
529 latency: Self::compute_vote_latency(next_vote_slot, current_slot),
530 lockout: Lockout::new(next_vote_slot),
531 };
532
533 if self.votes.len() == MAX_LOCKOUT_HISTORY {
535 let credits = self.credits_for_vote_at_index(0);
536 let landed_vote = self.votes.pop_front().unwrap();
537 self.root_slot = Some(landed_vote.slot());
538
539 self.increment_credits(epoch, credits);
540 }
541 self.votes.push_back(landed_vote);
542 self.double_lockouts();
543 }
544
545 pub fn increment_credits(&mut self, epoch: Epoch, credits: u64) {
547 if self.epoch_credits.is_empty() {
551 self.epoch_credits.push((epoch, 0, 0));
552 } else if epoch != self.epoch_credits.last().unwrap().0 {
553 let (_, credits, prev_credits) = *self.epoch_credits.last().unwrap();
554
555 if credits != prev_credits {
556 self.epoch_credits.push((epoch, credits, credits));
559 } else {
560 self.epoch_credits.last_mut().unwrap().0 = epoch;
562 }
563
564 if self.epoch_credits.len() > MAX_EPOCH_CREDITS_HISTORY {
566 self.epoch_credits.remove(0);
567 }
568 }
569
570 self.epoch_credits.last_mut().unwrap().1 =
571 self.epoch_credits.last().unwrap().1.saturating_add(credits);
572 }
573
574 pub fn compute_vote_latency(voted_for_slot: Slot, current_slot: Slot) -> u8 {
576 std::cmp::min(current_slot.saturating_sub(voted_for_slot), u8::MAX as u64) as u8
577 }
578
579 pub fn credits_for_vote_at_index(&self, index: usize) -> u64 {
581 let latency = self
582 .votes
583 .get(index)
584 .map_or(0, |landed_vote| landed_vote.latency);
585
586 if latency == 0 {
589 1
590 } else {
591 match latency.checked_sub(VOTE_CREDITS_GRACE_SLOTS) {
592 None | Some(0) => {
593 VOTE_CREDITS_MAXIMUM_PER_SLOT as u64
595 }
596
597 Some(diff) => {
598 match VOTE_CREDITS_MAXIMUM_PER_SLOT.checked_sub(diff) {
601 None | Some(0) => 1,
603
604 Some(credits) => credits as u64,
605 }
606 }
607 }
608 }
609 }
610
611 pub fn nth_recent_lockout(&self, position: usize) -> Option<&Lockout> {
612 if position < self.votes.len() {
613 let pos = self
614 .votes
615 .len()
616 .checked_sub(position)
617 .and_then(|pos| pos.checked_sub(1))?;
618 self.votes.get(pos).map(|vote| &vote.lockout)
619 } else {
620 None
621 }
622 }
623
624 pub fn last_lockout(&self) -> Option<&Lockout> {
625 self.votes.back().map(|vote| &vote.lockout)
626 }
627
628 pub fn last_voted_slot(&self) -> Option<Slot> {
629 self.last_lockout().map(|v| v.slot())
630 }
631
632 pub fn tower(&self) -> Vec<Slot> {
635 self.votes.iter().map(|v| v.slot()).collect()
636 }
637
638 pub fn current_epoch(&self) -> Epoch {
639 if self.epoch_credits.is_empty() {
640 0
641 } else {
642 self.epoch_credits.last().unwrap().0
643 }
644 }
645
646 pub fn credits(&self) -> u64 {
649 if self.epoch_credits.is_empty() {
650 0
651 } else {
652 self.epoch_credits.last().unwrap().1
653 }
654 }
655
656 pub fn epoch_credits(&self) -> &Vec<(Epoch, u64, u64)> {
662 &self.epoch_credits
663 }
664
665 pub fn set_new_authorized_voter<F>(
666 &mut self,
667 authorized_pubkey: &Pubkey,
668 current_epoch: Epoch,
669 target_epoch: Epoch,
670 verify: F,
671 ) -> Result<(), InstructionError>
672 where
673 F: Fn(Pubkey) -> Result<(), InstructionError>,
674 {
675 let epoch_authorized_voter = self.get_and_update_authorized_voter(current_epoch)?;
676 verify(epoch_authorized_voter)?;
677
678 if self.authorized_voters.contains(target_epoch) {
684 return Err(VoteError::TooSoonToReauthorize.into());
685 }
686
687 let (latest_epoch, latest_authorized_pubkey) = self
689 .authorized_voters
690 .last()
691 .ok_or(InstructionError::InvalidAccountData)?;
692
693 if latest_authorized_pubkey != authorized_pubkey {
697 let epoch_of_last_authorized_switch =
699 self.prior_voters.last().map(|range| range.2).unwrap_or(0);
700
701 assert!(target_epoch > *latest_epoch);
708
709 self.prior_voters.append((
711 *latest_authorized_pubkey,
712 epoch_of_last_authorized_switch,
713 target_epoch,
714 ));
715 }
716
717 self.authorized_voters
718 .insert(target_epoch, *authorized_pubkey);
719
720 Ok(())
721 }
722
723 pub fn get_and_update_authorized_voter(
724 &mut self,
725 current_epoch: Epoch,
726 ) -> Result<Pubkey, InstructionError> {
727 let pubkey = self
728 .authorized_voters
729 .get_and_cache_authorized_voter_for_epoch(current_epoch)
730 .ok_or(InstructionError::InvalidAccountData)?;
731 self.authorized_voters
732 .purge_authorized_voters(current_epoch);
733 Ok(pubkey)
734 }
735
736 pub fn pop_expired_votes(&mut self, next_vote_slot: Slot) {
741 while let Some(vote) = self.last_lockout() {
742 if !vote.is_locked_out_at_slot(next_vote_slot) {
743 self.votes.pop_back();
744 } else {
745 break;
746 }
747 }
748 }
749
750 pub fn double_lockouts(&mut self) {
751 let stack_depth = self.votes.len();
752 for (i, v) in self.votes.iter_mut().enumerate() {
753 if stack_depth >
756 i.checked_add(v.confirmation_count() as usize)
757 .expect("`confirmation_count` and tower_size should be bounded by `MAX_LOCKOUT_HISTORY`")
758 {
759 v.lockout.increase_confirmation_count(1);
760 }
761 }
762 }
763
764 pub fn process_timestamp(
765 &mut self,
766 slot: Slot,
767 timestamp: UnixTimestamp,
768 ) -> Result<(), VoteError> {
769 if (slot < self.last_timestamp.slot || timestamp < self.last_timestamp.timestamp)
770 || (slot == self.last_timestamp.slot
771 && BlockTimestamp { slot, timestamp } != self.last_timestamp
772 && self.last_timestamp.slot != 0)
773 {
774 return Err(VoteError::TimestampTooOld);
775 }
776 self.last_timestamp = BlockTimestamp { slot, timestamp };
777 Ok(())
778 }
779
780 pub fn is_correct_size_and_initialized(data: &[u8]) -> bool {
781 const VERSION_OFFSET: usize = 4;
782 const DEFAULT_PRIOR_VOTERS_END: usize = VERSION_OFFSET + DEFAULT_PRIOR_VOTERS_OFFSET;
783 data.len() == VoteState::size_of()
784 && data[VERSION_OFFSET..DEFAULT_PRIOR_VOTERS_END] != [0; DEFAULT_PRIOR_VOTERS_OFFSET]
785 }
786}
787
788pub mod serde_compact_vote_state_update {
789 use {
790 super::*,
791 crate::{
792 clock::{Slot, UnixTimestamp},
793 serde_varint, short_vec,
794 vote::state::Lockout,
795 },
796 serde::{Deserialize, Deserializer, Serialize, Serializer},
797 };
798
799 #[derive(Deserialize, Serialize, AbiExample)]
800 struct LockoutOffset {
801 #[serde(with = "serde_varint")]
802 offset: Slot,
803 confirmation_count: u8,
804 }
805
806 #[derive(Deserialize, Serialize)]
807 struct CompactVoteStateUpdate {
808 root: Slot,
809 #[serde(with = "short_vec")]
810 lockout_offsets: Vec<LockoutOffset>,
811 hash: Hash,
812 timestamp: Option<UnixTimestamp>,
813 }
814
815 pub fn serialize<S>(
816 vote_state_update: &VoteStateUpdate,
817 serializer: S,
818 ) -> Result<S::Ok, S::Error>
819 where
820 S: Serializer,
821 {
822 let lockout_offsets = vote_state_update.lockouts.iter().scan(
823 vote_state_update.root.unwrap_or_default(),
824 |slot, lockout| {
825 let Some(offset) = lockout.slot().checked_sub(*slot) else {
826 return Some(Err(serde::ser::Error::custom("Invalid vote lockout")));
827 };
828 let Ok(confirmation_count) = u8::try_from(lockout.confirmation_count()) else {
829 return Some(Err(serde::ser::Error::custom("Invalid confirmation count")));
830 };
831 let lockout_offset = LockoutOffset {
832 offset,
833 confirmation_count,
834 };
835 *slot = lockout.slot();
836 Some(Ok(lockout_offset))
837 },
838 );
839 let compact_vote_state_update = CompactVoteStateUpdate {
840 root: vote_state_update.root.unwrap_or(Slot::MAX),
841 lockout_offsets: lockout_offsets.collect::<Result<_, _>>()?,
842 hash: vote_state_update.hash,
843 timestamp: vote_state_update.timestamp,
844 };
845 compact_vote_state_update.serialize(serializer)
846 }
847
848 pub fn deserialize<'de, D>(deserializer: D) -> Result<VoteStateUpdate, D::Error>
849 where
850 D: Deserializer<'de>,
851 {
852 let CompactVoteStateUpdate {
853 root,
854 lockout_offsets,
855 hash,
856 timestamp,
857 } = CompactVoteStateUpdate::deserialize(deserializer)?;
858 let root = (root != Slot::MAX).then_some(root);
859 let lockouts =
860 lockout_offsets
861 .iter()
862 .scan(root.unwrap_or_default(), |slot, lockout_offset| {
863 *slot = match slot.checked_add(lockout_offset.offset) {
864 None => {
865 return Some(Err(serde::de::Error::custom("Invalid lockout offset")))
866 }
867 Some(slot) => slot,
868 };
869 let lockout = Lockout::new_with_confirmation_count(
870 *slot,
871 u32::from(lockout_offset.confirmation_count),
872 );
873 Some(Ok(lockout))
874 });
875 Ok(VoteStateUpdate {
876 root,
877 lockouts: lockouts.collect::<Result<_, _>>()?,
878 hash,
879 timestamp,
880 })
881 }
882}
883
884#[cfg(test)]
885mod tests {
886 use {super::*, itertools::Itertools, rand::Rng};
887
888 #[test]
889 fn test_vote_serialize() {
890 let mut buffer: Vec<u8> = vec![0; VoteState::size_of()];
891 let mut vote_state = VoteState::default();
892 vote_state
893 .votes
894 .resize(MAX_LOCKOUT_HISTORY, LandedVote::default());
895 vote_state.root_slot = Some(1);
896 let versioned = VoteStateVersions::new_current(vote_state);
897 assert!(VoteState::serialize(&versioned, &mut buffer[0..4]).is_err());
898 VoteState::serialize(&versioned, &mut buffer).unwrap();
899 assert_eq!(
900 VoteState::deserialize(&buffer).unwrap(),
901 versioned.convert_to_current()
902 );
903 }
904
905 #[test]
906 fn test_vote_deserialize_into() {
907 let target_vote_state = VoteState::default();
909 let vote_state_buf =
910 bincode::serialize(&VoteStateVersions::new_current(target_vote_state.clone())).unwrap();
911
912 let mut test_vote_state = VoteState::default();
913 VoteState::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap();
914
915 assert_eq!(target_vote_state, test_vote_state);
916
917 let struct_bytes_x4 = std::mem::size_of::<VoteState>() * 4;
920 for _ in 0..1000 {
921 let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
922 let mut unstructured = Unstructured::new(&raw_data);
923
924 let target_vote_state_versions =
925 VoteStateVersions::arbitrary(&mut unstructured).unwrap();
926 let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
927 let target_vote_state = target_vote_state_versions.convert_to_current();
928
929 let mut test_vote_state = VoteState::default();
930 VoteState::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap();
931
932 assert_eq!(target_vote_state, test_vote_state);
933 }
934 }
935
936 #[test]
937 fn test_vote_deserialize_into_nopanic() {
938 let mut test_vote_state = VoteState::default();
940 let e = VoteState::deserialize_into(&[], &mut test_vote_state).unwrap_err();
941 assert_eq!(e, InstructionError::InvalidAccountData);
942
943 let serialized_len_x4 = serialized_size(&test_vote_state).unwrap() * 4;
945 let mut rng = rand::thread_rng();
946 for _ in 0..1000 {
947 let raw_data_length = rng.gen_range(1..serialized_len_x4);
948 let raw_data: Vec<u8> = (0..raw_data_length).map(|_| rng.gen::<u8>()).collect();
949
950 let mut test_vote_state = VoteState::default();
953 let _ = VoteState::deserialize_into(&raw_data, &mut test_vote_state);
954 }
955 }
956
957 #[test]
958 fn test_vote_state_commission_split() {
959 let vote_state = VoteState::default();
960
961 assert_eq!(vote_state.commission_split(1), (0, 1, false));
962
963 let mut vote_state = VoteState {
964 commission: std::u8::MAX,
965 ..VoteState::default()
966 };
967 assert_eq!(vote_state.commission_split(1), (1, 0, false));
968
969 vote_state.commission = 99;
970 assert_eq!(vote_state.commission_split(10), (9, 0, true));
971
972 vote_state.commission = 1;
973 assert_eq!(vote_state.commission_split(10), (0, 9, true));
974
975 vote_state.commission = 50;
976 let (voter_portion, staker_portion, was_split) = vote_state.commission_split(10);
977
978 assert_eq!((voter_portion, staker_portion, was_split), (5, 5, true));
979 }
980
981 #[test]
982 fn test_vote_state_epoch_credits() {
983 let mut vote_state = VoteState::default();
984
985 assert_eq!(vote_state.credits(), 0);
986 assert_eq!(vote_state.epoch_credits().clone(), vec![]);
987
988 let mut expected = vec![];
989 let mut credits = 0;
990 let epochs = (MAX_EPOCH_CREDITS_HISTORY + 2) as u64;
991 for epoch in 0..epochs {
992 for _j in 0..epoch {
993 vote_state.increment_credits(epoch, 1);
994 credits += 1;
995 }
996 expected.push((epoch, credits, credits - epoch));
997 }
998
999 while expected.len() > MAX_EPOCH_CREDITS_HISTORY {
1000 expected.remove(0);
1001 }
1002
1003 assert_eq!(vote_state.credits(), credits);
1004 assert_eq!(vote_state.epoch_credits().clone(), expected);
1005 }
1006
1007 #[test]
1008 fn test_vote_state_epoch0_no_credits() {
1009 let mut vote_state = VoteState::default();
1010
1011 assert_eq!(vote_state.epoch_credits().len(), 0);
1012 vote_state.increment_credits(1, 1);
1013 assert_eq!(vote_state.epoch_credits().len(), 1);
1014
1015 vote_state.increment_credits(2, 1);
1016 assert_eq!(vote_state.epoch_credits().len(), 2);
1017 }
1018
1019 #[test]
1020 fn test_vote_state_increment_credits() {
1021 let mut vote_state = VoteState::default();
1022
1023 let credits = (MAX_EPOCH_CREDITS_HISTORY + 2) as u64;
1024 for i in 0..credits {
1025 vote_state.increment_credits(i, 1);
1026 }
1027 assert_eq!(vote_state.credits(), credits);
1028 assert!(vote_state.epoch_credits().len() <= MAX_EPOCH_CREDITS_HISTORY);
1029 }
1030
1031 #[test]
1032 fn test_vote_process_timestamp() {
1033 let (slot, timestamp) = (15, 1_575_412_285);
1034 let mut vote_state = VoteState {
1035 last_timestamp: BlockTimestamp { slot, timestamp },
1036 ..VoteState::default()
1037 };
1038
1039 assert_eq!(
1040 vote_state.process_timestamp(slot - 1, timestamp + 1),
1041 Err(VoteError::TimestampTooOld)
1042 );
1043 assert_eq!(
1044 vote_state.last_timestamp,
1045 BlockTimestamp { slot, timestamp }
1046 );
1047 assert_eq!(
1048 vote_state.process_timestamp(slot + 1, timestamp - 1),
1049 Err(VoteError::TimestampTooOld)
1050 );
1051 assert_eq!(
1052 vote_state.process_timestamp(slot, timestamp + 1),
1053 Err(VoteError::TimestampTooOld)
1054 );
1055 assert_eq!(vote_state.process_timestamp(slot, timestamp), Ok(()));
1056 assert_eq!(
1057 vote_state.last_timestamp,
1058 BlockTimestamp { slot, timestamp }
1059 );
1060 assert_eq!(vote_state.process_timestamp(slot + 1, timestamp), Ok(()));
1061 assert_eq!(
1062 vote_state.last_timestamp,
1063 BlockTimestamp {
1064 slot: slot + 1,
1065 timestamp
1066 }
1067 );
1068 assert_eq!(
1069 vote_state.process_timestamp(slot + 2, timestamp + 1),
1070 Ok(())
1071 );
1072 assert_eq!(
1073 vote_state.last_timestamp,
1074 BlockTimestamp {
1075 slot: slot + 2,
1076 timestamp: timestamp + 1
1077 }
1078 );
1079
1080 vote_state.last_timestamp = BlockTimestamp::default();
1082 assert_eq!(vote_state.process_timestamp(0, timestamp), Ok(()));
1083 }
1084
1085 #[test]
1086 fn test_get_and_update_authorized_voter() {
1087 let original_voter = Pubkey::new_unique();
1088 let mut vote_state = VoteState::new(
1089 &VoteInit {
1090 node_pubkey: original_voter,
1091 authorized_voter: original_voter,
1092 authorized_withdrawer: original_voter,
1093 commission: 0,
1094 },
1095 &Clock::default(),
1096 );
1097
1098 assert_eq!(vote_state.authorized_voters.len(), 1);
1099 assert_eq!(
1100 *vote_state.authorized_voters.first().unwrap().1,
1101 original_voter
1102 );
1103
1104 assert_eq!(
1107 vote_state.get_and_update_authorized_voter(1).unwrap(),
1108 original_voter
1109 );
1110
1111 assert_eq!(
1114 vote_state.get_and_update_authorized_voter(5).unwrap(),
1115 original_voter
1116 );
1117
1118 assert_eq!(vote_state.authorized_voters.len(), 1);
1121 for i in 0..5 {
1122 assert!(vote_state
1123 .authorized_voters
1124 .get_authorized_voter(i)
1125 .is_none());
1126 }
1127
1128 let new_authorized_voter = Pubkey::new_unique();
1130 vote_state
1131 .set_new_authorized_voter(&new_authorized_voter, 5, 7, |_| Ok(()))
1132 .unwrap();
1133
1134 assert_eq!(
1136 vote_state.get_and_update_authorized_voter(6).unwrap(),
1137 original_voter
1138 );
1139
1140 for i in 7..10 {
1143 assert_eq!(
1144 vote_state.get_and_update_authorized_voter(i).unwrap(),
1145 new_authorized_voter
1146 );
1147 }
1148 assert_eq!(vote_state.authorized_voters.len(), 1);
1149 }
1150
1151 #[test]
1152 fn test_set_new_authorized_voter() {
1153 let original_voter = Pubkey::new_unique();
1154 let epoch_offset = 15;
1155 let mut vote_state = VoteState::new(
1156 &VoteInit {
1157 node_pubkey: original_voter,
1158 authorized_voter: original_voter,
1159 authorized_withdrawer: original_voter,
1160 commission: 0,
1161 },
1162 &Clock::default(),
1163 );
1164
1165 assert!(vote_state.prior_voters.last().is_none());
1166
1167 let new_voter = Pubkey::new_unique();
1168 vote_state
1170 .set_new_authorized_voter(&new_voter, 0, epoch_offset, |_| Ok(()))
1171 .unwrap();
1172
1173 assert_eq!(vote_state.prior_voters.idx, 0);
1174 assert_eq!(
1175 vote_state.prior_voters.last(),
1176 Some(&(original_voter, 0, epoch_offset))
1177 );
1178
1179 assert_eq!(
1181 vote_state.set_new_authorized_voter(&new_voter, 0, epoch_offset, |_| Ok(())),
1182 Err(VoteError::TooSoonToReauthorize.into())
1183 );
1184
1185 vote_state
1187 .set_new_authorized_voter(&new_voter, 2, 2 + epoch_offset, |_| Ok(()))
1188 .unwrap();
1189
1190 let new_voter2 = Pubkey::new_unique();
1192 vote_state
1193 .set_new_authorized_voter(&new_voter2, 3, 3 + epoch_offset, |_| Ok(()))
1194 .unwrap();
1195 assert_eq!(vote_state.prior_voters.idx, 1);
1196 assert_eq!(
1197 vote_state.prior_voters.last(),
1198 Some(&(new_voter, epoch_offset, 3 + epoch_offset))
1199 );
1200
1201 let new_voter3 = Pubkey::new_unique();
1202 vote_state
1203 .set_new_authorized_voter(&new_voter3, 6, 6 + epoch_offset, |_| Ok(()))
1204 .unwrap();
1205 assert_eq!(vote_state.prior_voters.idx, 2);
1206 assert_eq!(
1207 vote_state.prior_voters.last(),
1208 Some(&(new_voter2, 3 + epoch_offset, 6 + epoch_offset))
1209 );
1210
1211 vote_state
1213 .set_new_authorized_voter(&original_voter, 9, 9 + epoch_offset, |_| Ok(()))
1214 .unwrap();
1215
1216 for i in 9..epoch_offset {
1219 assert_eq!(
1220 vote_state.get_and_update_authorized_voter(i).unwrap(),
1221 original_voter
1222 );
1223 }
1224 for i in epoch_offset..3 + epoch_offset {
1225 assert_eq!(
1226 vote_state.get_and_update_authorized_voter(i).unwrap(),
1227 new_voter
1228 );
1229 }
1230 for i in 3 + epoch_offset..6 + epoch_offset {
1231 assert_eq!(
1232 vote_state.get_and_update_authorized_voter(i).unwrap(),
1233 new_voter2
1234 );
1235 }
1236 for i in 6 + epoch_offset..9 + epoch_offset {
1237 assert_eq!(
1238 vote_state.get_and_update_authorized_voter(i).unwrap(),
1239 new_voter3
1240 );
1241 }
1242 for i in 9 + epoch_offset..=10 + epoch_offset {
1243 assert_eq!(
1244 vote_state.get_and_update_authorized_voter(i).unwrap(),
1245 original_voter
1246 );
1247 }
1248 }
1249
1250 #[test]
1251 fn test_authorized_voter_is_locked_within_epoch() {
1252 let original_voter = Pubkey::new_unique();
1253 let mut vote_state = VoteState::new(
1254 &VoteInit {
1255 node_pubkey: original_voter,
1256 authorized_voter: original_voter,
1257 authorized_withdrawer: original_voter,
1258 commission: 0,
1259 },
1260 &Clock::default(),
1261 );
1262
1263 let new_voter = Pubkey::new_unique();
1267 assert_eq!(
1268 vote_state.set_new_authorized_voter(&new_voter, 1, 1, |_| Ok(())),
1269 Err(VoteError::TooSoonToReauthorize.into())
1270 );
1271
1272 assert_eq!(vote_state.get_authorized_voter(1), Some(original_voter));
1273
1274 assert_eq!(
1276 vote_state.set_new_authorized_voter(&new_voter, 1, 2, |_| Ok(())),
1277 Ok(())
1278 );
1279
1280 assert_eq!(
1284 vote_state.set_new_authorized_voter(&original_voter, 3, 3, |_| Ok(())),
1285 Err(VoteError::TooSoonToReauthorize.into())
1286 );
1287
1288 assert_eq!(vote_state.get_authorized_voter(3), Some(new_voter));
1289 }
1290
1291 #[test]
1292 fn test_vote_state_size_of() {
1293 let vote_state = VoteState::get_max_sized_vote_state();
1294 let vote_state = VoteStateVersions::new_current(vote_state);
1295 let size = serialized_size(&vote_state).unwrap();
1296 assert_eq!(VoteState::size_of() as u64, size);
1297 }
1298
1299 #[test]
1300 fn test_vote_state_max_size() {
1301 let mut max_sized_data = vec![0; VoteState::size_of()];
1302 let vote_state = VoteState::get_max_sized_vote_state();
1303 let (start_leader_schedule_epoch, _) = vote_state.authorized_voters.last().unwrap();
1304 let start_current_epoch =
1305 start_leader_schedule_epoch - MAX_LEADER_SCHEDULE_EPOCH_OFFSET + 1;
1306
1307 let mut vote_state = Some(vote_state);
1308 for i in start_current_epoch..start_current_epoch + 2 * MAX_LEADER_SCHEDULE_EPOCH_OFFSET {
1309 vote_state.as_mut().map(|vote_state| {
1310 vote_state.set_new_authorized_voter(
1311 &Pubkey::new_unique(),
1312 i,
1313 i + MAX_LEADER_SCHEDULE_EPOCH_OFFSET,
1314 |_| Ok(()),
1315 )
1316 });
1317
1318 let versioned = VoteStateVersions::new_current(vote_state.take().unwrap());
1319 VoteState::serialize(&versioned, &mut max_sized_data).unwrap();
1320 vote_state = Some(versioned.convert_to_current());
1321 }
1322 }
1323
1324 #[test]
1325 fn test_default_vote_state_is_uninitialized() {
1326 assert!(VoteStateVersions::new_current(VoteState::default()).is_uninitialized());
1330 }
1331
1332 #[test]
1333 fn test_is_correct_size_and_initialized() {
1334 let mut vote_account_data = vec![0; VoteStateVersions::vote_state_size_of(true)];
1336 assert!(!VoteStateVersions::is_correct_size_and_initialized(
1337 &vote_account_data
1338 ));
1339
1340 let default_account_state = VoteStateVersions::new_current(VoteState::default());
1342 VoteState::serialize(&default_account_state, &mut vote_account_data).unwrap();
1343 assert!(!VoteStateVersions::is_correct_size_and_initialized(
1344 &vote_account_data
1345 ));
1346
1347 let short_data = vec![1; DEFAULT_PRIOR_VOTERS_OFFSET];
1349 assert!(!VoteStateVersions::is_correct_size_and_initialized(
1350 &short_data
1351 ));
1352
1353 let mut large_vote_data = vec![1; 2 * VoteStateVersions::vote_state_size_of(true)];
1355 let default_account_state = VoteStateVersions::new_current(VoteState::default());
1356 VoteState::serialize(&default_account_state, &mut large_vote_data).unwrap();
1357 assert!(!VoteStateVersions::is_correct_size_and_initialized(
1358 &vote_account_data
1359 ));
1360
1361 let vote_state = VoteState::new(
1363 &VoteInit {
1364 node_pubkey: Pubkey::new_unique(),
1365 authorized_voter: Pubkey::new_unique(),
1366 authorized_withdrawer: Pubkey::new_unique(),
1367 commission: 0,
1368 },
1369 &Clock::default(),
1370 );
1371 let account_state = VoteStateVersions::new_current(vote_state.clone());
1372 VoteState::serialize(&account_state, &mut vote_account_data).unwrap();
1373 assert!(VoteStateVersions::is_correct_size_and_initialized(
1374 &vote_account_data
1375 ));
1376
1377 let old_vote_state = VoteState1_14_11::from(vote_state);
1379 let account_state = VoteStateVersions::V1_14_11(Box::new(old_vote_state));
1380 let mut vote_account_data = vec![0; VoteStateVersions::vote_state_size_of(false)];
1381 VoteState::serialize(&account_state, &mut vote_account_data).unwrap();
1382 assert!(VoteStateVersions::is_correct_size_and_initialized(
1383 &vote_account_data
1384 ));
1385 }
1386
1387 #[test]
1388 fn test_minimum_balance() {
1389 let rent = miraland_program::rent::Rent::default();
1390 let minimum_balance = rent.minimum_balance(VoteState::size_of());
1391 assert!(minimum_balance as f64 / 10f64.powf(9.0) < 0.04)
1393 }
1394
1395 #[test]
1396 fn test_serde_compact_vote_state_update() {
1397 let mut rng = rand::thread_rng();
1398 for _ in 0..5000 {
1399 run_serde_compact_vote_state_update(&mut rng);
1400 }
1401 }
1402
1403 fn run_serde_compact_vote_state_update<R: Rng>(rng: &mut R) {
1404 let lockouts: VecDeque<_> = std::iter::repeat_with(|| {
1405 let slot = 149_303_885_u64.saturating_add(rng.gen_range(0..10_000));
1406 let confirmation_count = rng.gen_range(0..33);
1407 Lockout::new_with_confirmation_count(slot, confirmation_count)
1408 })
1409 .take(32)
1410 .sorted_by_key(|lockout| lockout.slot())
1411 .collect();
1412 let root = rng.gen_ratio(1, 2).then(|| {
1413 lockouts[0]
1414 .slot()
1415 .checked_sub(rng.gen_range(0..1_000))
1416 .expect("All slots should be greater than 1_000")
1417 });
1418 let timestamp = rng.gen_ratio(1, 2).then(|| rng.gen());
1419 let hash = Hash::from(rng.gen::<[u8; 32]>());
1420 let vote_state_update = VoteStateUpdate {
1421 lockouts,
1422 root,
1423 hash,
1424 timestamp,
1425 };
1426 #[derive(Debug, Eq, PartialEq, Deserialize, Serialize)]
1427 enum VoteInstruction {
1428 #[serde(with = "serde_compact_vote_state_update")]
1429 UpdateVoteState(VoteStateUpdate),
1430 UpdateVoteStateSwitch(
1431 #[serde(with = "serde_compact_vote_state_update")] VoteStateUpdate,
1432 Hash,
1433 ),
1434 }
1435 let vote = VoteInstruction::UpdateVoteState(vote_state_update.clone());
1436 let bytes = bincode::serialize(&vote).unwrap();
1437 assert_eq!(vote, bincode::deserialize(&bytes).unwrap());
1438 let hash = Hash::from(rng.gen::<[u8; 32]>());
1439 let vote = VoteInstruction::UpdateVoteStateSwitch(vote_state_update, hash);
1440 let bytes = bincode::serialize(&vote).unwrap();
1441 assert_eq!(vote, bincode::deserialize(&bytes).unwrap());
1442 }
1443}