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