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