1#[cfg(feature = "stable-abi")]
4use solana_frozen_abi_macro::{frozen_abi, StableAbi, StableAbiSample};
5use {
6 super::state::TowerSync,
7 crate::state::{
8 Vote, VoteAuthorize, VoteAuthorizeCheckedWithSeedArgs, VoteAuthorizeWithSeedArgs, VoteInit,
9 VoteInitV2, VoteStateUpdate, VoteStateV4,
10 },
11 solana_clock::{Slot, UnixTimestamp},
12 solana_hash::Hash,
13 solana_pubkey::Pubkey,
14};
15#[cfg(any(feature = "bincode", feature = "wincode"))]
16use {
17 crate::program::id,
18 solana_instruction::{AccountMeta, Instruction},
19 solana_sdk_ids::{system_program, sysvar},
20};
21#[cfg(feature = "wincode")]
22use {
23 crate::state::wincode_compact::{CompactTowerSync, CompactVoteStateUpdate},
24 wincode::{SchemaRead, SchemaWrite},
25};
26#[cfg(feature = "serde")]
27use {
28 crate::state::{serde_compact_vote_state_update, serde_tower_sync},
29 serde_derive::{Deserialize, Serialize},
30};
31
32#[repr(u8)]
33#[cfg_attr(feature = "stable-abi", derive(StableAbi, StableAbiSample))]
34#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
35#[cfg_attr(feature = "wincode", derive(SchemaWrite, SchemaRead))]
36#[derive(Debug, PartialEq, Eq, Clone)]
37pub enum CommissionKind {
38 InflationRewards = 0,
39 BlockRevenue = 1,
40}
41
42#[cfg_attr(
43 feature = "stable-abi",
44 frozen_abi(
45 abi_digest = "9bqZ5L1KnMFnjQPMoRtfhdgUok3G5W2KKRGuw8uwbkuY",
46 abi_serializer = ["bincode", "wincode"]
47 ),
48 derive(StableAbi, StableAbiSample)
49)]
50#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
51#[cfg_attr(feature = "wincode", derive(SchemaWrite, SchemaRead))]
52#[derive(Debug, PartialEq, Eq, Clone)]
53pub enum VoteInstruction {
54 InitializeAccount(VoteInit),
67
68 Authorize(Pubkey, VoteAuthorize),
78
79 Vote(Vote),
87
88 Withdraw(u64),
95
96 UpdateValidatorIdentity,
103
104 UpdateCommission(u8),
110
111 VoteSwitch(Vote, Hash),
119
120 AuthorizeChecked(VoteAuthorize),
134
135 UpdateVoteState(VoteStateUpdate),
141
142 UpdateVoteStateSwitch(VoteStateUpdate, Hash),
148
149 AuthorizeWithSeed(VoteAuthorizeWithSeedArgs),
162
163 AuthorizeCheckedWithSeed(VoteAuthorizeCheckedWithSeedArgs),
180
181 #[cfg_attr(feature = "serde", serde(with = "serde_compact_vote_state_update"))]
187 CompactUpdateVoteState(
188 #[cfg_attr(feature = "wincode", wincode(with = "CompactVoteStateUpdate"))] VoteStateUpdate,
189 ),
190
191 CompactUpdateVoteStateSwitch(
197 #[cfg_attr(feature = "serde", serde(with = "serde_compact_vote_state_update"))]
198 #[cfg_attr(feature = "wincode", wincode(with = "CompactVoteStateUpdate"))]
199 VoteStateUpdate,
200 Hash,
201 ),
202
203 #[cfg_attr(feature = "serde", serde(with = "serde_tower_sync"))]
209 TowerSync(#[cfg_attr(feature = "wincode", wincode(with = "CompactTowerSync"))] TowerSync),
210
211 TowerSyncSwitch(
217 #[cfg_attr(feature = "serde", serde(with = "serde_tower_sync"))]
218 #[cfg_attr(feature = "wincode", wincode(with = "CompactTowerSync"))]
219 TowerSync,
220 Hash,
221 ),
222
223 InitializeAccountV2(VoteInitV2),
244
245 UpdateCommissionCollector(CommissionKind),
254
255 UpdateCommissionBps {
262 commission_bps: u16,
263 kind: CommissionKind,
264 },
265
266 DepositDelegatorRewards { deposit: u64 },
273}
274
275impl VoteInstruction {
276 pub fn is_simple_vote(&self) -> bool {
277 matches!(
278 self,
279 Self::Vote(_)
280 | Self::VoteSwitch(_, _)
281 | Self::UpdateVoteState(_)
282 | Self::UpdateVoteStateSwitch(_, _)
283 | Self::CompactUpdateVoteState(_)
284 | Self::CompactUpdateVoteStateSwitch(_, _)
285 | Self::TowerSync(_)
286 | Self::TowerSyncSwitch(_, _),
287 )
288 }
289
290 pub fn is_single_vote_state_update(&self) -> bool {
291 matches!(
292 self,
293 Self::UpdateVoteState(_)
294 | Self::UpdateVoteStateSwitch(_, _)
295 | Self::CompactUpdateVoteState(_)
296 | Self::CompactUpdateVoteStateSwitch(_, _)
297 | Self::TowerSync(_)
298 | Self::TowerSyncSwitch(_, _),
299 )
300 }
301
302 pub fn last_voted_slot(&self) -> Option<Slot> {
304 assert!(self.is_simple_vote());
305 match self {
306 Self::Vote(v) | Self::VoteSwitch(v, _) => v.last_voted_slot(),
307 Self::UpdateVoteState(vote_state_update)
308 | Self::UpdateVoteStateSwitch(vote_state_update, _)
309 | Self::CompactUpdateVoteState(vote_state_update)
310 | Self::CompactUpdateVoteStateSwitch(vote_state_update, _) => {
311 vote_state_update.last_voted_slot()
312 }
313 Self::TowerSync(tower_sync) | Self::TowerSyncSwitch(tower_sync, _) => {
314 tower_sync.last_voted_slot()
315 }
316 _ => panic!("Tried to get slot on non simple vote instruction"),
317 }
318 }
319
320 pub fn hash(&self) -> Hash {
322 assert!(self.is_simple_vote());
323 let hash = match self {
324 Self::Vote(v) | Self::VoteSwitch(v, _) => &v.hash,
325 Self::UpdateVoteState(vote_state_update)
326 | Self::UpdateVoteStateSwitch(vote_state_update, _)
327 | Self::CompactUpdateVoteState(vote_state_update)
328 | Self::CompactUpdateVoteStateSwitch(vote_state_update, _) => &vote_state_update.hash,
329 Self::TowerSync(tower_sync) | Self::TowerSyncSwitch(tower_sync, _) => &tower_sync.hash,
330 _ => panic!("Tried to get hash on non simple vote instruction"),
331 };
332 Hash::new_from_array(hash.to_bytes())
333 }
334 pub fn timestamp(&self) -> Option<UnixTimestamp> {
336 assert!(self.is_simple_vote());
337 match self {
338 Self::Vote(v) | Self::VoteSwitch(v, _) => v.timestamp,
339 Self::UpdateVoteState(vote_state_update)
340 | Self::UpdateVoteStateSwitch(vote_state_update, _)
341 | Self::CompactUpdateVoteState(vote_state_update)
342 | Self::CompactUpdateVoteStateSwitch(vote_state_update, _) => {
343 vote_state_update.timestamp
344 }
345 Self::TowerSync(tower_sync) | Self::TowerSyncSwitch(tower_sync, _) => {
346 tower_sync.timestamp
347 }
348 _ => panic!("Tried to get timestamp on non simple vote instruction"),
349 }
350 }
351}
352
353#[cfg(all(feature = "bincode", not(feature = "wincode")))]
354#[inline(always)]
355fn create_instruction(
356 program_id: Pubkey,
357 data: &VoteInstruction,
358 accounts: Vec<AccountMeta>,
359) -> Instruction {
360 Instruction::new_with_bincode(program_id, data, accounts)
361}
362
363#[cfg(feature = "wincode")]
364#[inline(always)]
365fn create_instruction(
366 program_id: Pubkey,
367 data: &VoteInstruction,
368 accounts: Vec<AccountMeta>,
369) -> Instruction {
370 Instruction::new_with_wincode(program_id, data, accounts)
371}
372
373#[cfg(any(feature = "bincode", feature = "wincode"))]
374fn initialize_account(vote_pubkey: &Pubkey, vote_init: &VoteInit) -> Instruction {
375 let account_metas = vec![
376 AccountMeta::new(*vote_pubkey, false),
377 AccountMeta::new_readonly(sysvar::rent::id(), false),
378 AccountMeta::new_readonly(sysvar::clock::id(), false),
379 AccountMeta::new_readonly(vote_init.node_pubkey, true),
380 ];
381
382 create_instruction(
383 id(),
384 &VoteInstruction::InitializeAccount(*vote_init),
385 account_metas,
386 )
387}
388
389#[cfg(any(feature = "bincode", feature = "wincode"))]
390fn initialize_account_v2(
391 vote_pubkey: &Pubkey,
392 vote_init: &VoteInitV2,
393 inflation_rewards_collector: &Pubkey,
394 block_revenue_collector: &Pubkey,
395) -> Instruction {
396 let account_metas = vec![
397 AccountMeta::new(*vote_pubkey, false),
398 AccountMeta::new_readonly(vote_init.node_pubkey, true),
399 AccountMeta::new(*inflation_rewards_collector, false),
400 AccountMeta::new(*block_revenue_collector, false),
401 ];
402
403 create_instruction(
404 id(),
405 &VoteInstruction::InitializeAccountV2(*vote_init),
406 account_metas,
407 )
408}
409
410pub struct CreateVoteAccountConfig<'a> {
411 pub space: u64,
412 pub with_seed: Option<(&'a Pubkey, &'a str)>,
413}
414
415impl Default for CreateVoteAccountConfig<'_> {
416 fn default() -> Self {
417 Self {
418 space: VoteStateV4::size_of() as u64,
420 with_seed: None,
421 }
422 }
423}
424
425#[cfg(any(feature = "bincode", feature = "wincode"))]
426pub fn create_account_with_config(
427 from_pubkey: &Pubkey,
428 vote_pubkey: &Pubkey,
429 vote_init: &VoteInit,
430 lamports: u64,
431 config: CreateVoteAccountConfig,
432) -> Vec<Instruction> {
433 let create_ix = if let Some((base, seed)) = config.with_seed {
434 solana_system_interface::instruction::create_account_with_seed(
435 from_pubkey,
436 vote_pubkey,
437 base,
438 seed,
439 lamports,
440 config.space,
441 &id(),
442 )
443 } else {
444 solana_system_interface::instruction::create_account(
445 from_pubkey,
446 vote_pubkey,
447 lamports,
448 config.space,
449 &id(),
450 )
451 };
452 let init_ix = initialize_account(vote_pubkey, vote_init);
453 vec![create_ix, init_ix]
454}
455
456#[cfg(any(feature = "bincode", feature = "wincode"))]
457pub fn create_account_with_config_v2(
458 from_pubkey: &Pubkey,
459 vote_pubkey: &Pubkey,
460 vote_init: &VoteInitV2,
461 inflation_rewards_collector: &Pubkey,
462 block_revenue_collector: &Pubkey,
463 lamports: u64,
464 config: CreateVoteAccountConfig,
465) -> Vec<Instruction> {
466 let create_ix = if let Some((base, seed)) = config.with_seed {
467 solana_system_interface::instruction::create_account_with_seed(
468 from_pubkey,
469 vote_pubkey,
470 base,
471 seed,
472 lamports,
473 config.space,
474 &id(),
475 )
476 } else {
477 solana_system_interface::instruction::create_account(
478 from_pubkey,
479 vote_pubkey,
480 lamports,
481 config.space,
482 &id(),
483 )
484 };
485 let init_ix = initialize_account_v2(
486 vote_pubkey,
487 vote_init,
488 inflation_rewards_collector,
489 block_revenue_collector,
490 );
491 vec![create_ix, init_ix]
492}
493
494#[cfg(any(feature = "bincode", feature = "wincode"))]
495pub fn authorize(
496 vote_pubkey: &Pubkey,
497 authorized_pubkey: &Pubkey, new_authorized_pubkey: &Pubkey,
499 vote_authorize: VoteAuthorize,
500) -> Instruction {
501 let account_metas = vec![
502 AccountMeta::new(*vote_pubkey, false),
503 AccountMeta::new_readonly(sysvar::clock::id(), false),
504 AccountMeta::new_readonly(*authorized_pubkey, true),
505 ];
506
507 create_instruction(
508 id(),
509 &VoteInstruction::Authorize(*new_authorized_pubkey, vote_authorize),
510 account_metas,
511 )
512}
513
514#[cfg(any(feature = "bincode", feature = "wincode"))]
515pub fn authorize_checked(
516 vote_pubkey: &Pubkey,
517 authorized_pubkey: &Pubkey, new_authorized_pubkey: &Pubkey,
519 vote_authorize: VoteAuthorize,
520) -> Instruction {
521 let account_metas = vec![
522 AccountMeta::new(*vote_pubkey, false),
523 AccountMeta::new_readonly(sysvar::clock::id(), false),
524 AccountMeta::new_readonly(*authorized_pubkey, true),
525 AccountMeta::new_readonly(*new_authorized_pubkey, true),
526 ];
527
528 create_instruction(
529 id(),
530 &VoteInstruction::AuthorizeChecked(vote_authorize),
531 account_metas,
532 )
533}
534
535#[cfg(any(feature = "bincode", feature = "wincode"))]
536pub fn authorize_with_seed(
537 vote_pubkey: &Pubkey,
538 current_authority_base_key: &Pubkey,
539 current_authority_derived_key_owner: &Pubkey,
540 current_authority_derived_key_seed: &str,
541 new_authority: &Pubkey,
542 authorization_type: VoteAuthorize,
543) -> Instruction {
544 let account_metas = vec![
545 AccountMeta::new(*vote_pubkey, false),
546 AccountMeta::new_readonly(sysvar::clock::id(), false),
547 AccountMeta::new_readonly(*current_authority_base_key, true),
548 ];
549
550 create_instruction(
551 id(),
552 &VoteInstruction::AuthorizeWithSeed(VoteAuthorizeWithSeedArgs {
553 authorization_type,
554 current_authority_derived_key_owner: *current_authority_derived_key_owner,
555 current_authority_derived_key_seed: current_authority_derived_key_seed.to_string(),
556 new_authority: *new_authority,
557 }),
558 account_metas,
559 )
560}
561
562#[cfg(any(feature = "bincode", feature = "wincode"))]
563pub fn authorize_checked_with_seed(
564 vote_pubkey: &Pubkey,
565 current_authority_base_key: &Pubkey,
566 current_authority_derived_key_owner: &Pubkey,
567 current_authority_derived_key_seed: &str,
568 new_authority: &Pubkey,
569 authorization_type: VoteAuthorize,
570) -> Instruction {
571 let account_metas = vec![
572 AccountMeta::new(*vote_pubkey, false),
573 AccountMeta::new_readonly(sysvar::clock::id(), false),
574 AccountMeta::new_readonly(*current_authority_base_key, true),
575 AccountMeta::new_readonly(*new_authority, true),
576 ];
577
578 create_instruction(
579 id(),
580 &VoteInstruction::AuthorizeCheckedWithSeed(VoteAuthorizeCheckedWithSeedArgs {
581 authorization_type,
582 current_authority_derived_key_owner: *current_authority_derived_key_owner,
583 current_authority_derived_key_seed: current_authority_derived_key_seed.to_string(),
584 }),
585 account_metas,
586 )
587}
588
589#[cfg(any(feature = "bincode", feature = "wincode"))]
590pub fn update_validator_identity(
591 vote_pubkey: &Pubkey,
592 authorized_withdrawer_pubkey: &Pubkey,
593 node_pubkey: &Pubkey,
594) -> Instruction {
595 let account_metas = vec![
596 AccountMeta::new(*vote_pubkey, false),
597 AccountMeta::new_readonly(*node_pubkey, true),
598 AccountMeta::new_readonly(*authorized_withdrawer_pubkey, true),
599 ];
600
601 create_instruction(
602 id(),
603 &VoteInstruction::UpdateValidatorIdentity,
604 account_metas,
605 )
606}
607
608#[cfg(any(feature = "bincode", feature = "wincode"))]
609pub fn update_commission(
610 vote_pubkey: &Pubkey,
611 authorized_withdrawer_pubkey: &Pubkey,
612 commission: u8,
613) -> Instruction {
614 let account_metas = vec![
615 AccountMeta::new(*vote_pubkey, false),
616 AccountMeta::new_readonly(*authorized_withdrawer_pubkey, true),
617 ];
618
619 create_instruction(
620 id(),
621 &VoteInstruction::UpdateCommission(commission),
622 account_metas,
623 )
624}
625
626#[cfg(any(feature = "bincode", feature = "wincode"))]
627pub fn update_commission_collector(
628 vote_pubkey: &Pubkey,
629 authorized_withdrawer_pubkey: &Pubkey,
630 new_collector_pubkey: &Pubkey,
631 kind: CommissionKind,
632) -> Instruction {
633 let account_metas = vec![
634 AccountMeta::new(*vote_pubkey, false),
635 AccountMeta::new(*new_collector_pubkey, false),
636 AccountMeta::new_readonly(*authorized_withdrawer_pubkey, true),
637 ];
638
639 create_instruction(
640 id(),
641 &VoteInstruction::UpdateCommissionCollector(kind),
642 account_metas,
643 )
644}
645
646#[cfg(any(feature = "bincode", feature = "wincode"))]
647pub fn update_commission_bps(
648 vote_pubkey: &Pubkey,
649 authorized_withdrawer_pubkey: &Pubkey,
650 kind: CommissionKind,
651 commission_bps: u16,
652) -> Instruction {
653 let account_metas = vec![
654 AccountMeta::new(*vote_pubkey, false),
655 AccountMeta::new_readonly(*authorized_withdrawer_pubkey, true),
656 ];
657
658 create_instruction(
659 id(),
660 &VoteInstruction::UpdateCommissionBps {
661 kind,
662 commission_bps,
663 },
664 account_metas,
665 )
666}
667
668#[cfg(any(feature = "bincode", feature = "wincode"))]
669pub fn deposit_delegator_rewards(
670 vote_pubkey: &Pubkey,
671 source_pubkey: &Pubkey,
672 deposit: u64,
673) -> Instruction {
674 let account_metas = vec![
675 AccountMeta::new(*vote_pubkey, false),
676 AccountMeta::new(*source_pubkey, true),
677 AccountMeta::new_readonly(system_program::id(), false),
678 ];
679
680 create_instruction(
681 id(),
682 &VoteInstruction::DepositDelegatorRewards { deposit },
683 account_metas,
684 )
685}
686
687#[cfg(any(feature = "bincode", feature = "wincode"))]
688pub fn vote(vote_pubkey: &Pubkey, authorized_voter_pubkey: &Pubkey, vote: Vote) -> Instruction {
689 let account_metas = vec![
690 AccountMeta::new(*vote_pubkey, false),
691 AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
692 AccountMeta::new_readonly(sysvar::clock::id(), false),
693 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
694 ];
695
696 create_instruction(id(), &VoteInstruction::Vote(vote), account_metas)
697}
698
699#[cfg(any(feature = "bincode", feature = "wincode"))]
700pub fn vote_switch(
701 vote_pubkey: &Pubkey,
702 authorized_voter_pubkey: &Pubkey,
703 vote: Vote,
704 proof_hash: Hash,
705) -> Instruction {
706 let account_metas = vec![
707 AccountMeta::new(*vote_pubkey, false),
708 AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
709 AccountMeta::new_readonly(sysvar::clock::id(), false),
710 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
711 ];
712
713 create_instruction(
714 id(),
715 &VoteInstruction::VoteSwitch(vote, proof_hash),
716 account_metas,
717 )
718}
719
720#[cfg(any(feature = "bincode", feature = "wincode"))]
721pub fn update_vote_state(
722 vote_pubkey: &Pubkey,
723 authorized_voter_pubkey: &Pubkey,
724 vote_state_update: VoteStateUpdate,
725) -> Instruction {
726 let account_metas = vec![
727 AccountMeta::new(*vote_pubkey, false),
728 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
729 ];
730
731 create_instruction(
732 id(),
733 &VoteInstruction::UpdateVoteState(vote_state_update),
734 account_metas,
735 )
736}
737
738#[cfg(any(feature = "bincode", feature = "wincode"))]
739pub fn update_vote_state_switch(
740 vote_pubkey: &Pubkey,
741 authorized_voter_pubkey: &Pubkey,
742 vote_state_update: VoteStateUpdate,
743 proof_hash: Hash,
744) -> Instruction {
745 let account_metas = vec![
746 AccountMeta::new(*vote_pubkey, false),
747 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
748 ];
749
750 create_instruction(
751 id(),
752 &VoteInstruction::UpdateVoteStateSwitch(vote_state_update, proof_hash),
753 account_metas,
754 )
755}
756
757#[cfg(any(feature = "bincode", feature = "wincode"))]
758pub fn compact_update_vote_state(
759 vote_pubkey: &Pubkey,
760 authorized_voter_pubkey: &Pubkey,
761 vote_state_update: VoteStateUpdate,
762) -> Instruction {
763 let account_metas = vec![
764 AccountMeta::new(*vote_pubkey, false),
765 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
766 ];
767
768 create_instruction(
769 id(),
770 &VoteInstruction::CompactUpdateVoteState(vote_state_update),
771 account_metas,
772 )
773}
774
775#[cfg(any(feature = "bincode", feature = "wincode"))]
776pub fn compact_update_vote_state_switch(
777 vote_pubkey: &Pubkey,
778 authorized_voter_pubkey: &Pubkey,
779 vote_state_update: VoteStateUpdate,
780 proof_hash: Hash,
781) -> Instruction {
782 let account_metas = vec![
783 AccountMeta::new(*vote_pubkey, false),
784 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
785 ];
786
787 create_instruction(
788 id(),
789 &VoteInstruction::CompactUpdateVoteStateSwitch(vote_state_update, proof_hash),
790 account_metas,
791 )
792}
793
794#[cfg(any(feature = "bincode", feature = "wincode"))]
795pub fn tower_sync(
796 vote_pubkey: &Pubkey,
797 authorized_voter_pubkey: &Pubkey,
798 tower_sync: TowerSync,
799) -> Instruction {
800 let account_metas = vec![
801 AccountMeta::new(*vote_pubkey, false),
802 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
803 ];
804
805 create_instruction(id(), &VoteInstruction::TowerSync(tower_sync), account_metas)
806}
807
808#[cfg(any(feature = "bincode", feature = "wincode"))]
809pub fn tower_sync_switch(
810 vote_pubkey: &Pubkey,
811 authorized_voter_pubkey: &Pubkey,
812 tower_sync: TowerSync,
813 proof_hash: Hash,
814) -> Instruction {
815 let account_metas = vec![
816 AccountMeta::new(*vote_pubkey, false),
817 AccountMeta::new_readonly(*authorized_voter_pubkey, true),
818 ];
819
820 create_instruction(
821 id(),
822 &VoteInstruction::TowerSyncSwitch(tower_sync, proof_hash),
823 account_metas,
824 )
825}
826
827#[cfg(any(feature = "bincode", feature = "wincode"))]
828pub fn withdraw(
829 vote_pubkey: &Pubkey,
830 authorized_withdrawer_pubkey: &Pubkey,
831 lamports: u64,
832 to_pubkey: &Pubkey,
833) -> Instruction {
834 let account_metas = vec![
835 AccountMeta::new(*vote_pubkey, false),
836 AccountMeta::new(*to_pubkey, false),
837 AccountMeta::new_readonly(*authorized_withdrawer_pubkey, true),
838 ];
839
840 create_instruction(id(), &VoteInstruction::Withdraw(lamports), account_metas)
841}
842
843#[cfg(all(test, feature = "bincode"))]
844mod tests {
845 use {super::*, crate::state::Lockout, std::collections::VecDeque};
846
847 #[test]
848 fn test_compact_serialize_rejects_confirmation_count_above_u8() {
849 let lockouts = VecDeque::from([Lockout::new_with_confirmation_count(1, 256)]);
853 let vote_state_update = VoteStateUpdate::new(lockouts.clone(), None, Hash::default());
854 let tower_sync = TowerSync::new(lockouts, None, Hash::default(), Hash::default());
855
856 for ix in [
857 VoteInstruction::CompactUpdateVoteState(vote_state_update),
858 VoteInstruction::TowerSync(tower_sync),
859 ] {
860 let err = bincode::serialize(&ix).unwrap_err();
861 assert!(
862 err.to_string().contains("Invalid confirmation count"),
863 "unexpected error: {err}"
864 );
865 #[cfg(feature = "wincode")]
866 assert!(wincode::serialize(&ix).is_err());
867 }
868 }
869
870 #[test]
871 fn test_deposit_delegator_rewards_includes_system_program() {
872 let vote_pubkey = Pubkey::new_unique();
873 let source_pubkey = Pubkey::new_unique();
874
875 let instruction = deposit_delegator_rewards(&vote_pubkey, &source_pubkey, 100_000);
876
877 assert_eq!(instruction.program_id, id());
878 assert_eq!(instruction.accounts.len(), 3);
879
880 let vote_meta = &instruction.accounts[0];
881 assert_eq!(vote_meta.pubkey, vote_pubkey);
882 assert!(!vote_meta.is_signer);
883 assert!(vote_meta.is_writable);
884
885 let source_meta = &instruction.accounts[1];
886 assert_eq!(source_meta.pubkey, source_pubkey);
887 assert!(source_meta.is_signer);
888 assert!(source_meta.is_writable);
889
890 let system_program_meta = &instruction.accounts[2];
893 assert_eq!(system_program_meta.pubkey, system_program::id());
894 assert!(!system_program_meta.is_signer);
895 assert!(!system_program_meta.is_writable);
896 }
897
898 #[test]
899 fn test_builders_match_bincode_encoding() {
900 let vote_pubkey = Pubkey::new_unique();
901 let voter_pubkey = Pubkey::new_unique();
902 let lockouts = VecDeque::from([Lockout::new_with_confirmation_count(1, 2)]);
903 let tower_sync = TowerSync::new(
904 lockouts,
905 Some(0),
906 Hash::new_from_array([1; 32]),
907 Hash::new_from_array([2; 32]),
908 );
909 let vote_init = VoteInit {
910 node_pubkey: Pubkey::new_unique(),
911 authorized_voter: voter_pubkey,
912 authorized_withdrawer: Pubkey::new_unique(),
913 commission: 7,
914 };
915
916 for (ix, expected) in [
917 (
918 tower_sync_switch(
919 &vote_pubkey,
920 &voter_pubkey,
921 tower_sync.clone(),
922 Hash::default(),
923 ),
924 VoteInstruction::TowerSyncSwitch(tower_sync, Hash::default()),
925 ),
926 (
927 authorize_with_seed(
928 &vote_pubkey,
929 &voter_pubkey,
930 &vote_pubkey,
931 "seed",
932 &voter_pubkey,
933 VoteAuthorize::Withdrawer,
934 ),
935 VoteInstruction::AuthorizeWithSeed(VoteAuthorizeWithSeedArgs {
936 authorization_type: VoteAuthorize::Withdrawer,
937 current_authority_derived_key_owner: vote_pubkey,
938 current_authority_derived_key_seed: "seed".to_string(),
939 new_authority: voter_pubkey,
940 }),
941 ),
942 (
943 create_account_with_config(
944 &voter_pubkey,
945 &vote_pubkey,
946 &vote_init,
947 42,
948 CreateVoteAccountConfig::default(),
949 )
950 .pop()
951 .unwrap(),
952 VoteInstruction::InitializeAccount(vote_init),
953 ),
954 ] {
955 assert_eq!(ix.data, bincode::serialize(&expected).unwrap());
956 }
957 }
958}