Skip to main content

rialo_s_system_program/
system_processor.rs

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