1#[cfg(feature = "bincode")]
2use super::VoteStateVersions;
3#[cfg(test)]
4use super::{MAX_EPOCH_CREDITS_HISTORY, MAX_LOCKOUT_HISTORY};
5#[cfg(feature = "dev-context-only-utils")]
6use arbitrary::Arbitrary;
7#[cfg(feature = "serde")]
8use serde_derive::{Deserialize, Serialize};
9#[cfg(feature = "frozen-abi")]
10use solana_frozen_abi_macro::{frozen_abi, AbiExample, StableAbi, StableAbiSample};
11#[cfg(any(target_os = "solana", feature = "bincode"))]
12use solana_instruction_error::InstructionError;
13use {
14 super::{BlockTimestamp, CircBuf, LandedVote, Lockout, VoteInit},
15 crate::{authorized_voters::AuthorizedVoters, state::DEFAULT_PRIOR_VOTERS_OFFSET},
16 solana_clock::{Clock, Epoch, Slot},
17 solana_pubkey::Pubkey,
18 solana_rent::Rent,
19 std::{collections::VecDeque, fmt::Debug},
20};
21
22#[cfg_attr(
23 feature = "frozen-abi",
24 frozen_abi(
25 api_digest = "pZqasQc6duzMYzpzU7eriHH9cMXmubuUP4NmCrkWZjt",
26 abi_digest = "4VUwurjnJ96aMgYXaAmkDut56mMkC4uo6b5bm8iH7WzJ",
27 abi_serializer = ["bincode", "wincode"]
28 ),
29 derive(AbiExample, StableAbi, StableAbiSample)
30)]
31#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
32#[cfg_attr(feature = "wincode", derive(wincode::SchemaWrite, wincode::SchemaRead))]
33#[derive(Debug, Default, PartialEq, Eq, Clone)]
34#[cfg_attr(feature = "dev-context-only-utils", derive(Arbitrary))]
35pub struct VoteStateV3 {
36 pub node_pubkey: Pubkey,
38
39 pub authorized_withdrawer: Pubkey,
41 pub commission: u8,
44
45 pub votes: VecDeque<LandedVote>,
46
47 pub root_slot: Option<Slot>,
50
51 pub authorized_voters: AuthorizedVoters,
53
54 pub prior_voters: CircBuf<(Pubkey, Epoch, Epoch)>,
58
59 pub epoch_credits: Vec<(Epoch, u64, u64)>,
62
63 pub last_timestamp: BlockTimestamp,
65}
66
67impl VoteStateV3 {
68 pub fn new(vote_init: &VoteInit, clock: &Clock) -> Self {
69 Self {
70 node_pubkey: vote_init.node_pubkey,
71 authorized_voters: AuthorizedVoters::new(clock.epoch, vote_init.authorized_voter),
72 authorized_withdrawer: vote_init.authorized_withdrawer,
73 commission: vote_init.commission,
74 ..VoteStateV3::default()
75 }
76 }
77
78 pub fn new_rand_for_tests(node_pubkey: Pubkey, root_slot: Slot) -> Self {
79 let votes = (1..32)
80 .map(|x| LandedVote {
81 latency: 0,
82 lockout: Lockout::new_with_confirmation_count(
83 u64::from(x).saturating_add(root_slot),
84 32_u32.saturating_sub(x),
85 ),
86 })
87 .collect();
88 Self {
89 node_pubkey,
90 root_slot: Some(root_slot),
91 votes,
92 ..VoteStateV3::default()
93 }
94 }
95
96 #[deprecated(
97 since = "5.1.0",
98 note = "Use `rent.minimum_balance(VoteStateV3::size_of())` directly"
99 )]
100 pub fn get_rent_exempt_reserve(rent: &Rent) -> u64 {
101 rent.minimum_balance(VoteStateV3::size_of())
102 }
103
104 pub const fn size_of() -> usize {
107 3762 }
109
110 pub fn is_uninitialized(&self) -> bool {
111 self.authorized_voters.is_empty()
112 }
113
114 #[cfg(any(target_os = "solana", feature = "bincode"))]
115 pub fn deserialize(input: &[u8]) -> Result<Self, InstructionError> {
116 let mut vote_state = Self::default();
117 Self::deserialize_into(input, &mut vote_state)?;
118 Ok(vote_state)
119 }
120
121 #[cfg(any(target_os = "solana", feature = "bincode"))]
128 pub fn deserialize_into(
129 input: &[u8],
130 vote_state: &mut VoteStateV3,
131 ) -> Result<(), InstructionError> {
132 use super::vote_state_deserialize;
133 vote_state_deserialize::deserialize_into(input, vote_state, Self::deserialize_into_ptr)
134 }
135
136 #[cfg(any(target_os = "solana", feature = "bincode"))]
147 pub fn deserialize_into_uninit(
148 input: &[u8],
149 vote_state: &mut std::mem::MaybeUninit<VoteStateV3>,
150 ) -> Result<(), InstructionError> {
151 VoteStateV3::deserialize_into_ptr(input, vote_state.as_mut_ptr())
152 }
153
154 #[cfg(any(target_os = "solana", feature = "bincode"))]
155 fn deserialize_into_ptr(
156 input: &[u8],
157 vote_state: *mut VoteStateV3,
158 ) -> Result<(), InstructionError> {
159 use super::vote_state_deserialize::deserialize_vote_state_into_v3;
160
161 let mut cursor = std::io::Cursor::new(input);
162
163 let variant = solana_serialize_utils::cursor::read_u32(&mut cursor)?;
164 match variant {
165 0 => Err(InstructionError::InvalidAccountData),
167 1 => deserialize_vote_state_into_v3(&mut cursor, vote_state, false),
169 2 => deserialize_vote_state_into_v3(&mut cursor, vote_state, true),
171 _ => Err(InstructionError::InvalidAccountData),
172 }?;
173
174 Ok(())
175 }
176
177 #[cfg(feature = "bincode")]
178 pub fn serialize(
179 versioned: &VoteStateVersions,
180 output: &mut [u8],
181 ) -> Result<(), InstructionError> {
182 bincode::serialize_into(output, versioned).map_err(|err| match *err {
183 bincode::ErrorKind::SizeLimit => InstructionError::AccountDataTooSmall,
184 _ => InstructionError::GenericError,
185 })
186 }
187
188 #[cfg(test)]
189 pub(crate) fn get_max_sized_vote_state() -> VoteStateV3 {
190 use solana_epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET;
191 let mut authorized_voters = AuthorizedVoters::default();
192 for i in 0..=MAX_LEADER_SCHEDULE_EPOCH_OFFSET {
193 authorized_voters.insert(i, Pubkey::new_unique());
194 }
195
196 VoteStateV3 {
197 votes: VecDeque::from(vec![LandedVote::default(); MAX_LOCKOUT_HISTORY]),
198 root_slot: Some(u64::MAX),
199 epoch_credits: vec![(0, 0, 0); MAX_EPOCH_CREDITS_HISTORY],
200 authorized_voters,
201 ..Self::default()
202 }
203 }
204
205 pub fn current_epoch(&self) -> Epoch {
206 self.epoch_credits.last().map_or(0, |v| v.0)
207 }
208
209 pub fn credits(&self) -> u64 {
212 self.epoch_credits.last().map_or(0, |v| v.1)
213 }
214
215 pub fn is_correct_size_and_initialized(data: &[u8]) -> bool {
216 const VERSION_OFFSET: usize = 4;
217 const DEFAULT_PRIOR_VOTERS_END: usize = VERSION_OFFSET + DEFAULT_PRIOR_VOTERS_OFFSET;
218 data.len() == VoteStateV3::size_of()
219 && data[VERSION_OFFSET..DEFAULT_PRIOR_VOTERS_END] != [0; DEFAULT_PRIOR_VOTERS_OFFSET]
220 }
221}
222
223#[cfg(test)]
224mod tests {
225 use {
226 super::{
227 super::{VoteState1_14_11, VoteStateVersions, MAX_LOCKOUT_HISTORY},
228 *,
229 },
230 arbitrary::Unstructured,
231 bincode::serialized_size,
232 core::mem::MaybeUninit,
233 rand::Rng,
234 solana_instruction::error::InstructionError,
235 };
236
237 #[test]
238 fn test_size_of() {
239 let vote_state = VoteStateV3::get_max_sized_vote_state();
240 let vote_state = VoteStateVersions::new_v3(vote_state);
241 let size = serialized_size(&vote_state).unwrap();
242 assert_eq!(VoteStateV3::size_of() as u64, size);
243 }
244
245 #[test]
246 fn test_minimum_balance() {
247 let rent = solana_rent::Rent::default();
248 let minimum_balance = rent.minimum_balance(VoteStateV3::size_of());
249 assert!(minimum_balance as f64 / 10f64.powf(9.0) < 0.04)
251 }
252
253 #[test]
254 fn test_vote_serialize() {
255 let mut buffer: Vec<u8> = vec![0; VoteStateV3::size_of()];
256 let mut vote_state = VoteStateV3::default();
257 vote_state
258 .votes
259 .resize(MAX_LOCKOUT_HISTORY, LandedVote::default());
260 vote_state.root_slot = Some(1);
261 let versioned = VoteStateVersions::new_v3(vote_state);
262 assert!(VoteStateV3::serialize(&versioned, &mut buffer[0..4]).is_err());
263 VoteStateV3::serialize(&versioned, &mut buffer).unwrap();
264 assert_eq!(
265 VoteStateV3::deserialize(&buffer).unwrap(),
266 versioned.try_convert_to_v3().unwrap()
267 );
268 }
269
270 #[test]
271 fn test_vote_deserialize_into() {
272 let target_vote_state = VoteStateV3::default();
274 let vote_state_buf =
275 bincode::serialize(&VoteStateVersions::new_v3(target_vote_state.clone())).unwrap();
276
277 let mut test_vote_state = VoteStateV3::default();
278 VoteStateV3::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap();
279
280 assert_eq!(target_vote_state, test_vote_state);
281
282 let struct_bytes_x4 = std::mem::size_of::<VoteStateV3>() * 4;
285 for _ in 0..1000 {
286 let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
287 let mut unstructured = Unstructured::new(&raw_data);
288
289 let target_vote_state_versions =
290 VoteStateVersions::arbitrary(&mut unstructured).unwrap();
291 let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
292
293 if let Ok(target_vote_state) = target_vote_state_versions.try_convert_to_v3() {
295 let mut test_vote_state = VoteStateV3::default();
296 VoteStateV3::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap();
297
298 assert_eq!(target_vote_state, test_vote_state);
299 }
300 }
301 }
302
303 #[test]
304 fn test_vote_deserialize_into_trailing_data() {
305 let target_vote_state = VoteStateV3::new_rand_for_tests(Pubkey::new_unique(), 42);
306 let vote_state_buf =
307 bincode::serialize(&VoteStateVersions::new_v3(target_vote_state.clone())).unwrap();
308
309 let mut buf_with_garbage = vote_state_buf.clone();
311 buf_with_garbage.extend_from_slice(&[0xDE, 0xAD, 0xBE, 0xEF]);
312 let mut test_vote_state = VoteStateV3::default();
313 VoteStateV3::deserialize_into(&buf_with_garbage, &mut test_vote_state).unwrap();
314 assert_eq!(target_vote_state, test_vote_state);
315
316 let mut buf_with_zeroes = vote_state_buf;
318 buf_with_zeroes.extend_from_slice(&[0u8; 64]);
319 let mut test_vote_state = VoteStateV3::default();
320 VoteStateV3::deserialize_into(&buf_with_zeroes, &mut test_vote_state).unwrap();
321 assert_eq!(target_vote_state, test_vote_state);
322 }
323
324 #[test]
325 fn test_vote_deserialize_into_error() {
326 let target_vote_state = VoteStateV3::new_rand_for_tests(Pubkey::new_unique(), 42);
327 let mut vote_state_buf =
328 bincode::serialize(&VoteStateVersions::new_v3(target_vote_state.clone())).unwrap();
329 let len = vote_state_buf.len();
330 vote_state_buf.truncate(len - 1);
331
332 let mut test_vote_state = VoteStateV3::default();
333 VoteStateV3::deserialize_into(&vote_state_buf, &mut test_vote_state).unwrap_err();
334 assert_eq!(test_vote_state, VoteStateV3::default());
335 }
336
337 #[test]
338 fn test_vote_deserialize_into_error_with_pre_state() {
339 let mut vote_state = VoteStateV3::new_rand_for_tests(Pubkey::new_unique(), 42);
341 vote_state.epoch_credits = vec![(0, 100, 0), (1, 200, 100), (2, 300, 200)];
342
343 let mut buf =
345 bincode::serialize(&VoteStateVersions::new_v3(VoteStateV3::default())).unwrap();
346 buf.truncate(buf.len() - 1);
347
348 VoteStateV3::deserialize_into(&buf, &mut vote_state).unwrap_err();
349 assert_eq!(vote_state, VoteStateV3::default());
351 }
352
353 #[test]
354 fn test_deserialize_into_uninit_no_reset_on_error() {
355 let target = VoteStateV3::new_rand_for_tests(Pubkey::new_unique(), 42);
360 let mut buf = bincode::serialize(&VoteStateVersions::new_v3(target)).unwrap();
361 buf.truncate(buf.len() - 1);
362
363 let mut test_vote_state = MaybeUninit::uninit();
364 let err = VoteStateV3::deserialize_into_uninit(&buf, &mut test_vote_state);
365 assert_eq!(err, Err(InstructionError::InvalidAccountData));
366 }
368
369 #[test]
370 fn test_vote_deserialize_into_uninit() {
371 let target_vote_state = VoteStateV3::default();
373 let vote_state_buf =
374 bincode::serialize(&VoteStateVersions::new_v3(target_vote_state.clone())).unwrap();
375
376 let mut test_vote_state = MaybeUninit::uninit();
377 VoteStateV3::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state).unwrap();
378 let test_vote_state = unsafe { test_vote_state.assume_init() };
379
380 assert_eq!(target_vote_state, test_vote_state);
381
382 let struct_bytes_x4 = std::mem::size_of::<VoteStateV3>() * 4;
385 for _ in 0..1000 {
386 let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
387 let mut unstructured = Unstructured::new(&raw_data);
388
389 let target_vote_state_versions =
390 VoteStateVersions::arbitrary(&mut unstructured).unwrap();
391 let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
392
393 if let Ok(target_vote_state) = target_vote_state_versions.try_convert_to_v3() {
395 let mut test_vote_state = MaybeUninit::uninit();
396 VoteStateV3::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state)
397 .unwrap();
398 let test_vote_state = unsafe { test_vote_state.assume_init() };
399
400 assert_eq!(target_vote_state, test_vote_state);
401 }
402 }
403 }
404
405 #[test]
406 fn test_vote_deserialize_into_uninit_trailing_data() {
407 let target_vote_state = VoteStateV3::new_rand_for_tests(Pubkey::new_unique(), 42);
408 let vote_state_buf =
409 bincode::serialize(&VoteStateVersions::new_v3(target_vote_state.clone())).unwrap();
410
411 let mut buf_with_garbage = vote_state_buf.clone();
413 buf_with_garbage.extend_from_slice(&[0xDE, 0xAD, 0xBE, 0xEF]);
414 let mut test_vote_state = MaybeUninit::uninit();
415 VoteStateV3::deserialize_into_uninit(&buf_with_garbage, &mut test_vote_state).unwrap();
416 let test_vote_state = unsafe { test_vote_state.assume_init() };
417 assert_eq!(target_vote_state, test_vote_state);
418
419 let mut buf_with_zeroes = vote_state_buf;
421 buf_with_zeroes.extend_from_slice(&[0u8; 64]);
422 let mut test_vote_state = MaybeUninit::uninit();
423 VoteStateV3::deserialize_into_uninit(&buf_with_zeroes, &mut test_vote_state).unwrap();
424 let test_vote_state = unsafe { test_vote_state.assume_init() };
425 assert_eq!(target_vote_state, test_vote_state);
426 }
427
428 #[test]
429 fn test_vote_deserialize_into_uninit_nopanic() {
430 let mut test_vote_state = MaybeUninit::uninit();
432 let e = VoteStateV3::deserialize_into_uninit(&[], &mut test_vote_state).unwrap_err();
433 assert_eq!(e, InstructionError::InvalidAccountData);
434
435 let serialized_len_x4 = serialized_size(&VoteStateV3::default()).unwrap() * 4;
437 let mut rng = rand::rng();
438 for _ in 0..1000 {
439 let raw_data_length = rng.random_range(1..serialized_len_x4);
440 let mut raw_data: Vec<u8> = (0..raw_data_length).map(|_| rng.random::<u8>()).collect();
441
442 if raw_data_length >= 4 && rng.random::<bool>() {
444 let tag = rng.random_range(1u8..=3);
445 raw_data[0] = tag;
446 raw_data[1] = 0;
447 raw_data[2] = 0;
448 raw_data[3] = 0;
449 }
450
451 let mut test_vote_state = MaybeUninit::uninit();
454 let test_res = VoteStateV3::deserialize_into_uninit(&raw_data, &mut test_vote_state);
455
456 let bincode_res = bincode::deserialize::<VoteStateVersions>(&raw_data)
458 .map_err(|_| InstructionError::InvalidAccountData)
459 .and_then(|versioned| versioned.try_convert_to_v3());
460
461 if test_res.is_err() {
462 assert!(bincode_res.is_err());
463 } else {
464 let test_vote_state = unsafe { test_vote_state.assume_init() };
465 assert_eq!(test_vote_state, bincode_res.unwrap());
466 }
467 }
468 }
469
470 #[test]
471 fn test_vote_deserialize_into_uninit_ill_sized() {
472 let struct_bytes_x4 = std::mem::size_of::<VoteStateV3>() * 4;
474 for _ in 0..1000 {
475 let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
476 let mut unstructured = Unstructured::new(&raw_data);
477
478 let original_vote_state_versions =
479 VoteStateVersions::arbitrary(&mut unstructured).unwrap();
480 let original_buf = bincode::serialize(&original_vote_state_versions).unwrap();
481
482 if !matches!(original_vote_state_versions, VoteStateVersions::V4(_)) {
484 let mut truncated_buf = original_buf.clone();
485 let mut expanded_buf = original_buf.clone();
486
487 truncated_buf.resize(original_buf.len() - 8, 0);
488 expanded_buf.resize(original_buf.len() + 8, 0);
489
490 let mut test_vote_state = MaybeUninit::uninit();
492 let test_res =
493 VoteStateV3::deserialize_into_uninit(&truncated_buf, &mut test_vote_state);
494 let bincode_res = bincode::deserialize::<VoteStateVersions>(&truncated_buf)
497 .map_err(|_| InstructionError::InvalidAccountData)
498 .and_then(|versioned| versioned.try_convert_to_v3());
499
500 assert!(test_res.is_err());
501 assert!(bincode_res.is_err());
502
503 let mut test_vote_state = MaybeUninit::uninit();
505 VoteStateV3::deserialize_into_uninit(&expanded_buf, &mut test_vote_state).unwrap();
506 let bincode_res = bincode::deserialize::<VoteStateVersions>(&expanded_buf)
509 .map_err(|_| InstructionError::InvalidAccountData)
510 .and_then(|versioned| versioned.try_convert_to_v3());
511
512 let test_vote_state = unsafe { test_vote_state.assume_init() };
513 assert_eq!(test_vote_state, bincode_res.unwrap());
514 }
515 }
516 }
517
518 #[test]
519 fn test_deserialize_invalid_variant_tags() {
520 let mut buf = vec![0u8; VoteStateV3::size_of()];
521
522 let mut vs = VoteStateV3::default();
524 assert_eq!(
525 VoteStateV3::deserialize_into(&buf, &mut vs),
526 Err(InstructionError::InvalidAccountData)
527 );
528
529 buf[..4].copy_from_slice(&3u32.to_le_bytes());
531 assert_eq!(
532 VoteStateV3::deserialize_into(&buf, &mut vs),
533 Err(InstructionError::InvalidAccountData)
534 );
535
536 buf[..4].copy_from_slice(&4u32.to_le_bytes());
538 assert_eq!(
539 VoteStateV3::deserialize_into(&buf, &mut vs),
540 Err(InstructionError::InvalidAccountData)
541 );
542
543 buf[..4].copy_from_slice(&u32::MAX.to_le_bytes());
545 assert_eq!(
546 VoteStateV3::deserialize_into(&buf, &mut vs),
547 Err(InstructionError::InvalidAccountData)
548 );
549 }
550
551 #[test]
552 fn test_invalid_option_bool_discriminants() {
553 let vote_state = VoteStateV3 {
554 root_slot: Some(42),
555 ..VoteStateV3::default()
556 };
557 let valid_buf = bincode::serialize(&VoteStateVersions::new_v3(vote_state)).unwrap();
558
559 let root_slot_offset = 4 + 32 + 32 + 1 + 8;
563 assert_eq!(valid_buf[root_slot_offset], 1); {
566 let mut buf = valid_buf.clone();
567 buf[root_slot_offset] = 2;
568 let mut vs = VoteStateV3::default();
569 assert_eq!(
570 VoteStateV3::deserialize_into(&buf, &mut vs),
571 Err(InstructionError::InvalidAccountData)
572 );
573 }
574
575 let is_empty_offset = root_slot_offset + 1 + 8 + 8 + 32 * 48 + 8;
579 assert_eq!(valid_buf[is_empty_offset], 1); {
582 let mut buf = valid_buf.clone();
583 buf[is_empty_offset] = 2;
584 let mut vs = VoteStateV3::default();
585 assert_eq!(
586 VoteStateV3::deserialize_into(&buf, &mut vs),
587 Err(InstructionError::InvalidAccountData)
588 );
589 }
590 }
591
592 #[test]
593 fn test_has_latency() {
594 let mut v1_state = VoteState1_14_11::default();
596 v1_state.votes.push_back(Lockout::new(100));
597 v1_state.votes.push_back(Lockout::new(200));
598 let buf = bincode::serialize(&VoteStateVersions::V1_14_11(Box::new(v1_state))).unwrap();
599 let deserialized = VoteStateV3::deserialize(&buf).unwrap();
600 assert_eq!(deserialized.votes.len(), 2);
601 for vote in &deserialized.votes {
602 assert_eq!(vote.latency, 0);
603 }
604
605 let mut v3_state = VoteStateV3::default();
607 v3_state.votes.push_back(LandedVote {
608 latency: 42,
609 lockout: Lockout::new(100),
610 });
611 v3_state.votes.push_back(LandedVote {
612 latency: 7,
613 lockout: Lockout::new(200),
614 });
615 let buf = bincode::serialize(&VoteStateVersions::new_v3(v3_state)).unwrap();
616 let deserialized = VoteStateV3::deserialize(&buf).unwrap();
617 assert_eq!(deserialized.votes[0].latency, 42);
618 assert_eq!(deserialized.votes[1].latency, 7);
619 }
620
621 #[test]
622 fn test_empty_collections_round_trip() {
623 let vote_state = VoteStateV3 {
625 node_pubkey: Pubkey::new_unique(),
626 authorized_withdrawer: Pubkey::new_unique(),
627 commission: 50,
628 root_slot: Some(100),
629 ..VoteStateV3::default()
630 };
631 let versioned = VoteStateVersions::new_v3(vote_state.clone());
632 let buf = bincode::serialize(&versioned).unwrap();
633 let deserialized = VoteStateV3::deserialize(&buf).unwrap();
634 assert_eq!(vote_state, deserialized);
635 }
636}