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_log_collector::ic_msg,
10 solana_nonce as nonce,
11 solana_program_runtime::{
12 declare_process_instruction, invoke_context::InvokeContext,
13 sysvar_cache::get_sysvar_with_account_check,
14 },
15 solana_pubkey::Pubkey,
16 solana_sdk_ids::system_program,
17 solana_system_interface::{
18 error::SystemError, instruction::SystemInstruction, MAX_PERMITTED_DATA_LENGTH,
19 },
20 solana_transaction_context::{
21 BorrowedAccount, IndexOfAccount, InstructionContext, TransactionContext,
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 =
306 limited_deserialize(instruction_data, solana_packet::PACKET_DATA_SIZE as u64)?;
307
308 trace!("process_instruction: {:?}", instruction);
309
310 let signers = instruction_context.get_signers(transaction_context)?;
311 match instruction {
312 SystemInstruction::CreateAccount {
313 lamports,
314 space,
315 owner,
316 } => {
317 instruction_context.check_number_of_instruction_accounts(2)?;
318 let to_address = Address::create(
319 transaction_context.get_key_of_account_at_index(
320 instruction_context.get_index_of_instruction_account_in_transaction(1)?,
321 )?,
322 None,
323 invoke_context,
324 )?;
325 create_account(
326 0,
327 1,
328 &to_address,
329 lamports,
330 space,
331 &owner,
332 &signers,
333 invoke_context,
334 transaction_context,
335 instruction_context,
336 )
337 }
338 SystemInstruction::CreateAccountWithSeed {
339 base,
340 seed,
341 lamports,
342 space,
343 owner,
344 } => {
345 instruction_context.check_number_of_instruction_accounts(2)?;
346 let to_address = Address::create(
347 transaction_context.get_key_of_account_at_index(
348 instruction_context.get_index_of_instruction_account_in_transaction(1)?,
349 )?,
350 Some((&base, &seed, &owner)),
351 invoke_context,
352 )?;
353 create_account(
354 0,
355 1,
356 &to_address,
357 lamports,
358 space,
359 &owner,
360 &signers,
361 invoke_context,
362 transaction_context,
363 instruction_context,
364 )
365 }
366 SystemInstruction::Assign { owner } => {
367 instruction_context.check_number_of_instruction_accounts(1)?;
368 let mut account =
369 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
370 let address = Address::create(
371 transaction_context.get_key_of_account_at_index(
372 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
373 )?,
374 None,
375 invoke_context,
376 )?;
377 assign(&mut account, &address, &owner, &signers, invoke_context)
378 }
379 SystemInstruction::Transfer { lamports } => {
380 instruction_context.check_number_of_instruction_accounts(2)?;
381 transfer(
382 0,
383 1,
384 lamports,
385 invoke_context,
386 transaction_context,
387 instruction_context,
388 )
389 }
390 SystemInstruction::TransferWithSeed {
391 lamports,
392 from_seed,
393 from_owner,
394 } => {
395 instruction_context.check_number_of_instruction_accounts(3)?;
396 transfer_with_seed(
397 0,
398 1,
399 &from_seed,
400 &from_owner,
401 2,
402 lamports,
403 invoke_context,
404 transaction_context,
405 instruction_context,
406 )
407 }
408 SystemInstruction::AdvanceNonceAccount => {
409 instruction_context.check_number_of_instruction_accounts(1)?;
410 let mut me =
411 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
412 #[allow(deprecated)]
413 let recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes(
414 invoke_context,
415 instruction_context,
416 1,
417 )?;
418 if recent_blockhashes.is_empty() {
419 ic_msg!(
420 invoke_context,
421 "Advance nonce account: recent blockhash list is empty",
422 );
423 return Err(SystemError::NonceNoRecentBlockhashes.into());
424 }
425 advance_nonce_account(&mut me, &signers, invoke_context)
426 }
427 SystemInstruction::WithdrawNonceAccount(lamports) => {
428 instruction_context.check_number_of_instruction_accounts(2)?;
429 #[allow(deprecated)]
430 let _recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes(
431 invoke_context,
432 instruction_context,
433 2,
434 )?;
435 let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 3)?;
436 withdraw_nonce_account(
437 0,
438 lamports,
439 1,
440 &rent,
441 &signers,
442 invoke_context,
443 transaction_context,
444 instruction_context,
445 )
446 }
447 SystemInstruction::InitializeNonceAccount(authorized) => {
448 instruction_context.check_number_of_instruction_accounts(1)?;
449 let mut me =
450 instruction_context.try_borrow_instruction_account(transaction_context, 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 = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 2)?;
465 initialize_nonce_account(&mut me, &authorized, &rent, invoke_context)
466 }
467 SystemInstruction::AuthorizeNonceAccount(nonce_authority) => {
468 instruction_context.check_number_of_instruction_accounts(1)?;
469 let mut me =
470 instruction_context.try_borrow_instruction_account(transaction_context, 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 =
476 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
477 if !system_program::check_id(nonce_account.get_owner()) {
478 return Err(InstructionError::InvalidAccountOwner);
479 }
480 if !nonce_account.is_writable() {
481 return Err(InstructionError::InvalidArgument);
482 }
483 let nonce_versions: nonce::versions::Versions = nonce_account.get_state()?;
484 match nonce_versions.upgrade() {
485 None => Err(InstructionError::InvalidArgument),
486 Some(nonce_versions) => nonce_account.set_state(&nonce_versions),
487 }
488 }
489 SystemInstruction::Allocate { space } => {
490 instruction_context.check_number_of_instruction_accounts(1)?;
491 let mut account =
492 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
493 let address = Address::create(
494 transaction_context.get_key_of_account_at_index(
495 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
496 )?,
497 None,
498 invoke_context,
499 )?;
500 allocate(&mut account, &address, space, &signers, invoke_context)
501 }
502 SystemInstruction::AllocateWithSeed {
503 base,
504 seed,
505 space,
506 owner,
507 } => {
508 instruction_context.check_number_of_instruction_accounts(1)?;
509 let mut account =
510 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
511 let address = Address::create(
512 transaction_context.get_key_of_account_at_index(
513 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
514 )?,
515 Some((&base, &seed, &owner)),
516 invoke_context,
517 )?;
518 allocate_and_assign(
519 &mut account,
520 &address,
521 space,
522 &owner,
523 &signers,
524 invoke_context,
525 )
526 }
527 SystemInstruction::AssignWithSeed { base, seed, owner } => {
528 instruction_context.check_number_of_instruction_accounts(1)?;
529 let mut account =
530 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
531 let address = Address::create(
532 transaction_context.get_key_of_account_at_index(
533 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
534 )?,
535 Some((&base, &seed, &owner)),
536 invoke_context,
537 )?;
538 assign(&mut account, &address, &owner, &signers, invoke_context)
539 }
540 }
541});
542
543#[cfg(test)]
544mod tests {
545 use {
546 super::*,
547 bincode::serialize,
548 solana_nonce_account::{get_system_account_kind, SystemAccountKind},
549 solana_program_runtime::{
550 invoke_context::mock_process_instruction, with_mock_invoke_context,
551 },
552 std::collections::BinaryHeap,
553 };
554 #[allow(deprecated)]
555 use {
556 solana_account::{
557 self as account, create_account_shared_data_with_fields, to_account, Account,
558 AccountSharedData, ReadableAccount, DUMMY_INHERITABLE_ACCOUNT_FIELDS,
559 },
560 solana_fee_calculator::FeeCalculator,
561 solana_hash::Hash,
562 solana_instruction::{error::InstructionError, AccountMeta, Instruction},
563 solana_nonce::{
564 self as nonce,
565 state::{Data as NonceData, DurableNonce, State as NonceState},
566 versions::Versions as NonceVersions,
567 },
568 solana_nonce_account as nonce_account,
569 solana_sha256_hasher::hash,
570 solana_system_interface::{instruction as system_instruction, program as system_program},
571 solana_sysvar::{
572 self as sysvar,
573 recent_blockhashes::{IntoIterSorted, IterItem, RecentBlockhashes, MAX_ENTRIES},
574 rent::Rent,
575 },
576 };
577
578 impl From<Pubkey> for Address {
579 fn from(address: Pubkey) -> Self {
580 Self {
581 address,
582 base: None,
583 }
584 }
585 }
586
587 fn process_instruction(
588 instruction_data: &[u8],
589 transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
590 instruction_accounts: Vec<AccountMeta>,
591 expected_result: Result<(), InstructionError>,
592 ) -> Vec<AccountSharedData> {
593 mock_process_instruction(
594 &system_program::id(),
595 Vec::new(),
596 instruction_data,
597 transaction_accounts,
598 instruction_accounts,
599 expected_result,
600 Entrypoint::vm,
601 |_invoke_context| {},
602 |_invoke_context| {},
603 )
604 }
605
606 fn create_default_account() -> AccountSharedData {
607 AccountSharedData::new(0, 0, &Pubkey::new_unique())
608 }
609 #[allow(deprecated)]
610 fn create_recent_blockhashes_account_for_test<'a, I>(
611 recent_blockhash_iter: I,
612 ) -> AccountSharedData
613 where
614 I: IntoIterator<Item = IterItem<'a>>,
615 {
616 let mut account = create_account_shared_data_with_fields::<RecentBlockhashes>(
617 &RecentBlockhashes::default(),
618 DUMMY_INHERITABLE_ACCOUNT_FIELDS,
619 );
620 let sorted = BinaryHeap::from_iter(recent_blockhash_iter);
621 let sorted_iter = IntoIterSorted::new(sorted);
622 let recent_blockhash_iter = sorted_iter.take(MAX_ENTRIES);
623 let recent_blockhashes: RecentBlockhashes = recent_blockhash_iter.collect();
624 to_account(&recent_blockhashes, &mut account);
625 account
626 }
627 fn create_default_recent_blockhashes_account() -> AccountSharedData {
628 #[allow(deprecated)]
629 create_recent_blockhashes_account_for_test(vec![
630 IterItem(0u64, &Hash::default(), 0);
631 sysvar::recent_blockhashes::MAX_ENTRIES
632 ])
633 }
634 fn create_default_rent_account() -> AccountSharedData {
635 account::create_account_shared_data_for_test(&Rent::free())
636 }
637
638 #[test]
639 fn test_create_account() {
640 let new_owner = Pubkey::from([9; 32]);
641 let from = Pubkey::new_unique();
642 let to = Pubkey::new_unique();
643 let from_account = AccountSharedData::new(100, 0, &system_program::id());
644 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
645
646 let accounts = process_instruction(
647 &bincode::serialize(&SystemInstruction::CreateAccount {
648 lamports: 50,
649 space: 2,
650 owner: new_owner,
651 })
652 .unwrap(),
653 vec![(from, from_account), (to, to_account)],
654 vec![
655 AccountMeta {
656 pubkey: from,
657 is_signer: true,
658 is_writable: true,
659 },
660 AccountMeta {
661 pubkey: to,
662 is_signer: true,
663 is_writable: true,
664 },
665 ],
666 Ok(()),
667 );
668 assert_eq!(accounts[0].lamports(), 50);
669 assert_eq!(accounts[1].lamports(), 50);
670 assert_eq!(accounts[1].owner(), &new_owner);
671 assert_eq!(accounts[1].data(), &[0, 0]);
672 }
673
674 #[test]
675 fn test_create_account_with_seed() {
676 let new_owner = Pubkey::from([9; 32]);
677 let from = Pubkey::new_unique();
678 let seed = "shiny pepper";
679 let to = Pubkey::create_with_seed(&from, seed, &new_owner).unwrap();
680 let from_account = AccountSharedData::new(100, 0, &system_program::id());
681 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
682
683 let accounts = process_instruction(
684 &bincode::serialize(&SystemInstruction::CreateAccountWithSeed {
685 base: from,
686 seed: seed.to_string(),
687 lamports: 50,
688 space: 2,
689 owner: new_owner,
690 })
691 .unwrap(),
692 vec![(from, from_account), (to, to_account)],
693 vec![
694 AccountMeta {
695 pubkey: from,
696 is_signer: true,
697 is_writable: true,
698 },
699 AccountMeta {
700 pubkey: to,
701 is_signer: true,
702 is_writable: true,
703 },
704 ],
705 Ok(()),
706 );
707 assert_eq!(accounts[0].lamports(), 50);
708 assert_eq!(accounts[1].lamports(), 50);
709 assert_eq!(accounts[1].owner(), &new_owner);
710 assert_eq!(accounts[1].data(), &[0, 0]);
711 }
712
713 #[test]
714 fn test_create_account_with_seed_separate_base_account() {
715 let new_owner = Pubkey::from([9; 32]);
716 let from = Pubkey::new_unique();
717 let base = Pubkey::new_unique();
718 let seed = "shiny pepper";
719 let to = Pubkey::create_with_seed(&base, seed, &new_owner).unwrap();
720 let from_account = AccountSharedData::new(100, 0, &system_program::id());
721 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
722 let base_account = AccountSharedData::new(0, 0, &Pubkey::default());
723
724 let accounts = process_instruction(
725 &bincode::serialize(&SystemInstruction::CreateAccountWithSeed {
726 base,
727 seed: seed.to_string(),
728 lamports: 50,
729 space: 2,
730 owner: new_owner,
731 })
732 .unwrap(),
733 vec![(from, from_account), (to, to_account), (base, base_account)],
734 vec![
735 AccountMeta {
736 pubkey: from,
737 is_signer: true,
738 is_writable: true,
739 },
740 AccountMeta {
741 pubkey: to,
742 is_signer: false,
743 is_writable: true,
744 },
745 AccountMeta {
746 pubkey: base,
747 is_signer: true,
748 is_writable: false,
749 },
750 ],
751 Ok(()),
752 );
753 assert_eq!(accounts[0].lamports(), 50);
754 assert_eq!(accounts[1].lamports(), 50);
755 assert_eq!(accounts[1].owner(), &new_owner);
756 assert_eq!(accounts[1].data(), &[0, 0]);
757 }
758
759 #[test]
760 fn test_address_create_with_seed_mismatch() {
761 with_mock_invoke_context!(invoke_context, transaction_context, Vec::new());
762 let from = Pubkey::new_unique();
763 let seed = "dull boy";
764 let to = Pubkey::new_unique();
765 let owner = Pubkey::new_unique();
766
767 assert_eq!(
768 Address::create(&to, Some((&from, seed, &owner)), &invoke_context),
769 Err(SystemError::AddressWithSeedMismatch.into())
770 );
771 }
772
773 #[test]
774 fn test_create_account_with_seed_missing_sig() {
775 let new_owner = Pubkey::from([9; 32]);
776 let from = Pubkey::new_unique();
777 let seed = "dull boy";
778 let to = Pubkey::create_with_seed(&from, seed, &new_owner).unwrap();
779 let from_account = AccountSharedData::new(100, 0, &system_program::id());
780 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
781
782 let accounts = process_instruction(
783 &bincode::serialize(&SystemInstruction::CreateAccount {
784 lamports: 50,
785 space: 2,
786 owner: new_owner,
787 })
788 .unwrap(),
789 vec![(from, from_account), (to, to_account)],
790 vec![
791 AccountMeta {
792 pubkey: from,
793 is_signer: true,
794 is_writable: false,
795 },
796 AccountMeta {
797 pubkey: to,
798 is_signer: false,
799 is_writable: false,
800 },
801 ],
802 Err(InstructionError::MissingRequiredSignature),
803 );
804 assert_eq!(accounts[0].lamports(), 100);
805 assert_eq!(accounts[1], AccountSharedData::default());
806 }
807
808 #[test]
809 fn test_create_with_zero_lamports() {
810 let new_owner = Pubkey::from([9; 32]);
812 let from = Pubkey::new_unique();
813 let from_account = AccountSharedData::new(100, 0, &Pubkey::new_unique()); let to = Pubkey::new_unique();
815 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
816
817 let accounts = process_instruction(
818 &bincode::serialize(&SystemInstruction::CreateAccount {
819 lamports: 0,
820 space: 2,
821 owner: new_owner,
822 })
823 .unwrap(),
824 vec![(from, from_account), (to, to_account)],
825 vec![
826 AccountMeta {
827 pubkey: from,
828 is_signer: true,
829 is_writable: true,
830 },
831 AccountMeta {
832 pubkey: to,
833 is_signer: true,
834 is_writable: true,
835 },
836 ],
837 Ok(()),
838 );
839 assert_eq!(accounts[0].lamports(), 100);
840 assert_eq!(accounts[1].lamports(), 0);
841 assert_eq!(*accounts[1].owner(), new_owner);
842 assert_eq!(accounts[1].data(), &[0, 0]);
843 }
844
845 #[test]
846 fn test_create_negative_lamports() {
847 let new_owner = Pubkey::from([9; 32]);
849 let from = Pubkey::new_unique();
850 let from_account = AccountSharedData::new(100, 0, &Pubkey::new_unique());
851 let to = Pubkey::new_unique();
852 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
853
854 process_instruction(
855 &bincode::serialize(&SystemInstruction::CreateAccount {
856 lamports: 150,
857 space: 2,
858 owner: new_owner,
859 })
860 .unwrap(),
861 vec![(from, from_account), (to, to_account)],
862 vec![
863 AccountMeta {
864 pubkey: from,
865 is_signer: true,
866 is_writable: true,
867 },
868 AccountMeta {
869 pubkey: to,
870 is_signer: true,
871 is_writable: true,
872 },
873 ],
874 Err(SystemError::ResultWithNegativeLamports.into()),
875 );
876 }
877
878 #[test]
879 fn test_request_more_than_allowed_data_length() {
880 let from = Pubkey::new_unique();
881 let from_account = AccountSharedData::new(100, 0, &system_program::id());
882 let to = Pubkey::new_unique();
883 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
884 let instruction_accounts = vec![
885 AccountMeta {
886 pubkey: from,
887 is_signer: true,
888 is_writable: true,
889 },
890 AccountMeta {
891 pubkey: to,
892 is_signer: true,
893 is_writable: true,
894 },
895 ];
896
897 process_instruction(
899 &bincode::serialize(&SystemInstruction::CreateAccount {
900 lamports: 50,
901 space: MAX_PERMITTED_DATA_LENGTH + 1,
902 owner: system_program::id(),
903 })
904 .unwrap(),
905 vec![(from, from_account.clone()), (to, to_account.clone())],
906 instruction_accounts.clone(),
907 Err(SystemError::InvalidAccountDataLength.into()),
908 );
909
910 let accounts = process_instruction(
912 &bincode::serialize(&SystemInstruction::CreateAccount {
913 lamports: 50,
914 space: MAX_PERMITTED_DATA_LENGTH,
915 owner: system_program::id(),
916 })
917 .unwrap(),
918 vec![(from, from_account), (to, to_account)],
919 instruction_accounts,
920 Ok(()),
921 );
922 assert_eq!(accounts[1].lamports(), 50);
923 assert_eq!(accounts[1].data().len() as u64, MAX_PERMITTED_DATA_LENGTH);
924 }
925
926 #[test]
927 fn test_create_already_in_use() {
928 let new_owner = Pubkey::from([9; 32]);
929 let from = Pubkey::new_unique();
930 let from_account = AccountSharedData::new(100, 0, &system_program::id());
931 let owned_key = Pubkey::new_unique();
932
933 let original_program_owner = Pubkey::from([5; 32]);
935 let owned_account = AccountSharedData::new(0, 0, &original_program_owner);
936 let unchanged_account = owned_account.clone();
937 let accounts = process_instruction(
938 &bincode::serialize(&SystemInstruction::CreateAccount {
939 lamports: 50,
940 space: 2,
941 owner: new_owner,
942 })
943 .unwrap(),
944 vec![(from, from_account.clone()), (owned_key, owned_account)],
945 vec![
946 AccountMeta {
947 pubkey: from,
948 is_signer: true,
949 is_writable: false,
950 },
951 AccountMeta {
952 pubkey: owned_key,
953 is_signer: true,
954 is_writable: false,
955 },
956 ],
957 Err(SystemError::AccountAlreadyInUse.into()),
958 );
959 assert_eq!(accounts[0].lamports(), 100);
960 assert_eq!(accounts[1], unchanged_account);
961
962 let owned_account = AccountSharedData::new(0, 1, &Pubkey::default());
964 let unchanged_account = owned_account.clone();
965 let accounts = process_instruction(
966 &bincode::serialize(&SystemInstruction::CreateAccount {
967 lamports: 50,
968 space: 2,
969 owner: new_owner,
970 })
971 .unwrap(),
972 vec![(from, from_account.clone()), (owned_key, owned_account)],
973 vec![
974 AccountMeta {
975 pubkey: from,
976 is_signer: true,
977 is_writable: false,
978 },
979 AccountMeta {
980 pubkey: owned_key,
981 is_signer: true,
982 is_writable: false,
983 },
984 ],
985 Err(SystemError::AccountAlreadyInUse.into()),
986 );
987 assert_eq!(accounts[0].lamports(), 100);
988 assert_eq!(accounts[1], unchanged_account);
989
990 let owned_account = AccountSharedData::new(1, 0, &Pubkey::default());
992 let unchanged_account = owned_account.clone();
993 let accounts = process_instruction(
994 &bincode::serialize(&SystemInstruction::CreateAccount {
995 lamports: 50,
996 space: 2,
997 owner: new_owner,
998 })
999 .unwrap(),
1000 vec![(from, from_account), (owned_key, owned_account)],
1001 vec![
1002 AccountMeta {
1003 pubkey: from,
1004 is_signer: true,
1005 is_writable: false,
1006 },
1007 AccountMeta {
1008 pubkey: owned_key,
1009 is_signer: true,
1010 is_writable: false,
1011 },
1012 ],
1013 Err(SystemError::AccountAlreadyInUse.into()),
1014 );
1015 assert_eq!(accounts[0].lamports(), 100);
1016 assert_eq!(accounts[1], unchanged_account);
1017 }
1018
1019 #[test]
1020 fn test_create_unsigned() {
1021 let new_owner = Pubkey::from([9; 32]);
1023 let from = Pubkey::new_unique();
1024 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1025 let owned_key = Pubkey::new_unique();
1026 let owned_account = AccountSharedData::new(0, 0, &Pubkey::default());
1027
1028 process_instruction(
1030 &bincode::serialize(&SystemInstruction::CreateAccount {
1031 lamports: 50,
1032 space: 2,
1033 owner: new_owner,
1034 })
1035 .unwrap(),
1036 vec![
1037 (from, from_account.clone()),
1038 (owned_key, owned_account.clone()),
1039 ],
1040 vec![
1041 AccountMeta {
1042 pubkey: from,
1043 is_signer: false,
1044 is_writable: false,
1045 },
1046 AccountMeta {
1047 pubkey: owned_key,
1048 is_signer: false,
1049 is_writable: false,
1050 },
1051 ],
1052 Err(InstructionError::MissingRequiredSignature),
1053 );
1054
1055 process_instruction(
1057 &bincode::serialize(&SystemInstruction::CreateAccount {
1058 lamports: 50,
1059 space: 2,
1060 owner: new_owner,
1061 })
1062 .unwrap(),
1063 vec![(from, from_account.clone()), (owned_key, owned_account)],
1064 vec![
1065 AccountMeta {
1066 pubkey: from,
1067 is_signer: true,
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 let owned_account = AccountSharedData::new(0, 0, &Pubkey::default());
1081 process_instruction(
1082 &bincode::serialize(&SystemInstruction::CreateAccount {
1083 lamports: 50,
1084 space: 2,
1085 owner: new_owner,
1086 })
1087 .unwrap(),
1088 vec![(from, from_account), (owned_key, owned_account)],
1089 vec![
1090 AccountMeta {
1091 pubkey: from,
1092 is_signer: false,
1093 is_writable: false,
1094 },
1095 AccountMeta {
1096 pubkey: owned_key,
1097 is_signer: false,
1098 is_writable: false,
1099 },
1100 ],
1101 Err(InstructionError::MissingRequiredSignature),
1102 );
1103 }
1104
1105 #[test]
1106 fn test_create_sysvar_invalid_id_with_feature() {
1107 let from = Pubkey::new_unique();
1109 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1110 let to = Pubkey::new_unique();
1111 let to_account = AccountSharedData::new(0, 0, &system_program::id());
1112
1113 process_instruction(
1115 &bincode::serialize(&SystemInstruction::CreateAccount {
1116 lamports: 50,
1117 space: 2,
1118 owner: solana_sdk_ids::sysvar::id(),
1119 })
1120 .unwrap(),
1121 vec![(from, from_account), (to, to_account)],
1122 vec![
1123 AccountMeta {
1124 pubkey: from,
1125 is_signer: true,
1126 is_writable: true,
1127 },
1128 AccountMeta {
1129 pubkey: to,
1130 is_signer: true,
1131 is_writable: true,
1132 },
1133 ],
1134 Ok(()),
1135 );
1136 }
1137
1138 #[test]
1139 fn test_create_data_populated() {
1140 let new_owner = Pubkey::from([9; 32]);
1142 let from = Pubkey::new_unique();
1143 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1144 let populated_key = Pubkey::new_unique();
1145 let populated_account = AccountSharedData::from(Account {
1146 data: vec![0, 1, 2, 3],
1147 ..Account::default()
1148 });
1149
1150 process_instruction(
1151 &bincode::serialize(&SystemInstruction::CreateAccount {
1152 lamports: 50,
1153 space: 2,
1154 owner: new_owner,
1155 })
1156 .unwrap(),
1157 vec![(from, from_account), (populated_key, populated_account)],
1158 vec![
1159 AccountMeta {
1160 pubkey: from,
1161 is_signer: true,
1162 is_writable: false,
1163 },
1164 AccountMeta {
1165 pubkey: populated_key,
1166 is_signer: true,
1167 is_writable: false,
1168 },
1169 ],
1170 Err(SystemError::AccountAlreadyInUse.into()),
1171 );
1172 }
1173
1174 #[test]
1175 fn test_create_from_account_is_nonce_fail() {
1176 let nonce = Pubkey::new_unique();
1177 let nonce_account = AccountSharedData::new_data(
1178 42,
1179 &nonce::versions::Versions::new(nonce::state::State::Initialized(
1180 nonce::state::Data::default(),
1181 )),
1182 &system_program::id(),
1183 )
1184 .unwrap();
1185 let new = Pubkey::new_unique();
1186 let new_account = AccountSharedData::new(0, 0, &system_program::id());
1187
1188 process_instruction(
1189 &bincode::serialize(&SystemInstruction::CreateAccount {
1190 lamports: 42,
1191 space: 0,
1192 owner: Pubkey::new_unique(),
1193 })
1194 .unwrap(),
1195 vec![(nonce, nonce_account), (new, new_account)],
1196 vec![
1197 AccountMeta {
1198 pubkey: nonce,
1199 is_signer: true,
1200 is_writable: false,
1201 },
1202 AccountMeta {
1203 pubkey: new,
1204 is_signer: true,
1205 is_writable: true,
1206 },
1207 ],
1208 Err(InstructionError::InvalidArgument),
1209 );
1210 }
1211
1212 #[test]
1213 fn test_assign() {
1214 let new_owner = Pubkey::from([9; 32]);
1215 let pubkey = Pubkey::new_unique();
1216 let account = AccountSharedData::new(100, 0, &system_program::id());
1217
1218 process_instruction(
1220 &bincode::serialize(&SystemInstruction::Assign {
1221 owner: system_program::id(),
1222 })
1223 .unwrap(),
1224 vec![(pubkey, account.clone())],
1225 vec![AccountMeta {
1226 pubkey,
1227 is_signer: false,
1228 is_writable: true,
1229 }],
1230 Ok(()),
1231 );
1232
1233 process_instruction(
1235 &bincode::serialize(&SystemInstruction::Assign { owner: new_owner }).unwrap(),
1236 vec![(pubkey, account.clone())],
1237 vec![AccountMeta {
1238 pubkey,
1239 is_signer: false,
1240 is_writable: true,
1241 }],
1242 Err(InstructionError::MissingRequiredSignature),
1243 );
1244
1245 process_instruction(
1246 &bincode::serialize(&SystemInstruction::Assign { owner: new_owner }).unwrap(),
1247 vec![(pubkey, account.clone())],
1248 vec![AccountMeta {
1249 pubkey,
1250 is_signer: true,
1251 is_writable: true,
1252 }],
1253 Ok(()),
1254 );
1255
1256 process_instruction(
1258 &bincode::serialize(&SystemInstruction::Assign {
1259 owner: solana_sdk_ids::sysvar::id(),
1260 })
1261 .unwrap(),
1262 vec![(pubkey, account)],
1263 vec![AccountMeta {
1264 pubkey,
1265 is_signer: true,
1266 is_writable: true,
1267 }],
1268 Ok(()),
1269 );
1270 }
1271
1272 #[test]
1273 fn test_process_bogus_instruction() {
1274 let instruction = SystemInstruction::Assign {
1276 owner: Pubkey::new_unique(),
1277 };
1278 let data = serialize(&instruction).unwrap();
1279 process_instruction(
1280 &data,
1281 Vec::new(),
1282 Vec::new(),
1283 Err(InstructionError::NotEnoughAccountKeys),
1284 );
1285
1286 let from = Pubkey::new_unique();
1288 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1289 let instruction = SystemInstruction::Transfer { lamports: 0 };
1290 let data = serialize(&instruction).unwrap();
1291 process_instruction(
1292 &data,
1293 vec![(from, from_account)],
1294 vec![AccountMeta {
1295 pubkey: from,
1296 is_signer: true,
1297 is_writable: false,
1298 }],
1299 Err(InstructionError::NotEnoughAccountKeys),
1300 );
1301 }
1302
1303 #[test]
1304 fn test_transfer_lamports() {
1305 let from = Pubkey::new_unique();
1306 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1307 let to = Pubkey::from([3; 32]);
1308 let to_account = AccountSharedData::new(1, 0, &to); let transaction_accounts = vec![(from, from_account), (to, to_account)];
1310 let instruction_accounts = vec![
1311 AccountMeta {
1312 pubkey: from,
1313 is_signer: true,
1314 is_writable: true,
1315 },
1316 AccountMeta {
1317 pubkey: to,
1318 is_signer: false,
1319 is_writable: true,
1320 },
1321 ];
1322
1323 let accounts = process_instruction(
1325 &bincode::serialize(&SystemInstruction::Transfer { lamports: 50 }).unwrap(),
1326 transaction_accounts.clone(),
1327 instruction_accounts.clone(),
1328 Ok(()),
1329 );
1330 assert_eq!(accounts[0].lamports(), 50);
1331 assert_eq!(accounts[1].lamports(), 51);
1332
1333 let accounts = process_instruction(
1335 &bincode::serialize(&SystemInstruction::Transfer { lamports: 101 }).unwrap(),
1336 transaction_accounts.clone(),
1337 instruction_accounts.clone(),
1338 Err(SystemError::ResultWithNegativeLamports.into()),
1339 );
1340 assert_eq!(accounts[0].lamports(), 100);
1341 assert_eq!(accounts[1].lamports(), 1);
1342
1343 let accounts = process_instruction(
1345 &bincode::serialize(&SystemInstruction::Transfer { lamports: 0 }).unwrap(),
1346 transaction_accounts.clone(),
1347 instruction_accounts,
1348 Ok(()),
1349 );
1350 assert_eq!(accounts[0].lamports(), 100);
1351 assert_eq!(accounts[1].lamports(), 1);
1352
1353 let accounts = process_instruction(
1355 &bincode::serialize(&SystemInstruction::Transfer { lamports: 0 }).unwrap(),
1356 transaction_accounts,
1357 vec![
1358 AccountMeta {
1359 pubkey: from,
1360 is_signer: false,
1361 is_writable: true,
1362 },
1363 AccountMeta {
1364 pubkey: to,
1365 is_signer: false,
1366 is_writable: true,
1367 },
1368 ],
1369 Err(InstructionError::MissingRequiredSignature),
1370 );
1371 assert_eq!(accounts[0].lamports(), 100);
1372 assert_eq!(accounts[1].lamports(), 1);
1373 }
1374
1375 #[test]
1376 fn test_transfer_with_seed() {
1377 let base = Pubkey::new_unique();
1378 let base_account = AccountSharedData::new(100, 0, &Pubkey::from([2; 32])); let from_seed = "42".to_string();
1380 let from_owner = system_program::id();
1381 let from = Pubkey::create_with_seed(&base, from_seed.as_str(), &from_owner).unwrap();
1382 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1383 let to = Pubkey::from([3; 32]);
1384 let to_account = AccountSharedData::new(1, 0, &to); let transaction_accounts =
1386 vec![(from, from_account), (base, base_account), (to, to_account)];
1387 let instruction_accounts = vec![
1388 AccountMeta {
1389 pubkey: from,
1390 is_signer: true,
1391 is_writable: true,
1392 },
1393 AccountMeta {
1394 pubkey: base,
1395 is_signer: true,
1396 is_writable: false,
1397 },
1398 AccountMeta {
1399 pubkey: to,
1400 is_signer: false,
1401 is_writable: true,
1402 },
1403 ];
1404
1405 let accounts = process_instruction(
1407 &bincode::serialize(&SystemInstruction::TransferWithSeed {
1408 lamports: 50,
1409 from_seed: from_seed.clone(),
1410 from_owner,
1411 })
1412 .unwrap(),
1413 transaction_accounts.clone(),
1414 instruction_accounts.clone(),
1415 Ok(()),
1416 );
1417 assert_eq!(accounts[0].lamports(), 50);
1418 assert_eq!(accounts[2].lamports(), 51);
1419
1420 let accounts = process_instruction(
1422 &bincode::serialize(&SystemInstruction::TransferWithSeed {
1423 lamports: 101,
1424 from_seed: from_seed.clone(),
1425 from_owner,
1426 })
1427 .unwrap(),
1428 transaction_accounts.clone(),
1429 instruction_accounts.clone(),
1430 Err(SystemError::ResultWithNegativeLamports.into()),
1431 );
1432 assert_eq!(accounts[0].lamports(), 100);
1433 assert_eq!(accounts[2].lamports(), 1);
1434
1435 let accounts = process_instruction(
1437 &bincode::serialize(&SystemInstruction::TransferWithSeed {
1438 lamports: 0,
1439 from_seed,
1440 from_owner,
1441 })
1442 .unwrap(),
1443 transaction_accounts,
1444 instruction_accounts,
1445 Ok(()),
1446 );
1447 assert_eq!(accounts[0].lamports(), 100);
1448 assert_eq!(accounts[2].lamports(), 1);
1449 }
1450
1451 #[test]
1452 fn test_transfer_lamports_from_nonce_account_fail() {
1453 let from = Pubkey::new_unique();
1454 let from_account = AccountSharedData::new_data(
1455 100,
1456 &nonce::versions::Versions::new(nonce::state::State::Initialized(nonce::state::Data {
1457 authority: from,
1458 ..nonce::state::Data::default()
1459 })),
1460 &system_program::id(),
1461 )
1462 .unwrap();
1463 assert_eq!(
1464 get_system_account_kind(&from_account),
1465 Some(SystemAccountKind::Nonce)
1466 );
1467 let to = Pubkey::from([3; 32]);
1468 let to_account = AccountSharedData::new(1, 0, &to); process_instruction(
1471 &bincode::serialize(&SystemInstruction::Transfer { lamports: 50 }).unwrap(),
1472 vec![(from, from_account), (to, to_account)],
1473 vec![
1474 AccountMeta {
1475 pubkey: from,
1476 is_signer: true,
1477 is_writable: false,
1478 },
1479 AccountMeta {
1480 pubkey: to,
1481 is_signer: false,
1482 is_writable: false,
1483 },
1484 ],
1485 Err(InstructionError::InvalidArgument),
1486 );
1487 }
1488
1489 fn process_nonce_instruction(
1490 instruction: Instruction,
1491 expected_result: Result<(), InstructionError>,
1492 ) -> Vec<AccountSharedData> {
1493 let transaction_accounts = instruction
1494 .accounts
1495 .iter()
1496 .map(|meta| {
1497 #[allow(deprecated)]
1498 (
1499 meta.pubkey,
1500 if sysvar::recent_blockhashes::check_id(&meta.pubkey) {
1501 create_default_recent_blockhashes_account()
1502 } else if sysvar::rent::check_id(&meta.pubkey) {
1503 account::create_account_shared_data_for_test(&Rent::free())
1504 } else {
1505 AccountSharedData::new(0, 0, &Pubkey::new_unique())
1506 },
1507 )
1508 })
1509 .collect();
1510 process_instruction(
1511 &instruction.data,
1512 transaction_accounts,
1513 instruction.accounts,
1514 expected_result,
1515 )
1516 }
1517
1518 #[test]
1519 fn test_process_nonce_ix_no_acc_data_fail() {
1520 let none_address = Pubkey::new_unique();
1521 process_nonce_instruction(
1522 system_instruction::advance_nonce_account(&none_address, &none_address),
1523 Err(InstructionError::InvalidAccountData),
1524 );
1525 }
1526
1527 #[test]
1528 fn test_process_nonce_ix_no_keyed_accs_fail() {
1529 process_instruction(
1530 &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
1531 Vec::new(),
1532 Vec::new(),
1533 Err(InstructionError::NotEnoughAccountKeys),
1534 );
1535 }
1536
1537 #[test]
1538 fn test_process_nonce_ix_only_nonce_acc_fail() {
1539 let pubkey = Pubkey::new_unique();
1540 process_instruction(
1541 &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
1542 vec![(pubkey, create_default_account())],
1543 vec![AccountMeta {
1544 pubkey,
1545 is_signer: true,
1546 is_writable: true,
1547 }],
1548 Err(InstructionError::NotEnoughAccountKeys),
1549 );
1550 }
1551
1552 #[test]
1553 fn test_process_nonce_ix_ok() {
1554 let nonce_address = Pubkey::new_unique();
1555 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1556 #[allow(deprecated)]
1557 let blockhash_id = sysvar::recent_blockhashes::id();
1558 let accounts = process_instruction(
1559 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1560 vec![
1561 (nonce_address, nonce_account),
1562 (blockhash_id, create_default_recent_blockhashes_account()),
1563 (sysvar::rent::id(), create_default_rent_account()),
1564 ],
1565 vec![
1566 AccountMeta {
1567 pubkey: nonce_address,
1568 is_signer: true,
1569 is_writable: true,
1570 },
1571 AccountMeta {
1572 pubkey: blockhash_id,
1573 is_signer: false,
1574 is_writable: false,
1575 },
1576 AccountMeta {
1577 pubkey: sysvar::rent::id(),
1578 is_signer: false,
1579 is_writable: false,
1580 },
1581 ],
1582 Ok(()),
1583 );
1584 let blockhash = hash(&serialize(&0).unwrap());
1585 #[allow(deprecated)]
1586 let new_recent_blockhashes_account = create_recent_blockhashes_account_for_test(vec![
1587 IterItem(0u64, &blockhash, 0);
1588 sysvar::recent_blockhashes::MAX_ENTRIES
1589 ]);
1590 mock_process_instruction(
1591 &system_program::id(),
1592 Vec::new(),
1593 &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
1594 vec![
1595 (nonce_address, accounts[0].clone()),
1596 (blockhash_id, new_recent_blockhashes_account),
1597 ],
1598 vec![
1599 AccountMeta {
1600 pubkey: nonce_address,
1601 is_signer: true,
1602 is_writable: true,
1603 },
1604 AccountMeta {
1605 pubkey: blockhash_id,
1606 is_signer: false,
1607 is_writable: false,
1608 },
1609 ],
1610 Ok(()),
1611 Entrypoint::vm,
1612 |invoke_context: &mut InvokeContext| {
1613 invoke_context.environment_config.blockhash = hash(&serialize(&0).unwrap());
1614 },
1615 |_invoke_context| {},
1616 );
1617 }
1618
1619 #[test]
1620 fn test_process_withdraw_ix_no_acc_data_fail() {
1621 let nonce_address = Pubkey::new_unique();
1622 process_nonce_instruction(
1623 system_instruction::withdraw_nonce_account(
1624 &nonce_address,
1625 &Pubkey::new_unique(),
1626 &nonce_address,
1627 1,
1628 ),
1629 Err(InstructionError::InvalidAccountData),
1630 );
1631 }
1632
1633 #[test]
1634 fn test_process_withdraw_ix_no_keyed_accs_fail() {
1635 process_instruction(
1636 &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
1637 Vec::new(),
1638 Vec::new(),
1639 Err(InstructionError::NotEnoughAccountKeys),
1640 );
1641 }
1642
1643 #[test]
1644 fn test_process_withdraw_ix_only_nonce_acc_fail() {
1645 let nonce_address = Pubkey::new_unique();
1646 process_instruction(
1647 &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
1648 vec![(nonce_address, create_default_account())],
1649 vec![AccountMeta {
1650 pubkey: nonce_address,
1651 is_signer: true,
1652 is_writable: true,
1653 }],
1654 Err(InstructionError::NotEnoughAccountKeys),
1655 );
1656 }
1657
1658 #[test]
1659 fn test_process_withdraw_ix_ok() {
1660 let nonce_address = Pubkey::new_unique();
1661 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1662 let pubkey = Pubkey::new_unique();
1663 #[allow(deprecated)]
1664 let blockhash_id = sysvar::recent_blockhashes::id();
1665 process_instruction(
1666 &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
1667 vec![
1668 (nonce_address, nonce_account),
1669 (pubkey, create_default_account()),
1670 (blockhash_id, create_default_recent_blockhashes_account()),
1671 (sysvar::rent::id(), create_default_rent_account()),
1672 ],
1673 vec![
1674 AccountMeta {
1675 pubkey: nonce_address,
1676 is_signer: true,
1677 is_writable: true,
1678 },
1679 AccountMeta {
1680 pubkey,
1681 is_signer: true,
1682 is_writable: true,
1683 },
1684 AccountMeta {
1685 pubkey: blockhash_id,
1686 is_signer: false,
1687 is_writable: false,
1688 },
1689 AccountMeta {
1690 pubkey: sysvar::rent::id(),
1691 is_signer: false,
1692 is_writable: false,
1693 },
1694 ],
1695 Ok(()),
1696 );
1697 }
1698
1699 #[test]
1700 fn test_process_initialize_ix_no_keyed_accs_fail() {
1701 process_instruction(
1702 &serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
1703 Vec::new(),
1704 Vec::new(),
1705 Err(InstructionError::NotEnoughAccountKeys),
1706 );
1707 }
1708
1709 #[test]
1710 fn test_process_initialize_ix_only_nonce_acc_fail() {
1711 let nonce_address = Pubkey::new_unique();
1712 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1713 process_instruction(
1714 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1715 vec![(nonce_address, nonce_account)],
1716 vec![AccountMeta {
1717 pubkey: nonce_address,
1718 is_signer: true,
1719 is_writable: true,
1720 }],
1721 Err(InstructionError::NotEnoughAccountKeys),
1722 );
1723 }
1724
1725 #[test]
1726 fn test_process_initialize_ix_ok() {
1727 let nonce_address = Pubkey::new_unique();
1728 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1729 #[allow(deprecated)]
1730 let blockhash_id = sysvar::recent_blockhashes::id();
1731 process_instruction(
1732 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1733 vec![
1734 (nonce_address, nonce_account),
1735 (blockhash_id, create_default_recent_blockhashes_account()),
1736 (sysvar::rent::id(), create_default_rent_account()),
1737 ],
1738 vec![
1739 AccountMeta {
1740 pubkey: nonce_address,
1741 is_signer: true,
1742 is_writable: true,
1743 },
1744 AccountMeta {
1745 pubkey: blockhash_id,
1746 is_signer: false,
1747 is_writable: false,
1748 },
1749 AccountMeta {
1750 pubkey: sysvar::rent::id(),
1751 is_signer: false,
1752 is_writable: false,
1753 },
1754 ],
1755 Ok(()),
1756 );
1757 }
1758
1759 #[test]
1760 fn test_process_authorize_ix_ok() {
1761 let nonce_address = Pubkey::new_unique();
1762 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1763 #[allow(deprecated)]
1764 let blockhash_id = sysvar::recent_blockhashes::id();
1765 let accounts = process_instruction(
1766 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1767 vec![
1768 (nonce_address, nonce_account),
1769 (blockhash_id, create_default_recent_blockhashes_account()),
1770 (sysvar::rent::id(), create_default_rent_account()),
1771 ],
1772 vec![
1773 AccountMeta {
1774 pubkey: nonce_address,
1775 is_signer: true,
1776 is_writable: true,
1777 },
1778 AccountMeta {
1779 pubkey: blockhash_id,
1780 is_signer: false,
1781 is_writable: false,
1782 },
1783 AccountMeta {
1784 pubkey: sysvar::rent::id(),
1785 is_signer: false,
1786 is_writable: false,
1787 },
1788 ],
1789 Ok(()),
1790 );
1791 process_instruction(
1792 &serialize(&SystemInstruction::AuthorizeNonceAccount(nonce_address)).unwrap(),
1793 vec![(nonce_address, accounts[0].clone())],
1794 vec![AccountMeta {
1795 pubkey: nonce_address,
1796 is_signer: true,
1797 is_writable: true,
1798 }],
1799 Ok(()),
1800 );
1801 }
1802
1803 #[test]
1804 fn test_process_authorize_bad_account_data_fail() {
1805 let nonce_address = Pubkey::new_unique();
1806 process_nonce_instruction(
1807 system_instruction::authorize_nonce_account(
1808 &nonce_address,
1809 &Pubkey::new_unique(),
1810 &nonce_address,
1811 ),
1812 Err(InstructionError::InvalidAccountData),
1813 );
1814 }
1815
1816 #[test]
1817 fn test_nonce_initialize_with_empty_recent_blockhashes_fail() {
1818 let nonce_address = Pubkey::new_unique();
1819 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1820 #[allow(deprecated)]
1821 let blockhash_id = sysvar::recent_blockhashes::id();
1822 #[allow(deprecated)]
1823 let new_recent_blockhashes_account = create_recent_blockhashes_account_for_test(vec![]);
1824 process_instruction(
1825 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1826 vec![
1827 (nonce_address, nonce_account),
1828 (blockhash_id, new_recent_blockhashes_account),
1829 (sysvar::rent::id(), create_default_rent_account()),
1830 ],
1831 vec![
1832 AccountMeta {
1833 pubkey: nonce_address,
1834 is_signer: true,
1835 is_writable: true,
1836 },
1837 AccountMeta {
1838 pubkey: blockhash_id,
1839 is_signer: false,
1840 is_writable: false,
1841 },
1842 AccountMeta {
1843 pubkey: sysvar::rent::id(),
1844 is_signer: false,
1845 is_writable: false,
1846 },
1847 ],
1848 Err(SystemError::NonceNoRecentBlockhashes.into()),
1849 );
1850 }
1851
1852 #[test]
1853 fn test_nonce_advance_with_empty_recent_blockhashes_fail() {
1854 let nonce_address = Pubkey::new_unique();
1855 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1856 #[allow(deprecated)]
1857 let blockhash_id = sysvar::recent_blockhashes::id();
1858 let accounts = process_instruction(
1859 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1860 vec![
1861 (nonce_address, nonce_account),
1862 (blockhash_id, create_default_recent_blockhashes_account()),
1863 (sysvar::rent::id(), create_default_rent_account()),
1864 ],
1865 vec![
1866 AccountMeta {
1867 pubkey: nonce_address,
1868 is_signer: true,
1869 is_writable: true,
1870 },
1871 AccountMeta {
1872 pubkey: blockhash_id,
1873 is_signer: false,
1874 is_writable: false,
1875 },
1876 AccountMeta {
1877 pubkey: sysvar::rent::id(),
1878 is_signer: false,
1879 is_writable: false,
1880 },
1881 ],
1882 Ok(()),
1883 );
1884 #[allow(deprecated)]
1885 let new_recent_blockhashes_account = create_recent_blockhashes_account_for_test(vec![]);
1886 mock_process_instruction(
1887 &system_program::id(),
1888 Vec::new(),
1889 &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
1890 vec![
1891 (nonce_address, accounts[0].clone()),
1892 (blockhash_id, new_recent_blockhashes_account),
1893 ],
1894 vec![
1895 AccountMeta {
1896 pubkey: nonce_address,
1897 is_signer: true,
1898 is_writable: true,
1899 },
1900 AccountMeta {
1901 pubkey: blockhash_id,
1902 is_signer: false,
1903 is_writable: false,
1904 },
1905 ],
1906 Err(SystemError::NonceNoRecentBlockhashes.into()),
1907 Entrypoint::vm,
1908 |invoke_context: &mut InvokeContext| {
1909 invoke_context.environment_config.blockhash = hash(&serialize(&0).unwrap());
1910 },
1911 |_invoke_context| {},
1912 );
1913 }
1914
1915 #[test]
1916 fn test_nonce_account_upgrade_check_owner() {
1917 let nonce_address = Pubkey::new_unique();
1918 let versions = NonceVersions::Legacy(Box::new(NonceState::Uninitialized));
1919 let nonce_account = AccountSharedData::new_data(
1920 1_000_000, &versions, &Pubkey::new_unique(), )
1924 .unwrap();
1925 let accounts = process_instruction(
1926 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
1927 vec![(nonce_address, nonce_account.clone())],
1928 vec![AccountMeta {
1929 pubkey: nonce_address,
1930 is_signer: false,
1931 is_writable: true,
1932 }],
1933 Err(InstructionError::InvalidAccountOwner),
1934 );
1935 assert_eq!(accounts.len(), 1);
1936 assert_eq!(accounts[0], nonce_account);
1937 }
1938
1939 fn new_nonce_account(versions: NonceVersions) -> AccountSharedData {
1940 let nonce_account = AccountSharedData::new_data(
1941 1_000_000, &versions, &system_program::id(), )
1945 .unwrap();
1946 assert_eq!(
1947 nonce_account.deserialize_data::<NonceVersions>().unwrap(),
1948 versions
1949 );
1950 nonce_account
1951 }
1952
1953 #[test]
1954 fn test_nonce_account_upgrade() {
1955 let nonce_address = Pubkey::new_unique();
1956 let versions = NonceVersions::Legacy(Box::new(NonceState::Uninitialized));
1957 let nonce_account = new_nonce_account(versions);
1958 let accounts = process_instruction(
1959 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
1960 vec![(nonce_address, nonce_account.clone())],
1961 vec![AccountMeta {
1962 pubkey: nonce_address,
1963 is_signer: false,
1964 is_writable: true,
1965 }],
1966 Err(InstructionError::InvalidArgument),
1967 );
1968 assert_eq!(accounts.len(), 1);
1969 assert_eq!(accounts[0], nonce_account);
1970 let versions = NonceVersions::Current(Box::new(NonceState::Uninitialized));
1971 let nonce_account = new_nonce_account(versions);
1972 let accounts = process_instruction(
1973 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
1974 vec![(nonce_address, nonce_account.clone())],
1975 vec![AccountMeta {
1976 pubkey: nonce_address,
1977 is_signer: false,
1978 is_writable: true,
1979 }],
1980 Err(InstructionError::InvalidArgument),
1981 );
1982 assert_eq!(accounts.len(), 1);
1983 assert_eq!(accounts[0], nonce_account);
1984 let blockhash = Hash::from([171; 32]);
1985 let durable_nonce = DurableNonce::from_blockhash(&blockhash);
1986 let data = NonceData {
1987 authority: Pubkey::new_unique(),
1988 durable_nonce,
1989 fee_calculator: FeeCalculator {
1990 lamports_per_signature: 2718,
1991 },
1992 };
1993 let versions = NonceVersions::Legacy(Box::new(NonceState::Initialized(data.clone())));
1994 let nonce_account = new_nonce_account(versions);
1995 let accounts = process_instruction(
1996 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
1997 vec![(nonce_address, nonce_account.clone())],
1998 vec![AccountMeta {
1999 pubkey: nonce_address,
2000 is_signer: false,
2001 is_writable: false, }],
2003 Err(InstructionError::InvalidArgument),
2004 );
2005 assert_eq!(accounts.len(), 1);
2006 assert_eq!(accounts[0], nonce_account);
2007 let mut accounts = process_instruction(
2008 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
2009 vec![(nonce_address, nonce_account)],
2010 vec![AccountMeta {
2011 pubkey: nonce_address,
2012 is_signer: false,
2013 is_writable: true,
2014 }],
2015 Ok(()),
2016 );
2017 assert_eq!(accounts.len(), 1);
2018 let nonce_account = accounts.remove(0);
2019 let durable_nonce = DurableNonce::from_blockhash(durable_nonce.as_hash());
2020 assert_ne!(data.durable_nonce, durable_nonce);
2021 let data = NonceData {
2022 durable_nonce,
2023 ..data
2024 };
2025 let upgraded_nonce_account =
2026 NonceVersions::Current(Box::new(NonceState::Initialized(data)));
2027 assert_eq!(
2028 nonce_account.deserialize_data::<NonceVersions>().unwrap(),
2029 upgraded_nonce_account
2030 );
2031 let accounts = process_instruction(
2032 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
2033 vec![(nonce_address, nonce_account)],
2034 vec![AccountMeta {
2035 pubkey: nonce_address,
2036 is_signer: false,
2037 is_writable: true,
2038 }],
2039 Err(InstructionError::InvalidArgument),
2040 );
2041 assert_eq!(accounts.len(), 1);
2042 assert_eq!(
2043 accounts[0].deserialize_data::<NonceVersions>().unwrap(),
2044 upgraded_nonce_account
2045 );
2046 }
2047
2048 #[test]
2049 fn test_assign_native_loader_and_transfer() {
2050 for size in [0, 10] {
2051 let pubkey = Pubkey::new_unique();
2052 let account = AccountSharedData::new(100, size, &system_program::id());
2053 let accounts = process_instruction(
2054 &bincode::serialize(&SystemInstruction::Assign {
2055 owner: solana_sdk_ids::native_loader::id(),
2056 })
2057 .unwrap(),
2058 vec![(pubkey, account.clone())],
2059 vec![AccountMeta {
2060 pubkey,
2061 is_signer: true,
2062 is_writable: true,
2063 }],
2064 Ok(()),
2065 );
2066 assert_eq!(accounts[0].owner(), &solana_sdk_ids::native_loader::id());
2067 assert_eq!(accounts[0].lamports(), 100);
2068
2069 let pubkey2 = Pubkey::new_unique();
2070 let accounts = process_instruction(
2071 &bincode::serialize(&SystemInstruction::Transfer { lamports: 50 }).unwrap(),
2072 vec![
2073 (
2074 pubkey2,
2075 AccountSharedData::new(100, 0, &system_program::id()),
2076 ),
2077 (pubkey, accounts[0].clone()),
2078 ],
2079 vec![
2080 AccountMeta {
2081 pubkey: pubkey2,
2082 is_signer: true,
2083 is_writable: true,
2084 },
2085 AccountMeta {
2086 pubkey,
2087 is_signer: false,
2088 is_writable: true,
2089 },
2090 ],
2091 Ok(()),
2092 );
2093 assert_eq!(accounts[1].owner(), &solana_sdk_ids::native_loader::id());
2094 assert_eq!(accounts[1].lamports(), 150);
2095 }
2096 }
2097}