solana_system_program/
system_processor.rs

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