1#[cfg(feature = "bincode")]
2use super::VoteStateVersions;
3#[cfg(feature = "dev-context-only-utils")]
4use arbitrary::Arbitrary;
5#[cfg(feature = "serde")]
6use serde_derive::{Deserialize, Serialize};
7#[cfg(feature = "serde")]
8use serde_with::serde_as;
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, LandedVote, VoteInit, VoteInitV2, BLS_PUBLIC_KEY_COMPRESSED_SIZE},
15 crate::authorized_voters::AuthorizedVoters,
16 solana_clock::{Clock, Epoch, Slot},
17 solana_pubkey::Pubkey,
18 std::{collections::VecDeque, fmt::Debug},
19};
20
21#[cfg_attr(
22 feature = "frozen-abi",
23 frozen_abi(
24 api_digest = "ALZS4x22Ga8M6KkLVgdEJu3ZQUUSBkFHAkErmSvFLzUM",
25 abi_digest = "DqcDSgyayprZqMjBEHzUuB6afr3rGckVqHHBWdvVZefU",
26 abi_serializer = ["bincode", "wincode"]
27 ),
28 derive(AbiExample, StableAbi, StableAbiSample)
29)]
30#[cfg_attr(feature = "serde", cfg_eval::cfg_eval, serde_as)]
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 VoteStateV4 {
36 pub node_pubkey: Pubkey,
38 pub authorized_withdrawer: Pubkey,
40
41 pub inflation_rewards_collector: Pubkey,
43 pub block_revenue_collector: Pubkey,
45
46 pub inflation_rewards_commission_bps: u16,
49 pub block_revenue_commission_bps: u16,
52
53 pub pending_delegator_rewards: u64,
55
56 #[cfg_attr(
58 feature = "serde",
59 serde_as(as = "Option<[_; BLS_PUBLIC_KEY_COMPRESSED_SIZE]>")
60 )]
61 pub bls_pubkey_compressed: Option<[u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE]>,
62
63 pub votes: VecDeque<LandedVote>,
64 pub root_slot: Option<Slot>,
65
66 pub authorized_voters: AuthorizedVoters,
69
70 pub epoch_credits: Vec<(Epoch, u64, u64)>,
73
74 pub last_timestamp: BlockTimestamp,
76}
77
78impl VoteStateV4 {
79 pub const fn size_of() -> usize {
82 3762 }
84
85 pub fn new_with_defaults(vote_pubkey: &Pubkey, vote_init: &VoteInit, clock: &Clock) -> Self {
86 Self {
87 node_pubkey: vote_init.node_pubkey,
88 authorized_voters: AuthorizedVoters::new(clock.epoch, vote_init.authorized_voter),
89 authorized_withdrawer: vote_init.authorized_withdrawer,
90 inflation_rewards_commission_bps: (vote_init.commission as u16).saturating_mul(100),
92 inflation_rewards_collector: *vote_pubkey,
94 block_revenue_collector: vote_init.node_pubkey,
95 block_revenue_commission_bps: 10_000, ..Self::default()
97 }
98 }
99
100 pub fn new(
103 vote_init: &VoteInitV2,
104 inflation_rewards_collector: &Pubkey,
105 block_revenue_collector: &Pubkey,
106 clock: &Clock,
107 ) -> Self {
108 Self {
109 node_pubkey: vote_init.node_pubkey,
110 authorized_voters: AuthorizedVoters::new(clock.epoch, vote_init.authorized_voter),
111 bls_pubkey_compressed: Some(vote_init.authorized_voter_bls_pubkey),
112 authorized_withdrawer: vote_init.authorized_withdrawer,
113 inflation_rewards_commission_bps: vote_init.inflation_rewards_commission_bps,
114 inflation_rewards_collector: *inflation_rewards_collector,
115 block_revenue_commission_bps: vote_init.block_revenue_commission_bps,
116 block_revenue_collector: *block_revenue_collector,
117 ..Self::default()
118 }
119 }
120
121 #[cfg(any(target_os = "solana", feature = "bincode"))]
122 pub fn deserialize(input: &[u8], vote_pubkey: &Pubkey) -> Result<Self, InstructionError> {
123 let mut vote_state = Self::default();
124 Self::deserialize_into(input, &mut vote_state, vote_pubkey)?;
125 Ok(vote_state)
126 }
127
128 #[cfg(any(target_os = "solana", feature = "bincode"))]
135 pub fn deserialize_into(
136 input: &[u8],
137 vote_state: &mut VoteStateV4,
138 vote_pubkey: &Pubkey,
139 ) -> Result<(), InstructionError> {
140 use super::vote_state_deserialize;
141 vote_state_deserialize::deserialize_into(input, vote_state, |input, vote_state| {
142 Self::deserialize_into_ptr(input, vote_state, vote_pubkey)
143 })
144 }
145
146 #[cfg(any(target_os = "solana", feature = "bincode"))]
157 pub fn deserialize_into_uninit(
158 input: &[u8],
159 vote_state: &mut std::mem::MaybeUninit<VoteStateV4>,
160 vote_pubkey: &Pubkey,
161 ) -> Result<(), InstructionError> {
162 Self::deserialize_into_ptr(input, vote_state.as_mut_ptr(), vote_pubkey)
163 }
164
165 #[cfg(any(target_os = "solana", feature = "bincode"))]
166 fn deserialize_into_ptr(
167 input: &[u8],
168 vote_state: *mut VoteStateV4,
169 vote_pubkey: &Pubkey,
170 ) -> Result<(), InstructionError> {
171 use super::vote_state_deserialize::{deserialize_vote_state_into_v4, SourceVersion};
172
173 let mut cursor = std::io::Cursor::new(input);
174
175 let variant = solana_serialize_utils::cursor::read_u32(&mut cursor)?;
176 match variant {
177 0 => Err(InstructionError::InvalidAccountData),
179 1 => deserialize_vote_state_into_v4(
181 &mut cursor,
182 vote_state,
183 SourceVersion::V1_14_11 { vote_pubkey },
184 ),
185 2 => deserialize_vote_state_into_v4(
187 &mut cursor,
188 vote_state,
189 SourceVersion::V3 { vote_pubkey },
190 ),
191 3 => deserialize_vote_state_into_v4(&mut cursor, vote_state, SourceVersion::V4),
193 _ => Err(InstructionError::InvalidAccountData),
194 }?;
195
196 Ok(())
197 }
198
199 #[cfg(feature = "bincode")]
200 pub fn serialize(
201 versioned: &VoteStateVersions,
202 output: &mut [u8],
203 ) -> Result<(), InstructionError> {
204 bincode::serialize_into(output, versioned).map_err(|err| match *err {
205 bincode::ErrorKind::SizeLimit => InstructionError::AccountDataTooSmall,
206 _ => InstructionError::GenericError,
207 })
208 }
209
210 pub fn is_correct_size_and_initialized(data: &[u8]) -> bool {
211 data.len() == VoteStateV4::size_of() && data[..4] == [3, 0, 0, 0] }
214
215 pub fn credits(&self) -> u64 {
217 self.epoch_credits.last().map_or(0, |v| v.1)
218 }
219
220 #[cfg(test)]
221 pub(crate) fn get_max_sized_vote_state() -> Self {
222 use super::{MAX_EPOCH_CREDITS_HISTORY, MAX_LOCKOUT_HISTORY};
223
224 const MAX_AUTHORIZED_VOTERS: usize = 4;
226
227 let mut authorized_voters = AuthorizedVoters::default();
228 for i in 0..MAX_AUTHORIZED_VOTERS as u64 {
229 authorized_voters.insert(i, Pubkey::new_unique());
230 }
231
232 Self {
233 votes: VecDeque::from(vec![LandedVote::default(); MAX_LOCKOUT_HISTORY]),
234 root_slot: Some(u64::MAX),
235 epoch_credits: vec![(0, 0, 0); MAX_EPOCH_CREDITS_HISTORY],
236 authorized_voters,
237 ..Self::default()
238 }
239 }
240
241 #[cfg(test)]
242 fn new_rand_for_tests(node_pubkey: Pubkey, root_slot: Slot) -> Self {
243 let votes = (1..32)
244 .map(|x| LandedVote {
245 latency: 0,
246 lockout: super::Lockout::new_with_confirmation_count(
247 u64::from(x).saturating_add(root_slot),
248 32_u32.saturating_sub(x),
249 ),
250 })
251 .collect();
252 Self {
253 node_pubkey,
254 root_slot: Some(root_slot),
255 votes,
256 ..Self::default()
257 }
258 }
259}
260
261#[cfg(test)]
262mod tests {
263 use {
264 super::{
265 super::{
266 CircBuf, Lockout, VoteState1_14_11, VoteStateV3, VoteStateVersions,
267 BLS_PUBLIC_KEY_COMPRESSED_SIZE, MAX_LOCKOUT_HISTORY,
268 },
269 *,
270 },
271 arbitrary::Unstructured,
272 bincode::serialized_size,
273 core::mem::MaybeUninit,
274 rand::Rng,
275 test_case::test_matrix,
276 };
277
278 #[test]
279 fn test_size_of() {
280 let vote_state = VoteStateV4::get_max_sized_vote_state();
281 let vote_state = VoteStateVersions::new_v4(vote_state);
282 let size = serialized_size(&vote_state).unwrap();
283 assert!(size < VoteStateV4::size_of() as u64); }
285
286 #[test]
287 fn test_minimum_balance() {
288 let rent = solana_rent::Rent::default();
289 let minimum_balance = rent.minimum_balance(VoteStateV4::size_of());
290 assert!(minimum_balance as f64 / 10f64.powf(9.0) < 0.04)
292 }
293
294 #[test]
295 fn test_new_with_defaults() {
296 let vote_pubkey = Pubkey::new_unique();
297 let vote_init = VoteInit {
298 node_pubkey: Pubkey::new_unique(),
299 authorized_voter: Pubkey::new_unique(),
300 authorized_withdrawer: Pubkey::new_unique(),
301 commission: 50,
302 };
303 let clock = Clock {
304 epoch: 7,
305 ..Clock::default()
306 };
307 let v4 = VoteStateV4::new_with_defaults(&vote_pubkey, &vote_init, &clock);
308
309 assert_eq!(v4.node_pubkey, vote_init.node_pubkey);
310 assert_eq!(v4.authorized_withdrawer, vote_init.authorized_withdrawer);
311 assert_eq!(v4.inflation_rewards_commission_bps, 5000);
312 assert_eq!(v4.inflation_rewards_collector, vote_pubkey);
313 assert_eq!(v4.block_revenue_collector, vote_init.node_pubkey);
314 assert_eq!(v4.block_revenue_commission_bps, 10_000);
315 assert_eq!(v4.pending_delegator_rewards, 0);
316 assert_eq!(v4.bls_pubkey_compressed, None);
317 assert!(!v4.authorized_voters.is_empty());
318 }
319
320 #[test]
321 fn test_vote_serialize() {
322 let vote_pubkey_for_deserialize = Pubkey::new_unique();
325 let vote_pubkey_for_convert = Pubkey::new_unique();
326
327 let mut buffer: Vec<u8> = vec![0; VoteStateV4::size_of()];
328 let mut vote_state = VoteStateV4::default();
329 vote_state
330 .votes
331 .resize(MAX_LOCKOUT_HISTORY, LandedVote::default());
332 vote_state.root_slot = Some(1);
333 let versioned = VoteStateVersions::new_v4(vote_state);
334 assert!(VoteStateV4::serialize(&versioned, &mut buffer[0..4]).is_err());
335 VoteStateV4::serialize(&versioned, &mut buffer).unwrap();
336 assert_eq!(
337 VoteStateV4::deserialize(&buffer, &vote_pubkey_for_deserialize).unwrap(),
338 versioned
339 .try_convert_to_v4(&vote_pubkey_for_convert)
340 .unwrap()
341 );
342 }
343
344 #[test]
345 fn test_vote_deserialize_into() {
346 let vote_pubkey = Pubkey::new_unique();
347
348 let target_vote_state = VoteStateV4::default();
350 let vote_state_buf =
351 bincode::serialize(&VoteStateVersions::new_v4(target_vote_state.clone())).unwrap();
352
353 let mut test_vote_state = VoteStateV4::default();
354 VoteStateV4::deserialize_into(&vote_state_buf, &mut test_vote_state, &vote_pubkey).unwrap();
355
356 assert_eq!(target_vote_state, test_vote_state);
357
358 let struct_bytes_x4 = std::mem::size_of::<VoteStateV4>() * 4;
361 for _ in 0..1000 {
362 let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
363 let mut unstructured = Unstructured::new(&raw_data);
364
365 let target_vote_state_versions =
366 VoteStateVersions::arbitrary(&mut unstructured).unwrap();
367 let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
368 let target_vote_state = target_vote_state_versions
369 .try_convert_to_v4(&vote_pubkey)
370 .unwrap();
371
372 let mut test_vote_state = VoteStateV4::default();
373 VoteStateV4::deserialize_into(&vote_state_buf, &mut test_vote_state, &vote_pubkey)
374 .unwrap();
375
376 assert_eq!(target_vote_state, test_vote_state);
377 }
378 }
379
380 #[test]
381 fn test_deserialize_into_reuse_across_success_and_failure() {
382 let vote_pubkey = Pubkey::new_unique();
383 let mut vote_state = VoteStateV4::default();
384
385 let v4_a = VoteStateV4::new_rand_for_tests(Pubkey::new_unique(), 100);
387 let buf_a = bincode::serialize(&VoteStateVersions::new_v4(v4_a.clone())).unwrap();
388 VoteStateV4::deserialize_into(&buf_a, &mut vote_state, &vote_pubkey).unwrap();
389 assert_eq!(vote_state, v4_a);
390
391 let v4_b = VoteStateV4::new_rand_for_tests(Pubkey::new_unique(), 200);
393 let buf_b = bincode::serialize(&VoteStateVersions::new_v4(v4_b.clone())).unwrap();
394 VoteStateV4::deserialize_into(&buf_b, &mut vote_state, &vote_pubkey).unwrap();
395 assert_eq!(vote_state, v4_b);
396
397 let mut bad_buf = buf_b.clone();
399 bad_buf.truncate(bad_buf.len() - 1);
400 VoteStateV4::deserialize_into(&bad_buf, &mut vote_state, &vote_pubkey).unwrap_err();
401 assert_eq!(vote_state, VoteStateV4::default());
402
403 VoteStateV4::deserialize_into(&buf_a, &mut vote_state, &vote_pubkey).unwrap();
405 assert_eq!(vote_state, v4_a);
406 }
407
408 #[test]
409 fn test_vote_deserialize_into_trailing_data() {
410 let vote_pubkey = Pubkey::new_unique();
411 let target_vote_state = VoteStateV4::new_rand_for_tests(Pubkey::new_unique(), 42);
412 let vote_state_buf =
413 bincode::serialize(&VoteStateVersions::new_v4(target_vote_state.clone())).unwrap();
414
415 let mut buf_with_garbage = vote_state_buf.clone();
417 buf_with_garbage.extend_from_slice(&[0xDE, 0xAD, 0xBE, 0xEF]);
418 let mut test_vote_state = VoteStateV4::default();
419 VoteStateV4::deserialize_into(&buf_with_garbage, &mut test_vote_state, &vote_pubkey)
420 .unwrap();
421 assert_eq!(target_vote_state, test_vote_state);
422
423 let mut buf_with_zeroes = vote_state_buf;
425 buf_with_zeroes.extend_from_slice(&[0u8; 64]);
426 let mut test_vote_state = VoteStateV4::default();
427 VoteStateV4::deserialize_into(&buf_with_zeroes, &mut test_vote_state, &vote_pubkey)
428 .unwrap();
429 assert_eq!(target_vote_state, test_vote_state);
430 }
431
432 #[test]
433 fn test_vote_deserialize_into_error() {
434 let vote_pubkey = Pubkey::new_unique();
435
436 let target_vote_state = VoteStateV4::new_rand_for_tests(Pubkey::new_unique(), 42);
437 let mut vote_state_buf =
438 bincode::serialize(&VoteStateVersions::new_v4(target_vote_state.clone())).unwrap();
439 let len = vote_state_buf.len();
440 vote_state_buf.truncate(len - 1);
441
442 let mut test_vote_state = VoteStateV4::default();
443 VoteStateV4::deserialize_into(&vote_state_buf, &mut test_vote_state, &vote_pubkey)
444 .unwrap_err();
445 assert_eq!(test_vote_state, VoteStateV4::default());
446 }
447
448 #[test]
449 fn test_vote_deserialize_into_error_with_pre_state() {
450 let vote_pubkey = Pubkey::new_unique();
451
452 let mut vote_state = VoteStateV4::new_rand_for_tests(Pubkey::new_unique(), 42);
454 vote_state.epoch_credits = vec![(0, 100, 0), (1, 200, 100), (2, 300, 200)];
455
456 let mut buf =
458 bincode::serialize(&VoteStateVersions::new_v4(VoteStateV4::default())).unwrap();
459 buf.truncate(buf.len() - 1);
460
461 VoteStateV4::deserialize_into(&buf, &mut vote_state, &vote_pubkey).unwrap_err();
462 assert_eq!(vote_state, VoteStateV4::default());
464 }
465
466 #[test]
467 fn test_deserialize_into_uninit_no_reset_on_error() {
468 let vote_pubkey = Pubkey::new_unique();
473 let target = VoteStateV4::new_rand_for_tests(Pubkey::new_unique(), 42);
474 let mut buf = bincode::serialize(&VoteStateVersions::new_v4(target)).unwrap();
475 buf.truncate(buf.len() - 1);
476
477 let mut test_vote_state = MaybeUninit::uninit();
478 let err = VoteStateV4::deserialize_into_uninit(&buf, &mut test_vote_state, &vote_pubkey);
479 assert_eq!(err, Err(InstructionError::InvalidAccountData));
480 }
482
483 #[test]
484 fn test_vote_deserialize_into_uninit() {
485 let vote_pubkey = Pubkey::new_unique();
486
487 let target_vote_state = VoteStateV4::default();
489 let vote_state_buf =
490 bincode::serialize(&VoteStateVersions::new_v4(target_vote_state.clone())).unwrap();
491
492 let mut test_vote_state = MaybeUninit::uninit();
493 VoteStateV4::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state, &vote_pubkey)
494 .unwrap();
495 let test_vote_state = unsafe { test_vote_state.assume_init() };
496
497 assert_eq!(target_vote_state, test_vote_state);
498
499 let struct_bytes_x4 = std::mem::size_of::<VoteStateV4>() * 4;
502 for _ in 0..1000 {
503 let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
504 let mut unstructured = Unstructured::new(&raw_data);
505
506 let target_vote_state_versions =
507 VoteStateVersions::arbitrary(&mut unstructured).unwrap();
508 let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
509 let target_vote_state = target_vote_state_versions
510 .try_convert_to_v4(&Pubkey::default())
511 .unwrap();
512
513 let mut test_vote_state = MaybeUninit::uninit();
514 VoteStateV4::deserialize_into_uninit(
515 &vote_state_buf,
516 &mut test_vote_state,
517 &Pubkey::default(),
518 )
519 .unwrap();
520 let test_vote_state = unsafe { test_vote_state.assume_init() };
521
522 assert_eq!(target_vote_state, test_vote_state);
523 }
524 }
525
526 #[test]
527 fn test_vote_deserialize_into_uninit_trailing_data() {
528 let vote_pubkey = Pubkey::new_unique();
529 let target_vote_state = VoteStateV4::new_rand_for_tests(Pubkey::new_unique(), 42);
530 let vote_state_buf =
531 bincode::serialize(&VoteStateVersions::new_v4(target_vote_state.clone())).unwrap();
532
533 let mut buf_with_garbage = vote_state_buf.clone();
535 buf_with_garbage.extend_from_slice(&[0xDE, 0xAD, 0xBE, 0xEF]);
536 let mut test_vote_state = MaybeUninit::uninit();
537 VoteStateV4::deserialize_into_uninit(&buf_with_garbage, &mut test_vote_state, &vote_pubkey)
538 .unwrap();
539 let test_vote_state = unsafe { test_vote_state.assume_init() };
540 assert_eq!(target_vote_state, test_vote_state);
541
542 let mut buf_with_zeroes = vote_state_buf;
544 buf_with_zeroes.extend_from_slice(&[0u8; 64]);
545 let mut test_vote_state = MaybeUninit::uninit();
546 VoteStateV4::deserialize_into_uninit(&buf_with_zeroes, &mut test_vote_state, &vote_pubkey)
547 .unwrap();
548 let test_vote_state = unsafe { test_vote_state.assume_init() };
549 assert_eq!(target_vote_state, test_vote_state);
550 }
551
552 #[test]
553 fn test_vote_deserialize_into_uninit_nopanic() {
554 let vote_pubkey = Pubkey::new_unique();
555
556 let mut test_vote_state = MaybeUninit::uninit();
558 let e = VoteStateV4::deserialize_into_uninit(&[], &mut test_vote_state, &vote_pubkey)
559 .unwrap_err();
560 assert_eq!(e, InstructionError::InvalidAccountData);
561
562 let serialized_len_x4 = serialized_size(&VoteStateV4::default()).unwrap() * 4;
564 let mut rng = rand::rng();
565 for _ in 0..1000 {
566 let raw_data_length = rng.random_range(1..serialized_len_x4);
567 let mut raw_data: Vec<u8> = (0..raw_data_length).map(|_| rng.random::<u8>()).collect();
568
569 if raw_data_length >= 4 && rng.random::<bool>() {
571 let tag = rng.random_range(1u8..=3);
572 raw_data[0] = tag;
573 raw_data[1] = 0;
574 raw_data[2] = 0;
575 raw_data[3] = 0;
576 }
577
578 let mut test_vote_state = MaybeUninit::uninit();
581 let test_res =
582 VoteStateV4::deserialize_into_uninit(&raw_data, &mut test_vote_state, &vote_pubkey);
583 let bincode_res = bincode::deserialize::<VoteStateVersions>(&raw_data)
584 .map(|versioned| versioned.try_convert_to_v4(&vote_pubkey).unwrap());
585
586 if test_res.is_err() {
587 assert!(bincode_res.is_err());
588 } else {
589 let test_vote_state = unsafe { test_vote_state.assume_init() };
590 assert_eq!(test_vote_state, bincode_res.unwrap());
591 }
592 }
593 }
594
595 #[test]
596 fn test_vote_deserialize_into_uninit_ill_sized() {
597 let vote_pubkey = Pubkey::new_unique();
598
599 let struct_bytes_x4 = std::mem::size_of::<VoteStateV4>() * 4;
601 for _ in 0..1000 {
602 let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
603 let mut unstructured = Unstructured::new(&raw_data);
604
605 let original_vote_state_versions =
606 VoteStateVersions::arbitrary(&mut unstructured).unwrap();
607 let original_buf = bincode::serialize(&original_vote_state_versions).unwrap();
608
609 let mut truncated_buf = original_buf.clone();
610 let mut expanded_buf = original_buf.clone();
611
612 truncated_buf.resize(original_buf.len() - 8, 0);
613 expanded_buf.resize(original_buf.len() + 8, 0);
614
615 let mut test_vote_state = MaybeUninit::uninit();
617 let test_res = VoteStateV4::deserialize_into_uninit(
618 &truncated_buf,
619 &mut test_vote_state,
620 &vote_pubkey,
621 );
622 let bincode_res = bincode::deserialize::<VoteStateVersions>(&truncated_buf)
623 .map(|versioned| versioned.try_convert_to_v4(&vote_pubkey).unwrap());
624
625 assert!(test_res.is_err());
626 assert!(bincode_res.is_err());
627
628 let mut test_vote_state = MaybeUninit::uninit();
630 VoteStateV4::deserialize_into_uninit(&expanded_buf, &mut test_vote_state, &vote_pubkey)
631 .unwrap();
632 let bincode_res = bincode::deserialize::<VoteStateVersions>(&expanded_buf)
633 .map(|versioned| versioned.try_convert_to_v4(&vote_pubkey).unwrap());
634
635 let test_vote_state = unsafe { test_vote_state.assume_init() };
636 assert_eq!(test_vote_state, bincode_res.unwrap());
637 }
638 }
639
640 #[test]
641 fn test_bls_pubkey_compressed() {
642 let vote_pubkey = Pubkey::new_unique();
643
644 let run_test = |start, expected| {
645 let versioned = VoteStateVersions::new_v4(start);
646 let serialized = bincode::serialize(&versioned).unwrap();
647 let deserialized = VoteStateV4::deserialize(&serialized, &vote_pubkey).unwrap();
648 assert_eq!(deserialized.bls_pubkey_compressed, expected);
649 };
650
651 let vote_state_none = VoteStateV4::default();
653 assert_eq!(vote_state_none.bls_pubkey_compressed, None);
654 run_test(vote_state_none, None);
655
656 let test_bls_key = [42u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE];
658 let vote_state_some = VoteStateV4 {
659 bls_pubkey_compressed: Some(test_bls_key),
660 ..VoteStateV4::default()
661 };
662 assert_eq!(vote_state_some.bls_pubkey_compressed, Some(test_bls_key));
663 run_test(vote_state_some, Some(test_bls_key));
664 }
665
666 #[test]
667 fn test_deserialize_invalid_variant_tags() {
668 let vote_pubkey = Pubkey::new_unique();
669 let mut buf = vec![0u8; VoteStateV4::size_of()];
670
671 let mut vs = VoteStateV4::default();
673 assert_eq!(
674 VoteStateV4::deserialize_into(&buf, &mut vs, &vote_pubkey),
675 Err(InstructionError::InvalidAccountData)
676 );
677
678 buf[..4].copy_from_slice(&4u32.to_le_bytes());
680 assert_eq!(
681 VoteStateV4::deserialize_into(&buf, &mut vs, &vote_pubkey),
682 Err(InstructionError::InvalidAccountData)
683 );
684
685 buf[..4].copy_from_slice(&u32::MAX.to_le_bytes());
687 assert_eq!(
688 VoteStateV4::deserialize_into(&buf, &mut vs, &vote_pubkey),
689 Err(InstructionError::InvalidAccountData)
690 );
691 }
692
693 #[test]
694 fn test_invalid_option_discriminants() {
695 let vote_pubkey = Pubkey::new_unique();
696 let vote_state = VoteStateV4 {
697 root_slot: Some(42),
698 ..VoteStateV4::default()
699 };
700 let valid_buf = bincode::serialize(&VoteStateVersions::new_v4(vote_state)).unwrap();
701
702 let bls_offset = 4 + 32 + 32 + 32 + 32 + 2 + 2 + 8;
707 assert_eq!(valid_buf[bls_offset], 0); {
710 let mut buf = valid_buf.clone();
711 buf[bls_offset] = 2;
712 let mut vs = VoteStateV4::default();
713 assert_eq!(
714 VoteStateV4::deserialize_into(&buf, &mut vs, &vote_pubkey),
715 Err(InstructionError::InvalidAccountData)
716 );
717 }
718
719 let root_slot_offset = bls_offset + 1 + 8;
722 assert_eq!(valid_buf[root_slot_offset], 1); {
725 let mut buf = valid_buf.clone();
726 buf[root_slot_offset] = 2;
727 let mut vs = VoteStateV4::default();
728 assert_eq!(
729 VoteStateV4::deserialize_into(&buf, &mut vs, &vote_pubkey),
730 Err(InstructionError::InvalidAccountData)
731 );
732 }
733 }
734
735 #[allow(clippy::arithmetic_side_effects)]
736 #[test_matrix(
737 [0u8, 50, 100, 255],
738 [0usize, 1, 2]
739 )]
740 fn test_deserialize_prior_versions_simd_0185(commission: u8, prior_voters_count: usize) {
741 let vote_pubkey = Pubkey::new_unique();
742 let node_pubkey = Pubkey::new_unique();
743 let root_slot = Some(42);
744 let epoch_credits = vec![(0, 100, 0), (1, 200, 100)];
745 let last_timestamp = BlockTimestamp {
746 slot: 999,
747 timestamp: 12345,
748 };
749 let mut prior_voters = CircBuf::default();
750 for i in 0..prior_voters_count {
751 prior_voters.append((Pubkey::new_unique(), i as u64 * 5, (i as u64 + 1) * 5));
752 }
753
754 let assert_simd_0185_defaults = |v4: &VoteStateV4| {
764 assert_eq!(
765 v4.inflation_rewards_commission_bps,
766 u16::from(commission) * 100
767 );
768 assert_eq!(v4.block_revenue_commission_bps, 10_000);
769 assert_eq!(v4.inflation_rewards_collector, vote_pubkey);
770 assert_eq!(v4.block_revenue_collector, node_pubkey);
771 assert_eq!(v4.pending_delegator_rewards, 0);
772 assert_eq!(v4.bls_pubkey_compressed, None);
773
774 assert_eq!(v4.epoch_credits, epoch_credits);
776 assert_eq!(v4.last_timestamp, last_timestamp);
777 };
778
779 let v1_state = VoteState1_14_11 {
781 node_pubkey,
782 commission,
783 root_slot,
784 epoch_credits: epoch_credits.clone(),
785 last_timestamp: last_timestamp.clone(),
786 prior_voters: prior_voters.clone(),
787 ..VoteState1_14_11::default()
788 };
789 let buf = bincode::serialize(&VoteStateVersions::V1_14_11(Box::new(v1_state))).unwrap();
790 let v4 = VoteStateV4::deserialize(&buf, &vote_pubkey).unwrap();
791 assert_simd_0185_defaults(&v4);
792
793 let v3_state = VoteStateV3 {
795 node_pubkey,
796 commission,
797 root_slot,
798 epoch_credits: epoch_credits.clone(),
799 last_timestamp: last_timestamp.clone(),
800 prior_voters: prior_voters.clone(),
801 ..VoteStateV3::default()
802 };
803 let buf = bincode::serialize(&VoteStateVersions::new_v3(v3_state)).unwrap();
804 let v4 = VoteStateV4::deserialize(&buf, &vote_pubkey).unwrap();
805 assert_simd_0185_defaults(&v4);
806 }
807
808 #[test]
809 fn test_has_latency() {
810 let vote_pubkey = Pubkey::new_unique();
811
812 let mut v1_state = VoteState1_14_11::default();
814 v1_state.votes.push_back(Lockout::new(100));
815 v1_state.votes.push_back(Lockout::new(200));
816 let buf = bincode::serialize(&VoteStateVersions::V1_14_11(Box::new(v1_state))).unwrap();
817 let deserialized = VoteStateV4::deserialize(&buf, &vote_pubkey).unwrap();
818 assert_eq!(deserialized.votes.len(), 2);
819 for vote in &deserialized.votes {
820 assert_eq!(vote.latency, 0);
821 }
822
823 let mut v4_state = VoteStateV4::default();
825 v4_state.votes.push_back(LandedVote {
826 latency: 42,
827 lockout: Lockout::new(100),
828 });
829 let buf = bincode::serialize(&VoteStateVersions::new_v4(v4_state)).unwrap();
830 let deserialized = VoteStateV4::deserialize(&buf, &vote_pubkey).unwrap();
831 assert_eq!(deserialized.votes[0].latency, 42);
832 }
833}