solana_program_test/
programs.rs

1use solana_sdk::{
2    account::{Account, AccountSharedData},
3    bpf_loader,
4    bpf_loader_upgradeable::{self, get_program_data_address, UpgradeableLoaderState},
5    pubkey::Pubkey,
6    rent::Rent,
7};
8
9mod spl_memo_1_0 {
10    solana_sdk::declare_id!("Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo");
11}
12mod spl_memo_3_0 {
13    solana_sdk::declare_id!("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr");
14}
15static SPL_PROGRAMS: &[(Pubkey, Pubkey, &[u8])] = &[
16    (
17        solana_inline_spl::token::ID,
18        solana_sdk::bpf_loader::ID,
19        include_bytes!("programs/spl_token-3.5.0.so"),
20    ),
21    (
22        solana_inline_spl::token_2022::ID,
23        solana_sdk::bpf_loader_upgradeable::ID,
24        include_bytes!("programs/spl_token_2022-5.0.2.so"),
25    ),
26    (
27        spl_memo_1_0::ID,
28        solana_sdk::bpf_loader::ID,
29        include_bytes!("programs/spl_memo-1.0.0.so"),
30    ),
31    (
32        spl_memo_3_0::ID,
33        solana_sdk::bpf_loader::ID,
34        include_bytes!("programs/spl_memo-3.0.0.so"),
35    ),
36    (
37        solana_inline_spl::associated_token_account::ID,
38        solana_sdk::bpf_loader::ID,
39        include_bytes!("programs/spl_associated_token_account-1.1.1.so"),
40    ),
41];
42
43/// Returns a tuple `(Pubkey, Account)` for a BPF program, where the key is the
44/// provided program ID and the account is a valid BPF Loader program account
45/// containing the ELF.
46fn bpf_loader_program_account(program_id: &Pubkey, elf: &[u8], rent: &Rent) -> (Pubkey, Account) {
47    (
48        *program_id,
49        Account {
50            lamports: rent.minimum_balance(elf.len()).max(1),
51            data: elf.to_vec(),
52            owner: bpf_loader::id(),
53            executable: true,
54            rent_epoch: 0,
55        },
56    )
57}
58
59/// Returns two tuples `(Pubkey, Account)` for a BPF upgradeable program.
60/// The first tuple is the program account. It contains the provided program ID
61/// and an account with a pointer to its program data account.
62/// The second tuple is the program data account. It contains the program data
63/// address and an account with the program data - a valid BPF Loader Upgradeable
64/// program data account containing the ELF.
65pub(crate) fn bpf_loader_upgradeable_program_accounts(
66    program_id: &Pubkey,
67    elf: &[u8],
68    rent: &Rent,
69) -> [(Pubkey, Account); 2] {
70    let programdata_address = get_program_data_address(program_id);
71    let program_account = {
72        let space = UpgradeableLoaderState::size_of_program();
73        let lamports = rent.minimum_balance(space);
74        let data = bincode::serialize(&UpgradeableLoaderState::Program {
75            programdata_address,
76        })
77        .unwrap();
78        Account {
79            lamports,
80            data,
81            owner: bpf_loader_upgradeable::id(),
82            executable: true,
83            rent_epoch: 0,
84        }
85    };
86    let programdata_account = {
87        let space = UpgradeableLoaderState::size_of_programdata_metadata() + elf.len();
88        let lamports = rent.minimum_balance(space);
89        let mut data = bincode::serialize(&UpgradeableLoaderState::ProgramData {
90            slot: 0,
91            upgrade_authority_address: Some(Pubkey::default()),
92        })
93        .unwrap();
94        data.extend_from_slice(elf);
95        Account {
96            lamports,
97            data,
98            owner: bpf_loader_upgradeable::id(),
99            executable: false,
100            rent_epoch: 0,
101        }
102    };
103    [
104        (*program_id, program_account),
105        (programdata_address, programdata_account),
106    ]
107}
108
109pub fn spl_programs(rent: &Rent) -> Vec<(Pubkey, AccountSharedData)> {
110    SPL_PROGRAMS
111        .iter()
112        .flat_map(|(program_id, loader_id, elf)| {
113            let mut accounts = vec![];
114            if loader_id.eq(&solana_sdk::bpf_loader_upgradeable::ID) {
115                for (key, account) in bpf_loader_upgradeable_program_accounts(program_id, elf, rent)
116                {
117                    accounts.push((key, AccountSharedData::from(account)));
118                }
119            } else {
120                let (key, account) = bpf_loader_program_account(program_id, elf, rent);
121                accounts.push((key, AccountSharedData::from(account)));
122            }
123            accounts
124        })
125        .collect()
126}