solana_program_test/
programs.rs

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