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, error::InstructionError},
588        solana_nonce::{
589            self as nonce,
590            state::{Data as NonceData, DurableNonce, State as NonceState},
591            versions::Versions as NonceVersions,
592        },
593        solana_nonce_account as nonce_account,
594        solana_sha256_hasher::hash,
595        solana_system_interface::{instruction as system_instruction, program as system_program},
596        solana_sysvar::{
597            self as sysvar,
598            recent_blockhashes::{IntoIterSorted, IterItem, MAX_ENTRIES, RecentBlockhashes},
599            rent::Rent,
600        },
601        solana_sysvar_id::SysvarId,
602    };
603
604    fn create_sysvar_account<T>(value: &T) -> AccountSharedData
605    where
606        T: wincode::Serialize<Src = T> + SysvarId,
607    {
608        let serialized_len = wincode::serialized_size(value).unwrap() as usize;
609        let canonical_data_len = match T::id() {
610            sysvar::recent_blockhashes::ID => sysvar::recent_blockhashes::SIZE,
611            sysvar::rent::ID => solana_rent::SIZE,
612            id => panic!("unsupported sysvar: {id}"),
613        };
614        let required_data_len = canonical_data_len.max(serialized_len);
615        let mut account =
616            AccountSharedData::new(1, required_data_len, &solana_sdk_ids::sysvar::id());
617        wincode::serialize_into(account.data_as_mut_slice(), value).unwrap();
618        account
619    }
620
621    impl From<Pubkey> for Address {
622        fn from(address: Pubkey) -> Self {
623            Self {
624                address,
625                base: None,
626            }
627        }
628    }
629
630    fn process_instruction(
631        instruction_data: &[u8],
632        transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
633        instruction_accounts: Vec<AccountMeta>,
634        expected_result: Result<(), InstructionError>,
635    ) -> Vec<AccountSharedData> {
636        mock_process_instruction(
637            &system_program::id(),
638            instruction_data,
639            transaction_accounts,
640            instruction_accounts,
641            expected_result,
642            Entrypoint::register,
643            |_invoke_context| {},
644            |_invoke_context| {},
645        )
646    }
647
648    fn create_default_account() -> AccountSharedData {
649        AccountSharedData::new(0, 0, &Pubkey::new_unique())
650    }
651    #[allow(deprecated)]
652    fn create_recent_blockhashes_account_for_test<'a, I>(
653        recent_blockhash_iter: I,
654    ) -> AccountSharedData
655    where
656        I: IntoIterator<Item = IterItem<'a>>,
657    {
658        let sorted = BinaryHeap::from_iter(recent_blockhash_iter);
659        let sorted_iter = IntoIterSorted::new(sorted);
660        let recent_blockhash_iter = sorted_iter.take(MAX_ENTRIES);
661        let recent_blockhashes: RecentBlockhashes = recent_blockhash_iter.collect();
662        create_sysvar_account(&recent_blockhashes)
663    }
664    fn create_default_recent_blockhashes_account() -> AccountSharedData {
665        #[allow(deprecated)]
666        create_recent_blockhashes_account_for_test(vec![
667            IterItem(0u64, &Hash::default(), 0);
668            sysvar::recent_blockhashes::MAX_ENTRIES
669        ])
670    }
671    fn create_default_rent_account() -> AccountSharedData {
672        create_sysvar_account(&Rent::free())
673    }
674
675    #[test]
676    fn test_create_account() {
677        let new_owner = Pubkey::from([9; 32]);
678        let from = Pubkey::new_unique();
679        let to = Pubkey::new_unique();
680        let from_account = AccountSharedData::new(100, 0, &system_program::id());
681        let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
682
683        let accounts = process_instruction(
684            &bincode::serialize(&SystemInstruction::CreateAccount {
685                lamports: 50,
686                space: 2,
687                owner: new_owner,
688            })
689            .unwrap(),
690            vec![(from, from_account), (to, to_account)],
691            vec![
692                AccountMeta {
693                    pubkey: from,
694                    is_signer: true,
695                    is_writable: true,
696                },
697                AccountMeta {
698                    pubkey: to,
699                    is_signer: true,
700                    is_writable: true,
701                },
702            ],
703            Ok(()),
704        );
705        assert_eq!(accounts[0].lamports(), 50);
706        assert_eq!(accounts[1].lamports(), 50);
707        assert_eq!(accounts[1].owner(), &new_owner);
708        assert_eq!(accounts[1].data(), &[0, 0]);
709    }
710
711    #[test]
712    fn test_create_account_with_seed() {
713        let new_owner = Pubkey::from([9; 32]);
714        let from = Pubkey::new_unique();
715        let seed = "shiny pepper";
716        let to = Pubkey::create_with_seed(&from, seed, &new_owner).unwrap();
717        let from_account = AccountSharedData::new(100, 0, &system_program::id());
718        let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
719
720        let accounts = process_instruction(
721            &bincode::serialize(&SystemInstruction::CreateAccountWithSeed {
722                base: from,
723                seed: seed.to_string(),
724                lamports: 50,
725                space: 2,
726                owner: new_owner,
727            })
728            .unwrap(),
729            vec![(from, from_account), (to, to_account)],
730            vec![
731                AccountMeta {
732                    pubkey: from,
733                    is_signer: true,
734                    is_writable: true,
735                },
736                AccountMeta {
737                    pubkey: to,
738                    is_signer: true,
739                    is_writable: true,
740                },
741            ],
742            Ok(()),
743        );
744        assert_eq!(accounts[0].lamports(), 50);
745        assert_eq!(accounts[1].lamports(), 50);
746        assert_eq!(accounts[1].owner(), &new_owner);
747        assert_eq!(accounts[1].data(), &[0, 0]);
748    }
749
750    #[test]
751    fn test_create_account_with_seed_separate_base_account() {
752        let new_owner = Pubkey::from([9; 32]);
753        let from = Pubkey::new_unique();
754        let base = Pubkey::new_unique();
755        let seed = "shiny pepper";
756        let to = Pubkey::create_with_seed(&base, seed, &new_owner).unwrap();
757        let from_account = AccountSharedData::new(100, 0, &system_program::id());
758        let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
759        let base_account = AccountSharedData::new(0, 0, &Pubkey::default());
760
761        let accounts = process_instruction(
762            &bincode::serialize(&SystemInstruction::CreateAccountWithSeed {
763                base,
764                seed: seed.to_string(),
765                lamports: 50,
766                space: 2,
767                owner: new_owner,
768            })
769            .unwrap(),
770            vec![(from, from_account), (to, to_account), (base, base_account)],
771            vec![
772                AccountMeta {
773                    pubkey: from,
774                    is_signer: true,
775                    is_writable: true,
776                },
777                AccountMeta {
778                    pubkey: to,
779                    is_signer: false,
780                    is_writable: true,
781                },
782                AccountMeta {
783                    pubkey: base,
784                    is_signer: true,
785                    is_writable: false,
786                },
787            ],
788            Ok(()),
789        );
790        assert_eq!(accounts[0].lamports(), 50);
791        assert_eq!(accounts[1].lamports(), 50);
792        assert_eq!(accounts[1].owner(), &new_owner);
793        assert_eq!(accounts[1].data(), &[0, 0]);
794    }
795
796    #[test]
797    fn test_address_create_with_seed_mismatch() {
798        with_mock_invoke_context!(invoke_context, transaction_context, Vec::new());
799        let from = Pubkey::new_unique();
800        let seed = "dull boy";
801        let to = Pubkey::new_unique();
802        let owner = Pubkey::new_unique();
803
804        assert_eq!(
805            Address::create(&to, Some((&from, seed, &owner)), &invoke_context),
806            Err(SystemError::AddressWithSeedMismatch.into())
807        );
808    }
809
810    #[test]
811    fn test_create_account_with_seed_missing_sig() {
812        let new_owner = Pubkey::from([9; 32]);
813        let from = Pubkey::new_unique();
814        let seed = "dull boy";
815        let to = Pubkey::create_with_seed(&from, seed, &new_owner).unwrap();
816        let from_account = AccountSharedData::new(100, 0, &system_program::id());
817        let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
818
819        let accounts = process_instruction(
820            &bincode::serialize(&SystemInstruction::CreateAccount {
821                lamports: 50,
822                space: 2,
823                owner: new_owner,
824            })
825            .unwrap(),
826            vec![(from, from_account), (to, to_account)],
827            vec![
828                AccountMeta {
829                    pubkey: from,
830                    is_signer: true,
831                    is_writable: false,
832                },
833                AccountMeta {
834                    pubkey: to,
835                    is_signer: false,
836                    is_writable: false,
837                },
838            ],
839            Err(InstructionError::MissingRequiredSignature),
840        );
841        assert_eq!(accounts[0].lamports(), 100);
842        assert_eq!(accounts[1], AccountSharedData::default());
843    }
844
845    #[test]
846    fn test_create_with_zero_lamports() {
847        // create account with zero lamports transferred
848        let new_owner = Pubkey::from([9; 32]);
849        let from = Pubkey::new_unique();
850        let from_account = AccountSharedData::new(100, 0, &Pubkey::new_unique()); // not from system account
851        let to = Pubkey::new_unique();
852        let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
853
854        let accounts = process_instruction(
855            &bincode::serialize(&SystemInstruction::CreateAccount {
856                lamports: 0,
857                space: 2,
858                owner: new_owner,
859            })
860            .unwrap(),
861            vec![(from, from_account), (to, to_account)],
862            vec![
863                AccountMeta {
864                    pubkey: from,
865                    is_signer: true,
866                    is_writable: true,
867                },
868                AccountMeta {
869                    pubkey: to,
870                    is_signer: true,
871                    is_writable: true,
872                },
873            ],
874            Ok(()),
875        );
876        assert_eq!(accounts[0].lamports(), 100);
877        assert_eq!(accounts[1].lamports(), 0);
878        assert_eq!(*accounts[1].owner(), new_owner);
879        assert_eq!(accounts[1].data(), &[0, 0]);
880    }
881
882    #[test]
883    fn test_create_negative_lamports() {
884        // Attempt to create account with more lamports than from_account has
885        let new_owner = Pubkey::from([9; 32]);
886        let from = Pubkey::new_unique();
887        let from_account = AccountSharedData::new(100, 0, &Pubkey::new_unique());
888        let to = Pubkey::new_unique();
889        let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
890
891        process_instruction(
892            &bincode::serialize(&SystemInstruction::CreateAccount {
893                lamports: 150,
894                space: 2,
895                owner: new_owner,
896            })
897            .unwrap(),
898            vec![(from, from_account), (to, to_account)],
899            vec![
900                AccountMeta {
901                    pubkey: from,
902                    is_signer: true,
903                    is_writable: true,
904                },
905                AccountMeta {
906                    pubkey: to,
907                    is_signer: true,
908                    is_writable: true,
909                },
910            ],
911            Err(SystemError::ResultWithNegativeLamports.into()),
912        );
913    }
914
915    #[test]
916    fn test_request_more_than_allowed_data_length() {
917        let from = Pubkey::new_unique();
918        let from_account = AccountSharedData::new(100, 0, &system_program::id());
919        let to = Pubkey::new_unique();
920        let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
921        let instruction_accounts = vec![
922            AccountMeta {
923                pubkey: from,
924                is_signer: true,
925                is_writable: true,
926            },
927            AccountMeta {
928                pubkey: to,
929                is_signer: true,
930                is_writable: true,
931            },
932        ];
933
934        // Trying to request more data length than permitted will result in failure
935        process_instruction(
936            &bincode::serialize(&SystemInstruction::CreateAccount {
937                lamports: 50,
938                space: MAX_PERMITTED_DATA_LENGTH + 1,
939                owner: system_program::id(),
940            })
941            .unwrap(),
942            vec![(from, from_account.clone()), (to, to_account.clone())],
943            instruction_accounts.clone(),
944            Err(SystemError::InvalidAccountDataLength.into()),
945        );
946
947        // Trying to request equal or less data length than permitted will be successful
948        let accounts = process_instruction(
949            &bincode::serialize(&SystemInstruction::CreateAccount {
950                lamports: 50,
951                space: MAX_PERMITTED_DATA_LENGTH,
952                owner: system_program::id(),
953            })
954            .unwrap(),
955            vec![(from, from_account), (to, to_account)],
956            instruction_accounts,
957            Ok(()),
958        );
959        assert_eq!(accounts[1].lamports(), 50);
960        assert_eq!(accounts[1].data().len() as u64, MAX_PERMITTED_DATA_LENGTH);
961    }
962
963    #[test]
964    fn test_create_already_in_use() {
965        let new_owner = Pubkey::from([9; 32]);
966        let from = Pubkey::new_unique();
967        let from_account = AccountSharedData::new(100, 0, &system_program::id());
968        let owned_key = Pubkey::new_unique();
969
970        // Attempt to create system account in account already owned by another program
971        let original_program_owner = Pubkey::from([5; 32]);
972        let owned_account = AccountSharedData::new(0, 0, &original_program_owner);
973        let unchanged_account = owned_account.clone();
974        let accounts = process_instruction(
975            &bincode::serialize(&SystemInstruction::CreateAccount {
976                lamports: 50,
977                space: 2,
978                owner: new_owner,
979            })
980            .unwrap(),
981            vec![(from, from_account.clone()), (owned_key, owned_account)],
982            vec![
983                AccountMeta {
984                    pubkey: from,
985                    is_signer: true,
986                    is_writable: false,
987                },
988                AccountMeta {
989                    pubkey: owned_key,
990                    is_signer: true,
991                    is_writable: false,
992                },
993            ],
994            Err(SystemError::AccountAlreadyInUse.into()),
995        );
996        assert_eq!(accounts[0].lamports(), 100);
997        assert_eq!(accounts[1], unchanged_account);
998
999        // Attempt to create system account in account that already has data
1000        let owned_account = AccountSharedData::new(0, 1, &Pubkey::default());
1001        let unchanged_account = owned_account.clone();
1002        let accounts = process_instruction(
1003            &bincode::serialize(&SystemInstruction::CreateAccount {
1004                lamports: 50,
1005                space: 2,
1006                owner: new_owner,
1007            })
1008            .unwrap(),
1009            vec![(from, from_account.clone()), (owned_key, owned_account)],
1010            vec![
1011                AccountMeta {
1012                    pubkey: from,
1013                    is_signer: true,
1014                    is_writable: false,
1015                },
1016                AccountMeta {
1017                    pubkey: owned_key,
1018                    is_signer: true,
1019                    is_writable: false,
1020                },
1021            ],
1022            Err(SystemError::AccountAlreadyInUse.into()),
1023        );
1024        assert_eq!(accounts[0].lamports(), 100);
1025        assert_eq!(accounts[1], unchanged_account);
1026
1027        // Attempt to create an account that already has lamports
1028        let owned_account = AccountSharedData::new(1, 0, &Pubkey::default());
1029        let unchanged_account = owned_account.clone();
1030        let accounts = process_instruction(
1031            &bincode::serialize(&SystemInstruction::CreateAccount {
1032                lamports: 50,
1033                space: 2,
1034                owner: new_owner,
1035            })
1036            .unwrap(),
1037            vec![(from, from_account), (owned_key, owned_account)],
1038            vec![
1039                AccountMeta {
1040                    pubkey: from,
1041                    is_signer: true,
1042                    is_writable: false,
1043                },
1044                AccountMeta {
1045                    pubkey: owned_key,
1046                    is_signer: true,
1047                    is_writable: false,
1048                },
1049            ],
1050            Err(SystemError::AccountAlreadyInUse.into()),
1051        );
1052        assert_eq!(accounts[0].lamports(), 100);
1053        assert_eq!(accounts[1], unchanged_account);
1054    }
1055
1056    #[test]
1057    fn test_create_unsigned() {
1058        // Attempt to create an account without signing the transfer
1059        let new_owner = Pubkey::from([9; 32]);
1060        let from = Pubkey::new_unique();
1061        let from_account = AccountSharedData::new(100, 0, &system_program::id());
1062        let owned_key = Pubkey::new_unique();
1063        let owned_account = AccountSharedData::new(0, 0, &Pubkey::default());
1064
1065        // Haven't signed from account
1066        process_instruction(
1067            &bincode::serialize(&SystemInstruction::CreateAccount {
1068                lamports: 50,
1069                space: 2,
1070                owner: new_owner,
1071            })
1072            .unwrap(),
1073            vec![
1074                (from, from_account.clone()),
1075                (owned_key, owned_account.clone()),
1076            ],
1077            vec![
1078                AccountMeta {
1079                    pubkey: from,
1080                    is_signer: false,
1081                    is_writable: false,
1082                },
1083                AccountMeta {
1084                    pubkey: owned_key,
1085                    is_signer: false,
1086                    is_writable: false,
1087                },
1088            ],
1089            Err(InstructionError::MissingRequiredSignature),
1090        );
1091
1092        // Haven't signed to account
1093        process_instruction(
1094            &bincode::serialize(&SystemInstruction::CreateAccount {
1095                lamports: 50,
1096                space: 2,
1097                owner: new_owner,
1098            })
1099            .unwrap(),
1100            vec![(from, from_account.clone()), (owned_key, owned_account)],
1101            vec![
1102                AccountMeta {
1103                    pubkey: from,
1104                    is_signer: true,
1105                    is_writable: false,
1106                },
1107                AccountMeta {
1108                    pubkey: owned_key,
1109                    is_signer: false,
1110                    is_writable: false,
1111                },
1112            ],
1113            Err(InstructionError::MissingRequiredSignature),
1114        );
1115
1116        // Don't support unsigned creation with zero lamports (ephemeral account)
1117        let owned_account = AccountSharedData::new(0, 0, &Pubkey::default());
1118        process_instruction(
1119            &bincode::serialize(&SystemInstruction::CreateAccount {
1120                lamports: 50,
1121                space: 2,
1122                owner: new_owner,
1123            })
1124            .unwrap(),
1125            vec![(from, from_account), (owned_key, owned_account)],
1126            vec![
1127                AccountMeta {
1128                    pubkey: from,
1129                    is_signer: false,
1130                    is_writable: false,
1131                },
1132                AccountMeta {
1133                    pubkey: owned_key,
1134                    is_signer: false,
1135                    is_writable: false,
1136                },
1137            ],
1138            Err(InstructionError::MissingRequiredSignature),
1139        );
1140    }
1141
1142    #[test]
1143    fn test_create_sysvar_invalid_id_with_feature() {
1144        // Attempt to create system account in account already owned by another program
1145        let from = Pubkey::new_unique();
1146        let from_account = AccountSharedData::new(100, 0, &system_program::id());
1147        let to = Pubkey::new_unique();
1148        let to_account = AccountSharedData::new(0, 0, &system_program::id());
1149
1150        // fail to create a sysvar::id() owned account
1151        process_instruction(
1152            &bincode::serialize(&SystemInstruction::CreateAccount {
1153                lamports: 50,
1154                space: 2,
1155                owner: solana_sdk_ids::sysvar::id(),
1156            })
1157            .unwrap(),
1158            vec![(from, from_account), (to, to_account)],
1159            vec![
1160                AccountMeta {
1161                    pubkey: from,
1162                    is_signer: true,
1163                    is_writable: true,
1164                },
1165                AccountMeta {
1166                    pubkey: to,
1167                    is_signer: true,
1168                    is_writable: true,
1169                },
1170            ],
1171            Ok(()),
1172        );
1173    }
1174
1175    #[test]
1176    fn test_create_data_populated() {
1177        // Attempt to create system account in account with populated data
1178        let new_owner = Pubkey::from([9; 32]);
1179        let from = Pubkey::new_unique();
1180        let from_account = AccountSharedData::new(100, 0, &system_program::id());
1181        let populated_key = Pubkey::new_unique();
1182        let populated_account = AccountSharedData::from(Account {
1183            data: vec![0, 1, 2, 3],
1184            ..Account::default()
1185        });
1186
1187        process_instruction(
1188            &bincode::serialize(&SystemInstruction::CreateAccount {
1189                lamports: 50,
1190                space: 2,
1191                owner: new_owner,
1192            })
1193            .unwrap(),
1194            vec![(from, from_account), (populated_key, populated_account)],
1195            vec![
1196                AccountMeta {
1197                    pubkey: from,
1198                    is_signer: true,
1199                    is_writable: false,
1200                },
1201                AccountMeta {
1202                    pubkey: populated_key,
1203                    is_signer: true,
1204                    is_writable: false,
1205                },
1206            ],
1207            Err(SystemError::AccountAlreadyInUse.into()),
1208        );
1209    }
1210
1211    #[test]
1212    fn test_create_from_account_is_nonce_fail() {
1213        let nonce = Pubkey::new_unique();
1214        let nonce_account = AccountSharedData::new_data(
1215            42,
1216            &nonce::versions::Versions::new(nonce::state::State::Initialized(
1217                nonce::state::Data::default(),
1218            )),
1219            &system_program::id(),
1220        )
1221        .unwrap();
1222        let new = Pubkey::new_unique();
1223        let new_account = AccountSharedData::new(0, 0, &system_program::id());
1224
1225        process_instruction(
1226            &bincode::serialize(&SystemInstruction::CreateAccount {
1227                lamports: 42,
1228                space: 0,
1229                owner: Pubkey::new_unique(),
1230            })
1231            .unwrap(),
1232            vec![(nonce, nonce_account), (new, new_account)],
1233            vec![
1234                AccountMeta {
1235                    pubkey: nonce,
1236                    is_signer: true,
1237                    is_writable: false,
1238                },
1239                AccountMeta {
1240                    pubkey: new,
1241                    is_signer: true,
1242                    is_writable: true,
1243                },
1244            ],
1245            Err(InstructionError::InvalidArgument),
1246        );
1247    }
1248
1249    #[test]
1250    fn test_assign() {
1251        let new_owner = Pubkey::from([9; 32]);
1252        let pubkey = Pubkey::new_unique();
1253        let account = AccountSharedData::new(100, 0, &system_program::id());
1254
1255        // owner does not change, no signature needed
1256        process_instruction(
1257            &bincode::serialize(&SystemInstruction::Assign {
1258                owner: system_program::id(),
1259            })
1260            .unwrap(),
1261            vec![(pubkey, account.clone())],
1262            vec![AccountMeta {
1263                pubkey,
1264                is_signer: false,
1265                is_writable: true,
1266            }],
1267            Ok(()),
1268        );
1269
1270        // owner does change, signature needed
1271        process_instruction(
1272            &bincode::serialize(&SystemInstruction::Assign { owner: new_owner }).unwrap(),
1273            vec![(pubkey, account.clone())],
1274            vec![AccountMeta {
1275                pubkey,
1276                is_signer: false,
1277                is_writable: true,
1278            }],
1279            Err(InstructionError::MissingRequiredSignature),
1280        );
1281
1282        process_instruction(
1283            &bincode::serialize(&SystemInstruction::Assign { owner: new_owner }).unwrap(),
1284            vec![(pubkey, account.clone())],
1285            vec![AccountMeta {
1286                pubkey,
1287                is_signer: true,
1288                is_writable: true,
1289            }],
1290            Ok(()),
1291        );
1292
1293        // assign to sysvar instead of system_program
1294        process_instruction(
1295            &bincode::serialize(&SystemInstruction::Assign {
1296                owner: solana_sdk_ids::sysvar::id(),
1297            })
1298            .unwrap(),
1299            vec![(pubkey, account)],
1300            vec![AccountMeta {
1301                pubkey,
1302                is_signer: true,
1303                is_writable: true,
1304            }],
1305            Ok(()),
1306        );
1307    }
1308
1309    #[test]
1310    fn test_process_bogus_instruction() {
1311        // Attempt to assign with no accounts
1312        let instruction = SystemInstruction::Assign {
1313            owner: Pubkey::new_unique(),
1314        };
1315        let data = serialize(&instruction).unwrap();
1316        process_instruction(
1317            &data,
1318            Vec::new(),
1319            Vec::new(),
1320            Err(InstructionError::MissingAccount),
1321        );
1322
1323        // Attempt to transfer with no destination
1324        let from = Pubkey::new_unique();
1325        let from_account = AccountSharedData::new(100, 0, &system_program::id());
1326        let instruction = SystemInstruction::Transfer { lamports: 0 };
1327        let data = serialize(&instruction).unwrap();
1328        process_instruction(
1329            &data,
1330            vec![(from, from_account)],
1331            vec![AccountMeta {
1332                pubkey: from,
1333                is_signer: true,
1334                is_writable: false,
1335            }],
1336            Err(InstructionError::MissingAccount),
1337        );
1338    }
1339
1340    #[test]
1341    fn test_transfer_lamports() {
1342        let from = Pubkey::new_unique();
1343        let from_account = AccountSharedData::new(100, 0, &system_program::id());
1344        let to = Pubkey::from([3; 32]);
1345        let to_account = AccountSharedData::new(1, 0, &to); // account owner should not matter
1346        let transaction_accounts = vec![(from, from_account), (to, to_account)];
1347        let instruction_accounts = vec![
1348            AccountMeta {
1349                pubkey: from,
1350                is_signer: true,
1351                is_writable: true,
1352            },
1353            AccountMeta {
1354                pubkey: to,
1355                is_signer: false,
1356                is_writable: true,
1357            },
1358        ];
1359
1360        // Success case
1361        let accounts = process_instruction(
1362            &bincode::serialize(&SystemInstruction::Transfer { lamports: 50 }).unwrap(),
1363            transaction_accounts.clone(),
1364            instruction_accounts.clone(),
1365            Ok(()),
1366        );
1367        assert_eq!(accounts[0].lamports(), 50);
1368        assert_eq!(accounts[1].lamports(), 51);
1369
1370        // Attempt to move more lamports than from_account has
1371        let accounts = process_instruction(
1372            &bincode::serialize(&SystemInstruction::Transfer { lamports: 101 }).unwrap(),
1373            transaction_accounts.clone(),
1374            instruction_accounts.clone(),
1375            Err(SystemError::ResultWithNegativeLamports.into()),
1376        );
1377        assert_eq!(accounts[0].lamports(), 100);
1378        assert_eq!(accounts[1].lamports(), 1);
1379
1380        // test signed transfer of zero
1381        let accounts = process_instruction(
1382            &bincode::serialize(&SystemInstruction::Transfer { lamports: 0 }).unwrap(),
1383            transaction_accounts.clone(),
1384            instruction_accounts,
1385            Ok(()),
1386        );
1387        assert_eq!(accounts[0].lamports(), 100);
1388        assert_eq!(accounts[1].lamports(), 1);
1389
1390        // test unsigned transfer of zero
1391        let accounts = process_instruction(
1392            &bincode::serialize(&SystemInstruction::Transfer { lamports: 0 }).unwrap(),
1393            transaction_accounts,
1394            vec![
1395                AccountMeta {
1396                    pubkey: from,
1397                    is_signer: false,
1398                    is_writable: true,
1399                },
1400                AccountMeta {
1401                    pubkey: to,
1402                    is_signer: false,
1403                    is_writable: true,
1404                },
1405            ],
1406            Err(InstructionError::MissingRequiredSignature),
1407        );
1408        assert_eq!(accounts[0].lamports(), 100);
1409        assert_eq!(accounts[1].lamports(), 1);
1410    }
1411
1412    #[test]
1413    fn test_transfer_with_seed() {
1414        let base = Pubkey::new_unique();
1415        let base_account = AccountSharedData::new(100, 0, &Pubkey::from([2; 32])); // account owner should not matter
1416        let from_seed = "42".to_string();
1417        let from_owner = system_program::id();
1418        let from = Pubkey::create_with_seed(&base, from_seed.as_str(), &from_owner).unwrap();
1419        let from_account = AccountSharedData::new(100, 0, &system_program::id());
1420        let to = Pubkey::from([3; 32]);
1421        let to_account = AccountSharedData::new(1, 0, &to); // account owner should not matter
1422        let transaction_accounts =
1423            vec![(from, from_account), (base, base_account), (to, to_account)];
1424        let instruction_accounts = vec![
1425            AccountMeta {
1426                pubkey: from,
1427                is_signer: true,
1428                is_writable: true,
1429            },
1430            AccountMeta {
1431                pubkey: base,
1432                is_signer: true,
1433                is_writable: false,
1434            },
1435            AccountMeta {
1436                pubkey: to,
1437                is_signer: false,
1438                is_writable: true,
1439            },
1440        ];
1441
1442        // Success case
1443        let accounts = process_instruction(
1444            &bincode::serialize(&SystemInstruction::TransferWithSeed {
1445                lamports: 50,
1446                from_seed: from_seed.clone(),
1447                from_owner,
1448            })
1449            .unwrap(),
1450            transaction_accounts.clone(),
1451            instruction_accounts.clone(),
1452            Ok(()),
1453        );
1454        assert_eq!(accounts[0].lamports(), 50);
1455        assert_eq!(accounts[2].lamports(), 51);
1456
1457        // Attempt to move more lamports than from_account has
1458        let accounts = process_instruction(
1459            &bincode::serialize(&SystemInstruction::TransferWithSeed {
1460                lamports: 101,
1461                from_seed: from_seed.clone(),
1462                from_owner,
1463            })
1464            .unwrap(),
1465            transaction_accounts.clone(),
1466            instruction_accounts.clone(),
1467            Err(SystemError::ResultWithNegativeLamports.into()),
1468        );
1469        assert_eq!(accounts[0].lamports(), 100);
1470        assert_eq!(accounts[2].lamports(), 1);
1471
1472        // Test unsigned transfer of zero
1473        let accounts = process_instruction(
1474            &bincode::serialize(&SystemInstruction::TransferWithSeed {
1475                lamports: 0,
1476                from_seed,
1477                from_owner,
1478            })
1479            .unwrap(),
1480            transaction_accounts,
1481            instruction_accounts,
1482            Ok(()),
1483        );
1484        assert_eq!(accounts[0].lamports(), 100);
1485        assert_eq!(accounts[2].lamports(), 1);
1486    }
1487
1488    #[test]
1489    fn test_transfer_lamports_from_nonce_account_fail() {
1490        let from = Pubkey::new_unique();
1491        let from_account = AccountSharedData::new_data(
1492            100,
1493            &nonce::versions::Versions::new(nonce::state::State::Initialized(nonce::state::Data {
1494                authority: from,
1495                ..nonce::state::Data::default()
1496            })),
1497            &system_program::id(),
1498        )
1499        .unwrap();
1500        assert_eq!(
1501            get_system_account_kind(&from_account),
1502            Some(SystemAccountKind::Nonce)
1503        );
1504        let to = Pubkey::from([3; 32]);
1505        let to_account = AccountSharedData::new(1, 0, &to); // account owner should not matter
1506
1507        process_instruction(
1508            &bincode::serialize(&SystemInstruction::Transfer { lamports: 50 }).unwrap(),
1509            vec![(from, from_account), (to, to_account)],
1510            vec![
1511                AccountMeta {
1512                    pubkey: from,
1513                    is_signer: true,
1514                    is_writable: false,
1515                },
1516                AccountMeta {
1517                    pubkey: to,
1518                    is_signer: false,
1519                    is_writable: false,
1520                },
1521            ],
1522            Err(InstructionError::InvalidArgument),
1523        );
1524    }
1525
1526    fn process_nonce_instruction(
1527        instruction: Instruction,
1528        expected_result: Result<(), InstructionError>,
1529    ) -> Vec<AccountSharedData> {
1530        let transaction_accounts = instruction
1531            .accounts
1532            .iter()
1533            .map(|meta| {
1534                #[allow(deprecated)]
1535                (
1536                    meta.pubkey,
1537                    if sysvar::recent_blockhashes::check_id(&meta.pubkey) {
1538                        create_default_recent_blockhashes_account()
1539                    } else if sysvar::rent::check_id(&meta.pubkey) {
1540                        create_sysvar_account(&Rent::free())
1541                    } else {
1542                        AccountSharedData::new(0, 0, &Pubkey::new_unique())
1543                    },
1544                )
1545            })
1546            .collect();
1547        process_instruction(
1548            &instruction.data,
1549            transaction_accounts,
1550            instruction.accounts,
1551            expected_result,
1552        )
1553    }
1554
1555    #[test]
1556    fn test_process_nonce_ix_no_acc_data_fail() {
1557        let none_address = Pubkey::new_unique();
1558        process_nonce_instruction(
1559            system_instruction::advance_nonce_account(&none_address, &none_address),
1560            Err(InstructionError::InvalidAccountData),
1561        );
1562    }
1563
1564    #[test]
1565    fn test_process_nonce_ix_no_keyed_accs_fail() {
1566        process_instruction(
1567            &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
1568            Vec::new(),
1569            Vec::new(),
1570            Err(InstructionError::MissingAccount),
1571        );
1572    }
1573
1574    #[test]
1575    fn test_process_nonce_ix_only_nonce_acc_fail() {
1576        let pubkey = Pubkey::new_unique();
1577        process_instruction(
1578            &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
1579            vec![(pubkey, create_default_account())],
1580            vec![AccountMeta {
1581                pubkey,
1582                is_signer: true,
1583                is_writable: true,
1584            }],
1585            Err(InstructionError::MissingAccount),
1586        );
1587    }
1588
1589    #[test]
1590    fn test_process_nonce_ix_ok() {
1591        let nonce_address = Pubkey::new_unique();
1592        let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1593        #[allow(deprecated)]
1594        let blockhash_id = sysvar::recent_blockhashes::id();
1595        let accounts = process_instruction(
1596            &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1597            vec![
1598                (nonce_address, nonce_account),
1599                (blockhash_id, create_default_recent_blockhashes_account()),
1600                (sysvar::rent::id(), create_default_rent_account()),
1601            ],
1602            vec![
1603                AccountMeta {
1604                    pubkey: nonce_address,
1605                    is_signer: true,
1606                    is_writable: true,
1607                },
1608                AccountMeta {
1609                    pubkey: blockhash_id,
1610                    is_signer: false,
1611                    is_writable: false,
1612                },
1613                AccountMeta {
1614                    pubkey: sysvar::rent::id(),
1615                    is_signer: false,
1616                    is_writable: false,
1617                },
1618            ],
1619            Ok(()),
1620        );
1621        let blockhash = hash(&serialize(&0).unwrap());
1622        #[allow(deprecated)]
1623        let new_recent_blockhashes_account = create_recent_blockhashes_account_for_test(vec![
1624                IterItem(0u64, &blockhash, 0);
1625                sysvar::recent_blockhashes::MAX_ENTRIES
1626            ]);
1627        mock_process_instruction(
1628            &system_program::id(),
1629            &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
1630            vec![
1631                (nonce_address, accounts[0].clone()),
1632                (blockhash_id, new_recent_blockhashes_account),
1633            ],
1634            vec![
1635                AccountMeta {
1636                    pubkey: nonce_address,
1637                    is_signer: true,
1638                    is_writable: true,
1639                },
1640                AccountMeta {
1641                    pubkey: blockhash_id,
1642                    is_signer: false,
1643                    is_writable: false,
1644                },
1645            ],
1646            Ok(()),
1647            Entrypoint::register,
1648            |invoke_context: &mut InvokeContext| {
1649                invoke_context.environment_config.blockhash = hash(&serialize(&0).unwrap());
1650            },
1651            |_invoke_context| {},
1652        );
1653    }
1654
1655    #[test]
1656    fn test_process_withdraw_ix_no_acc_data_fail() {
1657        let nonce_address = Pubkey::new_unique();
1658        process_nonce_instruction(
1659            system_instruction::withdraw_nonce_account(
1660                &nonce_address,
1661                &Pubkey::new_unique(),
1662                &nonce_address,
1663                1,
1664            ),
1665            Err(InstructionError::InvalidAccountData),
1666        );
1667    }
1668
1669    #[test]
1670    fn test_process_withdraw_ix_no_keyed_accs_fail() {
1671        process_instruction(
1672            &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
1673            Vec::new(),
1674            Vec::new(),
1675            Err(InstructionError::MissingAccount),
1676        );
1677    }
1678
1679    #[test]
1680    fn test_process_withdraw_ix_only_nonce_acc_fail() {
1681        let nonce_address = Pubkey::new_unique();
1682        process_instruction(
1683            &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
1684            vec![(nonce_address, create_default_account())],
1685            vec![AccountMeta {
1686                pubkey: nonce_address,
1687                is_signer: true,
1688                is_writable: true,
1689            }],
1690            Err(InstructionError::MissingAccount),
1691        );
1692    }
1693
1694    #[test]
1695    fn test_process_withdraw_ix_ok() {
1696        let nonce_address = Pubkey::new_unique();
1697        let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1698        let pubkey = Pubkey::new_unique();
1699        #[allow(deprecated)]
1700        let blockhash_id = sysvar::recent_blockhashes::id();
1701        process_instruction(
1702            &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
1703            vec![
1704                (nonce_address, nonce_account),
1705                (pubkey, create_default_account()),
1706                (blockhash_id, create_default_recent_blockhashes_account()),
1707                (sysvar::rent::id(), create_default_rent_account()),
1708            ],
1709            vec![
1710                AccountMeta {
1711                    pubkey: nonce_address,
1712                    is_signer: true,
1713                    is_writable: true,
1714                },
1715                AccountMeta {
1716                    pubkey,
1717                    is_signer: true,
1718                    is_writable: true,
1719                },
1720                AccountMeta {
1721                    pubkey: blockhash_id,
1722                    is_signer: false,
1723                    is_writable: false,
1724                },
1725                AccountMeta {
1726                    pubkey: sysvar::rent::id(),
1727                    is_signer: false,
1728                    is_writable: false,
1729                },
1730            ],
1731            Ok(()),
1732        );
1733    }
1734
1735    #[test]
1736    fn test_process_initialize_ix_no_keyed_accs_fail() {
1737        process_instruction(
1738            &serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
1739            Vec::new(),
1740            Vec::new(),
1741            Err(InstructionError::MissingAccount),
1742        );
1743    }
1744
1745    #[test]
1746    fn test_process_initialize_ix_only_nonce_acc_fail() {
1747        let nonce_address = Pubkey::new_unique();
1748        let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1749        process_instruction(
1750            &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1751            vec![(nonce_address, nonce_account)],
1752            vec![AccountMeta {
1753                pubkey: nonce_address,
1754                is_signer: true,
1755                is_writable: true,
1756            }],
1757            Err(InstructionError::MissingAccount),
1758        );
1759    }
1760
1761    #[test]
1762    fn test_process_initialize_ix_ok() {
1763        let nonce_address = Pubkey::new_unique();
1764        let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1765        #[allow(deprecated)]
1766        let blockhash_id = sysvar::recent_blockhashes::id();
1767        process_instruction(
1768            &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1769            vec![
1770                (nonce_address, nonce_account),
1771                (blockhash_id, create_default_recent_blockhashes_account()),
1772                (sysvar::rent::id(), create_default_rent_account()),
1773            ],
1774            vec![
1775                AccountMeta {
1776                    pubkey: nonce_address,
1777                    is_signer: true,
1778                    is_writable: true,
1779                },
1780                AccountMeta {
1781                    pubkey: blockhash_id,
1782                    is_signer: false,
1783                    is_writable: false,
1784                },
1785                AccountMeta {
1786                    pubkey: sysvar::rent::id(),
1787                    is_signer: false,
1788                    is_writable: false,
1789                },
1790            ],
1791            Ok(()),
1792        );
1793    }
1794
1795    #[test]
1796    fn test_process_authorize_ix_ok() {
1797        let nonce_address = Pubkey::new_unique();
1798        let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1799        #[allow(deprecated)]
1800        let blockhash_id = sysvar::recent_blockhashes::id();
1801        let accounts = process_instruction(
1802            &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1803            vec![
1804                (nonce_address, nonce_account),
1805                (blockhash_id, create_default_recent_blockhashes_account()),
1806                (sysvar::rent::id(), create_default_rent_account()),
1807            ],
1808            vec![
1809                AccountMeta {
1810                    pubkey: nonce_address,
1811                    is_signer: true,
1812                    is_writable: true,
1813                },
1814                AccountMeta {
1815                    pubkey: blockhash_id,
1816                    is_signer: false,
1817                    is_writable: false,
1818                },
1819                AccountMeta {
1820                    pubkey: sysvar::rent::id(),
1821                    is_signer: false,
1822                    is_writable: false,
1823                },
1824            ],
1825            Ok(()),
1826        );
1827        process_instruction(
1828            &serialize(&SystemInstruction::AuthorizeNonceAccount(nonce_address)).unwrap(),
1829            vec![(nonce_address, accounts[0].clone())],
1830            vec![AccountMeta {
1831                pubkey: nonce_address,
1832                is_signer: true,
1833                is_writable: true,
1834            }],
1835            Ok(()),
1836        );
1837    }
1838
1839    #[test]
1840    fn test_process_authorize_bad_account_data_fail() {
1841        let nonce_address = Pubkey::new_unique();
1842        process_nonce_instruction(
1843            system_instruction::authorize_nonce_account(
1844                &nonce_address,
1845                &Pubkey::new_unique(),
1846                &nonce_address,
1847            ),
1848            Err(InstructionError::InvalidAccountData),
1849        );
1850    }
1851
1852    #[test]
1853    fn test_nonce_initialize_with_empty_recent_blockhashes_fail() {
1854        let nonce_address = Pubkey::new_unique();
1855        let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1856        #[allow(deprecated)]
1857        let blockhash_id = sysvar::recent_blockhashes::id();
1858        #[allow(deprecated)]
1859        let new_recent_blockhashes_account = create_recent_blockhashes_account_for_test(vec![]);
1860        process_instruction(
1861            &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1862            vec![
1863                (nonce_address, nonce_account),
1864                (blockhash_id, new_recent_blockhashes_account),
1865                (sysvar::rent::id(), create_default_rent_account()),
1866            ],
1867            vec![
1868                AccountMeta {
1869                    pubkey: nonce_address,
1870                    is_signer: true,
1871                    is_writable: true,
1872                },
1873                AccountMeta {
1874                    pubkey: blockhash_id,
1875                    is_signer: false,
1876                    is_writable: false,
1877                },
1878                AccountMeta {
1879                    pubkey: sysvar::rent::id(),
1880                    is_signer: false,
1881                    is_writable: false,
1882                },
1883            ],
1884            Err(SystemError::NonceNoRecentBlockhashes.into()),
1885        );
1886    }
1887
1888    #[test]
1889    fn test_nonce_advance_with_empty_recent_blockhashes_fail() {
1890        let nonce_address = Pubkey::new_unique();
1891        let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1892        #[allow(deprecated)]
1893        let blockhash_id = sysvar::recent_blockhashes::id();
1894        let accounts = process_instruction(
1895            &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1896            vec![
1897                (nonce_address, nonce_account),
1898                (blockhash_id, create_default_recent_blockhashes_account()),
1899                (sysvar::rent::id(), create_default_rent_account()),
1900            ],
1901            vec![
1902                AccountMeta {
1903                    pubkey: nonce_address,
1904                    is_signer: true,
1905                    is_writable: true,
1906                },
1907                AccountMeta {
1908                    pubkey: blockhash_id,
1909                    is_signer: false,
1910                    is_writable: false,
1911                },
1912                AccountMeta {
1913                    pubkey: sysvar::rent::id(),
1914                    is_signer: false,
1915                    is_writable: false,
1916                },
1917            ],
1918            Ok(()),
1919        );
1920        #[allow(deprecated)]
1921        let new_recent_blockhashes_account = create_recent_blockhashes_account_for_test(vec![]);
1922        mock_process_instruction(
1923            &system_program::id(),
1924            &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
1925            vec![
1926                (nonce_address, accounts[0].clone()),
1927                (blockhash_id, new_recent_blockhashes_account),
1928            ],
1929            vec![
1930                AccountMeta {
1931                    pubkey: nonce_address,
1932                    is_signer: true,
1933                    is_writable: true,
1934                },
1935                AccountMeta {
1936                    pubkey: blockhash_id,
1937                    is_signer: false,
1938                    is_writable: false,
1939                },
1940            ],
1941            Err(SystemError::NonceNoRecentBlockhashes.into()),
1942            Entrypoint::register,
1943            |invoke_context: &mut InvokeContext| {
1944                invoke_context.environment_config.blockhash = hash(&serialize(&0).unwrap());
1945            },
1946            |_invoke_context| {},
1947        );
1948    }
1949
1950    #[test]
1951    fn test_nonce_account_upgrade_check_owner() {
1952        let nonce_address = Pubkey::new_unique();
1953        let versions = NonceVersions::Legacy(Box::new(NonceState::Uninitialized));
1954        let nonce_account = AccountSharedData::new_data(
1955            1_000_000,             // lamports
1956            &versions,             // state
1957            &Pubkey::new_unique(), // owner
1958        )
1959        .unwrap();
1960        let accounts = process_instruction(
1961            &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
1962            vec![(nonce_address, nonce_account.clone())],
1963            vec![AccountMeta {
1964                pubkey: nonce_address,
1965                is_signer: false,
1966                is_writable: true,
1967            }],
1968            Err(InstructionError::InvalidAccountOwner),
1969        );
1970        assert_eq!(accounts.len(), 1);
1971        assert_eq!(accounts[0], nonce_account);
1972    }
1973
1974    fn new_nonce_account(versions: NonceVersions) -> AccountSharedData {
1975        let nonce_account = AccountSharedData::new_data(
1976            1_000_000,             // lamports
1977            &versions,             // state
1978            &system_program::id(), // owner
1979        )
1980        .unwrap();
1981        let stored: NonceVersions = nonce_account.state().unwrap();
1982        assert_eq!(stored, versions);
1983        nonce_account
1984    }
1985
1986    #[test]
1987    fn test_nonce_account_upgrade() {
1988        let nonce_address = Pubkey::new_unique();
1989        let versions = NonceVersions::Legacy(Box::new(NonceState::Uninitialized));
1990        let nonce_account = new_nonce_account(versions);
1991        let accounts = process_instruction(
1992            &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
1993            vec![(nonce_address, nonce_account.clone())],
1994            vec![AccountMeta {
1995                pubkey: nonce_address,
1996                is_signer: false,
1997                is_writable: true,
1998            }],
1999            Err(InstructionError::InvalidArgument),
2000        );
2001        assert_eq!(accounts.len(), 1);
2002        assert_eq!(accounts[0], nonce_account);
2003        let versions = NonceVersions::Current(Box::new(NonceState::Uninitialized));
2004        let nonce_account = new_nonce_account(versions);
2005        let accounts = process_instruction(
2006            &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
2007            vec![(nonce_address, nonce_account.clone())],
2008            vec![AccountMeta {
2009                pubkey: nonce_address,
2010                is_signer: false,
2011                is_writable: true,
2012            }],
2013            Err(InstructionError::InvalidArgument),
2014        );
2015        assert_eq!(accounts.len(), 1);
2016        assert_eq!(accounts[0], nonce_account);
2017        let blockhash = Hash::from([171; 32]);
2018        let durable_nonce = DurableNonce::from_blockhash(&blockhash);
2019        let data = NonceData {
2020            authority: Pubkey::new_unique(),
2021            durable_nonce,
2022            fee_calculator: FeeCalculator {
2023                lamports_per_signature: 2718,
2024            },
2025        };
2026        let versions = NonceVersions::Legacy(Box::new(NonceState::Initialized(data.clone())));
2027        let nonce_account = new_nonce_account(versions);
2028        let accounts = process_instruction(
2029            &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
2030            vec![(nonce_address, nonce_account.clone())],
2031            vec![AccountMeta {
2032                pubkey: nonce_address,
2033                is_signer: false,
2034                is_writable: false, // Should fail!
2035            }],
2036            Err(InstructionError::InvalidArgument),
2037        );
2038        assert_eq!(accounts.len(), 1);
2039        assert_eq!(accounts[0], nonce_account);
2040        let mut accounts = process_instruction(
2041            &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
2042            vec![(nonce_address, nonce_account)],
2043            vec![AccountMeta {
2044                pubkey: nonce_address,
2045                is_signer: false,
2046                is_writable: true,
2047            }],
2048            Ok(()),
2049        );
2050        assert_eq!(accounts.len(), 1);
2051        let nonce_account = accounts.remove(0);
2052        let durable_nonce = DurableNonce::from_blockhash(durable_nonce.as_hash());
2053        assert_ne!(data.durable_nonce, durable_nonce);
2054        let data = NonceData {
2055            durable_nonce,
2056            ..data
2057        };
2058        let upgraded_nonce_account =
2059            NonceVersions::Current(Box::new(NonceState::Initialized(data)));
2060        let stored: NonceVersions = nonce_account.state().unwrap();
2061        assert_eq!(stored, upgraded_nonce_account);
2062        let accounts = process_instruction(
2063            &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
2064            vec![(nonce_address, nonce_account)],
2065            vec![AccountMeta {
2066                pubkey: nonce_address,
2067                is_signer: false,
2068                is_writable: true,
2069            }],
2070            Err(InstructionError::InvalidArgument),
2071        );
2072        assert_eq!(accounts.len(), 1);
2073        let stored: NonceVersions = accounts[0].state().unwrap();
2074        assert_eq!(stored, upgraded_nonce_account);
2075    }
2076
2077    #[test]
2078    fn test_assign_native_loader_and_transfer() {
2079        for size in [0, 10] {
2080            let pubkey = Pubkey::new_unique();
2081            let account = AccountSharedData::new(100, size, &system_program::id());
2082            let accounts = process_instruction(
2083                &bincode::serialize(&SystemInstruction::Assign {
2084                    owner: solana_sdk_ids::native_loader::id(),
2085                })
2086                .unwrap(),
2087                vec![(pubkey, account.clone())],
2088                vec![AccountMeta {
2089                    pubkey,
2090                    is_signer: true,
2091                    is_writable: true,
2092                }],
2093                Ok(()),
2094            );
2095            assert_eq!(accounts[0].owner(), &solana_sdk_ids::native_loader::id());
2096            assert_eq!(accounts[0].lamports(), 100);
2097
2098            let pubkey2 = Pubkey::new_unique();
2099            let accounts = process_instruction(
2100                &bincode::serialize(&SystemInstruction::Transfer { lamports: 50 }).unwrap(),
2101                vec![
2102                    (
2103                        pubkey2,
2104                        AccountSharedData::new(100, 0, &system_program::id()),
2105                    ),
2106                    (pubkey, accounts[0].clone()),
2107                ],
2108                vec![
2109                    AccountMeta {
2110                        pubkey: pubkey2,
2111                        is_signer: true,
2112                        is_writable: true,
2113                    },
2114                    AccountMeta {
2115                        pubkey,
2116                        is_signer: false,
2117                        is_writable: true,
2118                    },
2119                ],
2120                Ok(()),
2121            );
2122            assert_eq!(accounts[1].owner(), &solana_sdk_ids::native_loader::id());
2123            assert_eq!(accounts[1].lamports(), 150);
2124        }
2125    }
2126
2127    #[test]
2128    fn test_create_account_allow_prefund() {
2129        let new_owner = Pubkey::from([9; 32]);
2130        let to = Pubkey::new_unique();
2131        let from = Pubkey::new_unique();
2132        let ix_accounts = vec![AccountMeta::new(to, true), AccountMeta::new(from, true)];
2133
2134        // With nonzero lamports (payer transfers additional funds)
2135        let accounts = process_instruction(
2136            &bincode::serialize(&SystemInstruction::CreateAccountAllowPrefund {
2137                lamports: 50,
2138                space: 2,
2139                owner: new_owner,
2140            })
2141            .unwrap(),
2142            vec![
2143                (to, AccountSharedData::new(100, 0, &Pubkey::default())),
2144                (from, AccountSharedData::new(100, 0, &system_program::id())),
2145            ],
2146            ix_accounts,
2147            Ok(()),
2148        );
2149        assert_eq!(accounts[0].lamports(), 150);
2150        assert_eq!(accounts[0].owner(), &new_owner);
2151        assert_eq!(accounts[0].data(), &[0, 0]);
2152        assert_eq!(accounts[1].lamports(), 50);
2153
2154        // With zero lamports (account prefunded), no payer needed
2155        let accounts = process_instruction(
2156            &bincode::serialize(&SystemInstruction::CreateAccountAllowPrefund {
2157                lamports: 0,
2158                space: 2,
2159                owner: new_owner,
2160            })
2161            .unwrap(),
2162            vec![(to, AccountSharedData::new(100, 0, &Pubkey::default()))],
2163            vec![AccountMeta::new(to, true)],
2164            Ok(()),
2165        );
2166        assert_eq!(accounts[0].lamports(), 100);
2167        assert_eq!(accounts[0].owner(), &new_owner);
2168        assert_eq!(accounts[0].data(), &[0, 0]);
2169
2170        // Feature gate off - instruction rejected
2171        use solana_program_runtime::invoke_context::mock_process_instruction_with_feature_set;
2172        mock_process_instruction_with_feature_set(
2173            &system_program::id(),
2174            &bincode::serialize(&SystemInstruction::CreateAccountAllowPrefund {
2175                lamports: 50,
2176                space: 0,
2177                owner: new_owner,
2178            })
2179            .unwrap(),
2180            vec![
2181                (to, AccountSharedData::new(0, 0, &Pubkey::default())),
2182                (from, AccountSharedData::new(100, 0, &system_program::id())),
2183            ],
2184            vec![AccountMeta::new(to, true), AccountMeta::new(from, true)],
2185            Err(InstructionError::InvalidInstructionData),
2186            Entrypoint::register,
2187            |_| {},
2188            |_| {},
2189            &solana_svm_feature_set::SVMFeatureSet::default(),
2190        );
2191    }
2192
2193    #[test]
2194    fn test_create_account_allow_prefund_already_in_use() {
2195        let new_owner = Pubkey::from([9; 32]);
2196        let to = Pubkey::new_unique();
2197        let from = Pubkey::new_unique();
2198        let from_account = AccountSharedData::new(100, 0, &system_program::id());
2199        let ix_data = bincode::serialize(&SystemInstruction::CreateAccountAllowPrefund {
2200            lamports: 50,
2201            space: 2,
2202            owner: new_owner,
2203        })
2204        .unwrap();
2205        let ix_accounts = vec![AccountMeta::new(to, true), AccountMeta::new(from, true)];
2206
2207        // Account already has data
2208        process_instruction(
2209            &ix_data,
2210            vec![
2211                (to, AccountSharedData::new(0, 1, &Pubkey::default())),
2212                (from, from_account.clone()),
2213            ],
2214            ix_accounts.clone(),
2215            Err(SystemError::AccountAlreadyInUse.into()),
2216        );
2217
2218        // Account already owned by another program
2219        process_instruction(
2220            &ix_data,
2221            vec![
2222                (to, AccountSharedData::new(0, 0, &Pubkey::from([5; 32]))),
2223                (from, from_account),
2224            ],
2225            ix_accounts,
2226            Err(SystemError::AccountAlreadyInUse.into()),
2227        );
2228    }
2229
2230    #[test]
2231    fn test_create_account_allow_prefund_missing_signer() {
2232        let new_owner = Pubkey::from([9; 32]);
2233        let to = Pubkey::new_unique();
2234        let from = Pubkey::new_unique();
2235        let tx_accounts = vec![
2236            (to, AccountSharedData::new(0, 0, &Pubkey::default())),
2237            (from, AccountSharedData::new(100, 0, &system_program::id())),
2238        ];
2239        let ix_data = bincode::serialize(&SystemInstruction::CreateAccountAllowPrefund {
2240            lamports: 50,
2241            space: 2,
2242            owner: new_owner,
2243        })
2244        .unwrap();
2245
2246        // Payer not signed
2247        process_instruction(
2248            &ix_data,
2249            tx_accounts.clone(),
2250            vec![AccountMeta::new(to, true), AccountMeta::new(from, false)],
2251            Err(InstructionError::MissingRequiredSignature),
2252        );
2253
2254        // New account not signed
2255        process_instruction(
2256            &ix_data,
2257            tx_accounts,
2258            vec![AccountMeta::new(to, false), AccountMeta::new(from, true)],
2259            Err(InstructionError::MissingRequiredSignature),
2260        );
2261    }
2262}