1#![cfg(feature = "agave-unstable-api")]
2#![allow(clippy::arithmetic_side_effects)]
3
4use {
5 solana_account::{Account, AccountSharedData, ReadableAccount},
6 solana_loader_v3_interface::{get_program_data_address, state::UpgradeableLoaderState},
7 solana_pubkey::Pubkey,
8 solana_rent::Rent,
9 solana_sdk_ids::{bpf_loader, bpf_loader_upgradeable},
10};
11
12mod spl_memo_1_0 {
13 solana_pubkey::declare_id!("Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo");
14}
15mod spl_memo_3_0 {
16 solana_pubkey::declare_id!("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr");
17}
18
19static SPL_PROGRAMS: &[(Pubkey, Pubkey, &[u8])] = &[
20 (
21 spl_generic_token::token::ID,
22 solana_sdk_ids::bpf_loader_upgradeable::ID,
23 include_bytes!("programs/spl_p_token-1.0.0-rc.1.so"),
24 ),
25 (
26 spl_generic_token::token_2022::ID,
27 solana_sdk_ids::bpf_loader_upgradeable::ID,
28 include_bytes!("programs/spl_token_2022-10.0.0.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 spl_generic_token::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
47static CORE_BPF_PROGRAMS: &[(Pubkey, Option<Pubkey>, &[u8])] = &[
52 (
53 solana_sdk_ids::address_lookup_table::ID,
54 None,
55 include_bytes!("programs/core_bpf_address_lookup_table-3.0.0.so"),
56 ),
57 (
58 solana_sdk_ids::config::ID,
59 None,
60 include_bytes!("programs/core_bpf_config-3.0.0.so"),
61 ),
62 (
63 solana_sdk_ids::feature::ID,
64 None,
65 include_bytes!("programs/core_bpf_feature_gate-0.0.1.so"),
66 ),
67 (
68 solana_sdk_ids::stake::ID,
69 None,
70 include_bytes!("programs/core_bpf_stake-4.0.0.so"),
71 ),
72 ];
74
75pub fn bpf_loader_program_account(
79 program_id: &Pubkey,
80 elf: &[u8],
81 rent: &Rent,
82) -> (Pubkey, Account) {
83 (
84 *program_id,
85 Account {
86 lamports: rent.minimum_balance(elf.len()).max(1),
87 data: elf.to_vec(),
88 owner: bpf_loader::id(),
89 executable: true,
90 rent_epoch: u64::MAX,
91 },
92 )
93}
94
95pub fn bpf_loader_upgradeable_program_accounts(
102 program_id: &Pubkey,
103 elf: &[u8],
104 rent: &Rent,
105) -> [(Pubkey, Account); 2] {
106 let programdata_address = get_program_data_address(program_id);
107 let program_account = {
108 let space = UpgradeableLoaderState::size_of_program();
109 let lamports = rent.minimum_balance(space);
110 let data = bincode::serialize(&UpgradeableLoaderState::Program {
111 programdata_address,
112 })
113 .unwrap();
114 Account {
115 lamports,
116 data,
117 owner: bpf_loader_upgradeable::id(),
118 executable: true,
119 rent_epoch: u64::MAX,
120 }
121 };
122 let programdata_account = {
123 let space = UpgradeableLoaderState::size_of_programdata_metadata() + elf.len();
124 let lamports = rent.minimum_balance(space);
125 let mut data = bincode::serialize(&UpgradeableLoaderState::ProgramData {
126 slot: 0,
127 upgrade_authority_address: Some(Pubkey::default()),
128 })
129 .unwrap();
130 data.extend_from_slice(elf);
131 Account {
132 lamports,
133 data,
134 owner: bpf_loader_upgradeable::id(),
135 executable: false,
136 rent_epoch: u64::MAX,
137 }
138 };
139 [
140 (*program_id, program_account),
141 (programdata_address, programdata_account),
142 ]
143}
144
145pub fn spl_programs(rent: &Rent) -> Vec<(Pubkey, AccountSharedData)> {
146 SPL_PROGRAMS
147 .iter()
148 .flat_map(|(program_id, loader_id, elf)| {
149 let mut accounts = vec![];
150 if loader_id.eq(&solana_sdk_ids::bpf_loader_upgradeable::ID) {
151 for (key, account) in bpf_loader_upgradeable_program_accounts(program_id, elf, rent)
152 {
153 accounts.push((key, AccountSharedData::from(account)));
154 }
155 } else {
156 let (key, account) = bpf_loader_program_account(program_id, elf, rent);
157 accounts.push((key, AccountSharedData::from(account)));
158 }
159 accounts
160 })
161 .collect()
162}
163
164pub fn core_bpf_programs<F>(rent: &Rent, is_feature_active: F) -> Vec<(Pubkey, AccountSharedData)>
165where
166 F: Fn(&Pubkey) -> bool,
167{
168 CORE_BPF_PROGRAMS
169 .iter()
170 .flat_map(|(program_id, feature_id, elf)| {
171 let mut accounts = vec![];
172 if feature_id.is_none() || feature_id.is_some_and(|f| is_feature_active(&f)) {
173 for (key, account) in bpf_loader_upgradeable_program_accounts(program_id, elf, rent)
174 {
175 accounts.push((key, AccountSharedData::from(account)));
176 }
177 }
178 accounts
179 })
180 .collect()
181}
182
183pub fn by_id(program_id: &Pubkey, rent: &Rent) -> Option<Vec<(Pubkey, AccountSharedData)>> {
184 let programs = spl_programs(rent);
185 if let Some(i) = programs.iter().position(|(key, _)| key == program_id) {
186 let n = num_accounts(programs[i].1.owner());
187 return Some(programs.into_iter().skip(i).take(n).collect());
188 }
189
190 let programs = core_bpf_programs(rent, |_| true);
191 if let Some(i) = programs.iter().position(|(key, _)| key == program_id) {
192 let n = num_accounts(programs[i].1.owner());
193 return Some(programs.into_iter().skip(i).take(n).collect());
194 }
195
196 None
197}
198
199fn num_accounts(owner_id: &Pubkey) -> usize {
200 if *owner_id == bpf_loader_upgradeable::id() {
201 2
202 } else {
203 1
204 }
205}