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