1use crate::{
19 instruction::{AccountMeta, Instruction, InstructionError},
20 loader_upgradeable_instruction::UpgradeableLoaderInstruction,
21 pubkey::Pubkey,
22 system_instruction, sysvar,
23};
24
25crate::declare_id!("BPFLoaderUpgradeab1e11111111111111111111111");
26
27#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, AbiExample)]
29pub enum UpgradeableLoaderState {
30 Uninitialized,
32 Buffer {
34 authority_address: Option<Pubkey>,
36 },
39 Program {
41 programdata_address: Pubkey,
43 },
44 ProgramData {
46 slot: u64,
48 upgrade_authority_address: Option<Pubkey>,
50 },
53}
54impl UpgradeableLoaderState {
55 pub const fn size_of_uninitialized() -> usize {
57 4 }
59
60 pub const fn size_of_buffer_metadata() -> usize {
62 37 }
64
65 pub const fn size_of_programdata_metadata() -> usize {
67 45 }
69
70 pub const fn size_of_program() -> usize {
72 36 }
74
75 pub const fn size_of_buffer(program_len: usize) -> usize {
77 Self::size_of_buffer_metadata().saturating_add(program_len)
78 }
79
80 pub const fn size_of_programdata(program_len: usize) -> usize {
82 Self::size_of_programdata_metadata().saturating_add(program_len)
83 }
84
85 #[deprecated(since = "1.11.0", note = "Please use `size_of_buffer` instead")]
87 pub fn buffer_len(program_len: usize) -> Result<usize, InstructionError> {
88 Ok(Self::size_of_buffer(program_len))
89 }
90
91 #[deprecated(
93 since = "1.11.0",
94 note = "Please use `size_of_buffer_metadata` instead"
95 )]
96 pub fn buffer_data_offset() -> Result<usize, InstructionError> {
97 Ok(Self::size_of_buffer_metadata())
98 }
99
100 #[deprecated(since = "1.11.0", note = "Please use `size_of_program` instead")]
102 pub fn program_len() -> Result<usize, InstructionError> {
103 Ok(Self::size_of_program())
104 }
105
106 #[deprecated(since = "1.11.0", note = "Please use `size_of_programdata` instead")]
108 pub fn programdata_len(program_len: usize) -> Result<usize, InstructionError> {
109 Ok(Self::size_of_programdata(program_len))
110 }
111
112 #[deprecated(
114 since = "1.11.0",
115 note = "Please use `size_of_programdata_metadata` instead"
116 )]
117 pub fn programdata_data_offset() -> Result<usize, InstructionError> {
118 Ok(Self::size_of_programdata_metadata())
119 }
120}
121
122pub fn get_program_data_address(program_address: &Pubkey) -> Pubkey {
124 Pubkey::find_program_address(&[program_address.as_ref()], &id()).0
125}
126
127pub fn create_buffer(
129 payer_address: &Pubkey,
130 buffer_address: &Pubkey,
131 authority_address: &Pubkey,
132 lamports: u64,
133 program_len: usize,
134) -> Result<Vec<Instruction>, InstructionError> {
135 Ok(vec![
136 system_instruction::create_account(
137 payer_address,
138 buffer_address,
139 lamports,
140 UpgradeableLoaderState::size_of_buffer(program_len) as u64,
141 &id(),
142 ),
143 Instruction::new_with_bincode(
144 id(),
145 &UpgradeableLoaderInstruction::InitializeBuffer,
146 vec![
147 AccountMeta::new(*buffer_address, false),
148 AccountMeta::new_readonly(*authority_address, false),
149 ],
150 ),
151 ])
152}
153
154pub fn write(
157 buffer_address: &Pubkey,
158 authority_address: &Pubkey,
159 offset: u32,
160 bytes: Vec<u8>,
161) -> Instruction {
162 Instruction::new_with_bincode(
163 id(),
164 &UpgradeableLoaderInstruction::Write { offset, bytes },
165 vec![
166 AccountMeta::new(*buffer_address, false),
167 AccountMeta::new_readonly(*authority_address, true),
168 ],
169 )
170}
171
172pub fn deploy_with_max_program_len(
176 payer_address: &Pubkey,
177 program_address: &Pubkey,
178 buffer_address: &Pubkey,
179 upgrade_authority_address: &Pubkey,
180 program_lamports: u64,
181 max_data_len: usize,
182) -> Result<Vec<Instruction>, InstructionError> {
183 let programdata_address = get_program_data_address(program_address);
184 Ok(vec![
185 system_instruction::create_account(
186 payer_address,
187 program_address,
188 program_lamports,
189 UpgradeableLoaderState::size_of_program() as u64,
190 &id(),
191 ),
192 Instruction::new_with_bincode(
193 id(),
194 &UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len },
195 vec![
196 AccountMeta::new(*payer_address, true),
197 AccountMeta::new(programdata_address, false),
198 AccountMeta::new(*program_address, false),
199 AccountMeta::new(*buffer_address, false),
200 AccountMeta::new_readonly(sysvar::rent::id(), false),
201 AccountMeta::new_readonly(sysvar::clock::id(), false),
202 AccountMeta::new_readonly(crate::system_program::id(), false),
203 AccountMeta::new_readonly(*upgrade_authority_address, true),
204 ],
205 ),
206 ])
207}
208
209pub fn upgrade(
211 program_address: &Pubkey,
212 buffer_address: &Pubkey,
213 authority_address: &Pubkey,
214 spill_address: &Pubkey,
215) -> Instruction {
216 let programdata_address = get_program_data_address(program_address);
217 Instruction::new_with_bincode(
218 id(),
219 &UpgradeableLoaderInstruction::Upgrade,
220 vec![
221 AccountMeta::new(programdata_address, false),
222 AccountMeta::new(*program_address, false),
223 AccountMeta::new(*buffer_address, false),
224 AccountMeta::new(*spill_address, false),
225 AccountMeta::new_readonly(sysvar::rent::id(), false),
226 AccountMeta::new_readonly(sysvar::clock::id(), false),
227 AccountMeta::new_readonly(*authority_address, true),
228 ],
229 )
230}
231
232pub fn is_upgrade_instruction(instruction_data: &[u8]) -> bool {
233 !instruction_data.is_empty() && 3 == instruction_data[0]
234}
235
236pub fn is_set_authority_instruction(instruction_data: &[u8]) -> bool {
237 !instruction_data.is_empty() && 4 == instruction_data[0]
238}
239
240pub fn is_close_instruction(instruction_data: &[u8]) -> bool {
241 !instruction_data.is_empty() && 5 == instruction_data[0]
242}
243
244pub fn is_set_authority_checked_instruction(instruction_data: &[u8]) -> bool {
245 !instruction_data.is_empty() && 7 == instruction_data[0]
246}
247
248pub fn set_buffer_authority(
250 buffer_address: &Pubkey,
251 current_authority_address: &Pubkey,
252 new_authority_address: &Pubkey,
253) -> Instruction {
254 Instruction::new_with_bincode(
255 id(),
256 &UpgradeableLoaderInstruction::SetAuthority,
257 vec![
258 AccountMeta::new(*buffer_address, false),
259 AccountMeta::new_readonly(*current_authority_address, true),
260 AccountMeta::new_readonly(*new_authority_address, false),
261 ],
262 )
263}
264
265pub fn set_buffer_authority_checked(
268 buffer_address: &Pubkey,
269 current_authority_address: &Pubkey,
270 new_authority_address: &Pubkey,
271) -> Instruction {
272 Instruction::new_with_bincode(
273 id(),
274 &UpgradeableLoaderInstruction::SetAuthorityChecked,
275 vec![
276 AccountMeta::new(*buffer_address, false),
277 AccountMeta::new_readonly(*current_authority_address, true),
278 AccountMeta::new_readonly(*new_authority_address, true),
279 ],
280 )
281}
282
283pub fn set_upgrade_authority(
285 program_address: &Pubkey,
286 current_authority_address: &Pubkey,
287 new_authority_address: Option<&Pubkey>,
288) -> Instruction {
289 let programdata_address = get_program_data_address(program_address);
290
291 let mut metas = vec![
292 AccountMeta::new(programdata_address, false),
293 AccountMeta::new_readonly(*current_authority_address, true),
294 ];
295 if let Some(address) = new_authority_address {
296 metas.push(AccountMeta::new_readonly(*address, false));
297 }
298 Instruction::new_with_bincode(id(), &UpgradeableLoaderInstruction::SetAuthority, metas)
299}
300
301pub fn set_upgrade_authority_checked(
304 program_address: &Pubkey,
305 current_authority_address: &Pubkey,
306 new_authority_address: &Pubkey,
307) -> Instruction {
308 let programdata_address = get_program_data_address(program_address);
309
310 let metas = vec![
311 AccountMeta::new(programdata_address, false),
312 AccountMeta::new_readonly(*current_authority_address, true),
313 AccountMeta::new_readonly(*new_authority_address, true),
314 ];
315 Instruction::new_with_bincode(
316 id(),
317 &UpgradeableLoaderInstruction::SetAuthorityChecked,
318 metas,
319 )
320}
321
322pub fn close(
324 close_address: &Pubkey,
325 recipient_address: &Pubkey,
326 authority_address: &Pubkey,
327) -> Instruction {
328 close_any(
329 close_address,
330 recipient_address,
331 Some(authority_address),
332 None,
333 )
334}
335
336pub fn close_any(
338 close_address: &Pubkey,
339 recipient_address: &Pubkey,
340 authority_address: Option<&Pubkey>,
341 program_address: Option<&Pubkey>,
342) -> Instruction {
343 let mut metas = vec![
344 AccountMeta::new(*close_address, false),
345 AccountMeta::new(*recipient_address, false),
346 ];
347 if let Some(authority_address) = authority_address {
348 metas.push(AccountMeta::new_readonly(*authority_address, true));
349 }
350 if let Some(program_address) = program_address {
351 metas.push(AccountMeta::new(*program_address, false));
352 }
353 Instruction::new_with_bincode(id(), &UpgradeableLoaderInstruction::Close, metas)
354}
355
356pub fn extend_program(
359 program_address: &Pubkey,
360 payer_address: Option<&Pubkey>,
361 additional_bytes: u32,
362) -> Instruction {
363 let program_data_address = get_program_data_address(program_address);
364 let mut metas = vec![
365 AccountMeta::new(program_data_address, false),
366 AccountMeta::new(*program_address, false),
367 ];
368 if let Some(payer_address) = payer_address {
369 metas.push(AccountMeta::new_readonly(
370 crate::system_program::id(),
371 false,
372 ));
373 metas.push(AccountMeta::new(*payer_address, true));
374 }
375 Instruction::new_with_bincode(
376 id(),
377 &UpgradeableLoaderInstruction::ExtendProgram { additional_bytes },
378 metas,
379 )
380}
381
382#[cfg(test)]
383mod tests {
384 use {super::*, bincode::serialized_size};
385
386 #[test]
387 fn test_state_size_of_uninitialized() {
388 let buffer_state = UpgradeableLoaderState::Uninitialized;
389 let size = serialized_size(&buffer_state).unwrap();
390 assert_eq!(UpgradeableLoaderState::size_of_uninitialized() as u64, size);
391 }
392
393 #[test]
394 fn test_state_size_of_buffer_metadata() {
395 let buffer_state = UpgradeableLoaderState::Buffer {
396 authority_address: Some(Pubkey::default()),
397 };
398 let size = serialized_size(&buffer_state).unwrap();
399 assert_eq!(
400 UpgradeableLoaderState::size_of_buffer_metadata() as u64,
401 size
402 );
403 }
404
405 #[test]
406 fn test_state_size_of_programdata_metadata() {
407 let programdata_state = UpgradeableLoaderState::ProgramData {
408 upgrade_authority_address: Some(Pubkey::default()),
409 slot: 0,
410 };
411 let size = serialized_size(&programdata_state).unwrap();
412 assert_eq!(
413 UpgradeableLoaderState::size_of_programdata_metadata() as u64,
414 size
415 );
416 }
417
418 #[test]
419 fn test_state_size_of_program() {
420 let program_state = UpgradeableLoaderState::Program {
421 programdata_address: Pubkey::default(),
422 };
423 let size = serialized_size(&program_state).unwrap();
424 assert_eq!(UpgradeableLoaderState::size_of_program() as u64, size);
425 }
426
427 #[test]
428 #[allow(deprecated)]
429 fn test_account_lengths() {
430 assert_eq!(
431 4,
432 serialized_size(&UpgradeableLoaderState::Uninitialized).unwrap()
433 );
434 assert_eq!(36, UpgradeableLoaderState::program_len().unwrap());
435 assert_eq!(
436 45,
437 UpgradeableLoaderState::programdata_data_offset().unwrap()
438 );
439 assert_eq!(
440 45 + 42,
441 UpgradeableLoaderState::programdata_len(42).unwrap()
442 );
443 }
444
445 fn assert_is_instruction<F>(
446 is_instruction_fn: F,
447 expected_instruction: UpgradeableLoaderInstruction,
448 ) where
449 F: Fn(&[u8]) -> bool,
450 {
451 let result = is_instruction_fn(
452 &bincode::serialize(&UpgradeableLoaderInstruction::InitializeBuffer).unwrap(),
453 );
454 let expected_result = matches!(
455 expected_instruction,
456 UpgradeableLoaderInstruction::InitializeBuffer
457 );
458 assert_eq!(expected_result, result);
459
460 let result = is_instruction_fn(
461 &bincode::serialize(&UpgradeableLoaderInstruction::Write {
462 offset: 0,
463 bytes: vec![],
464 })
465 .unwrap(),
466 );
467 let expected_result = matches!(
468 expected_instruction,
469 UpgradeableLoaderInstruction::Write {
470 offset: _,
471 bytes: _,
472 }
473 );
474 assert_eq!(expected_result, result);
475
476 let result = is_instruction_fn(
477 &bincode::serialize(&UpgradeableLoaderInstruction::DeployWithMaxDataLen {
478 max_data_len: 0,
479 })
480 .unwrap(),
481 );
482 let expected_result = matches!(
483 expected_instruction,
484 UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len: _ }
485 );
486 assert_eq!(expected_result, result);
487
488 let result =
489 is_instruction_fn(&bincode::serialize(&UpgradeableLoaderInstruction::Upgrade).unwrap());
490 let expected_result = matches!(expected_instruction, UpgradeableLoaderInstruction::Upgrade);
491 assert_eq!(expected_result, result);
492
493 let result = is_instruction_fn(
494 &bincode::serialize(&UpgradeableLoaderInstruction::SetAuthority).unwrap(),
495 );
496 let expected_result = matches!(
497 expected_instruction,
498 UpgradeableLoaderInstruction::SetAuthority
499 );
500 assert_eq!(expected_result, result);
501
502 let result =
503 is_instruction_fn(&bincode::serialize(&UpgradeableLoaderInstruction::Close).unwrap());
504 let expected_result = matches!(expected_instruction, UpgradeableLoaderInstruction::Close);
505 assert_eq!(expected_result, result);
506 }
507
508 #[test]
509 fn test_is_set_authority_instruction() {
510 assert!(!is_set_authority_instruction(&[]));
511 assert_is_instruction(
512 is_set_authority_instruction,
513 UpgradeableLoaderInstruction::SetAuthority {},
514 );
515 }
516
517 #[test]
518 fn test_is_set_authority_checked_instruction() {
519 assert!(!is_set_authority_checked_instruction(&[]));
520 assert_is_instruction(
521 is_set_authority_checked_instruction,
522 UpgradeableLoaderInstruction::SetAuthorityChecked {},
523 );
524 }
525
526 #[test]
527 fn test_is_upgrade_instruction() {
528 assert!(!is_upgrade_instruction(&[]));
529 assert_is_instruction(
530 is_upgrade_instruction,
531 UpgradeableLoaderInstruction::Upgrade {},
532 );
533 }
534}