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