1#![cfg(feature = "dev-context-only-utils")]
2use {
3 crate::{bank::Bank, bank_client::BankClient, bank_forks::BankForks},
4 solana_account::{AccountSharedData, WritableAccount},
5 solana_client_traits::{Client, SyncClient},
6 solana_clock::Clock,
7 solana_instruction::{AccountMeta, Instruction},
8 solana_keypair::Keypair,
9 solana_leader_schedule::SlotLeader,
10 solana_loader_v3_interface::state::UpgradeableLoaderState,
11 solana_message::Message,
12 solana_program_binaries::{
13 bpf_loader_program_account, bpf_loader_upgradeable_program_accounts,
14 },
15 solana_pubkey::Pubkey,
16 solana_rent::Rent,
17 solana_sdk_ids::bpf_loader_upgradeable,
18 solana_signer::Signer,
19 std::{
20 env,
21 fs::File,
22 io::Read,
23 path::PathBuf,
24 sync::{Arc, RwLock},
25 },
26};
27
28const CHUNK_SIZE: usize = 512; pub fn load_program_from_file(name: &str) -> Vec<u8> {
31 let mut pathbuf = {
32 let current_exe = env::current_exe().unwrap();
33 PathBuf::from(
34 current_exe
35 .parent()
36 .unwrap()
37 .parent()
38 .unwrap()
39 .parent()
40 .unwrap(),
41 )
42 };
43 pathbuf.push("deploy");
44 pathbuf.push(name);
45 pathbuf.set_extension("so");
46 let mut file = File::open(&pathbuf).unwrap_or_else(|err| {
47 panic!("Failed to open {}: {}", pathbuf.display(), err);
48 });
49 let mut program = Vec::new();
50 file.read_to_end(&mut program).unwrap();
51 program
52}
53
54pub fn create_program(bank: &Bank, loader_id: &Pubkey, name: &str) -> Pubkey {
56 create_program_with_elf(
57 bank,
58 loader_id,
59 &Pubkey::default(),
60 &load_program_from_file(name),
61 )
62}
63
64pub fn create_program_with_elf(
65 bank: &Bank,
66 loader_id: &Pubkey,
67 upgrade_authority: &Pubkey,
68 elf: &[u8],
69) -> Pubkey {
70 let program_id = Pubkey::new_unique();
71 let rent = Rent::default();
72 if bpf_loader_upgradeable::check_id(loader_id) {
73 let [(_, program_account), (programdata_id, programdata_account)] =
74 bpf_loader_upgradeable_program_accounts(&program_id, elf, upgrade_authority, &rent);
75 bank.store_account(&program_id, &AccountSharedData::from(program_account));
76 bank.store_account(
77 &programdata_id,
78 &AccountSharedData::from(programdata_account),
79 );
80 } else {
81 let (_, mut program_account) = bpf_loader_program_account(&program_id, elf, &rent);
82 program_account.owner = *loader_id;
83 bank.store_account(&program_id, &AccountSharedData::from(program_account));
84 }
85 program_id
86}
87
88pub fn create_buffer_with_elf(bank: &Bank, authority_address: &Pubkey, elf: &[u8]) -> Pubkey {
89 let buffer_address = Pubkey::new_unique();
90 let size = UpgradeableLoaderState::size_of_buffer(elf.len());
91 let mut account = AccountSharedData::new(
92 bank.get_minimum_balance_for_rent_exemption(size),
93 size,
94 &bpf_loader_upgradeable::id(),
95 );
96 wincode::serialize_into(
97 account.data_as_mut_slice(),
98 &UpgradeableLoaderState::Buffer {
99 authority_address: Some(*authority_address),
100 },
101 )
102 .unwrap();
103 account
104 .data_as_mut_slice()
105 .get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..)
106 .unwrap()
107 .copy_from_slice(elf);
108 bank.store_account(&buffer_address, &account);
109 buffer_address
110}
111
112pub fn load_upgradeable_buffer<T: Client>(
113 bank_client: &T,
114 from_keypair: &Keypair,
115 buffer_keypair: &Keypair,
116 buffer_authority_keypair: &Keypair,
117 name: &str,
118) -> Vec<u8> {
119 let program = load_program_from_file(name);
120 let buffer_pubkey = buffer_keypair.pubkey();
121 let buffer_authority_pubkey = buffer_authority_keypair.pubkey();
122 let program_buffer_bytes = UpgradeableLoaderState::size_of_buffer(program.len());
123
124 bank_client
125 .send_and_confirm_message(
126 &[from_keypair, buffer_keypair],
127 Message::new(
128 &solana_loader_v3_interface::instruction::create_buffer(
129 &from_keypair.pubkey(),
130 &buffer_pubkey,
131 &buffer_authority_pubkey,
132 1.max(
133 bank_client
134 .get_minimum_balance_for_rent_exemption(program_buffer_bytes)
135 .unwrap(),
136 ),
137 program.len(),
138 )
139 .unwrap(),
140 Some(&from_keypair.pubkey()),
141 ),
142 )
143 .unwrap();
144
145 let chunk_size = CHUNK_SIZE;
146 let mut offset = 0;
147 for chunk in program.chunks(chunk_size) {
148 let message = Message::new(
149 &[solana_loader_v3_interface::instruction::write(
150 &buffer_pubkey,
151 &buffer_authority_pubkey,
152 offset,
153 chunk.to_vec(),
154 )],
155 Some(&from_keypair.pubkey()),
156 );
157 bank_client
158 .send_and_confirm_message(&[from_keypair, buffer_authority_keypair], message)
159 .unwrap();
160 offset += chunk_size as u32;
161 }
162
163 program
164}
165
166pub fn load_upgradeable_program(
167 bank_client: &BankClient,
168 from_keypair: &Keypair,
169 buffer_keypair: &Keypair,
170 executable_keypair: &Keypair,
171 authority_keypair: &Keypair,
172 name: &str,
173) {
174 let program = load_upgradeable_buffer(
175 bank_client,
176 from_keypair,
177 buffer_keypair,
178 authority_keypair,
179 name,
180 );
181
182 #[allow(deprecated)]
183 let message = Message::new(
184 &solana_loader_v3_interface::instruction::deploy_with_max_program_len(
185 &from_keypair.pubkey(),
186 &executable_keypair.pubkey(),
187 &buffer_keypair.pubkey(),
188 &authority_keypair.pubkey(),
189 1.max(
190 bank_client
191 .get_minimum_balance_for_rent_exemption(
192 UpgradeableLoaderState::size_of_program(),
193 )
194 .unwrap(),
195 ),
196 program.len() * 2,
197 )
198 .unwrap(),
199 Some(&from_keypair.pubkey()),
200 );
201 bank_client
202 .send_and_confirm_message(
203 &[from_keypair, executable_keypair, authority_keypair],
204 message,
205 )
206 .unwrap();
207 bank_client.set_sysvar_for_tests(&Clock {
208 slot: 1,
209 ..Clock::default()
210 });
211}
212
213pub fn load_upgradeable_program_wrapper(
214 bank_client: &BankClient,
215 mint_keypair: &Keypair,
216 authority_keypair: &Keypair,
217 name: &str,
218) -> Pubkey {
219 let buffer_keypair = Keypair::new();
220 let program_keypair = Keypair::new();
221 load_upgradeable_program(
222 bank_client,
223 mint_keypair,
224 &buffer_keypair,
225 &program_keypair,
226 authority_keypair,
227 name,
228 );
229 program_keypair.pubkey()
230}
231
232pub fn load_upgradeable_program_and_advance_slot(
233 bank_client: &mut BankClient,
234 bank_forks: &RwLock<BankForks>,
235 mint_keypair: &Keypair,
236 authority_keypair: &Keypair,
237 name: &str,
238) -> (Arc<Bank>, Pubkey) {
239 let program_id =
240 load_upgradeable_program_wrapper(bank_client, mint_keypair, authority_keypair, name);
241
242 bank_client
245 .advance_slot(1, bank_forks, SlotLeader::default())
246 .expect("Failed to advance the slot");
247
248 let bank = bank_client
249 .advance_slot(1, bank_forks, SlotLeader::default())
250 .expect("Failed to advance the slot");
251
252 (bank, program_id)
253}
254
255pub fn upgrade_program<T: Client>(
256 bank_client: &T,
257 payer_keypair: &Keypair,
258 buffer_keypair: &Keypair,
259 executable_pubkey: &Pubkey,
260 authority_keypair: &Keypair,
261 name: &str,
262) {
263 load_upgradeable_buffer(
264 bank_client,
265 payer_keypair,
266 buffer_keypair,
267 authority_keypair,
268 name,
269 );
270 let message = Message::new(
271 &[solana_loader_v3_interface::instruction::upgrade(
272 executable_pubkey,
273 &buffer_keypair.pubkey(),
274 &authority_keypair.pubkey(),
275 &payer_keypair.pubkey(),
276 )],
277 Some(&payer_keypair.pubkey()),
278 );
279 bank_client
280 .send_and_confirm_message(&[payer_keypair, authority_keypair], message)
281 .unwrap();
282}
283
284pub fn set_upgrade_authority<T: Client>(
285 bank_client: &T,
286 from_keypair: &Keypair,
287 program_pubkey: &Pubkey,
288 current_authority_keypair: &Keypair,
289 new_authority_pubkey: Option<&Pubkey>,
290) {
291 let message = Message::new(
292 &[
293 solana_loader_v3_interface::instruction::set_upgrade_authority(
294 program_pubkey,
295 ¤t_authority_keypair.pubkey(),
296 new_authority_pubkey,
297 ),
298 ],
299 Some(&from_keypair.pubkey()),
300 );
301 bank_client
302 .send_and_confirm_message(&[from_keypair, current_authority_keypair], message)
303 .unwrap();
304}
305
306pub fn create_invoke_instruction<T: wincode::Serialize<Src = T>>(
309 from_pubkey: Pubkey,
310 program_id: Pubkey,
311 data: &T,
312) -> Instruction {
313 let account_metas = vec![AccountMeta::new(from_pubkey, true)];
314 Instruction::new_with_wincode(program_id, data, account_metas)
315}