1use {
2 crate::system_instruction::{
3 advance_nonce_account, authorize_nonce_account, initialize_nonce_account,
4 withdraw_nonce_account,
5 },
6 log::*,
7 solana_log_collector::ic_msg,
8 solana_program_runtime::{
9 declare_process_instruction, invoke_context::InvokeContext,
10 sysvar_cache::get_sysvar_with_account_check,
11 },
12 solana_sdk::{
13 instruction::InstructionError,
14 nonce,
15 program_utils::limited_deserialize,
16 pubkey::Pubkey,
17 system_instruction::{SystemError, SystemInstruction, MAX_PERMITTED_DATA_LENGTH},
18 system_program,
19 transaction_context::{
20 BorrowedAccount, IndexOfAccount, InstructionContext, TransactionContext,
21 },
22 },
23 std::collections::HashSet,
24};
25
26#[derive(PartialEq, Eq, Default, Debug)]
29struct Address {
30 address: Pubkey,
31 base: Option<Pubkey>,
32}
33
34impl Address {
35 fn is_signer(&self, signers: &HashSet<Pubkey>) -> bool {
36 if let Some(base) = self.base {
37 signers.contains(&base)
38 } else {
39 signers.contains(&self.address)
40 }
41 }
42 fn create(
43 address: &Pubkey,
44 with_seed: Option<(&Pubkey, &str, &Pubkey)>,
45 invoke_context: &InvokeContext,
46 ) -> Result<Self, InstructionError> {
47 let base = if let Some((base, seed, owner)) = with_seed {
48 let address_with_seed = Pubkey::create_with_seed(base, seed, owner)?;
49 if *address != address_with_seed {
51 ic_msg!(
52 invoke_context,
53 "Create: address {} does not match derived address {}",
54 address,
55 address_with_seed
56 );
57 return Err(SystemError::AddressWithSeedMismatch.into());
58 }
59 Some(*base)
60 } else {
61 None
62 };
63
64 Ok(Self {
65 address: *address,
66 base,
67 })
68 }
69}
70
71fn allocate(
72 account: &mut BorrowedAccount,
73 address: &Address,
74 space: u64,
75 signers: &HashSet<Pubkey>,
76 invoke_context: &InvokeContext,
77) -> Result<(), InstructionError> {
78 if !address.is_signer(signers) {
79 ic_msg!(
80 invoke_context,
81 "Allocate: 'to' account {:?} must sign",
82 address
83 );
84 return Err(InstructionError::MissingRequiredSignature);
85 }
86
87 if !account.get_data().is_empty() || !system_program::check_id(account.get_owner()) {
90 ic_msg!(
91 invoke_context,
92 "Allocate: account {:?} already in use",
93 address
94 );
95 return Err(SystemError::AccountAlreadyInUse.into());
96 }
97
98 if space > MAX_PERMITTED_DATA_LENGTH {
99 ic_msg!(
100 invoke_context,
101 "Allocate: requested {}, max allowed {}",
102 space,
103 MAX_PERMITTED_DATA_LENGTH
104 );
105 return Err(SystemError::InvalidAccountDataLength.into());
106 }
107
108 account.set_data_length(space as usize)?;
109
110 Ok(())
111}
112
113fn assign(
114 account: &mut BorrowedAccount,
115 address: &Address,
116 owner: &Pubkey,
117 signers: &HashSet<Pubkey>,
118 invoke_context: &InvokeContext,
119) -> Result<(), InstructionError> {
120 if account.get_owner() == owner {
122 return Ok(());
123 }
124
125 if !address.is_signer(signers) {
126 ic_msg!(invoke_context, "Assign: account {:?} must sign", address);
127 return Err(InstructionError::MissingRequiredSignature);
128 }
129
130 account.set_owner(&owner.to_bytes())
131}
132
133fn allocate_and_assign(
134 to: &mut BorrowedAccount,
135 to_address: &Address,
136 space: u64,
137 owner: &Pubkey,
138 signers: &HashSet<Pubkey>,
139 invoke_context: &InvokeContext,
140) -> Result<(), InstructionError> {
141 allocate(to, to_address, space, signers, invoke_context)?;
142 assign(to, to_address, owner, signers, invoke_context)
143}
144
145#[allow(clippy::too_many_arguments)]
146fn create_account(
147 from_account_index: IndexOfAccount,
148 to_account_index: IndexOfAccount,
149 to_address: &Address,
150 lamports: u64,
151 space: u64,
152 owner: &Pubkey,
153 signers: &HashSet<Pubkey>,
154 invoke_context: &InvokeContext,
155 transaction_context: &TransactionContext,
156 instruction_context: &InstructionContext,
157) -> Result<(), InstructionError> {
158 {
160 let mut to = instruction_context
161 .try_borrow_instruction_account(transaction_context, to_account_index)?;
162 if to.get_lamports() > 0 {
163 ic_msg!(
164 invoke_context,
165 "Create Account: account {:?} already in use",
166 to_address
167 );
168 return Err(SystemError::AccountAlreadyInUse.into());
169 }
170
171 allocate_and_assign(&mut to, to_address, space, owner, signers, invoke_context)?;
172 }
173 transfer(
174 from_account_index,
175 to_account_index,
176 lamports,
177 invoke_context,
178 transaction_context,
179 instruction_context,
180 )
181}
182
183fn transfer_verified(
184 from_account_index: IndexOfAccount,
185 to_account_index: IndexOfAccount,
186 lamports: u64,
187 invoke_context: &InvokeContext,
188 transaction_context: &TransactionContext,
189 instruction_context: &InstructionContext,
190) -> Result<(), InstructionError> {
191 let mut from = instruction_context
192 .try_borrow_instruction_account(transaction_context, from_account_index)?;
193 if !from.get_data().is_empty() {
194 ic_msg!(invoke_context, "Transfer: `from` must not carry data");
195 return Err(InstructionError::InvalidArgument);
196 }
197 if lamports > from.get_lamports() {
198 ic_msg!(
199 invoke_context,
200 "Transfer: insufficient lamports {}, need {}",
201 from.get_lamports(),
202 lamports
203 );
204 return Err(SystemError::ResultWithNegativeLamports.into());
205 }
206
207 from.checked_sub_lamports(lamports)?;
208 drop(from);
209 let mut to = instruction_context
210 .try_borrow_instruction_account(transaction_context, to_account_index)?;
211 to.checked_add_lamports(lamports)?;
212 Ok(())
213}
214
215fn transfer(
216 from_account_index: IndexOfAccount,
217 to_account_index: IndexOfAccount,
218 lamports: u64,
219 invoke_context: &InvokeContext,
220 transaction_context: &TransactionContext,
221 instruction_context: &InstructionContext,
222) -> Result<(), InstructionError> {
223 if !instruction_context.is_instruction_account_signer(from_account_index)? {
224 ic_msg!(
225 invoke_context,
226 "Transfer: `from` account {} must sign",
227 transaction_context.get_key_of_account_at_index(
228 instruction_context
229 .get_index_of_instruction_account_in_transaction(from_account_index)?,
230 )?,
231 );
232 return Err(InstructionError::MissingRequiredSignature);
233 }
234
235 transfer_verified(
236 from_account_index,
237 to_account_index,
238 lamports,
239 invoke_context,
240 transaction_context,
241 instruction_context,
242 )
243}
244
245fn transfer_with_seed(
246 from_account_index: IndexOfAccount,
247 from_base_account_index: IndexOfAccount,
248 from_seed: &str,
249 from_owner: &Pubkey,
250 to_account_index: IndexOfAccount,
251 lamports: u64,
252 invoke_context: &InvokeContext,
253 transaction_context: &TransactionContext,
254 instruction_context: &InstructionContext,
255) -> Result<(), InstructionError> {
256 if !instruction_context.is_instruction_account_signer(from_base_account_index)? {
257 ic_msg!(
258 invoke_context,
259 "Transfer: 'from' account {:?} must sign",
260 transaction_context.get_key_of_account_at_index(
261 instruction_context
262 .get_index_of_instruction_account_in_transaction(from_base_account_index)?,
263 )?,
264 );
265 return Err(InstructionError::MissingRequiredSignature);
266 }
267 let address_from_seed = Pubkey::create_with_seed(
268 transaction_context.get_key_of_account_at_index(
269 instruction_context
270 .get_index_of_instruction_account_in_transaction(from_base_account_index)?,
271 )?,
272 from_seed,
273 from_owner,
274 )?;
275
276 let from_key = transaction_context.get_key_of_account_at_index(
277 instruction_context.get_index_of_instruction_account_in_transaction(from_account_index)?,
278 )?;
279 if *from_key != address_from_seed {
280 ic_msg!(
281 invoke_context,
282 "Transfer: 'from' address {} does not match derived address {}",
283 from_key,
284 address_from_seed
285 );
286 return Err(SystemError::AddressWithSeedMismatch.into());
287 }
288
289 transfer_verified(
290 from_account_index,
291 to_account_index,
292 lamports,
293 invoke_context,
294 transaction_context,
295 instruction_context,
296 )
297}
298
299pub const DEFAULT_COMPUTE_UNITS: u64 = 150;
300
301declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| {
302 let transaction_context = &invoke_context.transaction_context;
303 let instruction_context = transaction_context.get_current_instruction_context()?;
304 let instruction_data = instruction_context.get_instruction_data();
305 let instruction = limited_deserialize(instruction_data)?;
306
307 trace!("process_instruction: {:?}", instruction);
308
309 let signers = instruction_context.get_signers(transaction_context)?;
310 match instruction {
311 SystemInstruction::CreateAccount {
312 lamports,
313 space,
314 owner,
315 } => {
316 instruction_context.check_number_of_instruction_accounts(2)?;
317 let to_address = Address::create(
318 transaction_context.get_key_of_account_at_index(
319 instruction_context.get_index_of_instruction_account_in_transaction(1)?,
320 )?,
321 None,
322 invoke_context,
323 )?;
324 create_account(
325 0,
326 1,
327 &to_address,
328 lamports,
329 space,
330 &owner,
331 &signers,
332 invoke_context,
333 transaction_context,
334 instruction_context,
335 )
336 }
337 SystemInstruction::CreateAccountWithSeed {
338 base,
339 seed,
340 lamports,
341 space,
342 owner,
343 } => {
344 instruction_context.check_number_of_instruction_accounts(2)?;
345 let to_address = Address::create(
346 transaction_context.get_key_of_account_at_index(
347 instruction_context.get_index_of_instruction_account_in_transaction(1)?,
348 )?,
349 Some((&base, &seed, &owner)),
350 invoke_context,
351 )?;
352 create_account(
353 0,
354 1,
355 &to_address,
356 lamports,
357 space,
358 &owner,
359 &signers,
360 invoke_context,
361 transaction_context,
362 instruction_context,
363 )
364 }
365 SystemInstruction::Assign { owner } => {
366 instruction_context.check_number_of_instruction_accounts(1)?;
367 let mut account =
368 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
369 let address = Address::create(
370 transaction_context.get_key_of_account_at_index(
371 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
372 )?,
373 None,
374 invoke_context,
375 )?;
376 assign(&mut account, &address, &owner, &signers, invoke_context)
377 }
378 SystemInstruction::Transfer { lamports } => {
379 instruction_context.check_number_of_instruction_accounts(2)?;
380 transfer(
381 0,
382 1,
383 lamports,
384 invoke_context,
385 transaction_context,
386 instruction_context,
387 )
388 }
389 SystemInstruction::TransferWithSeed {
390 lamports,
391 from_seed,
392 from_owner,
393 } => {
394 instruction_context.check_number_of_instruction_accounts(3)?;
395 transfer_with_seed(
396 0,
397 1,
398 &from_seed,
399 &from_owner,
400 2,
401 lamports,
402 invoke_context,
403 transaction_context,
404 instruction_context,
405 )
406 }
407 SystemInstruction::AdvanceNonceAccount => {
408 instruction_context.check_number_of_instruction_accounts(1)?;
409 let mut me =
410 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
411 #[allow(deprecated)]
412 let recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes(
413 invoke_context,
414 instruction_context,
415 1,
416 )?;
417 if recent_blockhashes.is_empty() {
418 ic_msg!(
419 invoke_context,
420 "Advance nonce account: recent blockhash list is empty",
421 );
422 return Err(SystemError::NonceNoRecentBlockhashes.into());
423 }
424 advance_nonce_account(&mut me, &signers, invoke_context)
425 }
426 SystemInstruction::WithdrawNonceAccount(lamports) => {
427 instruction_context.check_number_of_instruction_accounts(2)?;
428 #[allow(deprecated)]
429 let _recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes(
430 invoke_context,
431 instruction_context,
432 2,
433 )?;
434 let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 3)?;
435 withdraw_nonce_account(
436 0,
437 lamports,
438 1,
439 &rent,
440 &signers,
441 invoke_context,
442 transaction_context,
443 instruction_context,
444 )
445 }
446 SystemInstruction::InitializeNonceAccount(authorized) => {
447 instruction_context.check_number_of_instruction_accounts(1)?;
448 let mut me =
449 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
450 #[allow(deprecated)]
451 let recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes(
452 invoke_context,
453 instruction_context,
454 1,
455 )?;
456 if recent_blockhashes.is_empty() {
457 ic_msg!(
458 invoke_context,
459 "Initialize nonce account: recent blockhash list is empty",
460 );
461 return Err(SystemError::NonceNoRecentBlockhashes.into());
462 }
463 let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 2)?;
464 initialize_nonce_account(&mut me, &authorized, &rent, invoke_context)
465 }
466 SystemInstruction::AuthorizeNonceAccount(nonce_authority) => {
467 instruction_context.check_number_of_instruction_accounts(1)?;
468 let mut me =
469 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
470 authorize_nonce_account(&mut me, &nonce_authority, &signers, invoke_context)
471 }
472 SystemInstruction::UpgradeNonceAccount => {
473 instruction_context.check_number_of_instruction_accounts(1)?;
474 let mut nonce_account =
475 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
476 if !system_program::check_id(nonce_account.get_owner()) {
477 return Err(InstructionError::InvalidAccountOwner);
478 }
479 if !nonce_account.is_writable() {
480 return Err(InstructionError::InvalidArgument);
481 }
482 let nonce_versions: nonce::state::Versions = nonce_account.get_state()?;
483 match nonce_versions.upgrade() {
484 None => Err(InstructionError::InvalidArgument),
485 Some(nonce_versions) => nonce_account.set_state(&nonce_versions),
486 }
487 }
488 SystemInstruction::Allocate { space } => {
489 instruction_context.check_number_of_instruction_accounts(1)?;
490 let mut account =
491 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
492 let address = Address::create(
493 transaction_context.get_key_of_account_at_index(
494 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
495 )?,
496 None,
497 invoke_context,
498 )?;
499 allocate(&mut account, &address, space, &signers, invoke_context)
500 }
501 SystemInstruction::AllocateWithSeed {
502 base,
503 seed,
504 space,
505 owner,
506 } => {
507 instruction_context.check_number_of_instruction_accounts(1)?;
508 let mut account =
509 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
510 let address = Address::create(
511 transaction_context.get_key_of_account_at_index(
512 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
513 )?,
514 Some((&base, &seed, &owner)),
515 invoke_context,
516 )?;
517 allocate_and_assign(
518 &mut account,
519 &address,
520 space,
521 &owner,
522 &signers,
523 invoke_context,
524 )
525 }
526 SystemInstruction::AssignWithSeed { base, seed, owner } => {
527 instruction_context.check_number_of_instruction_accounts(1)?;
528 let mut account =
529 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
530 let address = Address::create(
531 transaction_context.get_key_of_account_at_index(
532 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
533 )?,
534 Some((&base, &seed, &owner)),
535 invoke_context,
536 )?;
537 assign(&mut account, &address, &owner, &signers, invoke_context)
538 }
539 }
540});
541
542#[cfg(test)]
543mod tests {
544 #[allow(deprecated)]
545 use solana_sdk::{
546 account::{
547 self, create_account_shared_data_with_fields, to_account, Account, AccountSharedData,
548 ReadableAccount, DUMMY_INHERITABLE_ACCOUNT_FIELDS,
549 },
550 fee_calculator::FeeCalculator,
551 hash::{hash, Hash},
552 instruction::{AccountMeta, Instruction, InstructionError},
553 nonce::{
554 self,
555 state::{
556 Data as NonceData, DurableNonce, State as NonceState, Versions as NonceVersions,
557 },
558 },
559 nonce_account, system_instruction, system_program,
560 sysvar::{
561 self,
562 recent_blockhashes::{IntoIterSorted, IterItem, RecentBlockhashes, MAX_ENTRIES},
563 rent::Rent,
564 },
565 };
566 use {
567 super::*,
568 crate::{get_system_account_kind, SystemAccountKind},
569 bincode::serialize,
570 solana_program_runtime::{
571 invoke_context::mock_process_instruction, with_mock_invoke_context,
572 },
573 std::collections::BinaryHeap,
574 };
575
576 impl From<Pubkey> for Address {
577 fn from(address: Pubkey) -> Self {
578 Self {
579 address,
580 base: None,
581 }
582 }
583 }
584
585 fn process_instruction(
586 instruction_data: &[u8],
587 transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
588 instruction_accounts: Vec<AccountMeta>,
589 expected_result: Result<(), InstructionError>,
590 ) -> Vec<AccountSharedData> {
591 mock_process_instruction(
592 &system_program::id(),
593 Vec::new(),
594 instruction_data,
595 transaction_accounts,
596 instruction_accounts,
597 expected_result,
598 Entrypoint::vm,
599 |_invoke_context| {},
600 |_invoke_context| {},
601 )
602 }
603
604 fn create_default_account() -> AccountSharedData {
605 AccountSharedData::new(0, 0, &Pubkey::new_unique())
606 }
607 #[allow(deprecated)]
608 fn create_recent_blockhashes_account_for_test<'a, I>(
609 recent_blockhash_iter: I,
610 ) -> AccountSharedData
611 where
612 I: IntoIterator<Item = IterItem<'a>>,
613 {
614 let mut account = create_account_shared_data_with_fields::<RecentBlockhashes>(
615 &RecentBlockhashes::default(),
616 DUMMY_INHERITABLE_ACCOUNT_FIELDS,
617 );
618 let sorted = BinaryHeap::from_iter(recent_blockhash_iter);
619 let sorted_iter = IntoIterSorted::new(sorted);
620 let recent_blockhash_iter = sorted_iter.take(MAX_ENTRIES);
621 let recent_blockhashes: RecentBlockhashes = recent_blockhash_iter.collect();
622 to_account(&recent_blockhashes, &mut account);
623 account
624 }
625 fn create_default_recent_blockhashes_account() -> AccountSharedData {
626 #[allow(deprecated)]
627 create_recent_blockhashes_account_for_test(vec![
628 IterItem(0u64, &Hash::default(), 0);
629 sysvar::recent_blockhashes::MAX_ENTRIES
630 ])
631 }
632 fn create_default_rent_account() -> AccountSharedData {
633 account::create_account_shared_data_for_test(&Rent::free())
634 }
635
636 #[test]
637 fn test_create_account() {
638 let new_owner = Pubkey::from([9; 32]);
639 let from = Pubkey::new_unique();
640 let to = Pubkey::new_unique();
641 let from_account = AccountSharedData::new(100, 0, &system_program::id());
642 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
643
644 let accounts = process_instruction(
645 &bincode::serialize(&SystemInstruction::CreateAccount {
646 lamports: 50,
647 space: 2,
648 owner: new_owner,
649 })
650 .unwrap(),
651 vec![(from, from_account), (to, to_account)],
652 vec![
653 AccountMeta {
654 pubkey: from,
655 is_signer: true,
656 is_writable: true,
657 },
658 AccountMeta {
659 pubkey: to,
660 is_signer: true,
661 is_writable: true,
662 },
663 ],
664 Ok(()),
665 );
666 assert_eq!(accounts[0].lamports(), 50);
667 assert_eq!(accounts[1].lamports(), 50);
668 assert_eq!(accounts[1].owner(), &new_owner);
669 assert_eq!(accounts[1].data(), &[0, 0]);
670 }
671
672 #[test]
673 fn test_create_account_with_seed() {
674 let new_owner = Pubkey::from([9; 32]);
675 let from = Pubkey::new_unique();
676 let seed = "shiny pepper";
677 let to = Pubkey::create_with_seed(&from, seed, &new_owner).unwrap();
678 let from_account = AccountSharedData::new(100, 0, &system_program::id());
679 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
680
681 let accounts = process_instruction(
682 &bincode::serialize(&SystemInstruction::CreateAccountWithSeed {
683 base: from,
684 seed: seed.to_string(),
685 lamports: 50,
686 space: 2,
687 owner: new_owner,
688 })
689 .unwrap(),
690 vec![(from, from_account), (to, to_account)],
691 vec![
692 AccountMeta {
693 pubkey: from,
694 is_signer: true,
695 is_writable: true,
696 },
697 AccountMeta {
698 pubkey: to,
699 is_signer: true,
700 is_writable: true,
701 },
702 ],
703 Ok(()),
704 );
705 assert_eq!(accounts[0].lamports(), 50);
706 assert_eq!(accounts[1].lamports(), 50);
707 assert_eq!(accounts[1].owner(), &new_owner);
708 assert_eq!(accounts[1].data(), &[0, 0]);
709 }
710
711 #[test]
712 fn test_create_account_with_seed_separate_base_account() {
713 let new_owner = Pubkey::from([9; 32]);
714 let from = Pubkey::new_unique();
715 let base = Pubkey::new_unique();
716 let seed = "shiny pepper";
717 let to = Pubkey::create_with_seed(&base, seed, &new_owner).unwrap();
718 let from_account = AccountSharedData::new(100, 0, &system_program::id());
719 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
720 let base_account = AccountSharedData::new(0, 0, &Pubkey::default());
721
722 let accounts = process_instruction(
723 &bincode::serialize(&SystemInstruction::CreateAccountWithSeed {
724 base,
725 seed: seed.to_string(),
726 lamports: 50,
727 space: 2,
728 owner: new_owner,
729 })
730 .unwrap(),
731 vec![(from, from_account), (to, to_account), (base, base_account)],
732 vec![
733 AccountMeta {
734 pubkey: from,
735 is_signer: true,
736 is_writable: true,
737 },
738 AccountMeta {
739 pubkey: to,
740 is_signer: false,
741 is_writable: true,
742 },
743 AccountMeta {
744 pubkey: base,
745 is_signer: true,
746 is_writable: false,
747 },
748 ],
749 Ok(()),
750 );
751 assert_eq!(accounts[0].lamports(), 50);
752 assert_eq!(accounts[1].lamports(), 50);
753 assert_eq!(accounts[1].owner(), &new_owner);
754 assert_eq!(accounts[1].data(), &[0, 0]);
755 }
756
757 #[test]
758 fn test_address_create_with_seed_mismatch() {
759 with_mock_invoke_context!(invoke_context, transaction_context, Vec::new());
760 let from = Pubkey::new_unique();
761 let seed = "dull boy";
762 let to = Pubkey::new_unique();
763 let owner = Pubkey::new_unique();
764
765 assert_eq!(
766 Address::create(&to, Some((&from, seed, &owner)), &invoke_context),
767 Err(SystemError::AddressWithSeedMismatch.into())
768 );
769 }
770
771 #[test]
772 fn test_create_account_with_seed_missing_sig() {
773 let new_owner = Pubkey::from([9; 32]);
774 let from = Pubkey::new_unique();
775 let seed = "dull boy";
776 let to = Pubkey::create_with_seed(&from, seed, &new_owner).unwrap();
777 let from_account = AccountSharedData::new(100, 0, &system_program::id());
778 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
779
780 let accounts = process_instruction(
781 &bincode::serialize(&SystemInstruction::CreateAccount {
782 lamports: 50,
783 space: 2,
784 owner: new_owner,
785 })
786 .unwrap(),
787 vec![(from, from_account), (to, to_account)],
788 vec![
789 AccountMeta {
790 pubkey: from,
791 is_signer: true,
792 is_writable: false,
793 },
794 AccountMeta {
795 pubkey: to,
796 is_signer: false,
797 is_writable: false,
798 },
799 ],
800 Err(InstructionError::MissingRequiredSignature),
801 );
802 assert_eq!(accounts[0].lamports(), 100);
803 assert_eq!(accounts[1], AccountSharedData::default());
804 }
805
806 #[test]
807 fn test_create_with_zero_lamports() {
808 let new_owner = Pubkey::from([9; 32]);
810 let from = Pubkey::new_unique();
811 let from_account = AccountSharedData::new(100, 0, &Pubkey::new_unique()); let to = Pubkey::new_unique();
813 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
814
815 let accounts = process_instruction(
816 &bincode::serialize(&SystemInstruction::CreateAccount {
817 lamports: 0,
818 space: 2,
819 owner: new_owner,
820 })
821 .unwrap(),
822 vec![(from, from_account), (to, to_account)],
823 vec![
824 AccountMeta {
825 pubkey: from,
826 is_signer: true,
827 is_writable: true,
828 },
829 AccountMeta {
830 pubkey: to,
831 is_signer: true,
832 is_writable: true,
833 },
834 ],
835 Ok(()),
836 );
837 assert_eq!(accounts[0].lamports(), 100);
838 assert_eq!(accounts[1].lamports(), 0);
839 assert_eq!(*accounts[1].owner(), new_owner);
840 assert_eq!(accounts[1].data(), &[0, 0]);
841 }
842
843 #[test]
844 fn test_create_negative_lamports() {
845 let new_owner = Pubkey::from([9; 32]);
847 let from = Pubkey::new_unique();
848 let from_account = AccountSharedData::new(100, 0, &Pubkey::new_unique());
849 let to = Pubkey::new_unique();
850 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
851
852 process_instruction(
853 &bincode::serialize(&SystemInstruction::CreateAccount {
854 lamports: 150,
855 space: 2,
856 owner: new_owner,
857 })
858 .unwrap(),
859 vec![(from, from_account), (to, to_account)],
860 vec![
861 AccountMeta {
862 pubkey: from,
863 is_signer: true,
864 is_writable: true,
865 },
866 AccountMeta {
867 pubkey: to,
868 is_signer: true,
869 is_writable: true,
870 },
871 ],
872 Err(SystemError::ResultWithNegativeLamports.into()),
873 );
874 }
875
876 #[test]
877 fn test_request_more_than_allowed_data_length() {
878 let from = Pubkey::new_unique();
879 let from_account = AccountSharedData::new(100, 0, &system_program::id());
880 let to = Pubkey::new_unique();
881 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
882 let instruction_accounts = vec![
883 AccountMeta {
884 pubkey: from,
885 is_signer: true,
886 is_writable: true,
887 },
888 AccountMeta {
889 pubkey: to,
890 is_signer: true,
891 is_writable: true,
892 },
893 ];
894
895 process_instruction(
897 &bincode::serialize(&SystemInstruction::CreateAccount {
898 lamports: 50,
899 space: MAX_PERMITTED_DATA_LENGTH + 1,
900 owner: system_program::id(),
901 })
902 .unwrap(),
903 vec![(from, from_account.clone()), (to, to_account.clone())],
904 instruction_accounts.clone(),
905 Err(SystemError::InvalidAccountDataLength.into()),
906 );
907
908 let accounts = process_instruction(
910 &bincode::serialize(&SystemInstruction::CreateAccount {
911 lamports: 50,
912 space: MAX_PERMITTED_DATA_LENGTH,
913 owner: system_program::id(),
914 })
915 .unwrap(),
916 vec![(from, from_account), (to, to_account)],
917 instruction_accounts,
918 Ok(()),
919 );
920 assert_eq!(accounts[1].lamports(), 50);
921 assert_eq!(accounts[1].data().len() as u64, MAX_PERMITTED_DATA_LENGTH);
922 }
923
924 #[test]
925 fn test_create_already_in_use() {
926 let new_owner = Pubkey::from([9; 32]);
927 let from = Pubkey::new_unique();
928 let from_account = AccountSharedData::new(100, 0, &system_program::id());
929 let owned_key = Pubkey::new_unique();
930
931 let original_program_owner = Pubkey::from([5; 32]);
933 let owned_account = AccountSharedData::new(0, 0, &original_program_owner);
934 let unchanged_account = owned_account.clone();
935 let accounts = process_instruction(
936 &bincode::serialize(&SystemInstruction::CreateAccount {
937 lamports: 50,
938 space: 2,
939 owner: new_owner,
940 })
941 .unwrap(),
942 vec![(from, from_account.clone()), (owned_key, owned_account)],
943 vec![
944 AccountMeta {
945 pubkey: from,
946 is_signer: true,
947 is_writable: false,
948 },
949 AccountMeta {
950 pubkey: owned_key,
951 is_signer: true,
952 is_writable: false,
953 },
954 ],
955 Err(SystemError::AccountAlreadyInUse.into()),
956 );
957 assert_eq!(accounts[0].lamports(), 100);
958 assert_eq!(accounts[1], unchanged_account);
959
960 let owned_account = AccountSharedData::new(0, 1, &Pubkey::default());
962 let unchanged_account = owned_account.clone();
963 let accounts = process_instruction(
964 &bincode::serialize(&SystemInstruction::CreateAccount {
965 lamports: 50,
966 space: 2,
967 owner: new_owner,
968 })
969 .unwrap(),
970 vec![(from, from_account.clone()), (owned_key, owned_account)],
971 vec![
972 AccountMeta {
973 pubkey: from,
974 is_signer: true,
975 is_writable: false,
976 },
977 AccountMeta {
978 pubkey: owned_key,
979 is_signer: true,
980 is_writable: false,
981 },
982 ],
983 Err(SystemError::AccountAlreadyInUse.into()),
984 );
985 assert_eq!(accounts[0].lamports(), 100);
986 assert_eq!(accounts[1], unchanged_account);
987
988 let owned_account = AccountSharedData::new(1, 0, &Pubkey::default());
990 let unchanged_account = owned_account.clone();
991 let accounts = process_instruction(
992 &bincode::serialize(&SystemInstruction::CreateAccount {
993 lamports: 50,
994 space: 2,
995 owner: new_owner,
996 })
997 .unwrap(),
998 vec![(from, from_account), (owned_key, owned_account)],
999 vec![
1000 AccountMeta {
1001 pubkey: from,
1002 is_signer: true,
1003 is_writable: false,
1004 },
1005 AccountMeta {
1006 pubkey: owned_key,
1007 is_signer: true,
1008 is_writable: false,
1009 },
1010 ],
1011 Err(SystemError::AccountAlreadyInUse.into()),
1012 );
1013 assert_eq!(accounts[0].lamports(), 100);
1014 assert_eq!(accounts[1], unchanged_account);
1015 }
1016
1017 #[test]
1018 fn test_create_unsigned() {
1019 let new_owner = Pubkey::from([9; 32]);
1021 let from = Pubkey::new_unique();
1022 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1023 let owned_key = Pubkey::new_unique();
1024 let owned_account = AccountSharedData::new(0, 0, &Pubkey::default());
1025
1026 process_instruction(
1028 &bincode::serialize(&SystemInstruction::CreateAccount {
1029 lamports: 50,
1030 space: 2,
1031 owner: new_owner,
1032 })
1033 .unwrap(),
1034 vec![
1035 (from, from_account.clone()),
1036 (owned_key, owned_account.clone()),
1037 ],
1038 vec![
1039 AccountMeta {
1040 pubkey: from,
1041 is_signer: false,
1042 is_writable: false,
1043 },
1044 AccountMeta {
1045 pubkey: owned_key,
1046 is_signer: false,
1047 is_writable: false,
1048 },
1049 ],
1050 Err(InstructionError::MissingRequiredSignature),
1051 );
1052
1053 process_instruction(
1055 &bincode::serialize(&SystemInstruction::CreateAccount {
1056 lamports: 50,
1057 space: 2,
1058 owner: new_owner,
1059 })
1060 .unwrap(),
1061 vec![(from, from_account.clone()), (owned_key, owned_account)],
1062 vec![
1063 AccountMeta {
1064 pubkey: from,
1065 is_signer: true,
1066 is_writable: false,
1067 },
1068 AccountMeta {
1069 pubkey: owned_key,
1070 is_signer: false,
1071 is_writable: false,
1072 },
1073 ],
1074 Err(InstructionError::MissingRequiredSignature),
1075 );
1076
1077 let owned_account = AccountSharedData::new(0, 0, &Pubkey::default());
1079 process_instruction(
1080 &bincode::serialize(&SystemInstruction::CreateAccount {
1081 lamports: 50,
1082 space: 2,
1083 owner: new_owner,
1084 })
1085 .unwrap(),
1086 vec![(from, from_account), (owned_key, owned_account)],
1087 vec![
1088 AccountMeta {
1089 pubkey: from,
1090 is_signer: false,
1091 is_writable: false,
1092 },
1093 AccountMeta {
1094 pubkey: owned_key,
1095 is_signer: false,
1096 is_writable: false,
1097 },
1098 ],
1099 Err(InstructionError::MissingRequiredSignature),
1100 );
1101 }
1102
1103 #[test]
1104 fn test_create_sysvar_invalid_id_with_feature() {
1105 let from = Pubkey::new_unique();
1107 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1108 let to = Pubkey::new_unique();
1109 let to_account = AccountSharedData::new(0, 0, &system_program::id());
1110
1111 process_instruction(
1113 &bincode::serialize(&SystemInstruction::CreateAccount {
1114 lamports: 50,
1115 space: 2,
1116 owner: sysvar::id(),
1117 })
1118 .unwrap(),
1119 vec![(from, from_account), (to, to_account)],
1120 vec![
1121 AccountMeta {
1122 pubkey: from,
1123 is_signer: true,
1124 is_writable: true,
1125 },
1126 AccountMeta {
1127 pubkey: to,
1128 is_signer: true,
1129 is_writable: true,
1130 },
1131 ],
1132 Ok(()),
1133 );
1134 }
1135
1136 #[test]
1137 fn test_create_data_populated() {
1138 let new_owner = Pubkey::from([9; 32]);
1140 let from = Pubkey::new_unique();
1141 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1142 let populated_key = Pubkey::new_unique();
1143 let populated_account = AccountSharedData::from(Account {
1144 data: vec![0, 1, 2, 3],
1145 ..Account::default()
1146 });
1147
1148 process_instruction(
1149 &bincode::serialize(&SystemInstruction::CreateAccount {
1150 lamports: 50,
1151 space: 2,
1152 owner: new_owner,
1153 })
1154 .unwrap(),
1155 vec![(from, from_account), (populated_key, populated_account)],
1156 vec![
1157 AccountMeta {
1158 pubkey: from,
1159 is_signer: true,
1160 is_writable: false,
1161 },
1162 AccountMeta {
1163 pubkey: populated_key,
1164 is_signer: true,
1165 is_writable: false,
1166 },
1167 ],
1168 Err(SystemError::AccountAlreadyInUse.into()),
1169 );
1170 }
1171
1172 #[test]
1173 fn test_create_from_account_is_nonce_fail() {
1174 let nonce = Pubkey::new_unique();
1175 let nonce_account = AccountSharedData::new_data(
1176 42,
1177 &nonce::state::Versions::new(nonce::State::Initialized(nonce::state::Data::default())),
1178 &system_program::id(),
1179 )
1180 .unwrap();
1181 let new = Pubkey::new_unique();
1182 let new_account = AccountSharedData::new(0, 0, &system_program::id());
1183
1184 process_instruction(
1185 &bincode::serialize(&SystemInstruction::CreateAccount {
1186 lamports: 42,
1187 space: 0,
1188 owner: Pubkey::new_unique(),
1189 })
1190 .unwrap(),
1191 vec![(nonce, nonce_account), (new, new_account)],
1192 vec![
1193 AccountMeta {
1194 pubkey: nonce,
1195 is_signer: true,
1196 is_writable: false,
1197 },
1198 AccountMeta {
1199 pubkey: new,
1200 is_signer: true,
1201 is_writable: true,
1202 },
1203 ],
1204 Err(InstructionError::InvalidArgument),
1205 );
1206 }
1207
1208 #[test]
1209 fn test_assign() {
1210 let new_owner = Pubkey::from([9; 32]);
1211 let pubkey = Pubkey::new_unique();
1212 let account = AccountSharedData::new(100, 0, &system_program::id());
1213
1214 process_instruction(
1216 &bincode::serialize(&SystemInstruction::Assign {
1217 owner: system_program::id(),
1218 })
1219 .unwrap(),
1220 vec![(pubkey, account.clone())],
1221 vec![AccountMeta {
1222 pubkey,
1223 is_signer: false,
1224 is_writable: true,
1225 }],
1226 Ok(()),
1227 );
1228
1229 process_instruction(
1231 &bincode::serialize(&SystemInstruction::Assign { owner: new_owner }).unwrap(),
1232 vec![(pubkey, account.clone())],
1233 vec![AccountMeta {
1234 pubkey,
1235 is_signer: false,
1236 is_writable: true,
1237 }],
1238 Err(InstructionError::MissingRequiredSignature),
1239 );
1240
1241 process_instruction(
1242 &bincode::serialize(&SystemInstruction::Assign { owner: new_owner }).unwrap(),
1243 vec![(pubkey, account.clone())],
1244 vec![AccountMeta {
1245 pubkey,
1246 is_signer: true,
1247 is_writable: true,
1248 }],
1249 Ok(()),
1250 );
1251
1252 process_instruction(
1254 &bincode::serialize(&SystemInstruction::Assign {
1255 owner: sysvar::id(),
1256 })
1257 .unwrap(),
1258 vec![(pubkey, account)],
1259 vec![AccountMeta {
1260 pubkey,
1261 is_signer: true,
1262 is_writable: true,
1263 }],
1264 Ok(()),
1265 );
1266 }
1267
1268 #[test]
1269 fn test_process_bogus_instruction() {
1270 let instruction = SystemInstruction::Assign {
1272 owner: Pubkey::new_unique(),
1273 };
1274 let data = serialize(&instruction).unwrap();
1275 process_instruction(
1276 &data,
1277 Vec::new(),
1278 Vec::new(),
1279 Err(InstructionError::NotEnoughAccountKeys),
1280 );
1281
1282 let from = Pubkey::new_unique();
1284 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1285 let instruction = SystemInstruction::Transfer { lamports: 0 };
1286 let data = serialize(&instruction).unwrap();
1287 process_instruction(
1288 &data,
1289 vec![(from, from_account)],
1290 vec![AccountMeta {
1291 pubkey: from,
1292 is_signer: true,
1293 is_writable: false,
1294 }],
1295 Err(InstructionError::NotEnoughAccountKeys),
1296 );
1297 }
1298
1299 #[test]
1300 fn test_transfer_lamports() {
1301 let from = Pubkey::new_unique();
1302 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1303 let to = Pubkey::from([3; 32]);
1304 let to_account = AccountSharedData::new(1, 0, &to); let transaction_accounts = vec![(from, from_account), (to, to_account)];
1306 let instruction_accounts = vec![
1307 AccountMeta {
1308 pubkey: from,
1309 is_signer: true,
1310 is_writable: true,
1311 },
1312 AccountMeta {
1313 pubkey: to,
1314 is_signer: false,
1315 is_writable: true,
1316 },
1317 ];
1318
1319 let accounts = process_instruction(
1321 &bincode::serialize(&SystemInstruction::Transfer { lamports: 50 }).unwrap(),
1322 transaction_accounts.clone(),
1323 instruction_accounts.clone(),
1324 Ok(()),
1325 );
1326 assert_eq!(accounts[0].lamports(), 50);
1327 assert_eq!(accounts[1].lamports(), 51);
1328
1329 let accounts = process_instruction(
1331 &bincode::serialize(&SystemInstruction::Transfer { lamports: 101 }).unwrap(),
1332 transaction_accounts.clone(),
1333 instruction_accounts.clone(),
1334 Err(SystemError::ResultWithNegativeLamports.into()),
1335 );
1336 assert_eq!(accounts[0].lamports(), 100);
1337 assert_eq!(accounts[1].lamports(), 1);
1338
1339 let accounts = process_instruction(
1341 &bincode::serialize(&SystemInstruction::Transfer { lamports: 0 }).unwrap(),
1342 transaction_accounts.clone(),
1343 instruction_accounts,
1344 Ok(()),
1345 );
1346 assert_eq!(accounts[0].lamports(), 100);
1347 assert_eq!(accounts[1].lamports(), 1);
1348
1349 let accounts = process_instruction(
1351 &bincode::serialize(&SystemInstruction::Transfer { lamports: 0 }).unwrap(),
1352 transaction_accounts,
1353 vec![
1354 AccountMeta {
1355 pubkey: from,
1356 is_signer: false,
1357 is_writable: true,
1358 },
1359 AccountMeta {
1360 pubkey: to,
1361 is_signer: false,
1362 is_writable: true,
1363 },
1364 ],
1365 Err(InstructionError::MissingRequiredSignature),
1366 );
1367 assert_eq!(accounts[0].lamports(), 100);
1368 assert_eq!(accounts[1].lamports(), 1);
1369 }
1370
1371 #[test]
1372 fn test_transfer_with_seed() {
1373 let base = Pubkey::new_unique();
1374 let base_account = AccountSharedData::new(100, 0, &Pubkey::from([2; 32])); let from_seed = "42".to_string();
1376 let from_owner = system_program::id();
1377 let from = Pubkey::create_with_seed(&base, from_seed.as_str(), &from_owner).unwrap();
1378 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1379 let to = Pubkey::from([3; 32]);
1380 let to_account = AccountSharedData::new(1, 0, &to); let transaction_accounts =
1382 vec![(from, from_account), (base, base_account), (to, to_account)];
1383 let instruction_accounts = vec![
1384 AccountMeta {
1385 pubkey: from,
1386 is_signer: true,
1387 is_writable: true,
1388 },
1389 AccountMeta {
1390 pubkey: base,
1391 is_signer: true,
1392 is_writable: false,
1393 },
1394 AccountMeta {
1395 pubkey: to,
1396 is_signer: false,
1397 is_writable: true,
1398 },
1399 ];
1400
1401 let accounts = process_instruction(
1403 &bincode::serialize(&SystemInstruction::TransferWithSeed {
1404 lamports: 50,
1405 from_seed: from_seed.clone(),
1406 from_owner,
1407 })
1408 .unwrap(),
1409 transaction_accounts.clone(),
1410 instruction_accounts.clone(),
1411 Ok(()),
1412 );
1413 assert_eq!(accounts[0].lamports(), 50);
1414 assert_eq!(accounts[2].lamports(), 51);
1415
1416 let accounts = process_instruction(
1418 &bincode::serialize(&SystemInstruction::TransferWithSeed {
1419 lamports: 101,
1420 from_seed: from_seed.clone(),
1421 from_owner,
1422 })
1423 .unwrap(),
1424 transaction_accounts.clone(),
1425 instruction_accounts.clone(),
1426 Err(SystemError::ResultWithNegativeLamports.into()),
1427 );
1428 assert_eq!(accounts[0].lamports(), 100);
1429 assert_eq!(accounts[2].lamports(), 1);
1430
1431 let accounts = process_instruction(
1433 &bincode::serialize(&SystemInstruction::TransferWithSeed {
1434 lamports: 0,
1435 from_seed,
1436 from_owner,
1437 })
1438 .unwrap(),
1439 transaction_accounts,
1440 instruction_accounts,
1441 Ok(()),
1442 );
1443 assert_eq!(accounts[0].lamports(), 100);
1444 assert_eq!(accounts[2].lamports(), 1);
1445 }
1446
1447 #[test]
1448 fn test_transfer_lamports_from_nonce_account_fail() {
1449 let from = Pubkey::new_unique();
1450 let from_account = AccountSharedData::new_data(
1451 100,
1452 &nonce::state::Versions::new(nonce::State::Initialized(nonce::state::Data {
1453 authority: from,
1454 ..nonce::state::Data::default()
1455 })),
1456 &system_program::id(),
1457 )
1458 .unwrap();
1459 assert_eq!(
1460 get_system_account_kind(&from_account),
1461 Some(SystemAccountKind::Nonce)
1462 );
1463 let to = Pubkey::from([3; 32]);
1464 let to_account = AccountSharedData::new(1, 0, &to); process_instruction(
1467 &bincode::serialize(&SystemInstruction::Transfer { lamports: 50 }).unwrap(),
1468 vec![(from, from_account), (to, to_account)],
1469 vec![
1470 AccountMeta {
1471 pubkey: from,
1472 is_signer: true,
1473 is_writable: false,
1474 },
1475 AccountMeta {
1476 pubkey: to,
1477 is_signer: false,
1478 is_writable: false,
1479 },
1480 ],
1481 Err(InstructionError::InvalidArgument),
1482 );
1483 }
1484
1485 fn process_nonce_instruction(
1486 instruction: Instruction,
1487 expected_result: Result<(), InstructionError>,
1488 ) -> Vec<AccountSharedData> {
1489 let transaction_accounts = instruction
1490 .accounts
1491 .iter()
1492 .map(|meta| {
1493 #[allow(deprecated)]
1494 (
1495 meta.pubkey,
1496 if sysvar::recent_blockhashes::check_id(&meta.pubkey) {
1497 create_default_recent_blockhashes_account()
1498 } else if sysvar::rent::check_id(&meta.pubkey) {
1499 account::create_account_shared_data_for_test(&Rent::free())
1500 } else {
1501 AccountSharedData::new(0, 0, &Pubkey::new_unique())
1502 },
1503 )
1504 })
1505 .collect();
1506 process_instruction(
1507 &instruction.data,
1508 transaction_accounts,
1509 instruction.accounts,
1510 expected_result,
1511 )
1512 }
1513
1514 #[test]
1515 fn test_process_nonce_ix_no_acc_data_fail() {
1516 let none_address = Pubkey::new_unique();
1517 process_nonce_instruction(
1518 system_instruction::advance_nonce_account(&none_address, &none_address),
1519 Err(InstructionError::InvalidAccountData),
1520 );
1521 }
1522
1523 #[test]
1524 fn test_process_nonce_ix_no_keyed_accs_fail() {
1525 process_instruction(
1526 &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
1527 Vec::new(),
1528 Vec::new(),
1529 Err(InstructionError::NotEnoughAccountKeys),
1530 );
1531 }
1532
1533 #[test]
1534 fn test_process_nonce_ix_only_nonce_acc_fail() {
1535 let pubkey = Pubkey::new_unique();
1536 process_instruction(
1537 &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
1538 vec![(pubkey, create_default_account())],
1539 vec![AccountMeta {
1540 pubkey,
1541 is_signer: true,
1542 is_writable: true,
1543 }],
1544 Err(InstructionError::NotEnoughAccountKeys),
1545 );
1546 }
1547
1548 #[test]
1549 fn test_process_nonce_ix_ok() {
1550 let nonce_address = Pubkey::new_unique();
1551 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1552 #[allow(deprecated)]
1553 let blockhash_id = sysvar::recent_blockhashes::id();
1554 let accounts = process_instruction(
1555 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1556 vec![
1557 (nonce_address, nonce_account),
1558 (blockhash_id, create_default_recent_blockhashes_account()),
1559 (sysvar::rent::id(), create_default_rent_account()),
1560 ],
1561 vec![
1562 AccountMeta {
1563 pubkey: nonce_address,
1564 is_signer: true,
1565 is_writable: true,
1566 },
1567 AccountMeta {
1568 pubkey: blockhash_id,
1569 is_signer: false,
1570 is_writable: false,
1571 },
1572 AccountMeta {
1573 pubkey: sysvar::rent::id(),
1574 is_signer: false,
1575 is_writable: false,
1576 },
1577 ],
1578 Ok(()),
1579 );
1580 let blockhash = hash(&serialize(&0).unwrap());
1581 #[allow(deprecated)]
1582 let new_recent_blockhashes_account = create_recent_blockhashes_account_for_test(vec![
1583 IterItem(0u64, &blockhash, 0);
1584 sysvar::recent_blockhashes::MAX_ENTRIES
1585 ]);
1586 mock_process_instruction(
1587 &system_program::id(),
1588 Vec::new(),
1589 &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
1590 vec![
1591 (nonce_address, accounts[0].clone()),
1592 (blockhash_id, new_recent_blockhashes_account),
1593 ],
1594 vec![
1595 AccountMeta {
1596 pubkey: nonce_address,
1597 is_signer: true,
1598 is_writable: true,
1599 },
1600 AccountMeta {
1601 pubkey: blockhash_id,
1602 is_signer: false,
1603 is_writable: false,
1604 },
1605 ],
1606 Ok(()),
1607 Entrypoint::vm,
1608 |invoke_context: &mut InvokeContext| {
1609 invoke_context.environment_config.blockhash = hash(&serialize(&0).unwrap());
1610 },
1611 |_invoke_context| {},
1612 );
1613 }
1614
1615 #[test]
1616 fn test_process_withdraw_ix_no_acc_data_fail() {
1617 let nonce_address = Pubkey::new_unique();
1618 process_nonce_instruction(
1619 system_instruction::withdraw_nonce_account(
1620 &nonce_address,
1621 &Pubkey::new_unique(),
1622 &nonce_address,
1623 1,
1624 ),
1625 Err(InstructionError::InvalidAccountData),
1626 );
1627 }
1628
1629 #[test]
1630 fn test_process_withdraw_ix_no_keyed_accs_fail() {
1631 process_instruction(
1632 &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
1633 Vec::new(),
1634 Vec::new(),
1635 Err(InstructionError::NotEnoughAccountKeys),
1636 );
1637 }
1638
1639 #[test]
1640 fn test_process_withdraw_ix_only_nonce_acc_fail() {
1641 let nonce_address = Pubkey::new_unique();
1642 process_instruction(
1643 &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
1644 vec![(nonce_address, create_default_account())],
1645 vec![AccountMeta {
1646 pubkey: nonce_address,
1647 is_signer: true,
1648 is_writable: true,
1649 }],
1650 Err(InstructionError::NotEnoughAccountKeys),
1651 );
1652 }
1653
1654 #[test]
1655 fn test_process_withdraw_ix_ok() {
1656 let nonce_address = Pubkey::new_unique();
1657 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1658 let pubkey = Pubkey::new_unique();
1659 #[allow(deprecated)]
1660 let blockhash_id = sysvar::recent_blockhashes::id();
1661 process_instruction(
1662 &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
1663 vec![
1664 (nonce_address, nonce_account),
1665 (pubkey, create_default_account()),
1666 (blockhash_id, create_default_recent_blockhashes_account()),
1667 (sysvar::rent::id(), create_default_rent_account()),
1668 ],
1669 vec![
1670 AccountMeta {
1671 pubkey: nonce_address,
1672 is_signer: true,
1673 is_writable: true,
1674 },
1675 AccountMeta {
1676 pubkey,
1677 is_signer: true,
1678 is_writable: true,
1679 },
1680 AccountMeta {
1681 pubkey: blockhash_id,
1682 is_signer: false,
1683 is_writable: false,
1684 },
1685 AccountMeta {
1686 pubkey: sysvar::rent::id(),
1687 is_signer: false,
1688 is_writable: false,
1689 },
1690 ],
1691 Ok(()),
1692 );
1693 }
1694
1695 #[test]
1696 fn test_process_initialize_ix_no_keyed_accs_fail() {
1697 process_instruction(
1698 &serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
1699 Vec::new(),
1700 Vec::new(),
1701 Err(InstructionError::NotEnoughAccountKeys),
1702 );
1703 }
1704
1705 #[test]
1706 fn test_process_initialize_ix_only_nonce_acc_fail() {
1707 let nonce_address = Pubkey::new_unique();
1708 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1709 process_instruction(
1710 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1711 vec![(nonce_address, nonce_account)],
1712 vec![AccountMeta {
1713 pubkey: nonce_address,
1714 is_signer: true,
1715 is_writable: true,
1716 }],
1717 Err(InstructionError::NotEnoughAccountKeys),
1718 );
1719 }
1720
1721 #[test]
1722 fn test_process_initialize_ix_ok() {
1723 let nonce_address = Pubkey::new_unique();
1724 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1725 #[allow(deprecated)]
1726 let blockhash_id = sysvar::recent_blockhashes::id();
1727 process_instruction(
1728 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1729 vec![
1730 (nonce_address, nonce_account),
1731 (blockhash_id, create_default_recent_blockhashes_account()),
1732 (sysvar::rent::id(), create_default_rent_account()),
1733 ],
1734 vec![
1735 AccountMeta {
1736 pubkey: nonce_address,
1737 is_signer: true,
1738 is_writable: true,
1739 },
1740 AccountMeta {
1741 pubkey: blockhash_id,
1742 is_signer: false,
1743 is_writable: false,
1744 },
1745 AccountMeta {
1746 pubkey: sysvar::rent::id(),
1747 is_signer: false,
1748 is_writable: false,
1749 },
1750 ],
1751 Ok(()),
1752 );
1753 }
1754
1755 #[test]
1756 fn test_process_authorize_ix_ok() {
1757 let nonce_address = Pubkey::new_unique();
1758 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1759 #[allow(deprecated)]
1760 let blockhash_id = sysvar::recent_blockhashes::id();
1761 let accounts = process_instruction(
1762 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1763 vec![
1764 (nonce_address, nonce_account),
1765 (blockhash_id, create_default_recent_blockhashes_account()),
1766 (sysvar::rent::id(), create_default_rent_account()),
1767 ],
1768 vec![
1769 AccountMeta {
1770 pubkey: nonce_address,
1771 is_signer: true,
1772 is_writable: true,
1773 },
1774 AccountMeta {
1775 pubkey: blockhash_id,
1776 is_signer: false,
1777 is_writable: false,
1778 },
1779 AccountMeta {
1780 pubkey: sysvar::rent::id(),
1781 is_signer: false,
1782 is_writable: false,
1783 },
1784 ],
1785 Ok(()),
1786 );
1787 process_instruction(
1788 &serialize(&SystemInstruction::AuthorizeNonceAccount(nonce_address)).unwrap(),
1789 vec![(nonce_address, accounts[0].clone())],
1790 vec![AccountMeta {
1791 pubkey: nonce_address,
1792 is_signer: true,
1793 is_writable: true,
1794 }],
1795 Ok(()),
1796 );
1797 }
1798
1799 #[test]
1800 fn test_process_authorize_bad_account_data_fail() {
1801 let nonce_address = Pubkey::new_unique();
1802 process_nonce_instruction(
1803 system_instruction::authorize_nonce_account(
1804 &nonce_address,
1805 &Pubkey::new_unique(),
1806 &nonce_address,
1807 ),
1808 Err(InstructionError::InvalidAccountData),
1809 );
1810 }
1811
1812 #[test]
1813 fn test_get_system_account_kind_system_ok() {
1814 let system_account = AccountSharedData::default();
1815 assert_eq!(
1816 get_system_account_kind(&system_account),
1817 Some(SystemAccountKind::System)
1818 );
1819 }
1820
1821 #[test]
1822 fn test_get_system_account_kind_nonce_ok() {
1823 let nonce_account = AccountSharedData::new_data(
1824 42,
1825 &nonce::state::Versions::new(nonce::State::Initialized(nonce::state::Data::default())),
1826 &system_program::id(),
1827 )
1828 .unwrap();
1829 assert_eq!(
1830 get_system_account_kind(&nonce_account),
1831 Some(SystemAccountKind::Nonce)
1832 );
1833 }
1834
1835 #[test]
1836 fn test_get_system_account_kind_uninitialized_nonce_account_fail() {
1837 assert_eq!(
1838 get_system_account_kind(&nonce_account::create_account(42).borrow()),
1839 None
1840 );
1841 }
1842
1843 #[test]
1844 fn test_get_system_account_kind_system_owner_nonzero_nonnonce_data_fail() {
1845 let other_data_account =
1846 AccountSharedData::new_data(42, b"other", &Pubkey::default()).unwrap();
1847 assert_eq!(get_system_account_kind(&other_data_account), None);
1848 }
1849
1850 #[test]
1851 fn test_get_system_account_kind_nonsystem_owner_with_nonce_data_fail() {
1852 let nonce_account = AccountSharedData::new_data(
1853 42,
1854 &nonce::state::Versions::new(nonce::State::Initialized(nonce::state::Data::default())),
1855 &Pubkey::new_unique(),
1856 )
1857 .unwrap();
1858 assert_eq!(get_system_account_kind(&nonce_account), None);
1859 }
1860
1861 #[test]
1862 fn test_nonce_initialize_with_empty_recent_blockhashes_fail() {
1863 let nonce_address = Pubkey::new_unique();
1864 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1865 #[allow(deprecated)]
1866 let blockhash_id = sysvar::recent_blockhashes::id();
1867 #[allow(deprecated)]
1868 let new_recent_blockhashes_account = create_recent_blockhashes_account_for_test(vec![]);
1869 process_instruction(
1870 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1871 vec![
1872 (nonce_address, nonce_account),
1873 (blockhash_id, new_recent_blockhashes_account),
1874 (sysvar::rent::id(), create_default_rent_account()),
1875 ],
1876 vec![
1877 AccountMeta {
1878 pubkey: nonce_address,
1879 is_signer: true,
1880 is_writable: true,
1881 },
1882 AccountMeta {
1883 pubkey: blockhash_id,
1884 is_signer: false,
1885 is_writable: false,
1886 },
1887 AccountMeta {
1888 pubkey: sysvar::rent::id(),
1889 is_signer: false,
1890 is_writable: false,
1891 },
1892 ],
1893 Err(SystemError::NonceNoRecentBlockhashes.into()),
1894 );
1895 }
1896
1897 #[test]
1898 fn test_nonce_advance_with_empty_recent_blockhashes_fail() {
1899 let nonce_address = Pubkey::new_unique();
1900 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1901 #[allow(deprecated)]
1902 let blockhash_id = sysvar::recent_blockhashes::id();
1903 let accounts = process_instruction(
1904 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1905 vec![
1906 (nonce_address, nonce_account),
1907 (blockhash_id, create_default_recent_blockhashes_account()),
1908 (sysvar::rent::id(), create_default_rent_account()),
1909 ],
1910 vec![
1911 AccountMeta {
1912 pubkey: nonce_address,
1913 is_signer: true,
1914 is_writable: true,
1915 },
1916 AccountMeta {
1917 pubkey: blockhash_id,
1918 is_signer: false,
1919 is_writable: false,
1920 },
1921 AccountMeta {
1922 pubkey: sysvar::rent::id(),
1923 is_signer: false,
1924 is_writable: false,
1925 },
1926 ],
1927 Ok(()),
1928 );
1929 #[allow(deprecated)]
1930 let new_recent_blockhashes_account = create_recent_blockhashes_account_for_test(vec![]);
1931 mock_process_instruction(
1932 &system_program::id(),
1933 Vec::new(),
1934 &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
1935 vec![
1936 (nonce_address, accounts[0].clone()),
1937 (blockhash_id, new_recent_blockhashes_account),
1938 ],
1939 vec![
1940 AccountMeta {
1941 pubkey: nonce_address,
1942 is_signer: true,
1943 is_writable: true,
1944 },
1945 AccountMeta {
1946 pubkey: blockhash_id,
1947 is_signer: false,
1948 is_writable: false,
1949 },
1950 ],
1951 Err(SystemError::NonceNoRecentBlockhashes.into()),
1952 Entrypoint::vm,
1953 |invoke_context: &mut InvokeContext| {
1954 invoke_context.environment_config.blockhash = hash(&serialize(&0).unwrap());
1955 },
1956 |_invoke_context| {},
1957 );
1958 }
1959
1960 #[test]
1961 fn test_nonce_account_upgrade_check_owner() {
1962 let nonce_address = Pubkey::new_unique();
1963 let versions = NonceVersions::Legacy(Box::new(NonceState::Uninitialized));
1964 let nonce_account = AccountSharedData::new_data(
1965 1_000_000, &versions, &Pubkey::new_unique(), )
1969 .unwrap();
1970 let accounts = process_instruction(
1971 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
1972 vec![(nonce_address, nonce_account.clone())],
1973 vec![AccountMeta {
1974 pubkey: nonce_address,
1975 is_signer: false,
1976 is_writable: true,
1977 }],
1978 Err(InstructionError::InvalidAccountOwner),
1979 );
1980 assert_eq!(accounts.len(), 1);
1981 assert_eq!(accounts[0], nonce_account);
1982 }
1983
1984 fn new_nonce_account(versions: NonceVersions) -> AccountSharedData {
1985 let nonce_account = AccountSharedData::new_data(
1986 1_000_000, &versions, &system_program::id(), )
1990 .unwrap();
1991 assert_eq!(
1992 nonce_account.deserialize_data::<NonceVersions>().unwrap(),
1993 versions
1994 );
1995 nonce_account
1996 }
1997
1998 #[test]
1999 fn test_nonce_account_upgrade() {
2000 let nonce_address = Pubkey::new_unique();
2001 let versions = NonceVersions::Legacy(Box::new(NonceState::Uninitialized));
2002 let nonce_account = new_nonce_account(versions);
2003 let accounts = process_instruction(
2004 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
2005 vec![(nonce_address, nonce_account.clone())],
2006 vec![AccountMeta {
2007 pubkey: nonce_address,
2008 is_signer: false,
2009 is_writable: true,
2010 }],
2011 Err(InstructionError::InvalidArgument),
2012 );
2013 assert_eq!(accounts.len(), 1);
2014 assert_eq!(accounts[0], nonce_account);
2015 let versions = NonceVersions::Current(Box::new(NonceState::Uninitialized));
2016 let nonce_account = new_nonce_account(versions);
2017 let accounts = process_instruction(
2018 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
2019 vec![(nonce_address, nonce_account.clone())],
2020 vec![AccountMeta {
2021 pubkey: nonce_address,
2022 is_signer: false,
2023 is_writable: true,
2024 }],
2025 Err(InstructionError::InvalidArgument),
2026 );
2027 assert_eq!(accounts.len(), 1);
2028 assert_eq!(accounts[0], nonce_account);
2029 let blockhash = Hash::from([171; 32]);
2030 let durable_nonce = DurableNonce::from_blockhash(&blockhash);
2031 let data = NonceData {
2032 authority: Pubkey::new_unique(),
2033 durable_nonce,
2034 fee_calculator: FeeCalculator {
2035 lamports_per_signature: 2718,
2036 },
2037 };
2038 let versions = NonceVersions::Legacy(Box::new(NonceState::Initialized(data.clone())));
2039 let nonce_account = new_nonce_account(versions);
2040 let accounts = process_instruction(
2041 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
2042 vec![(nonce_address, nonce_account.clone())],
2043 vec![AccountMeta {
2044 pubkey: nonce_address,
2045 is_signer: false,
2046 is_writable: false, }],
2048 Err(InstructionError::InvalidArgument),
2049 );
2050 assert_eq!(accounts.len(), 1);
2051 assert_eq!(accounts[0], nonce_account);
2052 let mut accounts = process_instruction(
2053 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
2054 vec![(nonce_address, nonce_account)],
2055 vec![AccountMeta {
2056 pubkey: nonce_address,
2057 is_signer: false,
2058 is_writable: true,
2059 }],
2060 Ok(()),
2061 );
2062 assert_eq!(accounts.len(), 1);
2063 let nonce_account = accounts.remove(0);
2064 let durable_nonce = DurableNonce::from_blockhash(durable_nonce.as_hash());
2065 assert_ne!(data.durable_nonce, durable_nonce);
2066 let data = NonceData {
2067 durable_nonce,
2068 ..data
2069 };
2070 let upgraded_nonce_account =
2071 NonceVersions::Current(Box::new(NonceState::Initialized(data)));
2072 assert_eq!(
2073 nonce_account.deserialize_data::<NonceVersions>().unwrap(),
2074 upgraded_nonce_account
2075 );
2076 let accounts = process_instruction(
2077 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
2078 vec![(nonce_address, nonce_account)],
2079 vec![AccountMeta {
2080 pubkey: nonce_address,
2081 is_signer: false,
2082 is_writable: true,
2083 }],
2084 Err(InstructionError::InvalidArgument),
2085 );
2086 assert_eq!(accounts.len(), 1);
2087 assert_eq!(
2088 accounts[0].deserialize_data::<NonceVersions>().unwrap(),
2089 upgraded_nonce_account
2090 );
2091 }
2092
2093 #[test]
2094 fn test_assign_native_loader_and_transfer() {
2095 for size in [0, 10] {
2096 let pubkey = Pubkey::new_unique();
2097 let account = AccountSharedData::new(100, size, &system_program::id());
2098 let accounts = process_instruction(
2099 &bincode::serialize(&SystemInstruction::Assign {
2100 owner: solana_sdk::native_loader::id(),
2101 })
2102 .unwrap(),
2103 vec![(pubkey, account.clone())],
2104 vec![AccountMeta {
2105 pubkey,
2106 is_signer: true,
2107 is_writable: true,
2108 }],
2109 Ok(()),
2110 );
2111 assert_eq!(accounts[0].owner(), &solana_sdk::native_loader::id());
2112 assert_eq!(accounts[0].lamports(), 100);
2113
2114 let pubkey2 = Pubkey::new_unique();
2115 let accounts = process_instruction(
2116 &bincode::serialize(&SystemInstruction::Transfer { lamports: 50 }).unwrap(),
2117 vec![
2118 (
2119 pubkey2,
2120 AccountSharedData::new(100, 0, &system_program::id()),
2121 ),
2122 (pubkey, accounts[0].clone()),
2123 ],
2124 vec![
2125 AccountMeta {
2126 pubkey: pubkey2,
2127 is_signer: true,
2128 is_writable: true,
2129 },
2130 AccountMeta {
2131 pubkey,
2132 is_signer: false,
2133 is_writable: true,
2134 },
2135 ],
2136 Ok(()),
2137 );
2138 assert_eq!(accounts[1].owner(), &solana_sdk::native_loader::id());
2139 assert_eq!(accounts[1].lamports(), 150);
2140 }
2141 }
2142}