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