miraland_system_program/
system_processor.rs

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// represents an address that may or may not have been generated
26//  from a seed
27#[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            // re-derive the address, must match the supplied address
49            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 it looks like the `to` account is already in use, bail
87    //   (note that the id check is also enforced by message_processor)
88    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    // no work to do, just return
120    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    // if it looks like the `to` account is already in use, bail
158    {
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        // create account with zero lamports transferred
783        let new_owner = Pubkey::from([9; 32]);
784        let from = Pubkey::new_unique();
785        let from_account = AccountSharedData::new(100, 0, &Pubkey::new_unique()); // not from system account
786        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        // Attempt to create account with more lamports than from_account has
820        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        // Trying to request more data length than permitted will result in failure
870        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        // Trying to request equal or less data length than permitted will be successful
883        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        // Attempt to create system account in account already owned by another program
906        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        // Attempt to create system account in account that already has data
935        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        // Attempt to create an account that already has lamports
963        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        // Attempt to create an account without signing the transfer
994        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        // Haven't signed from account
1001        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        // Haven't signed to account
1028        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        // Don't support unsigned creation with zero lamports (ephemeral account)
1052        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        // Attempt to create system account in account already owned by another program
1080        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        // fail to create a sysvar::id() owned account
1086        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        // Attempt to create system account in account with populated data
1113        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        // owner does not change, no signature needed
1189        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        // owner does change, signature needed
1204        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        // assign to sysvar instead of system_program
1227        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        // Attempt to assign with no accounts
1245        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        // Attempt to transfer with no destination
1257        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); // account owner should not matter
1279        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        // Success case
1294        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        // Attempt to move more lamports than from_account has
1304        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        // test signed transfer of zero
1314        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        // test unsigned transfer of zero
1324        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])); // account owner should not matter
1349        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); // account owner should not matter
1355        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        // Success case
1376        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        // Attempt to move more lamports than from_account has
1391        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        // Test unsigned transfer of zero
1406        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); // account owner should not matter
1439
1440        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,             // lamports
1942            &versions,             // state
1943            &Pubkey::new_unique(), // owner
1944        )
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,             // lamports
1963            &versions,             // state
1964            &system_program::id(), // owner
1965        )
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, // Should fail!
2023            }],
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}