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