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