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