solana_vote_program/
vote_processor.rs

1//! Vote program processor
2
3use {
4    crate::vote_state,
5    log::*,
6    solana_feature_set as feature_set,
7    solana_program::vote::{instruction::VoteInstruction, program::id, state::VoteAuthorize},
8    solana_program_runtime::{
9        declare_process_instruction, invoke_context::InvokeContext,
10        sysvar_cache::get_sysvar_with_account_check,
11    },
12    solana_sdk::{
13        instruction::InstructionError,
14        program_utils::limited_deserialize,
15        pubkey::Pubkey,
16        transaction_context::{BorrowedAccount, InstructionContext, TransactionContext},
17    },
18    std::collections::HashSet,
19};
20
21fn process_authorize_with_seed_instruction(
22    invoke_context: &InvokeContext,
23    instruction_context: &InstructionContext,
24    transaction_context: &TransactionContext,
25    vote_account: &mut BorrowedAccount,
26    new_authority: &Pubkey,
27    authorization_type: VoteAuthorize,
28    current_authority_derived_key_owner: &Pubkey,
29    current_authority_derived_key_seed: &str,
30) -> Result<(), InstructionError> {
31    let clock = get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?;
32    let mut expected_authority_keys: HashSet<Pubkey> = HashSet::default();
33    if instruction_context.is_instruction_account_signer(2)? {
34        let base_pubkey = transaction_context.get_key_of_account_at_index(
35            instruction_context.get_index_of_instruction_account_in_transaction(2)?,
36        )?;
37        expected_authority_keys.insert(Pubkey::create_with_seed(
38            base_pubkey,
39            current_authority_derived_key_seed,
40            current_authority_derived_key_owner,
41        )?);
42    };
43    vote_state::authorize(
44        vote_account,
45        new_authority,
46        authorization_type,
47        &expected_authority_keys,
48        &clock,
49    )
50}
51
52// Citing `runtime/src/block_cost_limit.rs`, vote has statically defined 2100
53// units; can consume based on instructions in the future like `bpf_loader` does.
54pub const DEFAULT_COMPUTE_UNITS: u64 = 2_100;
55
56declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| {
57    let transaction_context = &invoke_context.transaction_context;
58    let instruction_context = transaction_context.get_current_instruction_context()?;
59    let data = instruction_context.get_instruction_data();
60
61    trace!("process_instruction: {:?}", data);
62
63    let mut me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
64    if *me.get_owner() != id() {
65        return Err(InstructionError::InvalidAccountOwner);
66    }
67
68    let signers = instruction_context.get_signers(transaction_context)?;
69    match limited_deserialize(data)? {
70        VoteInstruction::InitializeAccount(vote_init) => {
71            let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?;
72            if !rent.is_exempt(me.get_lamports(), me.get_data().len()) {
73                return Err(InstructionError::InsufficientFunds);
74            }
75            let clock =
76                get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
77            vote_state::initialize_account(&mut me, &vote_init, &signers, &clock)
78        }
79        VoteInstruction::Authorize(voter_pubkey, vote_authorize) => {
80            let clock =
81                get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?;
82            vote_state::authorize(&mut me, &voter_pubkey, vote_authorize, &signers, &clock)
83        }
84        VoteInstruction::AuthorizeWithSeed(args) => {
85            instruction_context.check_number_of_instruction_accounts(3)?;
86            process_authorize_with_seed_instruction(
87                invoke_context,
88                instruction_context,
89                transaction_context,
90                &mut me,
91                &args.new_authority,
92                args.authorization_type,
93                &args.current_authority_derived_key_owner,
94                args.current_authority_derived_key_seed.as_str(),
95            )
96        }
97        VoteInstruction::AuthorizeCheckedWithSeed(args) => {
98            instruction_context.check_number_of_instruction_accounts(4)?;
99            let new_authority = transaction_context.get_key_of_account_at_index(
100                instruction_context.get_index_of_instruction_account_in_transaction(3)?,
101            )?;
102            if !instruction_context.is_instruction_account_signer(3)? {
103                return Err(InstructionError::MissingRequiredSignature);
104            }
105            process_authorize_with_seed_instruction(
106                invoke_context,
107                instruction_context,
108                transaction_context,
109                &mut me,
110                new_authority,
111                args.authorization_type,
112                &args.current_authority_derived_key_owner,
113                args.current_authority_derived_key_seed.as_str(),
114            )
115        }
116        VoteInstruction::UpdateValidatorIdentity => {
117            instruction_context.check_number_of_instruction_accounts(2)?;
118            let node_pubkey = transaction_context.get_key_of_account_at_index(
119                instruction_context.get_index_of_instruction_account_in_transaction(1)?,
120            )?;
121            vote_state::update_validator_identity(&mut me, node_pubkey, &signers)
122        }
123        VoteInstruction::UpdateCommission(commission) => {
124            let sysvar_cache = invoke_context.get_sysvar_cache();
125
126            vote_state::update_commission(
127                &mut me,
128                commission,
129                &signers,
130                sysvar_cache.get_epoch_schedule()?.as_ref(),
131                sysvar_cache.get_clock()?.as_ref(),
132                invoke_context.get_feature_set(),
133            )
134        }
135        VoteInstruction::Vote(vote) | VoteInstruction::VoteSwitch(vote, _) => {
136            if invoke_context
137                .get_feature_set()
138                .is_active(&feature_set::deprecate_legacy_vote_ixs::id())
139                && invoke_context
140                    .get_feature_set()
141                    .is_active(&feature_set::enable_tower_sync_ix::id())
142            {
143                return Err(InstructionError::InvalidInstructionData);
144            }
145            let slot_hashes =
146                get_sysvar_with_account_check::slot_hashes(invoke_context, instruction_context, 1)?;
147            let clock =
148                get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
149            vote_state::process_vote_with_account(
150                &mut me,
151                &slot_hashes,
152                &clock,
153                &vote,
154                &signers,
155                invoke_context.get_feature_set(),
156            )
157        }
158        VoteInstruction::UpdateVoteState(vote_state_update)
159        | VoteInstruction::UpdateVoteStateSwitch(vote_state_update, _) => {
160            if invoke_context
161                .get_feature_set()
162                .is_active(&feature_set::deprecate_legacy_vote_ixs::id())
163                && invoke_context
164                    .get_feature_set()
165                    .is_active(&feature_set::enable_tower_sync_ix::id())
166            {
167                return Err(InstructionError::InvalidInstructionData);
168            }
169            let sysvar_cache = invoke_context.get_sysvar_cache();
170            let slot_hashes = sysvar_cache.get_slot_hashes()?;
171            let clock = sysvar_cache.get_clock()?;
172            vote_state::process_vote_state_update(
173                &mut me,
174                slot_hashes.slot_hashes(),
175                &clock,
176                vote_state_update,
177                &signers,
178                invoke_context.get_feature_set(),
179            )
180        }
181        VoteInstruction::CompactUpdateVoteState(vote_state_update)
182        | VoteInstruction::CompactUpdateVoteStateSwitch(vote_state_update, _) => {
183            if invoke_context
184                .get_feature_set()
185                .is_active(&feature_set::deprecate_legacy_vote_ixs::id())
186                && invoke_context
187                    .get_feature_set()
188                    .is_active(&feature_set::enable_tower_sync_ix::id())
189            {
190                return Err(InstructionError::InvalidInstructionData);
191            }
192            let sysvar_cache = invoke_context.get_sysvar_cache();
193            let slot_hashes = sysvar_cache.get_slot_hashes()?;
194            let clock = sysvar_cache.get_clock()?;
195            vote_state::process_vote_state_update(
196                &mut me,
197                slot_hashes.slot_hashes(),
198                &clock,
199                vote_state_update,
200                &signers,
201                invoke_context.get_feature_set(),
202            )
203        }
204        VoteInstruction::TowerSync(tower_sync)
205        | VoteInstruction::TowerSyncSwitch(tower_sync, _) => {
206            if !invoke_context
207                .get_feature_set()
208                .is_active(&feature_set::enable_tower_sync_ix::id())
209            {
210                return Err(InstructionError::InvalidInstructionData);
211            }
212            let sysvar_cache = invoke_context.get_sysvar_cache();
213            let slot_hashes = sysvar_cache.get_slot_hashes()?;
214            let clock = sysvar_cache.get_clock()?;
215            vote_state::process_tower_sync(
216                &mut me,
217                slot_hashes.slot_hashes(),
218                &clock,
219                tower_sync,
220                &signers,
221                invoke_context.get_feature_set(),
222            )
223        }
224        VoteInstruction::Withdraw(lamports) => {
225            instruction_context.check_number_of_instruction_accounts(2)?;
226            let rent_sysvar = invoke_context.get_sysvar_cache().get_rent()?;
227            let clock_sysvar = invoke_context.get_sysvar_cache().get_clock()?;
228
229            drop(me);
230            vote_state::withdraw(
231                transaction_context,
232                instruction_context,
233                0,
234                lamports,
235                1,
236                &signers,
237                &rent_sysvar,
238                &clock_sysvar,
239            )
240        }
241        VoteInstruction::AuthorizeChecked(vote_authorize) => {
242            instruction_context.check_number_of_instruction_accounts(4)?;
243            let voter_pubkey = transaction_context.get_key_of_account_at_index(
244                instruction_context.get_index_of_instruction_account_in_transaction(3)?,
245            )?;
246            if !instruction_context.is_instruction_account_signer(3)? {
247                return Err(InstructionError::MissingRequiredSignature);
248            }
249            let clock =
250                get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?;
251            vote_state::authorize(&mut me, voter_pubkey, vote_authorize, &signers, &clock)
252        }
253    }
254});
255
256#[cfg(test)]
257mod tests {
258    use {
259        super::*,
260        crate::{
261            vote_error::VoteError,
262            vote_instruction::{
263                authorize, authorize_checked, compact_update_vote_state,
264                compact_update_vote_state_switch, create_account_with_config, update_commission,
265                update_validator_identity, update_vote_state, update_vote_state_switch, vote,
266                vote_switch, withdraw, CreateVoteAccountConfig, VoteInstruction,
267            },
268            vote_state::{
269                self, Lockout, TowerSync, Vote, VoteAuthorize, VoteAuthorizeCheckedWithSeedArgs,
270                VoteAuthorizeWithSeedArgs, VoteInit, VoteState, VoteStateUpdate, VoteStateVersions,
271            },
272        },
273        bincode::serialize,
274        solana_program_runtime::invoke_context::mock_process_instruction,
275        solana_sdk::{
276            account::{self, Account, AccountSharedData, ReadableAccount},
277            account_utils::StateMut,
278            hash::Hash,
279            instruction::{AccountMeta, Instruction},
280            pubkey::Pubkey,
281            sysvar::{
282                self, clock::Clock, epoch_schedule::EpochSchedule, rent::Rent,
283                slot_hashes::SlotHashes,
284            },
285            vote::instruction::{tower_sync, tower_sync_switch},
286        },
287        std::{collections::HashSet, str::FromStr},
288    };
289
290    struct VoteAccountTestFixtureWithAuthorities {
291        vote_account: AccountSharedData,
292        vote_pubkey: Pubkey,
293        voter_base_key: Pubkey,
294        voter_owner: Pubkey,
295        voter_seed: String,
296        withdrawer_base_key: Pubkey,
297        withdrawer_owner: Pubkey,
298        withdrawer_seed: String,
299    }
300
301    fn create_default_account() -> AccountSharedData {
302        AccountSharedData::new(0, 0, &Pubkey::new_unique())
303    }
304
305    fn process_instruction(
306        instruction_data: &[u8],
307        transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
308        instruction_accounts: Vec<AccountMeta>,
309        expected_result: Result<(), InstructionError>,
310    ) -> Vec<AccountSharedData> {
311        mock_process_instruction(
312            &id(),
313            Vec::new(),
314            instruction_data,
315            transaction_accounts,
316            instruction_accounts,
317            expected_result,
318            Entrypoint::vm,
319            |_invoke_context| {},
320            |_invoke_context| {},
321        )
322    }
323
324    fn process_instruction_as_one_arg(
325        instruction: &Instruction,
326        expected_result: Result<(), InstructionError>,
327    ) -> Vec<AccountSharedData> {
328        let mut pubkeys: HashSet<Pubkey> = instruction
329            .accounts
330            .iter()
331            .map(|meta| meta.pubkey)
332            .collect();
333        pubkeys.insert(sysvar::clock::id());
334        pubkeys.insert(sysvar::epoch_schedule::id());
335        pubkeys.insert(sysvar::rent::id());
336        pubkeys.insert(sysvar::slot_hashes::id());
337        let transaction_accounts: Vec<_> = pubkeys
338            .iter()
339            .map(|pubkey| {
340                (
341                    *pubkey,
342                    if sysvar::clock::check_id(pubkey) {
343                        account::create_account_shared_data_for_test(&Clock::default())
344                    } else if sysvar::epoch_schedule::check_id(pubkey) {
345                        account::create_account_shared_data_for_test(
346                            &EpochSchedule::without_warmup(),
347                        )
348                    } else if sysvar::slot_hashes::check_id(pubkey) {
349                        account::create_account_shared_data_for_test(&SlotHashes::default())
350                    } else if sysvar::rent::check_id(pubkey) {
351                        account::create_account_shared_data_for_test(&Rent::free())
352                    } else if *pubkey == invalid_vote_state_pubkey() {
353                        AccountSharedData::from(Account {
354                            owner: invalid_vote_state_pubkey(),
355                            ..Account::default()
356                        })
357                    } else {
358                        AccountSharedData::from(Account {
359                            owner: id(),
360                            ..Account::default()
361                        })
362                    },
363                )
364            })
365            .collect();
366        process_instruction(
367            &instruction.data,
368            transaction_accounts,
369            instruction.accounts.clone(),
370            expected_result,
371        )
372    }
373
374    fn invalid_vote_state_pubkey() -> Pubkey {
375        Pubkey::from_str("BadVote111111111111111111111111111111111111").unwrap()
376    }
377
378    fn create_default_rent_account() -> AccountSharedData {
379        account::create_account_shared_data_for_test(&Rent::free())
380    }
381
382    fn create_default_clock_account() -> AccountSharedData {
383        account::create_account_shared_data_for_test(&Clock::default())
384    }
385
386    fn create_test_account() -> (Pubkey, AccountSharedData) {
387        let rent = Rent::default();
388        let balance = VoteState::get_rent_exempt_reserve(&rent);
389        let vote_pubkey = solana_sdk::pubkey::new_rand();
390        (
391            vote_pubkey,
392            vote_state::create_account(&vote_pubkey, &solana_sdk::pubkey::new_rand(), 0, balance),
393        )
394    }
395
396    fn create_test_account_with_authorized() -> (Pubkey, Pubkey, Pubkey, AccountSharedData) {
397        let vote_pubkey = solana_sdk::pubkey::new_rand();
398        let authorized_voter = solana_sdk::pubkey::new_rand();
399        let authorized_withdrawer = solana_sdk::pubkey::new_rand();
400
401        (
402            vote_pubkey,
403            authorized_voter,
404            authorized_withdrawer,
405            vote_state::create_account_with_authorized(
406                &solana_sdk::pubkey::new_rand(),
407                &authorized_voter,
408                &authorized_withdrawer,
409                0,
410                100,
411            ),
412        )
413    }
414
415    fn create_test_account_with_authorized_from_seed() -> VoteAccountTestFixtureWithAuthorities {
416        let vote_pubkey = Pubkey::new_unique();
417        let voter_base_key = Pubkey::new_unique();
418        let voter_owner = Pubkey::new_unique();
419        let voter_seed = String::from("VOTER_SEED");
420        let withdrawer_base_key = Pubkey::new_unique();
421        let withdrawer_owner = Pubkey::new_unique();
422        let withdrawer_seed = String::from("WITHDRAWER_SEED");
423        let authorized_voter =
424            Pubkey::create_with_seed(&voter_base_key, voter_seed.as_str(), &voter_owner).unwrap();
425        let authorized_withdrawer = Pubkey::create_with_seed(
426            &withdrawer_base_key,
427            withdrawer_seed.as_str(),
428            &withdrawer_owner,
429        )
430        .unwrap();
431
432        VoteAccountTestFixtureWithAuthorities {
433            vote_account: vote_state::create_account_with_authorized(
434                &Pubkey::new_unique(),
435                &authorized_voter,
436                &authorized_withdrawer,
437                0,
438                100,
439            ),
440            vote_pubkey,
441            voter_base_key,
442            voter_owner,
443            voter_seed,
444            withdrawer_base_key,
445            withdrawer_owner,
446            withdrawer_seed,
447        }
448    }
449
450    fn create_test_account_with_epoch_credits(
451        credits_to_append: &[u64],
452    ) -> (Pubkey, AccountSharedData) {
453        let (vote_pubkey, vote_account) = create_test_account();
454        let vote_account_space = vote_account.data().len();
455
456        let mut vote_state = vote_state::from(&vote_account).unwrap();
457        vote_state.authorized_withdrawer = vote_pubkey;
458        vote_state.epoch_credits = Vec::new();
459
460        let mut current_epoch_credits: u64 = 0;
461        let mut previous_epoch_credits = 0;
462        for (epoch, credits) in credits_to_append.iter().enumerate() {
463            current_epoch_credits = current_epoch_credits.saturating_add(*credits);
464            vote_state.epoch_credits.push((
465                u64::try_from(epoch).unwrap(),
466                current_epoch_credits,
467                previous_epoch_credits,
468            ));
469            previous_epoch_credits = current_epoch_credits;
470        }
471
472        let lamports = vote_account.lamports();
473        let mut vote_account_with_epoch_credits =
474            AccountSharedData::new(lamports, vote_account_space, &id());
475        let versioned = VoteStateVersions::new_current(vote_state);
476        vote_state::to(&versioned, &mut vote_account_with_epoch_credits);
477
478        (vote_pubkey, vote_account_with_epoch_credits)
479    }
480
481    /// Returns Vec of serialized VoteInstruction and flag indicating if it is a tower sync
482    /// variant, along with the original vote
483    fn create_serialized_votes() -> (Vote, Vec<(Vec<u8>, bool)>) {
484        let vote = Vote::new(vec![1], Hash::default());
485        let vote_state_update = VoteStateUpdate::from(vec![(1, 1)]);
486        let tower_sync = TowerSync::from(vec![(1, 1)]);
487        (
488            vote.clone(),
489            vec![
490                (serialize(&VoteInstruction::Vote(vote)).unwrap(), false),
491                (
492                    serialize(&VoteInstruction::UpdateVoteState(vote_state_update.clone()))
493                        .unwrap(),
494                    false,
495                ),
496                (
497                    serialize(&VoteInstruction::CompactUpdateVoteState(vote_state_update)).unwrap(),
498                    false,
499                ),
500                (
501                    serialize(&VoteInstruction::TowerSync(tower_sync)).unwrap(),
502                    true,
503                ),
504            ],
505        )
506    }
507
508    #[test]
509    fn test_vote_process_instruction_decode_bail() {
510        process_instruction(
511            &[],
512            Vec::new(),
513            Vec::new(),
514            Err(InstructionError::NotEnoughAccountKeys),
515        );
516    }
517
518    #[test]
519    fn test_initialize_vote_account() {
520        let vote_pubkey = solana_sdk::pubkey::new_rand();
521        let vote_account = AccountSharedData::new(100, VoteState::size_of(), &id());
522        let node_pubkey = solana_sdk::pubkey::new_rand();
523        let node_account = AccountSharedData::default();
524        let instruction_data = serialize(&VoteInstruction::InitializeAccount(VoteInit {
525            node_pubkey,
526            authorized_voter: vote_pubkey,
527            authorized_withdrawer: vote_pubkey,
528            commission: 0,
529        }))
530        .unwrap();
531        let mut instruction_accounts = vec![
532            AccountMeta {
533                pubkey: vote_pubkey,
534                is_signer: false,
535                is_writable: true,
536            },
537            AccountMeta {
538                pubkey: sysvar::rent::id(),
539                is_signer: false,
540                is_writable: false,
541            },
542            AccountMeta {
543                pubkey: sysvar::clock::id(),
544                is_signer: false,
545                is_writable: false,
546            },
547            AccountMeta {
548                pubkey: node_pubkey,
549                is_signer: true,
550                is_writable: false,
551            },
552        ];
553
554        // init should pass
555        let accounts = process_instruction(
556            &instruction_data,
557            vec![
558                (vote_pubkey, vote_account.clone()),
559                (sysvar::rent::id(), create_default_rent_account()),
560                (sysvar::clock::id(), create_default_clock_account()),
561                (node_pubkey, node_account.clone()),
562            ],
563            instruction_accounts.clone(),
564            Ok(()),
565        );
566
567        // reinit should fail
568        process_instruction(
569            &instruction_data,
570            vec![
571                (vote_pubkey, accounts[0].clone()),
572                (sysvar::rent::id(), create_default_rent_account()),
573                (sysvar::clock::id(), create_default_clock_account()),
574                (node_pubkey, accounts[3].clone()),
575            ],
576            instruction_accounts.clone(),
577            Err(InstructionError::AccountAlreadyInitialized),
578        );
579
580        // init should fail, account is too big
581        process_instruction(
582            &instruction_data,
583            vec![
584                (
585                    vote_pubkey,
586                    AccountSharedData::new(100, 2 * VoteState::size_of(), &id()),
587                ),
588                (sysvar::rent::id(), create_default_rent_account()),
589                (sysvar::clock::id(), create_default_clock_account()),
590                (node_pubkey, node_account.clone()),
591            ],
592            instruction_accounts.clone(),
593            Err(InstructionError::InvalidAccountData),
594        );
595
596        // init should fail, node_pubkey didn't sign the transaction
597        instruction_accounts[3].is_signer = false;
598        process_instruction(
599            &instruction_data,
600            vec![
601                (vote_pubkey, vote_account),
602                (sysvar::rent::id(), create_default_rent_account()),
603                (sysvar::clock::id(), create_default_clock_account()),
604                (node_pubkey, node_account),
605            ],
606            instruction_accounts,
607            Err(InstructionError::MissingRequiredSignature),
608        );
609    }
610
611    #[test]
612    fn test_vote_update_validator_identity() {
613        let (vote_pubkey, _authorized_voter, authorized_withdrawer, vote_account) =
614            create_test_account_with_authorized();
615        let node_pubkey = solana_sdk::pubkey::new_rand();
616        let instruction_data = serialize(&VoteInstruction::UpdateValidatorIdentity).unwrap();
617        let transaction_accounts = vec![
618            (vote_pubkey, vote_account),
619            (node_pubkey, AccountSharedData::default()),
620            (authorized_withdrawer, AccountSharedData::default()),
621        ];
622        let mut instruction_accounts = vec![
623            AccountMeta {
624                pubkey: vote_pubkey,
625                is_signer: false,
626                is_writable: true,
627            },
628            AccountMeta {
629                pubkey: node_pubkey,
630                is_signer: true,
631                is_writable: false,
632            },
633            AccountMeta {
634                pubkey: authorized_withdrawer,
635                is_signer: true,
636                is_writable: false,
637            },
638        ];
639
640        // should fail, node_pubkey didn't sign the transaction
641        instruction_accounts[1].is_signer = false;
642        let accounts = process_instruction(
643            &instruction_data,
644            transaction_accounts.clone(),
645            instruction_accounts.clone(),
646            Err(InstructionError::MissingRequiredSignature),
647        );
648        instruction_accounts[1].is_signer = true;
649        let vote_state: VoteState = StateMut::<VoteStateVersions>::state(&accounts[0])
650            .unwrap()
651            .convert_to_current();
652        assert_ne!(vote_state.node_pubkey, node_pubkey);
653
654        // should fail, authorized_withdrawer didn't sign the transaction
655        instruction_accounts[2].is_signer = false;
656        let accounts = process_instruction(
657            &instruction_data,
658            transaction_accounts.clone(),
659            instruction_accounts.clone(),
660            Err(InstructionError::MissingRequiredSignature),
661        );
662        instruction_accounts[2].is_signer = true;
663        let vote_state: VoteState = StateMut::<VoteStateVersions>::state(&accounts[0])
664            .unwrap()
665            .convert_to_current();
666        assert_ne!(vote_state.node_pubkey, node_pubkey);
667
668        // should pass
669        let accounts = process_instruction(
670            &instruction_data,
671            transaction_accounts,
672            instruction_accounts,
673            Ok(()),
674        );
675        let vote_state: VoteState = StateMut::<VoteStateVersions>::state(&accounts[0])
676            .unwrap()
677            .convert_to_current();
678        assert_eq!(vote_state.node_pubkey, node_pubkey);
679    }
680
681    #[test]
682    fn test_vote_update_commission() {
683        let (vote_pubkey, _authorized_voter, authorized_withdrawer, vote_account) =
684            create_test_account_with_authorized();
685        let instruction_data = serialize(&VoteInstruction::UpdateCommission(42)).unwrap();
686        let transaction_accounts = vec![
687            (vote_pubkey, vote_account),
688            (authorized_withdrawer, AccountSharedData::default()),
689            // Add the sysvar accounts so they're in the cache for mock processing
690            (
691                sysvar::clock::id(),
692                account::create_account_shared_data_for_test(&Clock::default()),
693            ),
694            (
695                sysvar::epoch_schedule::id(),
696                account::create_account_shared_data_for_test(&EpochSchedule::without_warmup()),
697            ),
698        ];
699        let mut instruction_accounts = vec![
700            AccountMeta {
701                pubkey: vote_pubkey,
702                is_signer: false,
703                is_writable: true,
704            },
705            AccountMeta {
706                pubkey: authorized_withdrawer,
707                is_signer: true,
708                is_writable: false,
709            },
710        ];
711
712        // should pass
713        let accounts = process_instruction(
714            &serialize(&VoteInstruction::UpdateCommission(u8::MAX)).unwrap(),
715            transaction_accounts.clone(),
716            instruction_accounts.clone(),
717            Ok(()),
718        );
719        let vote_state: VoteState = StateMut::<VoteStateVersions>::state(&accounts[0])
720            .unwrap()
721            .convert_to_current();
722        assert_eq!(vote_state.commission, u8::MAX);
723
724        // should pass
725        let accounts = process_instruction(
726            &instruction_data,
727            transaction_accounts.clone(),
728            instruction_accounts.clone(),
729            Ok(()),
730        );
731        let vote_state: VoteState = StateMut::<VoteStateVersions>::state(&accounts[0])
732            .unwrap()
733            .convert_to_current();
734        assert_eq!(vote_state.commission, 42);
735
736        // should fail, authorized_withdrawer didn't sign the transaction
737        instruction_accounts[1].is_signer = false;
738        let accounts = process_instruction(
739            &instruction_data,
740            transaction_accounts,
741            instruction_accounts,
742            Err(InstructionError::MissingRequiredSignature),
743        );
744        let vote_state: VoteState = StateMut::<VoteStateVersions>::state(&accounts[0])
745            .unwrap()
746            .convert_to_current();
747        assert_eq!(vote_state.commission, 0);
748    }
749
750    #[test]
751    fn test_vote_signature() {
752        let (vote_pubkey, vote_account) = create_test_account();
753        let (vote, instruction_datas) = create_serialized_votes();
754        let slot_hashes = SlotHashes::new(&[(*vote.slots.last().unwrap(), vote.hash)]);
755        let slot_hashes_account = account::create_account_shared_data_for_test(&slot_hashes);
756        let mut instruction_accounts = vec![
757            AccountMeta {
758                pubkey: vote_pubkey,
759                is_signer: true,
760                is_writable: true,
761            },
762            AccountMeta {
763                pubkey: sysvar::slot_hashes::id(),
764                is_signer: false,
765                is_writable: false,
766            },
767            AccountMeta {
768                pubkey: sysvar::clock::id(),
769                is_signer: false,
770                is_writable: false,
771            },
772        ];
773
774        for (instruction_data, is_tower_sync) in instruction_datas {
775            let mut transaction_accounts = vec![
776                (vote_pubkey, vote_account.clone()),
777                (sysvar::slot_hashes::id(), slot_hashes_account.clone()),
778                (sysvar::clock::id(), create_default_clock_account()),
779            ];
780
781            let error = |err| {
782                if !is_tower_sync {
783                    Err(InstructionError::InvalidInstructionData)
784                } else {
785                    Err(err)
786                }
787            };
788
789            // should fail, unsigned
790            instruction_accounts[0].is_signer = false;
791            process_instruction(
792                &instruction_data,
793                transaction_accounts.clone(),
794                instruction_accounts.clone(),
795                error(InstructionError::MissingRequiredSignature),
796            );
797            instruction_accounts[0].is_signer = true;
798
799            // should pass
800            let accounts = process_instruction(
801                &instruction_data,
802                transaction_accounts.clone(),
803                instruction_accounts.clone(),
804                if is_tower_sync {
805                    Ok(())
806                } else {
807                    Err(InstructionError::InvalidInstructionData)
808                },
809            );
810            if is_tower_sync {
811                let vote_state: VoteState = StateMut::<VoteStateVersions>::state(&accounts[0])
812                    .unwrap()
813                    .convert_to_current();
814                assert_eq!(
815                    vote_state.votes,
816                    vec![vote_state::LandedVote::from(Lockout::new(
817                        *vote.slots.last().unwrap()
818                    ))]
819                );
820                assert_eq!(vote_state.credits(), 0);
821            }
822
823            // should fail, wrong hash
824            transaction_accounts[1] = (
825                sysvar::slot_hashes::id(),
826                account::create_account_shared_data_for_test(&SlotHashes::new(&[(
827                    *vote.slots.last().unwrap(),
828                    solana_sdk::hash::hash(&[0u8]),
829                )])),
830            );
831            process_instruction(
832                &instruction_data,
833                transaction_accounts.clone(),
834                instruction_accounts.clone(),
835                error(VoteError::SlotHashMismatch.into()),
836            );
837
838            // should fail, wrong slot
839            transaction_accounts[1] = (
840                sysvar::slot_hashes::id(),
841                account::create_account_shared_data_for_test(&SlotHashes::new(&[(0, vote.hash)])),
842            );
843            process_instruction(
844                &instruction_data,
845                transaction_accounts.clone(),
846                instruction_accounts.clone(),
847                error(VoteError::SlotsMismatch.into()),
848            );
849
850            // should fail, empty slot_hashes
851            transaction_accounts[1] = (
852                sysvar::slot_hashes::id(),
853                account::create_account_shared_data_for_test(&SlotHashes::new(&[])),
854            );
855            process_instruction(
856                &instruction_data,
857                transaction_accounts.clone(),
858                instruction_accounts.clone(),
859                error(VoteError::SlotsMismatch.into()),
860            );
861            transaction_accounts[1] = (sysvar::slot_hashes::id(), slot_hashes_account.clone());
862
863            // should fail, uninitialized
864            let vote_account = AccountSharedData::new(100, VoteState::size_of(), &id());
865            transaction_accounts[0] = (vote_pubkey, vote_account);
866            process_instruction(
867                &instruction_data,
868                transaction_accounts.clone(),
869                instruction_accounts.clone(),
870                error(InstructionError::UninitializedAccount),
871            );
872        }
873    }
874
875    #[test]
876    fn test_authorize_voter() {
877        let (vote_pubkey, vote_account) = create_test_account();
878        let authorized_voter_pubkey = solana_sdk::pubkey::new_rand();
879        let clock = Clock {
880            epoch: 1,
881            leader_schedule_epoch: 2,
882            ..Clock::default()
883        };
884        let clock_account = account::create_account_shared_data_for_test(&clock);
885        let instruction_data = serialize(&VoteInstruction::Authorize(
886            authorized_voter_pubkey,
887            VoteAuthorize::Voter,
888        ))
889        .unwrap();
890        let mut transaction_accounts = vec![
891            (vote_pubkey, vote_account),
892            (sysvar::clock::id(), clock_account),
893            (authorized_voter_pubkey, AccountSharedData::default()),
894        ];
895        let mut instruction_accounts = vec![
896            AccountMeta {
897                pubkey: vote_pubkey,
898                is_signer: true,
899                is_writable: true,
900            },
901            AccountMeta {
902                pubkey: sysvar::clock::id(),
903                is_signer: false,
904                is_writable: false,
905            },
906        ];
907
908        // should fail, unsigned
909        instruction_accounts[0].is_signer = false;
910        process_instruction(
911            &instruction_data,
912            transaction_accounts.clone(),
913            instruction_accounts.clone(),
914            Err(InstructionError::MissingRequiredSignature),
915        );
916        instruction_accounts[0].is_signer = true;
917
918        // should pass
919        let accounts = process_instruction(
920            &instruction_data,
921            transaction_accounts.clone(),
922            instruction_accounts.clone(),
923            Ok(()),
924        );
925
926        // should fail, already set an authorized voter earlier for leader_schedule_epoch == 2
927        transaction_accounts[0] = (vote_pubkey, accounts[0].clone());
928        process_instruction(
929            &instruction_data,
930            transaction_accounts.clone(),
931            instruction_accounts.clone(),
932            Err(VoteError::TooSoonToReauthorize.into()),
933        );
934
935        // should pass, verify authorized_voter_pubkey can authorize authorized_voter_pubkey ;)
936        instruction_accounts[0].is_signer = false;
937        instruction_accounts.push(AccountMeta {
938            pubkey: authorized_voter_pubkey,
939            is_signer: true,
940            is_writable: false,
941        });
942        let clock = Clock {
943            // The authorized voter was set when leader_schedule_epoch == 2, so will
944            // take effect when epoch == 3
945            epoch: 3,
946            leader_schedule_epoch: 4,
947            ..Clock::default()
948        };
949        let clock_account = account::create_account_shared_data_for_test(&clock);
950        transaction_accounts[1] = (sysvar::clock::id(), clock_account);
951        process_instruction(
952            &instruction_data,
953            transaction_accounts.clone(),
954            instruction_accounts.clone(),
955            Ok(()),
956        );
957        instruction_accounts[0].is_signer = true;
958        instruction_accounts.pop();
959
960        // should fail, not signed by authorized voter
961        let (vote, instruction_datas) = create_serialized_votes();
962        let slot_hashes = SlotHashes::new(&[(*vote.slots.last().unwrap(), vote.hash)]);
963        let slot_hashes_account = account::create_account_shared_data_for_test(&slot_hashes);
964        transaction_accounts.push((sysvar::slot_hashes::id(), slot_hashes_account));
965        instruction_accounts.insert(
966            1,
967            AccountMeta {
968                pubkey: sysvar::slot_hashes::id(),
969                is_signer: false,
970                is_writable: false,
971            },
972        );
973        let mut authorized_instruction_accounts = instruction_accounts.clone();
974        authorized_instruction_accounts.push(AccountMeta {
975            pubkey: authorized_voter_pubkey,
976            is_signer: true,
977            is_writable: false,
978        });
979
980        for (instruction_data, is_tower_sync) in instruction_datas {
981            process_instruction(
982                &instruction_data,
983                transaction_accounts.clone(),
984                instruction_accounts.clone(),
985                Err(if is_tower_sync {
986                    InstructionError::MissingRequiredSignature
987                } else {
988                    InstructionError::InvalidInstructionData
989                }),
990            );
991
992            // should pass, signed by authorized voter
993            process_instruction(
994                &instruction_data,
995                transaction_accounts.clone(),
996                authorized_instruction_accounts.clone(),
997                if is_tower_sync {
998                    Ok(())
999                } else {
1000                    Err(InstructionError::InvalidInstructionData)
1001                },
1002            );
1003        }
1004    }
1005
1006    #[test]
1007    fn test_authorize_withdrawer() {
1008        let (vote_pubkey, vote_account) = create_test_account();
1009        let authorized_withdrawer_pubkey = solana_sdk::pubkey::new_rand();
1010        let instruction_data = serialize(&VoteInstruction::Authorize(
1011            authorized_withdrawer_pubkey,
1012            VoteAuthorize::Withdrawer,
1013        ))
1014        .unwrap();
1015        let mut transaction_accounts = vec![
1016            (vote_pubkey, vote_account),
1017            (sysvar::clock::id(), create_default_clock_account()),
1018            (authorized_withdrawer_pubkey, AccountSharedData::default()),
1019        ];
1020        let mut instruction_accounts = vec![
1021            AccountMeta {
1022                pubkey: vote_pubkey,
1023                is_signer: true,
1024                is_writable: true,
1025            },
1026            AccountMeta {
1027                pubkey: sysvar::clock::id(),
1028                is_signer: false,
1029                is_writable: false,
1030            },
1031        ];
1032
1033        // should fail, unsigned
1034        instruction_accounts[0].is_signer = false;
1035        process_instruction(
1036            &instruction_data,
1037            transaction_accounts.clone(),
1038            instruction_accounts.clone(),
1039            Err(InstructionError::MissingRequiredSignature),
1040        );
1041        instruction_accounts[0].is_signer = true;
1042
1043        // should pass
1044        let accounts = process_instruction(
1045            &instruction_data,
1046            transaction_accounts.clone(),
1047            instruction_accounts.clone(),
1048            Ok(()),
1049        );
1050
1051        // should pass, verify authorized_withdrawer can authorize authorized_withdrawer ;)
1052        instruction_accounts[0].is_signer = false;
1053        instruction_accounts.push(AccountMeta {
1054            pubkey: authorized_withdrawer_pubkey,
1055            is_signer: true,
1056            is_writable: false,
1057        });
1058        transaction_accounts[0] = (vote_pubkey, accounts[0].clone());
1059        process_instruction(
1060            &instruction_data,
1061            transaction_accounts.clone(),
1062            instruction_accounts.clone(),
1063            Ok(()),
1064        );
1065
1066        // should pass, verify authorized_withdrawer can authorize a new authorized_voter
1067        let authorized_voter_pubkey = solana_sdk::pubkey::new_rand();
1068        transaction_accounts.push((authorized_voter_pubkey, AccountSharedData::default()));
1069        let instruction_data = serialize(&VoteInstruction::Authorize(
1070            authorized_voter_pubkey,
1071            VoteAuthorize::Voter,
1072        ))
1073        .unwrap();
1074        process_instruction(
1075            &instruction_data,
1076            transaction_accounts.clone(),
1077            instruction_accounts.clone(),
1078            Ok(()),
1079        );
1080    }
1081
1082    #[test]
1083    fn test_vote_withdraw() {
1084        let (vote_pubkey, vote_account) = create_test_account();
1085        let lamports = vote_account.lamports();
1086        let authorized_withdrawer_pubkey = solana_sdk::pubkey::new_rand();
1087        let mut transaction_accounts = vec![
1088            (vote_pubkey, vote_account.clone()),
1089            (sysvar::clock::id(), create_default_clock_account()),
1090            (sysvar::rent::id(), create_default_rent_account()),
1091            (authorized_withdrawer_pubkey, AccountSharedData::default()),
1092        ];
1093        let mut instruction_accounts = vec![
1094            AccountMeta {
1095                pubkey: vote_pubkey,
1096                is_signer: true,
1097                is_writable: true,
1098            },
1099            AccountMeta {
1100                pubkey: sysvar::clock::id(),
1101                is_signer: false,
1102                is_writable: false,
1103            },
1104        ];
1105
1106        // should pass, withdraw using authorized_withdrawer to authorized_withdrawer's account
1107        let accounts = process_instruction(
1108            &serialize(&VoteInstruction::Authorize(
1109                authorized_withdrawer_pubkey,
1110                VoteAuthorize::Withdrawer,
1111            ))
1112            .unwrap(),
1113            transaction_accounts.clone(),
1114            instruction_accounts.clone(),
1115            Ok(()),
1116        );
1117        instruction_accounts[0].is_signer = false;
1118        instruction_accounts[1] = AccountMeta {
1119            pubkey: authorized_withdrawer_pubkey,
1120            is_signer: true,
1121            is_writable: true,
1122        };
1123        transaction_accounts[0] = (vote_pubkey, accounts[0].clone());
1124        let accounts = process_instruction(
1125            &serialize(&VoteInstruction::Withdraw(lamports)).unwrap(),
1126            transaction_accounts.clone(),
1127            instruction_accounts.clone(),
1128            Ok(()),
1129        );
1130        assert_eq!(accounts[0].lamports(), 0);
1131        assert_eq!(accounts[3].lamports(), lamports);
1132        let post_state: VoteStateVersions = accounts[0].state().unwrap();
1133        // State has been deinitialized since balance is zero
1134        assert!(post_state.is_uninitialized());
1135
1136        // should fail, unsigned
1137        transaction_accounts[0] = (vote_pubkey, vote_account);
1138        process_instruction(
1139            &serialize(&VoteInstruction::Withdraw(lamports)).unwrap(),
1140            transaction_accounts.clone(),
1141            instruction_accounts.clone(),
1142            Err(InstructionError::MissingRequiredSignature),
1143        );
1144        instruction_accounts[0].is_signer = true;
1145
1146        // should pass
1147        process_instruction(
1148            &serialize(&VoteInstruction::Withdraw(lamports)).unwrap(),
1149            transaction_accounts.clone(),
1150            instruction_accounts.clone(),
1151            Ok(()),
1152        );
1153
1154        // should fail, insufficient funds
1155        process_instruction(
1156            &serialize(&VoteInstruction::Withdraw(lamports + 1)).unwrap(),
1157            transaction_accounts.clone(),
1158            instruction_accounts.clone(),
1159            Err(InstructionError::InsufficientFunds),
1160        );
1161
1162        // should pass, partial withdraw
1163        let withdraw_lamports = 42;
1164        let accounts = process_instruction(
1165            &serialize(&VoteInstruction::Withdraw(withdraw_lamports)).unwrap(),
1166            transaction_accounts,
1167            instruction_accounts,
1168            Ok(()),
1169        );
1170        assert_eq!(accounts[0].lamports(), lamports - withdraw_lamports);
1171        assert_eq!(accounts[3].lamports(), withdraw_lamports);
1172    }
1173
1174    #[test]
1175    fn test_vote_state_withdraw() {
1176        let authorized_withdrawer_pubkey = solana_sdk::pubkey::new_rand();
1177        let (vote_pubkey_1, vote_account_with_epoch_credits_1) =
1178            create_test_account_with_epoch_credits(&[2, 1]);
1179        let (vote_pubkey_2, vote_account_with_epoch_credits_2) =
1180            create_test_account_with_epoch_credits(&[2, 1, 3]);
1181        let clock = Clock {
1182            epoch: 3,
1183            ..Clock::default()
1184        };
1185        let clock_account = account::create_account_shared_data_for_test(&clock);
1186        let rent_sysvar = Rent::default();
1187        let minimum_balance = rent_sysvar
1188            .minimum_balance(vote_account_with_epoch_credits_1.data().len())
1189            .max(1);
1190        let lamports = vote_account_with_epoch_credits_1.lamports();
1191        let transaction_accounts = vec![
1192            (vote_pubkey_1, vote_account_with_epoch_credits_1),
1193            (vote_pubkey_2, vote_account_with_epoch_credits_2),
1194            (sysvar::clock::id(), clock_account),
1195            (
1196                sysvar::rent::id(),
1197                account::create_account_shared_data_for_test(&rent_sysvar),
1198            ),
1199            (authorized_withdrawer_pubkey, AccountSharedData::default()),
1200        ];
1201        let mut instruction_accounts = vec![
1202            AccountMeta {
1203                pubkey: vote_pubkey_1,
1204                is_signer: true,
1205                is_writable: true,
1206            },
1207            AccountMeta {
1208                pubkey: authorized_withdrawer_pubkey,
1209                is_signer: false,
1210                is_writable: true,
1211            },
1212        ];
1213
1214        // non rent exempt withdraw, with 0 credit epoch
1215        instruction_accounts[0].pubkey = vote_pubkey_1;
1216        process_instruction(
1217            &serialize(&VoteInstruction::Withdraw(lamports - minimum_balance + 1)).unwrap(),
1218            transaction_accounts.clone(),
1219            instruction_accounts.clone(),
1220            Err(InstructionError::InsufficientFunds),
1221        );
1222
1223        // non rent exempt withdraw, without 0 credit epoch
1224        instruction_accounts[0].pubkey = vote_pubkey_2;
1225        process_instruction(
1226            &serialize(&VoteInstruction::Withdraw(lamports - minimum_balance + 1)).unwrap(),
1227            transaction_accounts.clone(),
1228            instruction_accounts.clone(),
1229            Err(InstructionError::InsufficientFunds),
1230        );
1231
1232        // full withdraw, with 0 credit epoch
1233        instruction_accounts[0].pubkey = vote_pubkey_1;
1234        process_instruction(
1235            &serialize(&VoteInstruction::Withdraw(lamports)).unwrap(),
1236            transaction_accounts.clone(),
1237            instruction_accounts.clone(),
1238            Ok(()),
1239        );
1240
1241        // full withdraw, without 0 credit epoch
1242        instruction_accounts[0].pubkey = vote_pubkey_2;
1243        process_instruction(
1244            &serialize(&VoteInstruction::Withdraw(lamports)).unwrap(),
1245            transaction_accounts,
1246            instruction_accounts,
1247            Err(VoteError::ActiveVoteAccountClose.into()),
1248        );
1249    }
1250
1251    fn perform_authorize_with_seed_test(
1252        authorization_type: VoteAuthorize,
1253        vote_pubkey: Pubkey,
1254        vote_account: AccountSharedData,
1255        current_authority_base_key: Pubkey,
1256        current_authority_seed: String,
1257        current_authority_owner: Pubkey,
1258        new_authority_pubkey: Pubkey,
1259    ) {
1260        let clock = Clock {
1261            epoch: 1,
1262            leader_schedule_epoch: 2,
1263            ..Clock::default()
1264        };
1265        let clock_account = account::create_account_shared_data_for_test(&clock);
1266        let transaction_accounts = vec![
1267            (vote_pubkey, vote_account),
1268            (sysvar::clock::id(), clock_account),
1269            (current_authority_base_key, AccountSharedData::default()),
1270        ];
1271        let mut instruction_accounts = vec![
1272            AccountMeta {
1273                pubkey: vote_pubkey,
1274                is_signer: false,
1275                is_writable: true,
1276            },
1277            AccountMeta {
1278                pubkey: sysvar::clock::id(),
1279                is_signer: false,
1280                is_writable: false,
1281            },
1282            AccountMeta {
1283                pubkey: current_authority_base_key,
1284                is_signer: true,
1285                is_writable: false,
1286            },
1287        ];
1288
1289        // Can't change authority unless base key signs.
1290        instruction_accounts[2].is_signer = false;
1291        process_instruction(
1292            &serialize(&VoteInstruction::AuthorizeWithSeed(
1293                VoteAuthorizeWithSeedArgs {
1294                    authorization_type,
1295                    current_authority_derived_key_owner: current_authority_owner,
1296                    current_authority_derived_key_seed: current_authority_seed.clone(),
1297                    new_authority: new_authority_pubkey,
1298                },
1299            ))
1300            .unwrap(),
1301            transaction_accounts.clone(),
1302            instruction_accounts.clone(),
1303            Err(InstructionError::MissingRequiredSignature),
1304        );
1305        instruction_accounts[2].is_signer = true;
1306
1307        // Can't change authority if seed doesn't match.
1308        process_instruction(
1309            &serialize(&VoteInstruction::AuthorizeWithSeed(
1310                VoteAuthorizeWithSeedArgs {
1311                    authorization_type,
1312                    current_authority_derived_key_owner: current_authority_owner,
1313                    current_authority_derived_key_seed: String::from("WRONG_SEED"),
1314                    new_authority: new_authority_pubkey,
1315                },
1316            ))
1317            .unwrap(),
1318            transaction_accounts.clone(),
1319            instruction_accounts.clone(),
1320            Err(InstructionError::MissingRequiredSignature),
1321        );
1322
1323        // Can't change authority if owner doesn't match.
1324        process_instruction(
1325            &serialize(&VoteInstruction::AuthorizeWithSeed(
1326                VoteAuthorizeWithSeedArgs {
1327                    authorization_type,
1328                    current_authority_derived_key_owner: Pubkey::new_unique(), // Wrong owner.
1329                    current_authority_derived_key_seed: current_authority_seed.clone(),
1330                    new_authority: new_authority_pubkey,
1331                },
1332            ))
1333            .unwrap(),
1334            transaction_accounts.clone(),
1335            instruction_accounts.clone(),
1336            Err(InstructionError::MissingRequiredSignature),
1337        );
1338
1339        // Can change authority when base key signs for related derived key.
1340        process_instruction(
1341            &serialize(&VoteInstruction::AuthorizeWithSeed(
1342                VoteAuthorizeWithSeedArgs {
1343                    authorization_type,
1344                    current_authority_derived_key_owner: current_authority_owner,
1345                    current_authority_derived_key_seed: current_authority_seed,
1346                    new_authority: new_authority_pubkey,
1347                },
1348            ))
1349            .unwrap(),
1350            transaction_accounts,
1351            instruction_accounts,
1352            Ok(()),
1353        );
1354    }
1355
1356    fn perform_authorize_checked_with_seed_test(
1357        authorization_type: VoteAuthorize,
1358        vote_pubkey: Pubkey,
1359        vote_account: AccountSharedData,
1360        current_authority_base_key: Pubkey,
1361        current_authority_seed: String,
1362        current_authority_owner: Pubkey,
1363        new_authority_pubkey: Pubkey,
1364    ) {
1365        let clock = Clock {
1366            epoch: 1,
1367            leader_schedule_epoch: 2,
1368            ..Clock::default()
1369        };
1370        let clock_account = account::create_account_shared_data_for_test(&clock);
1371        let transaction_accounts = vec![
1372            (vote_pubkey, vote_account),
1373            (sysvar::clock::id(), clock_account),
1374            (current_authority_base_key, AccountSharedData::default()),
1375            (new_authority_pubkey, AccountSharedData::default()),
1376        ];
1377        let mut instruction_accounts = vec![
1378            AccountMeta {
1379                pubkey: vote_pubkey,
1380                is_signer: false,
1381                is_writable: true,
1382            },
1383            AccountMeta {
1384                pubkey: sysvar::clock::id(),
1385                is_signer: false,
1386                is_writable: false,
1387            },
1388            AccountMeta {
1389                pubkey: current_authority_base_key,
1390                is_signer: true,
1391                is_writable: false,
1392            },
1393            AccountMeta {
1394                pubkey: new_authority_pubkey,
1395                is_signer: true,
1396                is_writable: false,
1397            },
1398        ];
1399
1400        // Can't change authority unless base key signs.
1401        instruction_accounts[2].is_signer = false;
1402        process_instruction(
1403            &serialize(&VoteInstruction::AuthorizeCheckedWithSeed(
1404                VoteAuthorizeCheckedWithSeedArgs {
1405                    authorization_type,
1406                    current_authority_derived_key_owner: current_authority_owner,
1407                    current_authority_derived_key_seed: current_authority_seed.clone(),
1408                },
1409            ))
1410            .unwrap(),
1411            transaction_accounts.clone(),
1412            instruction_accounts.clone(),
1413            Err(InstructionError::MissingRequiredSignature),
1414        );
1415        instruction_accounts[2].is_signer = true;
1416
1417        // Can't change authority unless new authority signs.
1418        instruction_accounts[3].is_signer = false;
1419        process_instruction(
1420            &serialize(&VoteInstruction::AuthorizeCheckedWithSeed(
1421                VoteAuthorizeCheckedWithSeedArgs {
1422                    authorization_type,
1423                    current_authority_derived_key_owner: current_authority_owner,
1424                    current_authority_derived_key_seed: current_authority_seed.clone(),
1425                },
1426            ))
1427            .unwrap(),
1428            transaction_accounts.clone(),
1429            instruction_accounts.clone(),
1430            Err(InstructionError::MissingRequiredSignature),
1431        );
1432        instruction_accounts[3].is_signer = true;
1433
1434        // Can't change authority if seed doesn't match.
1435        process_instruction(
1436            &serialize(&VoteInstruction::AuthorizeCheckedWithSeed(
1437                VoteAuthorizeCheckedWithSeedArgs {
1438                    authorization_type,
1439                    current_authority_derived_key_owner: current_authority_owner,
1440                    current_authority_derived_key_seed: String::from("WRONG_SEED"),
1441                },
1442            ))
1443            .unwrap(),
1444            transaction_accounts.clone(),
1445            instruction_accounts.clone(),
1446            Err(InstructionError::MissingRequiredSignature),
1447        );
1448
1449        // Can't change authority if owner doesn't match.
1450        process_instruction(
1451            &serialize(&VoteInstruction::AuthorizeCheckedWithSeed(
1452                VoteAuthorizeCheckedWithSeedArgs {
1453                    authorization_type,
1454                    current_authority_derived_key_owner: Pubkey::new_unique(), // Wrong owner.
1455                    current_authority_derived_key_seed: current_authority_seed.clone(),
1456                },
1457            ))
1458            .unwrap(),
1459            transaction_accounts.clone(),
1460            instruction_accounts.clone(),
1461            Err(InstructionError::MissingRequiredSignature),
1462        );
1463
1464        // Can change authority when base key signs for related derived key and new authority signs.
1465        process_instruction(
1466            &serialize(&VoteInstruction::AuthorizeCheckedWithSeed(
1467                VoteAuthorizeCheckedWithSeedArgs {
1468                    authorization_type,
1469                    current_authority_derived_key_owner: current_authority_owner,
1470                    current_authority_derived_key_seed: current_authority_seed,
1471                },
1472            ))
1473            .unwrap(),
1474            transaction_accounts,
1475            instruction_accounts,
1476            Ok(()),
1477        );
1478    }
1479
1480    #[test]
1481    fn test_voter_base_key_can_authorize_new_voter() {
1482        let VoteAccountTestFixtureWithAuthorities {
1483            vote_pubkey,
1484            voter_base_key,
1485            voter_owner,
1486            voter_seed,
1487            vote_account,
1488            ..
1489        } = create_test_account_with_authorized_from_seed();
1490        let new_voter_pubkey = Pubkey::new_unique();
1491        perform_authorize_with_seed_test(
1492            VoteAuthorize::Voter,
1493            vote_pubkey,
1494            vote_account,
1495            voter_base_key,
1496            voter_seed,
1497            voter_owner,
1498            new_voter_pubkey,
1499        );
1500    }
1501
1502    #[test]
1503    fn test_withdrawer_base_key_can_authorize_new_voter() {
1504        let VoteAccountTestFixtureWithAuthorities {
1505            vote_pubkey,
1506            withdrawer_base_key,
1507            withdrawer_owner,
1508            withdrawer_seed,
1509            vote_account,
1510            ..
1511        } = create_test_account_with_authorized_from_seed();
1512        let new_voter_pubkey = Pubkey::new_unique();
1513        perform_authorize_with_seed_test(
1514            VoteAuthorize::Voter,
1515            vote_pubkey,
1516            vote_account,
1517            withdrawer_base_key,
1518            withdrawer_seed,
1519            withdrawer_owner,
1520            new_voter_pubkey,
1521        );
1522    }
1523
1524    #[test]
1525    fn test_voter_base_key_can_not_authorize_new_withdrawer() {
1526        let VoteAccountTestFixtureWithAuthorities {
1527            vote_pubkey,
1528            voter_base_key,
1529            voter_owner,
1530            voter_seed,
1531            vote_account,
1532            ..
1533        } = create_test_account_with_authorized_from_seed();
1534        let new_withdrawer_pubkey = Pubkey::new_unique();
1535        let clock = Clock {
1536            epoch: 1,
1537            leader_schedule_epoch: 2,
1538            ..Clock::default()
1539        };
1540        let clock_account = account::create_account_shared_data_for_test(&clock);
1541        let transaction_accounts = vec![
1542            (vote_pubkey, vote_account),
1543            (sysvar::clock::id(), clock_account),
1544            (voter_base_key, AccountSharedData::default()),
1545        ];
1546        let instruction_accounts = vec![
1547            AccountMeta {
1548                pubkey: vote_pubkey,
1549                is_signer: false,
1550                is_writable: true,
1551            },
1552            AccountMeta {
1553                pubkey: sysvar::clock::id(),
1554                is_signer: false,
1555                is_writable: false,
1556            },
1557            AccountMeta {
1558                pubkey: voter_base_key,
1559                is_signer: true,
1560                is_writable: false,
1561            },
1562        ];
1563        // Despite having Voter authority, you may not change the Withdrawer authority.
1564        process_instruction(
1565            &serialize(&VoteInstruction::AuthorizeWithSeed(
1566                VoteAuthorizeWithSeedArgs {
1567                    authorization_type: VoteAuthorize::Withdrawer,
1568                    current_authority_derived_key_owner: voter_owner,
1569                    current_authority_derived_key_seed: voter_seed,
1570                    new_authority: new_withdrawer_pubkey,
1571                },
1572            ))
1573            .unwrap(),
1574            transaction_accounts,
1575            instruction_accounts,
1576            Err(InstructionError::MissingRequiredSignature),
1577        );
1578    }
1579
1580    #[test]
1581    fn test_withdrawer_base_key_can_authorize_new_withdrawer() {
1582        let VoteAccountTestFixtureWithAuthorities {
1583            vote_pubkey,
1584            withdrawer_base_key,
1585            withdrawer_owner,
1586            withdrawer_seed,
1587            vote_account,
1588            ..
1589        } = create_test_account_with_authorized_from_seed();
1590        let new_withdrawer_pubkey = Pubkey::new_unique();
1591        perform_authorize_with_seed_test(
1592            VoteAuthorize::Withdrawer,
1593            vote_pubkey,
1594            vote_account,
1595            withdrawer_base_key,
1596            withdrawer_seed,
1597            withdrawer_owner,
1598            new_withdrawer_pubkey,
1599        );
1600    }
1601
1602    #[test]
1603    fn test_voter_base_key_can_authorize_new_voter_checked() {
1604        let VoteAccountTestFixtureWithAuthorities {
1605            vote_pubkey,
1606            voter_base_key,
1607            voter_owner,
1608            voter_seed,
1609            vote_account,
1610            ..
1611        } = create_test_account_with_authorized_from_seed();
1612        let new_voter_pubkey = Pubkey::new_unique();
1613        perform_authorize_checked_with_seed_test(
1614            VoteAuthorize::Voter,
1615            vote_pubkey,
1616            vote_account,
1617            voter_base_key,
1618            voter_seed,
1619            voter_owner,
1620            new_voter_pubkey,
1621        );
1622    }
1623
1624    #[test]
1625    fn test_withdrawer_base_key_can_authorize_new_voter_checked() {
1626        let VoteAccountTestFixtureWithAuthorities {
1627            vote_pubkey,
1628            withdrawer_base_key,
1629            withdrawer_owner,
1630            withdrawer_seed,
1631            vote_account,
1632            ..
1633        } = create_test_account_with_authorized_from_seed();
1634        let new_voter_pubkey = Pubkey::new_unique();
1635        perform_authorize_checked_with_seed_test(
1636            VoteAuthorize::Voter,
1637            vote_pubkey,
1638            vote_account,
1639            withdrawer_base_key,
1640            withdrawer_seed,
1641            withdrawer_owner,
1642            new_voter_pubkey,
1643        );
1644    }
1645
1646    #[test]
1647    fn test_voter_base_key_can_not_authorize_new_withdrawer_checked() {
1648        let VoteAccountTestFixtureWithAuthorities {
1649            vote_pubkey,
1650            voter_base_key,
1651            voter_owner,
1652            voter_seed,
1653            vote_account,
1654            ..
1655        } = create_test_account_with_authorized_from_seed();
1656        let new_withdrawer_pubkey = Pubkey::new_unique();
1657        let clock = Clock {
1658            epoch: 1,
1659            leader_schedule_epoch: 2,
1660            ..Clock::default()
1661        };
1662        let clock_account = account::create_account_shared_data_for_test(&clock);
1663        let transaction_accounts = vec![
1664            (vote_pubkey, vote_account),
1665            (sysvar::clock::id(), clock_account),
1666            (voter_base_key, AccountSharedData::default()),
1667            (new_withdrawer_pubkey, AccountSharedData::default()),
1668        ];
1669        let instruction_accounts = vec![
1670            AccountMeta {
1671                pubkey: vote_pubkey,
1672                is_signer: false,
1673                is_writable: true,
1674            },
1675            AccountMeta {
1676                pubkey: sysvar::clock::id(),
1677                is_signer: false,
1678                is_writable: false,
1679            },
1680            AccountMeta {
1681                pubkey: voter_base_key,
1682                is_signer: true,
1683                is_writable: false,
1684            },
1685            AccountMeta {
1686                pubkey: new_withdrawer_pubkey,
1687                is_signer: true,
1688                is_writable: false,
1689            },
1690        ];
1691        // Despite having Voter authority, you may not change the Withdrawer authority.
1692        process_instruction(
1693            &serialize(&VoteInstruction::AuthorizeCheckedWithSeed(
1694                VoteAuthorizeCheckedWithSeedArgs {
1695                    authorization_type: VoteAuthorize::Withdrawer,
1696                    current_authority_derived_key_owner: voter_owner,
1697                    current_authority_derived_key_seed: voter_seed,
1698                },
1699            ))
1700            .unwrap(),
1701            transaction_accounts,
1702            instruction_accounts,
1703            Err(InstructionError::MissingRequiredSignature),
1704        );
1705    }
1706
1707    #[test]
1708    fn test_withdrawer_base_key_can_authorize_new_withdrawer_checked() {
1709        let VoteAccountTestFixtureWithAuthorities {
1710            vote_pubkey,
1711            withdrawer_base_key,
1712            withdrawer_owner,
1713            withdrawer_seed,
1714            vote_account,
1715            ..
1716        } = create_test_account_with_authorized_from_seed();
1717        let new_withdrawer_pubkey = Pubkey::new_unique();
1718        perform_authorize_checked_with_seed_test(
1719            VoteAuthorize::Withdrawer,
1720            vote_pubkey,
1721            vote_account,
1722            withdrawer_base_key,
1723            withdrawer_seed,
1724            withdrawer_owner,
1725            new_withdrawer_pubkey,
1726        );
1727    }
1728
1729    #[test]
1730    fn test_spoofed_vote() {
1731        process_instruction_as_one_arg(
1732            &vote(
1733                &invalid_vote_state_pubkey(),
1734                &Pubkey::new_unique(),
1735                Vote::default(),
1736            ),
1737            Err(InstructionError::InvalidAccountOwner),
1738        );
1739        process_instruction_as_one_arg(
1740            &update_vote_state(
1741                &invalid_vote_state_pubkey(),
1742                &Pubkey::default(),
1743                VoteStateUpdate::default(),
1744            ),
1745            Err(InstructionError::InvalidAccountOwner),
1746        );
1747        process_instruction_as_one_arg(
1748            &compact_update_vote_state(
1749                &invalid_vote_state_pubkey(),
1750                &Pubkey::default(),
1751                VoteStateUpdate::default(),
1752            ),
1753            Err(InstructionError::InvalidAccountOwner),
1754        );
1755        process_instruction_as_one_arg(
1756            &tower_sync(
1757                &invalid_vote_state_pubkey(),
1758                &Pubkey::default(),
1759                TowerSync::default(),
1760            ),
1761            Err(InstructionError::InvalidAccountOwner),
1762        );
1763    }
1764
1765    #[test]
1766    fn test_create_account_vote_state_1_14_11() {
1767        let node_pubkey = Pubkey::new_unique();
1768        let vote_pubkey = Pubkey::new_unique();
1769        let instructions = create_account_with_config(
1770            &node_pubkey,
1771            &vote_pubkey,
1772            &VoteInit {
1773                node_pubkey,
1774                authorized_voter: vote_pubkey,
1775                authorized_withdrawer: vote_pubkey,
1776                commission: 0,
1777            },
1778            101,
1779            CreateVoteAccountConfig::default(),
1780        );
1781        // grab the `space` value from SystemInstruction::CreateAccount by directly indexing, for
1782        // expediency
1783        let space = usize::from_le_bytes(instructions[0].data[12..20].try_into().unwrap());
1784        assert_eq!(space, vote_state::VoteState1_14_11::size_of());
1785        let empty_vote_account = AccountSharedData::new(101, space, &id());
1786
1787        let transaction_accounts = vec![
1788            (vote_pubkey, empty_vote_account),
1789            (node_pubkey, AccountSharedData::default()),
1790            (sysvar::clock::id(), create_default_clock_account()),
1791            (sysvar::rent::id(), create_default_rent_account()),
1792        ];
1793
1794        // should fail, since VoteState1_14_11 isn't supported anymore
1795        process_instruction(
1796            &instructions[1].data,
1797            transaction_accounts,
1798            instructions[1].accounts.clone(),
1799            Err(InstructionError::InvalidAccountData),
1800        );
1801    }
1802
1803    #[test]
1804    fn test_create_account_vote_state_current() {
1805        let node_pubkey = Pubkey::new_unique();
1806        let vote_pubkey = Pubkey::new_unique();
1807        let instructions = create_account_with_config(
1808            &node_pubkey,
1809            &vote_pubkey,
1810            &VoteInit {
1811                node_pubkey,
1812                authorized_voter: vote_pubkey,
1813                authorized_withdrawer: vote_pubkey,
1814                commission: 0,
1815            },
1816            101,
1817            CreateVoteAccountConfig {
1818                space: vote_state::VoteState::size_of() as u64,
1819                ..CreateVoteAccountConfig::default()
1820            },
1821        );
1822        // grab the `space` value from SystemInstruction::CreateAccount by directly indexing, for
1823        // expediency
1824        let space = usize::from_le_bytes(instructions[0].data[12..20].try_into().unwrap());
1825        assert_eq!(space, vote_state::VoteState::size_of());
1826        let empty_vote_account = AccountSharedData::new(101, space, &id());
1827
1828        let transaction_accounts = vec![
1829            (vote_pubkey, empty_vote_account),
1830            (node_pubkey, AccountSharedData::default()),
1831            (sysvar::clock::id(), create_default_clock_account()),
1832            (sysvar::rent::id(), create_default_rent_account()),
1833        ];
1834
1835        process_instruction(
1836            &instructions[1].data,
1837            transaction_accounts,
1838            instructions[1].accounts.clone(),
1839            Ok(()),
1840        );
1841    }
1842
1843    #[test]
1844    fn test_vote_process_instruction() {
1845        solana_logger::setup();
1846        let instructions = create_account_with_config(
1847            &Pubkey::new_unique(),
1848            &Pubkey::new_unique(),
1849            &VoteInit::default(),
1850            101,
1851            CreateVoteAccountConfig::default(),
1852        );
1853        // this case fails regardless of CreateVoteAccountConfig::space, because
1854        // process_instruction_as_one_arg passes a default (empty) account
1855        process_instruction_as_one_arg(&instructions[1], Err(InstructionError::InvalidAccountData));
1856        process_instruction_as_one_arg(
1857            &vote(
1858                &Pubkey::new_unique(),
1859                &Pubkey::new_unique(),
1860                Vote::default(),
1861            ),
1862            Err(InstructionError::InvalidInstructionData),
1863        );
1864        process_instruction_as_one_arg(
1865            &vote_switch(
1866                &Pubkey::new_unique(),
1867                &Pubkey::new_unique(),
1868                Vote::default(),
1869                Hash::default(),
1870            ),
1871            Err(InstructionError::InvalidInstructionData),
1872        );
1873        process_instruction_as_one_arg(
1874            &authorize(
1875                &Pubkey::new_unique(),
1876                &Pubkey::new_unique(),
1877                &Pubkey::new_unique(),
1878                VoteAuthorize::Voter,
1879            ),
1880            Err(InstructionError::InvalidAccountData),
1881        );
1882        process_instruction_as_one_arg(
1883            &update_vote_state(
1884                &Pubkey::default(),
1885                &Pubkey::default(),
1886                VoteStateUpdate::default(),
1887            ),
1888            Err(InstructionError::InvalidInstructionData),
1889        );
1890
1891        process_instruction_as_one_arg(
1892            &update_vote_state_switch(
1893                &Pubkey::default(),
1894                &Pubkey::default(),
1895                VoteStateUpdate::default(),
1896                Hash::default(),
1897            ),
1898            Err(InstructionError::InvalidInstructionData),
1899        );
1900        process_instruction_as_one_arg(
1901            &compact_update_vote_state(
1902                &Pubkey::default(),
1903                &Pubkey::default(),
1904                VoteStateUpdate::default(),
1905            ),
1906            Err(InstructionError::InvalidInstructionData),
1907        );
1908        process_instruction_as_one_arg(
1909            &compact_update_vote_state_switch(
1910                &Pubkey::default(),
1911                &Pubkey::default(),
1912                VoteStateUpdate::default(),
1913                Hash::default(),
1914            ),
1915            Err(InstructionError::InvalidInstructionData),
1916        );
1917        process_instruction_as_one_arg(
1918            &tower_sync(&Pubkey::default(), &Pubkey::default(), TowerSync::default()),
1919            Err(InstructionError::InvalidAccountData),
1920        );
1921        process_instruction_as_one_arg(
1922            &tower_sync_switch(
1923                &Pubkey::default(),
1924                &Pubkey::default(),
1925                TowerSync::default(),
1926                Hash::default(),
1927            ),
1928            Err(InstructionError::InvalidAccountData),
1929        );
1930
1931        process_instruction_as_one_arg(
1932            &update_validator_identity(
1933                &Pubkey::new_unique(),
1934                &Pubkey::new_unique(),
1935                &Pubkey::new_unique(),
1936            ),
1937            Err(InstructionError::InvalidAccountData),
1938        );
1939        process_instruction_as_one_arg(
1940            &update_commission(&Pubkey::new_unique(), &Pubkey::new_unique(), 0),
1941            Err(InstructionError::InvalidAccountData),
1942        );
1943
1944        process_instruction_as_one_arg(
1945            &withdraw(
1946                &Pubkey::new_unique(),
1947                &Pubkey::new_unique(),
1948                0,
1949                &Pubkey::new_unique(),
1950            ),
1951            Err(InstructionError::InvalidAccountData),
1952        );
1953    }
1954
1955    #[test]
1956    fn test_vote_authorize_checked() {
1957        let vote_pubkey = Pubkey::new_unique();
1958        let authorized_pubkey = Pubkey::new_unique();
1959        let new_authorized_pubkey = Pubkey::new_unique();
1960
1961        // Test with vanilla authorize accounts
1962        let mut instruction = authorize_checked(
1963            &vote_pubkey,
1964            &authorized_pubkey,
1965            &new_authorized_pubkey,
1966            VoteAuthorize::Voter,
1967        );
1968        instruction.accounts = instruction.accounts[0..2].to_vec();
1969        process_instruction_as_one_arg(&instruction, Err(InstructionError::NotEnoughAccountKeys));
1970
1971        let mut instruction = authorize_checked(
1972            &vote_pubkey,
1973            &authorized_pubkey,
1974            &new_authorized_pubkey,
1975            VoteAuthorize::Withdrawer,
1976        );
1977        instruction.accounts = instruction.accounts[0..2].to_vec();
1978        process_instruction_as_one_arg(&instruction, Err(InstructionError::NotEnoughAccountKeys));
1979
1980        // Test with non-signing new_authorized_pubkey
1981        let mut instruction = authorize_checked(
1982            &vote_pubkey,
1983            &authorized_pubkey,
1984            &new_authorized_pubkey,
1985            VoteAuthorize::Voter,
1986        );
1987        instruction.accounts[3] = AccountMeta::new_readonly(new_authorized_pubkey, false);
1988        process_instruction_as_one_arg(
1989            &instruction,
1990            Err(InstructionError::MissingRequiredSignature),
1991        );
1992
1993        let mut instruction = authorize_checked(
1994            &vote_pubkey,
1995            &authorized_pubkey,
1996            &new_authorized_pubkey,
1997            VoteAuthorize::Withdrawer,
1998        );
1999        instruction.accounts[3] = AccountMeta::new_readonly(new_authorized_pubkey, false);
2000        process_instruction_as_one_arg(
2001            &instruction,
2002            Err(InstructionError::MissingRequiredSignature),
2003        );
2004
2005        // Test with new_authorized_pubkey signer
2006        let vote_account = AccountSharedData::new(100, VoteState::size_of(), &id());
2007        let clock_address = sysvar::clock::id();
2008        let clock_account = account::create_account_shared_data_for_test(&Clock::default());
2009        let default_authorized_pubkey = Pubkey::default();
2010        let authorized_account = create_default_account();
2011        let new_authorized_account = create_default_account();
2012        let transaction_accounts = vec![
2013            (vote_pubkey, vote_account),
2014            (clock_address, clock_account),
2015            (default_authorized_pubkey, authorized_account),
2016            (new_authorized_pubkey, new_authorized_account),
2017        ];
2018        let instruction_accounts = vec![
2019            AccountMeta {
2020                pubkey: vote_pubkey,
2021                is_signer: false,
2022                is_writable: true,
2023            },
2024            AccountMeta {
2025                pubkey: clock_address,
2026                is_signer: false,
2027                is_writable: false,
2028            },
2029            AccountMeta {
2030                pubkey: default_authorized_pubkey,
2031                is_signer: true,
2032                is_writable: false,
2033            },
2034            AccountMeta {
2035                pubkey: new_authorized_pubkey,
2036                is_signer: true,
2037                is_writable: false,
2038            },
2039        ];
2040        process_instruction(
2041            &serialize(&VoteInstruction::AuthorizeChecked(VoteAuthorize::Voter)).unwrap(),
2042            transaction_accounts.clone(),
2043            instruction_accounts.clone(),
2044            Ok(()),
2045        );
2046        process_instruction(
2047            &serialize(&VoteInstruction::AuthorizeChecked(
2048                VoteAuthorize::Withdrawer,
2049            ))
2050            .unwrap(),
2051            transaction_accounts,
2052            instruction_accounts,
2053            Ok(()),
2054        );
2055    }
2056}