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