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