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