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