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 solana_instruction::error::InstructionError,
276 test_case::test_matrix,
277 };
278
279 #[test]
280 fn test_size_of() {
281 let vote_state = VoteStateV4::get_max_sized_vote_state();
282 let vote_state = VoteStateVersions::new_v4(vote_state);
283 let size = serialized_size(&vote_state).unwrap();
284 assert!(size < VoteStateV4::size_of() as u64); }
286
287 #[test]
288 fn test_minimum_balance() {
289 let rent = solana_rent::Rent::default();
290 let minimum_balance = rent.minimum_balance(VoteStateV4::size_of());
291 assert!(minimum_balance as f64 / 10f64.powf(9.0) < 0.04)
293 }
294
295 #[test]
296 fn test_new_with_defaults() {
297 let vote_pubkey = Pubkey::new_unique();
298 let vote_init = VoteInit {
299 node_pubkey: Pubkey::new_unique(),
300 authorized_voter: Pubkey::new_unique(),
301 authorized_withdrawer: Pubkey::new_unique(),
302 commission: 50,
303 };
304 let clock = Clock {
305 epoch: 7,
306 ..Clock::default()
307 };
308 let v4 = VoteStateV4::new_with_defaults(&vote_pubkey, &vote_init, &clock);
309
310 assert_eq!(v4.node_pubkey, vote_init.node_pubkey);
311 assert_eq!(v4.authorized_withdrawer, vote_init.authorized_withdrawer);
312 assert_eq!(v4.inflation_rewards_commission_bps, 5000);
313 assert_eq!(v4.inflation_rewards_collector, vote_pubkey);
314 assert_eq!(v4.block_revenue_collector, vote_init.node_pubkey);
315 assert_eq!(v4.block_revenue_commission_bps, 10_000);
316 assert_eq!(v4.pending_delegator_rewards, 0);
317 assert_eq!(v4.bls_pubkey_compressed, None);
318 assert!(!v4.authorized_voters.is_empty());
319 }
320
321 #[test]
322 fn test_vote_serialize() {
323 let vote_pubkey_for_deserialize = Pubkey::new_unique();
326 let vote_pubkey_for_convert = Pubkey::new_unique();
327
328 let mut buffer: Vec<u8> = vec![0; VoteStateV4::size_of()];
329 let mut vote_state = VoteStateV4::default();
330 vote_state
331 .votes
332 .resize(MAX_LOCKOUT_HISTORY, LandedVote::default());
333 vote_state.root_slot = Some(1);
334 let versioned = VoteStateVersions::new_v4(vote_state);
335 assert!(VoteStateV4::serialize(&versioned, &mut buffer[0..4]).is_err());
336 VoteStateV4::serialize(&versioned, &mut buffer).unwrap();
337 assert_eq!(
338 VoteStateV4::deserialize(&buffer, &vote_pubkey_for_deserialize).unwrap(),
339 versioned
340 .try_convert_to_v4(&vote_pubkey_for_convert)
341 .unwrap()
342 );
343 }
344
345 #[test]
346 fn test_vote_deserialize_into() {
347 let vote_pubkey = Pubkey::new_unique();
348
349 let target_vote_state = VoteStateV4::default();
351 let vote_state_buf =
352 bincode::serialize(&VoteStateVersions::new_v4(target_vote_state.clone())).unwrap();
353
354 let mut test_vote_state = VoteStateV4::default();
355 VoteStateV4::deserialize_into(&vote_state_buf, &mut test_vote_state, &vote_pubkey).unwrap();
356
357 assert_eq!(target_vote_state, test_vote_state);
358
359 let struct_bytes_x4 = std::mem::size_of::<VoteStateV4>() * 4;
362 for _ in 0..1000 {
363 let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
364 let mut unstructured = Unstructured::new(&raw_data);
365
366 let target_vote_state_versions =
367 VoteStateVersions::arbitrary(&mut unstructured).unwrap();
368 let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
369 let target_vote_state = target_vote_state_versions
370 .try_convert_to_v4(&vote_pubkey)
371 .unwrap();
372
373 let mut test_vote_state = VoteStateV4::default();
374 VoteStateV4::deserialize_into(&vote_state_buf, &mut test_vote_state, &vote_pubkey)
375 .unwrap();
376
377 assert_eq!(target_vote_state, test_vote_state);
378 }
379 }
380
381 #[test]
382 fn test_deserialize_into_reuse_across_success_and_failure() {
383 let vote_pubkey = Pubkey::new_unique();
384 let mut vote_state = VoteStateV4::default();
385
386 let v4_a = VoteStateV4::new_rand_for_tests(Pubkey::new_unique(), 100);
388 let buf_a = bincode::serialize(&VoteStateVersions::new_v4(v4_a.clone())).unwrap();
389 VoteStateV4::deserialize_into(&buf_a, &mut vote_state, &vote_pubkey).unwrap();
390 assert_eq!(vote_state, v4_a);
391
392 let v4_b = VoteStateV4::new_rand_for_tests(Pubkey::new_unique(), 200);
394 let buf_b = bincode::serialize(&VoteStateVersions::new_v4(v4_b.clone())).unwrap();
395 VoteStateV4::deserialize_into(&buf_b, &mut vote_state, &vote_pubkey).unwrap();
396 assert_eq!(vote_state, v4_b);
397
398 let mut bad_buf = buf_b.clone();
400 bad_buf.truncate(bad_buf.len() - 1);
401 VoteStateV4::deserialize_into(&bad_buf, &mut vote_state, &vote_pubkey).unwrap_err();
402 assert_eq!(vote_state, VoteStateV4::default());
403
404 VoteStateV4::deserialize_into(&buf_a, &mut vote_state, &vote_pubkey).unwrap();
406 assert_eq!(vote_state, v4_a);
407 }
408
409 #[test]
410 fn test_vote_deserialize_into_trailing_data() {
411 let vote_pubkey = Pubkey::new_unique();
412 let target_vote_state = VoteStateV4::new_rand_for_tests(Pubkey::new_unique(), 42);
413 let vote_state_buf =
414 bincode::serialize(&VoteStateVersions::new_v4(target_vote_state.clone())).unwrap();
415
416 let mut buf_with_garbage = vote_state_buf.clone();
418 buf_with_garbage.extend_from_slice(&[0xDE, 0xAD, 0xBE, 0xEF]);
419 let mut test_vote_state = VoteStateV4::default();
420 VoteStateV4::deserialize_into(&buf_with_garbage, &mut test_vote_state, &vote_pubkey)
421 .unwrap();
422 assert_eq!(target_vote_state, test_vote_state);
423
424 let mut buf_with_zeroes = vote_state_buf;
426 buf_with_zeroes.extend_from_slice(&[0u8; 64]);
427 let mut test_vote_state = VoteStateV4::default();
428 VoteStateV4::deserialize_into(&buf_with_zeroes, &mut test_vote_state, &vote_pubkey)
429 .unwrap();
430 assert_eq!(target_vote_state, test_vote_state);
431 }
432
433 #[test]
434 fn test_vote_deserialize_into_error() {
435 let vote_pubkey = Pubkey::new_unique();
436
437 let target_vote_state = VoteStateV4::new_rand_for_tests(Pubkey::new_unique(), 42);
438 let mut vote_state_buf =
439 bincode::serialize(&VoteStateVersions::new_v4(target_vote_state.clone())).unwrap();
440 let len = vote_state_buf.len();
441 vote_state_buf.truncate(len - 1);
442
443 let mut test_vote_state = VoteStateV4::default();
444 VoteStateV4::deserialize_into(&vote_state_buf, &mut test_vote_state, &vote_pubkey)
445 .unwrap_err();
446 assert_eq!(test_vote_state, VoteStateV4::default());
447 }
448
449 #[test]
450 fn test_vote_deserialize_into_error_with_pre_state() {
451 let vote_pubkey = Pubkey::new_unique();
452
453 let mut vote_state = VoteStateV4::new_rand_for_tests(Pubkey::new_unique(), 42);
455 vote_state.epoch_credits = vec![(0, 100, 0), (1, 200, 100), (2, 300, 200)];
456
457 let mut buf =
459 bincode::serialize(&VoteStateVersions::new_v4(VoteStateV4::default())).unwrap();
460 buf.truncate(buf.len() - 1);
461
462 VoteStateV4::deserialize_into(&buf, &mut vote_state, &vote_pubkey).unwrap_err();
463 assert_eq!(vote_state, VoteStateV4::default());
465 }
466
467 #[test]
468 fn test_deserialize_into_uninit_no_reset_on_error() {
469 let vote_pubkey = Pubkey::new_unique();
474 let target = VoteStateV4::new_rand_for_tests(Pubkey::new_unique(), 42);
475 let mut buf = bincode::serialize(&VoteStateVersions::new_v4(target)).unwrap();
476 buf.truncate(buf.len() - 1);
477
478 let mut test_vote_state = MaybeUninit::uninit();
479 let err = VoteStateV4::deserialize_into_uninit(&buf, &mut test_vote_state, &vote_pubkey);
480 assert_eq!(err, Err(InstructionError::InvalidAccountData));
481 }
483
484 #[test]
485 fn test_vote_deserialize_into_uninit() {
486 let vote_pubkey = Pubkey::new_unique();
487
488 let target_vote_state = VoteStateV4::default();
490 let vote_state_buf =
491 bincode::serialize(&VoteStateVersions::new_v4(target_vote_state.clone())).unwrap();
492
493 let mut test_vote_state = MaybeUninit::uninit();
494 VoteStateV4::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state, &vote_pubkey)
495 .unwrap();
496 let test_vote_state = unsafe { test_vote_state.assume_init() };
497
498 assert_eq!(target_vote_state, test_vote_state);
499
500 let struct_bytes_x4 = std::mem::size_of::<VoteStateV4>() * 4;
503 for _ in 0..1000 {
504 let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
505 let mut unstructured = Unstructured::new(&raw_data);
506
507 let target_vote_state_versions =
508 VoteStateVersions::arbitrary(&mut unstructured).unwrap();
509 let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
510 let target_vote_state = target_vote_state_versions
511 .try_convert_to_v4(&Pubkey::default())
512 .unwrap();
513
514 let mut test_vote_state = MaybeUninit::uninit();
515 VoteStateV4::deserialize_into_uninit(
516 &vote_state_buf,
517 &mut test_vote_state,
518 &Pubkey::default(),
519 )
520 .unwrap();
521 let test_vote_state = unsafe { test_vote_state.assume_init() };
522
523 assert_eq!(target_vote_state, test_vote_state);
524 }
525 }
526
527 #[test]
528 fn test_vote_deserialize_into_uninit_trailing_data() {
529 let vote_pubkey = Pubkey::new_unique();
530 let target_vote_state = VoteStateV4::new_rand_for_tests(Pubkey::new_unique(), 42);
531 let vote_state_buf =
532 bincode::serialize(&VoteStateVersions::new_v4(target_vote_state.clone())).unwrap();
533
534 let mut buf_with_garbage = vote_state_buf.clone();
536 buf_with_garbage.extend_from_slice(&[0xDE, 0xAD, 0xBE, 0xEF]);
537 let mut test_vote_state = MaybeUninit::uninit();
538 VoteStateV4::deserialize_into_uninit(&buf_with_garbage, &mut test_vote_state, &vote_pubkey)
539 .unwrap();
540 let test_vote_state = unsafe { test_vote_state.assume_init() };
541 assert_eq!(target_vote_state, test_vote_state);
542
543 let mut buf_with_zeroes = vote_state_buf;
545 buf_with_zeroes.extend_from_slice(&[0u8; 64]);
546 let mut test_vote_state = MaybeUninit::uninit();
547 VoteStateV4::deserialize_into_uninit(&buf_with_zeroes, &mut test_vote_state, &vote_pubkey)
548 .unwrap();
549 let test_vote_state = unsafe { test_vote_state.assume_init() };
550 assert_eq!(target_vote_state, test_vote_state);
551 }
552
553 #[test]
554 fn test_vote_deserialize_into_uninit_nopanic() {
555 let vote_pubkey = Pubkey::new_unique();
556
557 let mut test_vote_state = MaybeUninit::uninit();
559 let e = VoteStateV4::deserialize_into_uninit(&[], &mut test_vote_state, &vote_pubkey)
560 .unwrap_err();
561 assert_eq!(e, InstructionError::InvalidAccountData);
562
563 let serialized_len_x4 = serialized_size(&VoteStateV4::default()).unwrap() * 4;
565 let mut rng = rand::rng();
566 for _ in 0..1000 {
567 let raw_data_length = rng.random_range(1..serialized_len_x4);
568 let mut raw_data: Vec<u8> = (0..raw_data_length).map(|_| rng.random::<u8>()).collect();
569
570 if raw_data_length >= 4 && rng.random::<bool>() {
572 let tag = rng.random_range(1u8..=3);
573 raw_data[0] = tag;
574 raw_data[1] = 0;
575 raw_data[2] = 0;
576 raw_data[3] = 0;
577 }
578
579 let mut test_vote_state = MaybeUninit::uninit();
582 let test_res =
583 VoteStateV4::deserialize_into_uninit(&raw_data, &mut test_vote_state, &vote_pubkey);
584 let bincode_res = bincode::deserialize::<VoteStateVersions>(&raw_data)
585 .map(|versioned| versioned.try_convert_to_v4(&vote_pubkey).unwrap());
586
587 if test_res.is_err() {
588 assert!(bincode_res.is_err());
589 } else {
590 let test_vote_state = unsafe { test_vote_state.assume_init() };
591 assert_eq!(test_vote_state, bincode_res.unwrap());
592 }
593 }
594 }
595
596 #[test]
597 fn test_vote_deserialize_into_uninit_ill_sized() {
598 let vote_pubkey = Pubkey::new_unique();
599
600 let struct_bytes_x4 = std::mem::size_of::<VoteStateV4>() * 4;
602 for _ in 0..1000 {
603 let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
604 let mut unstructured = Unstructured::new(&raw_data);
605
606 let original_vote_state_versions =
607 VoteStateVersions::arbitrary(&mut unstructured).unwrap();
608 let original_buf = bincode::serialize(&original_vote_state_versions).unwrap();
609
610 let mut truncated_buf = original_buf.clone();
611 let mut expanded_buf = original_buf.clone();
612
613 truncated_buf.resize(original_buf.len() - 8, 0);
614 expanded_buf.resize(original_buf.len() + 8, 0);
615
616 let mut test_vote_state = MaybeUninit::uninit();
618 let test_res = VoteStateV4::deserialize_into_uninit(
619 &truncated_buf,
620 &mut test_vote_state,
621 &vote_pubkey,
622 );
623 let bincode_res = bincode::deserialize::<VoteStateVersions>(&truncated_buf)
624 .map(|versioned| versioned.try_convert_to_v4(&vote_pubkey).unwrap());
625
626 assert!(test_res.is_err());
627 assert!(bincode_res.is_err());
628
629 let mut test_vote_state = MaybeUninit::uninit();
631 VoteStateV4::deserialize_into_uninit(&expanded_buf, &mut test_vote_state, &vote_pubkey)
632 .unwrap();
633 let bincode_res = bincode::deserialize::<VoteStateVersions>(&expanded_buf)
634 .map(|versioned| versioned.try_convert_to_v4(&vote_pubkey).unwrap());
635
636 let test_vote_state = unsafe { test_vote_state.assume_init() };
637 assert_eq!(test_vote_state, bincode_res.unwrap());
638 }
639 }
640
641 #[test]
642 fn test_bls_pubkey_compressed() {
643 let vote_pubkey = Pubkey::new_unique();
644
645 let run_test = |start, expected| {
646 let versioned = VoteStateVersions::new_v4(start);
647 let serialized = bincode::serialize(&versioned).unwrap();
648 let deserialized = VoteStateV4::deserialize(&serialized, &vote_pubkey).unwrap();
649 assert_eq!(deserialized.bls_pubkey_compressed, expected);
650 };
651
652 let vote_state_none = VoteStateV4::default();
654 assert_eq!(vote_state_none.bls_pubkey_compressed, None);
655 run_test(vote_state_none, None);
656
657 let test_bls_key = [42u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE];
659 let vote_state_some = VoteStateV4 {
660 bls_pubkey_compressed: Some(test_bls_key),
661 ..VoteStateV4::default()
662 };
663 assert_eq!(vote_state_some.bls_pubkey_compressed, Some(test_bls_key));
664 run_test(vote_state_some, Some(test_bls_key));
665 }
666
667 #[test]
668 fn test_deserialize_invalid_variant_tags() {
669 let vote_pubkey = Pubkey::new_unique();
670 let mut buf = vec![0u8; VoteStateV4::size_of()];
671
672 let mut vs = VoteStateV4::default();
674 assert_eq!(
675 VoteStateV4::deserialize_into(&buf, &mut vs, &vote_pubkey),
676 Err(InstructionError::InvalidAccountData)
677 );
678
679 buf[..4].copy_from_slice(&4u32.to_le_bytes());
681 assert_eq!(
682 VoteStateV4::deserialize_into(&buf, &mut vs, &vote_pubkey),
683 Err(InstructionError::InvalidAccountData)
684 );
685
686 buf[..4].copy_from_slice(&u32::MAX.to_le_bytes());
688 assert_eq!(
689 VoteStateV4::deserialize_into(&buf, &mut vs, &vote_pubkey),
690 Err(InstructionError::InvalidAccountData)
691 );
692 }
693
694 #[test]
695 fn test_invalid_option_discriminants() {
696 let vote_pubkey = Pubkey::new_unique();
697 let vote_state = VoteStateV4 {
698 root_slot: Some(42),
699 ..VoteStateV4::default()
700 };
701 let valid_buf = bincode::serialize(&VoteStateVersions::new_v4(vote_state)).unwrap();
702
703 let bls_offset = 4 + 32 + 32 + 32 + 32 + 2 + 2 + 8;
708 assert_eq!(valid_buf[bls_offset], 0); {
711 let mut buf = valid_buf.clone();
712 buf[bls_offset] = 2;
713 let mut vs = VoteStateV4::default();
714 assert_eq!(
715 VoteStateV4::deserialize_into(&buf, &mut vs, &vote_pubkey),
716 Err(InstructionError::InvalidAccountData)
717 );
718 }
719
720 let root_slot_offset = bls_offset + 1 + 8;
723 assert_eq!(valid_buf[root_slot_offset], 1); {
726 let mut buf = valid_buf.clone();
727 buf[root_slot_offset] = 2;
728 let mut vs = VoteStateV4::default();
729 assert_eq!(
730 VoteStateV4::deserialize_into(&buf, &mut vs, &vote_pubkey),
731 Err(InstructionError::InvalidAccountData)
732 );
733 }
734 }
735
736 #[allow(clippy::arithmetic_side_effects)]
737 #[test_matrix(
738 [0u8, 50, 100, 255],
739 [0usize, 1, 2]
740 )]
741 fn test_deserialize_prior_versions_simd_0185(commission: u8, prior_voters_count: usize) {
742 let vote_pubkey = Pubkey::new_unique();
743 let node_pubkey = Pubkey::new_unique();
744 let root_slot = Some(42);
745 let epoch_credits = vec![(0, 100, 0), (1, 200, 100)];
746 let last_timestamp = BlockTimestamp {
747 slot: 999,
748 timestamp: 12345,
749 };
750 let mut prior_voters = CircBuf::default();
751 for i in 0..prior_voters_count {
752 prior_voters.append((Pubkey::new_unique(), i as u64 * 5, (i as u64 + 1) * 5));
753 }
754
755 let assert_simd_0185_defaults = |v4: &VoteStateV4| {
765 assert_eq!(
766 v4.inflation_rewards_commission_bps,
767 u16::from(commission) * 100
768 );
769 assert_eq!(v4.block_revenue_commission_bps, 10_000);
770 assert_eq!(v4.inflation_rewards_collector, vote_pubkey);
771 assert_eq!(v4.block_revenue_collector, node_pubkey);
772 assert_eq!(v4.pending_delegator_rewards, 0);
773 assert_eq!(v4.bls_pubkey_compressed, None);
774
775 assert_eq!(v4.epoch_credits, epoch_credits);
777 assert_eq!(v4.last_timestamp, last_timestamp);
778 };
779
780 let v1_state = VoteState1_14_11 {
782 node_pubkey,
783 commission,
784 root_slot,
785 epoch_credits: epoch_credits.clone(),
786 last_timestamp: last_timestamp.clone(),
787 prior_voters: prior_voters.clone(),
788 ..VoteState1_14_11::default()
789 };
790 let buf = bincode::serialize(&VoteStateVersions::V1_14_11(Box::new(v1_state))).unwrap();
791 let v4 = VoteStateV4::deserialize(&buf, &vote_pubkey).unwrap();
792 assert_simd_0185_defaults(&v4);
793
794 let v3_state = VoteStateV3 {
796 node_pubkey,
797 commission,
798 root_slot,
799 epoch_credits: epoch_credits.clone(),
800 last_timestamp: last_timestamp.clone(),
801 prior_voters: prior_voters.clone(),
802 ..VoteStateV3::default()
803 };
804 let buf = bincode::serialize(&VoteStateVersions::new_v3(v3_state)).unwrap();
805 let v4 = VoteStateV4::deserialize(&buf, &vote_pubkey).unwrap();
806 assert_simd_0185_defaults(&v4);
807 }
808
809 #[test]
810 fn test_has_latency() {
811 let vote_pubkey = Pubkey::new_unique();
812
813 let mut v1_state = VoteState1_14_11::default();
815 v1_state.votes.push_back(Lockout::new(100));
816 v1_state.votes.push_back(Lockout::new(200));
817 let buf = bincode::serialize(&VoteStateVersions::V1_14_11(Box::new(v1_state))).unwrap();
818 let deserialized = VoteStateV4::deserialize(&buf, &vote_pubkey).unwrap();
819 assert_eq!(deserialized.votes.len(), 2);
820 for vote in &deserialized.votes {
821 assert_eq!(vote.latency, 0);
822 }
823
824 let mut v4_state = VoteStateV4::default();
826 v4_state.votes.push_back(LandedVote {
827 latency: 42,
828 lockout: Lockout::new(100),
829 });
830 let buf = bincode::serialize(&VoteStateVersions::new_v4(v4_state)).unwrap();
831 let deserialized = VoteStateV4::deserialize(&buf, &vote_pubkey).unwrap();
832 assert_eq!(deserialized.votes[0].latency, 42);
833 }
834}