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