solana_vote_program/
vote_processor.rs

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