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