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