Skip to main content

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