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    feature_set,
6    pubkey::Pubkey,
7    rent::Rent,
8};
9
10mod spl_memo_1_0 {
11    solana_sdk::declare_id!("Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo");
12}
13mod spl_memo_3_0 {
14    solana_sdk::declare_id!("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr");
15}
16
17static SPL_PROGRAMS: &[(Pubkey, Pubkey, &[u8])] = &[
18    (
19        solana_inline_spl::token::ID,
20        solana_sdk_ids::bpf_loader::ID,
21        include_bytes!("programs/spl_token-3.5.0.so"),
22    ),
23    (
24        solana_inline_spl::token_2022::ID,
25        solana_sdk_ids::bpf_loader_upgradeable::ID,
26        include_bytes!("programs/spl_token_2022-5.0.2.so"),
27    ),
28    (
29        spl_memo_1_0::ID,
30        solana_sdk_ids::bpf_loader::ID,
31        include_bytes!("programs/spl_memo-1.0.0.so"),
32    ),
33    (
34        spl_memo_3_0::ID,
35        solana_sdk_ids::bpf_loader::ID,
36        include_bytes!("programs/spl_memo-3.0.0.so"),
37    ),
38    (
39        solana_inline_spl::associated_token_account::ID,
40        solana_sdk_ids::bpf_loader::ID,
41        include_bytes!("programs/spl_associated_token_account-1.1.1.so"),
42    ),
43];
44
45// Programs that were previously builtins but have been migrated to Core BPF.
46// All Core BPF programs are owned by BPF loader v3.
47// Note the second pubkey is the migration feature ID.
48static CORE_BPF_PROGRAMS: &[(Pubkey, Pubkey, &[u8])] = &[
49    (
50        solana_sdk_ids::address_lookup_table::ID,
51        feature_set::migrate_address_lookup_table_program_to_core_bpf::ID,
52        include_bytes!("programs/core_bpf_address_lookup_table-3.0.0.so"),
53    ),
54    (
55        solana_sdk_ids::config::ID,
56        feature_set::migrate_config_program_to_core_bpf::ID,
57        include_bytes!("programs/core_bpf_config-3.0.0.so"),
58    ),
59    (
60        solana_sdk_ids::feature::ID,
61        feature_set::migrate_feature_gate_program_to_core_bpf::ID,
62        include_bytes!("programs/core_bpf_feature_gate-0.0.1.so"),
63    ),
64    // Add more programs here post-migration...
65];
66
67/// Returns a tuple `(Pubkey, Account)` for a BPF program, where the key is the
68/// provided program ID and the account is a valid BPF Loader program account
69/// containing the ELF.
70fn bpf_loader_program_account(program_id: &Pubkey, elf: &[u8], rent: &Rent) -> (Pubkey, Account) {
71    (
72        *program_id,
73        Account {
74            lamports: rent.minimum_balance(elf.len()).max(1),
75            data: elf.to_vec(),
76            owner: bpf_loader::id(),
77            executable: true,
78            rent_epoch: 0,
79        },
80    )
81}
82
83/// Returns two tuples `(Pubkey, Account)` for a BPF upgradeable program.
84/// The first tuple is the program account. It contains the provided program ID
85/// and an account with a pointer to its program data account.
86/// The second tuple is the program data account. It contains the program data
87/// address and an account with the program data - a valid BPF Loader Upgradeable
88/// program data account containing the ELF.
89pub(crate) fn bpf_loader_upgradeable_program_accounts(
90    program_id: &Pubkey,
91    elf: &[u8],
92    rent: &Rent,
93) -> [(Pubkey, Account); 2] {
94    let programdata_address = get_program_data_address(program_id);
95    let program_account = {
96        let space = UpgradeableLoaderState::size_of_program();
97        let lamports = rent.minimum_balance(space);
98        let data = bincode::serialize(&UpgradeableLoaderState::Program {
99            programdata_address,
100        })
101        .unwrap();
102        Account {
103            lamports,
104            data,
105            owner: bpf_loader_upgradeable::id(),
106            executable: true,
107            rent_epoch: 0,
108        }
109    };
110    let programdata_account = {
111        let space = UpgradeableLoaderState::size_of_programdata_metadata() + elf.len();
112        let lamports = rent.minimum_balance(space);
113        let mut data = bincode::serialize(&UpgradeableLoaderState::ProgramData {
114            slot: 0,
115            upgrade_authority_address: Some(Pubkey::default()),
116        })
117        .unwrap();
118        data.extend_from_slice(elf);
119        Account {
120            lamports,
121            data,
122            owner: bpf_loader_upgradeable::id(),
123            executable: false,
124            rent_epoch: 0,
125        }
126    };
127    [
128        (*program_id, program_account),
129        (programdata_address, programdata_account),
130    ]
131}
132
133pub fn spl_programs(rent: &Rent) -> Vec<(Pubkey, AccountSharedData)> {
134    SPL_PROGRAMS
135        .iter()
136        .flat_map(|(program_id, loader_id, elf)| {
137            let mut accounts = vec![];
138            if loader_id.eq(&solana_sdk_ids::bpf_loader_upgradeable::ID) {
139                for (key, account) in bpf_loader_upgradeable_program_accounts(program_id, elf, rent)
140                {
141                    accounts.push((key, AccountSharedData::from(account)));
142                }
143            } else {
144                let (key, account) = bpf_loader_program_account(program_id, elf, rent);
145                accounts.push((key, AccountSharedData::from(account)));
146            }
147            accounts
148        })
149        .collect()
150}
151
152pub fn core_bpf_programs<F>(rent: &Rent, is_feature_active: F) -> Vec<(Pubkey, AccountSharedData)>
153where
154    F: Fn(&Pubkey) -> bool,
155{
156    CORE_BPF_PROGRAMS
157        .iter()
158        .flat_map(|(program_id, feature_id, elf)| {
159            let mut accounts = vec![];
160            if is_feature_active(feature_id) {
161                for (key, account) in bpf_loader_upgradeable_program_accounts(program_id, elf, rent)
162                {
163                    accounts.push((key, AccountSharedData::from(account)));
164                }
165            }
166            accounts
167        })
168        .collect()
169}