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