1use crate::{
12 instruction::{AccountMeta, Instruction, InstructionError},
13 loader_upgradeable_instruction::UpgradeableLoaderInstruction,
14 pubkey::Pubkey,
15 system_instruction, sysvar,
16};
17use bincode::serialized_size;
18
19crate::declare_id!("BPFLoaderUpgradeab1e11111111111111111111111");
20
21#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)]
23pub enum UpgradeableLoaderState {
24 Uninitialized,
26 Buffer {
28 authority_address: Option<Pubkey>,
30 },
33 Program {
35 programdata_address: Pubkey,
37 },
38 ProgramData {
40 slot: u64,
42 upgrade_authority_address: Option<Pubkey>,
44 },
47}
48impl UpgradeableLoaderState {
49 pub fn buffer_len(program_len: usize) -> Result<usize, InstructionError> {
51 Ok(serialized_size(&Self::Buffer {
52 authority_address: Some(Pubkey::default()),
53 })
54 .map(|len| len as usize)
55 .map_err(|_| InstructionError::InvalidInstructionData)?
56 .saturating_add(program_len))
57 }
58 pub fn buffer_data_offset() -> Result<usize, InstructionError> {
60 Self::buffer_len(0)
61 }
62 pub fn program_len() -> Result<usize, InstructionError> {
64 serialized_size(&Self::Program {
65 programdata_address: Pubkey::default(),
66 })
67 .map(|len| len as usize)
68 .map_err(|_| InstructionError::InvalidInstructionData)
69 }
70 pub fn programdata_len(program_len: usize) -> Result<usize, InstructionError> {
72 Ok(serialized_size(&Self::ProgramData {
73 slot: 0,
74 upgrade_authority_address: Some(Pubkey::default()),
75 })
76 .map(|len| len as usize)
77 .map_err(|_| InstructionError::InvalidInstructionData)?
78 .saturating_add(program_len))
79 }
80 pub fn programdata_data_offset() -> Result<usize, InstructionError> {
82 Self::programdata_len(0)
83 }
84}
85
86pub fn create_buffer(
88 payer_address: &Pubkey,
89 buffer_address: &Pubkey,
90 authority_address: &Pubkey,
91 carats: u64,
92 program_len: usize,
93) -> Result<Vec<Instruction>, InstructionError> {
94 Ok(vec![
95 system_instruction::create_account(
96 payer_address,
97 buffer_address,
98 carats,
99 UpgradeableLoaderState::buffer_len(program_len)? as u64,
100 &id(),
101 ),
102 Instruction::new_with_bincode(
103 id(),
104 &UpgradeableLoaderInstruction::InitializeBuffer,
105 vec![
106 AccountMeta::new(*buffer_address, false),
107 AccountMeta::new_readonly(*authority_address, false),
108 ],
109 ),
110 ])
111}
112
113pub fn write(
116 buffer_address: &Pubkey,
117 authority_address: &Pubkey,
118 offset: u32,
119 bytes: Vec<u8>,
120) -> Instruction {
121 Instruction::new_with_bincode(
122 id(),
123 &UpgradeableLoaderInstruction::Write { offset, bytes },
124 vec![
125 AccountMeta::new(*buffer_address, false),
126 AccountMeta::new_readonly(*authority_address, true),
127 ],
128 )
129}
130
131pub fn deploy_with_max_program_len(
135 payer_address: &Pubkey,
136 program_address: &Pubkey,
137 buffer_address: &Pubkey,
138 upgrade_authority_address: &Pubkey,
139 program_carats: u64,
140 max_data_len: usize,
141) -> Result<Vec<Instruction>, InstructionError> {
142 let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
143 Ok(vec![
144 system_instruction::create_account(
145 payer_address,
146 program_address,
147 program_carats,
148 UpgradeableLoaderState::program_len()? as u64,
149 &id(),
150 ),
151 Instruction::new_with_bincode(
152 id(),
153 &UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len },
154 vec![
155 AccountMeta::new(*payer_address, true),
156 AccountMeta::new(programdata_address, false),
157 AccountMeta::new(*program_address, false),
158 AccountMeta::new(*buffer_address, false),
159 AccountMeta::new_readonly(sysvar::rent::id(), false),
160 AccountMeta::new_readonly(sysvar::clock::id(), false),
161 AccountMeta::new_readonly(crate::system_program::id(), false),
162 AccountMeta::new_readonly(*upgrade_authority_address, true),
163 ],
164 ),
165 ])
166}
167
168pub fn upgrade(
170 program_address: &Pubkey,
171 buffer_address: &Pubkey,
172 authority_address: &Pubkey,
173 spill_address: &Pubkey,
174) -> Instruction {
175 let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
176 Instruction::new_with_bincode(
177 id(),
178 &UpgradeableLoaderInstruction::Upgrade,
179 vec![
180 AccountMeta::new(programdata_address, false),
181 AccountMeta::new(*program_address, false),
182 AccountMeta::new(*buffer_address, false),
183 AccountMeta::new(*spill_address, false),
184 AccountMeta::new_readonly(sysvar::rent::id(), false),
185 AccountMeta::new_readonly(sysvar::clock::id(), false),
186 AccountMeta::new_readonly(*authority_address, true),
187 ],
188 )
189}
190
191pub fn is_upgrade_instruction(instruction_data: &[u8]) -> bool {
192 !instruction_data.is_empty() && 3 == instruction_data[0]
193}
194
195pub fn is_set_authority_instruction(instruction_data: &[u8]) -> bool {
196 !instruction_data.is_empty() && 4 == instruction_data[0]
197}
198
199pub fn is_close_instruction(instruction_data: &[u8]) -> bool {
200 !instruction_data.is_empty() && 5 == instruction_data[0]
201}
202
203pub fn set_buffer_authority(
205 buffer_address: &Pubkey,
206 current_authority_address: &Pubkey,
207 new_authority_address: &Pubkey,
208) -> Instruction {
209 Instruction::new_with_bincode(
210 id(),
211 &UpgradeableLoaderInstruction::SetAuthority,
212 vec![
213 AccountMeta::new(*buffer_address, false),
214 AccountMeta::new_readonly(*current_authority_address, true),
215 AccountMeta::new_readonly(*new_authority_address, false),
216 ],
217 )
218}
219
220pub fn set_upgrade_authority(
222 program_address: &Pubkey,
223 current_authority_address: &Pubkey,
224 new_authority_address: Option<&Pubkey>,
225) -> Instruction {
226 let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
227
228 let mut metas = vec![
229 AccountMeta::new(programdata_address, false),
230 AccountMeta::new_readonly(*current_authority_address, true),
231 ];
232 if let Some(address) = new_authority_address {
233 metas.push(AccountMeta::new_readonly(*address, false));
234 }
235 Instruction::new_with_bincode(id(), &UpgradeableLoaderInstruction::SetAuthority, metas)
236}
237
238pub fn close(
240 close_address: &Pubkey,
241 recipient_address: &Pubkey,
242 authority_address: &Pubkey,
243) -> Instruction {
244 close_any(
245 close_address,
246 recipient_address,
247 Some(authority_address),
248 None,
249 )
250}
251
252pub fn close_any(
254 close_address: &Pubkey,
255 recipient_address: &Pubkey,
256 authority_address: Option<&Pubkey>,
257 program_address: Option<&Pubkey>,
258) -> Instruction {
259 let mut metas = vec![
260 AccountMeta::new(*close_address, false),
261 AccountMeta::new(*recipient_address, false),
262 ];
263 if let Some(authority_address) = authority_address {
264 metas.push(AccountMeta::new(*authority_address, true));
265 }
266 if let Some(program_address) = program_address {
267 metas.push(AccountMeta::new(*program_address, false));
268 }
269 Instruction::new_with_bincode(id(), &UpgradeableLoaderInstruction::Close, metas)
270}
271
272#[cfg(test)]
273mod tests {
274 use super::*;
275
276 #[test]
277 fn test_account_lengths() {
278 assert_eq!(
279 4,
280 serialized_size(&UpgradeableLoaderState::Uninitialized).unwrap()
281 );
282 assert_eq!(36, UpgradeableLoaderState::program_len().unwrap());
283 assert_eq!(
284 45,
285 UpgradeableLoaderState::programdata_data_offset().unwrap()
286 );
287 assert_eq!(
288 45 + 42,
289 UpgradeableLoaderState::programdata_len(42).unwrap()
290 );
291 }
292
293 fn assert_is_instruction<F>(
294 is_instruction_fn: F,
295 expected_instruction: UpgradeableLoaderInstruction,
296 ) where
297 F: Fn(&[u8]) -> bool,
298 {
299 let result = is_instruction_fn(
300 &bincode::serialize(&UpgradeableLoaderInstruction::InitializeBuffer).unwrap(),
301 );
302 let expected_result = matches!(
303 expected_instruction,
304 UpgradeableLoaderInstruction::InitializeBuffer
305 );
306 assert_eq!(expected_result, result);
307
308 let result = is_instruction_fn(
309 &bincode::serialize(&UpgradeableLoaderInstruction::Write {
310 offset: 0,
311 bytes: vec![],
312 })
313 .unwrap(),
314 );
315 let expected_result = matches!(
316 expected_instruction,
317 UpgradeableLoaderInstruction::Write {
318 offset: _,
319 bytes: _,
320 }
321 );
322 assert_eq!(expected_result, result);
323
324 let result = is_instruction_fn(
325 &bincode::serialize(&UpgradeableLoaderInstruction::DeployWithMaxDataLen {
326 max_data_len: 0,
327 })
328 .unwrap(),
329 );
330 let expected_result = matches!(
331 expected_instruction,
332 UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len: _ }
333 );
334 assert_eq!(expected_result, result);
335
336 let result =
337 is_instruction_fn(&bincode::serialize(&UpgradeableLoaderInstruction::Upgrade).unwrap());
338 let expected_result = matches!(expected_instruction, UpgradeableLoaderInstruction::Upgrade);
339 assert_eq!(expected_result, result);
340
341 let result = is_instruction_fn(
342 &bincode::serialize(&UpgradeableLoaderInstruction::SetAuthority).unwrap(),
343 );
344 let expected_result = matches!(
345 expected_instruction,
346 UpgradeableLoaderInstruction::SetAuthority
347 );
348 assert_eq!(expected_result, result);
349
350 let result =
351 is_instruction_fn(&bincode::serialize(&UpgradeableLoaderInstruction::Close).unwrap());
352 let expected_result = matches!(expected_instruction, UpgradeableLoaderInstruction::Close);
353 assert_eq!(expected_result, result);
354 }
355
356 #[test]
357 fn test_is_set_authority_instruction() {
358 assert!(!is_set_authority_instruction(&[]));
359 assert_is_instruction(
360 is_set_authority_instruction,
361 UpgradeableLoaderInstruction::SetAuthority {},
362 );
363 }
364
365 #[test]
366 fn test_is_upgrade_instruction() {
367 assert!(!is_upgrade_instruction(&[]));
368 assert_is_instruction(
369 is_upgrade_instruction,
370 UpgradeableLoaderInstruction::Upgrade {},
371 );
372 }
373}