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