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