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