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