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