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