1#[cfg(feature = "bincode")]
4use {
5 crate::{get_program_data_address, state::UpgradeableLoaderState},
6 solana_instruction::{error::InstructionError, AccountMeta, Instruction},
7 solana_pubkey::Pubkey,
8 solana_sdk_ids::{bpf_loader_upgradeable::id, loader_v4, sysvar},
9 solana_system_interface::instruction as system_instruction,
10};
11
12#[repr(u8)]
13#[cfg_attr(
14 feature = "serde",
15 derive(serde_derive::Deserialize, serde_derive::Serialize)
16)]
17#[derive(Debug, PartialEq, Eq, Clone)]
18pub enum UpgradeableLoaderInstruction {
19 InitializeBuffer,
35
36 Write {
42 offset: u32,
44 #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
46 bytes: Vec<u8>,
47 },
48
49 DeployWithMaxDataLen {
91 max_data_len: usize,
93 },
94
95 Upgrade,
116
117 SetAuthority,
128
129 Close,
141
142 ExtendProgram {
158 additional_bytes: u32,
160 },
161
162 SetAuthorityChecked,
174
175 Migrate,
182
183 ExtendProgramChecked {
198 additional_bytes: u32,
200 },
201}
202
203#[cfg(feature = "bincode")]
204pub fn create_buffer(
206 payer_address: &Pubkey,
207 buffer_address: &Pubkey,
208 authority_address: &Pubkey,
209 lamports: u64,
210 program_len: usize,
211) -> Result<Vec<Instruction>, InstructionError> {
212 Ok(vec![
213 system_instruction::create_account(
214 payer_address,
215 buffer_address,
216 lamports,
217 UpgradeableLoaderState::size_of_buffer(program_len) as u64,
218 &id(),
219 ),
220 Instruction::new_with_bincode(
221 id(),
222 &UpgradeableLoaderInstruction::InitializeBuffer,
223 vec![
224 AccountMeta::new(*buffer_address, false),
225 AccountMeta::new_readonly(*authority_address, false),
226 ],
227 ),
228 ])
229}
230
231#[cfg(feature = "bincode")]
232pub fn write(
235 buffer_address: &Pubkey,
236 authority_address: &Pubkey,
237 offset: u32,
238 bytes: Vec<u8>,
239) -> Instruction {
240 Instruction::new_with_bincode(
241 id(),
242 &UpgradeableLoaderInstruction::Write { offset, bytes },
243 vec![
244 AccountMeta::new(*buffer_address, false),
245 AccountMeta::new_readonly(*authority_address, true),
246 ],
247 )
248}
249
250#[deprecated(since = "2.2.0", note = "Use loader-v4 instead")]
251#[cfg(feature = "bincode")]
252pub fn deploy_with_max_program_len(
256 payer_address: &Pubkey,
257 program_address: &Pubkey,
258 buffer_address: &Pubkey,
259 upgrade_authority_address: &Pubkey,
260 program_lamports: u64,
261 max_data_len: usize,
262) -> Result<Vec<Instruction>, InstructionError> {
263 let programdata_address = get_program_data_address(program_address);
264 Ok(vec![
265 system_instruction::create_account(
266 payer_address,
267 program_address,
268 program_lamports,
269 UpgradeableLoaderState::size_of_program() as u64,
270 &id(),
271 ),
272 Instruction::new_with_bincode(
273 id(),
274 &UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len },
275 vec![
276 AccountMeta::new(*payer_address, true),
277 AccountMeta::new(programdata_address, false),
278 AccountMeta::new(*program_address, false),
279 AccountMeta::new(*buffer_address, false),
280 AccountMeta::new_readonly(sysvar::rent::id(), false),
281 AccountMeta::new_readonly(sysvar::clock::id(), false),
282 AccountMeta::new_readonly(solana_sdk_ids::system_program::id(), false),
283 AccountMeta::new_readonly(*upgrade_authority_address, true),
284 ],
285 ),
286 ])
287}
288
289#[cfg(feature = "bincode")]
290pub fn upgrade(
292 program_address: &Pubkey,
293 buffer_address: &Pubkey,
294 authority_address: &Pubkey,
295 spill_address: &Pubkey,
296) -> Instruction {
297 let programdata_address = get_program_data_address(program_address);
298 Instruction::new_with_bincode(
299 id(),
300 &UpgradeableLoaderInstruction::Upgrade,
301 vec![
302 AccountMeta::new(programdata_address, false),
303 AccountMeta::new(*program_address, false),
304 AccountMeta::new(*buffer_address, false),
305 AccountMeta::new(*spill_address, false),
306 AccountMeta::new_readonly(sysvar::rent::id(), false),
307 AccountMeta::new_readonly(sysvar::clock::id(), false),
308 AccountMeta::new_readonly(*authority_address, true),
309 ],
310 )
311}
312
313pub fn is_upgrade_instruction(instruction_data: &[u8]) -> bool {
314 !instruction_data.is_empty() && 3 == instruction_data[0]
315}
316
317pub fn is_set_authority_instruction(instruction_data: &[u8]) -> bool {
318 !instruction_data.is_empty() && 4 == instruction_data[0]
319}
320
321pub fn is_close_instruction(instruction_data: &[u8]) -> bool {
322 !instruction_data.is_empty() && 5 == instruction_data[0]
323}
324
325pub fn is_set_authority_checked_instruction(instruction_data: &[u8]) -> bool {
326 !instruction_data.is_empty() && 7 == instruction_data[0]
327}
328
329pub fn is_migrate_instruction(instruction_data: &[u8]) -> bool {
330 !instruction_data.is_empty() && 8 == instruction_data[0]
331}
332
333pub fn is_extend_program_checked_instruction(instruction_data: &[u8]) -> bool {
334 !instruction_data.is_empty() && 9 == instruction_data[0]
335}
336
337#[cfg(feature = "bincode")]
338pub fn set_buffer_authority(
340 buffer_address: &Pubkey,
341 current_authority_address: &Pubkey,
342 new_authority_address: &Pubkey,
343) -> Instruction {
344 Instruction::new_with_bincode(
345 id(),
346 &UpgradeableLoaderInstruction::SetAuthority,
347 vec![
348 AccountMeta::new(*buffer_address, false),
349 AccountMeta::new_readonly(*current_authority_address, true),
350 AccountMeta::new_readonly(*new_authority_address, false),
351 ],
352 )
353}
354
355#[cfg(feature = "bincode")]
356pub fn set_buffer_authority_checked(
359 buffer_address: &Pubkey,
360 current_authority_address: &Pubkey,
361 new_authority_address: &Pubkey,
362) -> Instruction {
363 Instruction::new_with_bincode(
364 id(),
365 &UpgradeableLoaderInstruction::SetAuthorityChecked,
366 vec![
367 AccountMeta::new(*buffer_address, false),
368 AccountMeta::new_readonly(*current_authority_address, true),
369 AccountMeta::new_readonly(*new_authority_address, true),
370 ],
371 )
372}
373
374#[cfg(feature = "bincode")]
375pub fn set_upgrade_authority(
377 program_address: &Pubkey,
378 current_authority_address: &Pubkey,
379 new_authority_address: Option<&Pubkey>,
380) -> Instruction {
381 let programdata_address = get_program_data_address(program_address);
382
383 let mut metas = vec![
384 AccountMeta::new(programdata_address, false),
385 AccountMeta::new_readonly(*current_authority_address, true),
386 ];
387 if let Some(address) = new_authority_address {
388 metas.push(AccountMeta::new_readonly(*address, false));
389 }
390 Instruction::new_with_bincode(id(), &UpgradeableLoaderInstruction::SetAuthority, metas)
391}
392
393#[cfg(feature = "bincode")]
394pub fn set_upgrade_authority_checked(
397 program_address: &Pubkey,
398 current_authority_address: &Pubkey,
399 new_authority_address: &Pubkey,
400) -> Instruction {
401 let programdata_address = get_program_data_address(program_address);
402
403 let metas = vec![
404 AccountMeta::new(programdata_address, false),
405 AccountMeta::new_readonly(*current_authority_address, true),
406 AccountMeta::new_readonly(*new_authority_address, true),
407 ];
408 Instruction::new_with_bincode(
409 id(),
410 &UpgradeableLoaderInstruction::SetAuthorityChecked,
411 metas,
412 )
413}
414
415#[cfg(feature = "bincode")]
416pub fn close(
418 close_address: &Pubkey,
419 recipient_address: &Pubkey,
420 authority_address: &Pubkey,
421) -> Instruction {
422 close_any(
423 close_address,
424 recipient_address,
425 Some(authority_address),
426 None,
427 )
428}
429
430#[cfg(feature = "bincode")]
431pub fn close_any(
433 close_address: &Pubkey,
434 recipient_address: &Pubkey,
435 authority_address: Option<&Pubkey>,
436 program_address: Option<&Pubkey>,
437) -> Instruction {
438 let mut metas = vec![
439 AccountMeta::new(*close_address, false),
440 AccountMeta::new(*recipient_address, false),
441 ];
442 if let Some(authority_address) = authority_address {
443 metas.push(AccountMeta::new_readonly(*authority_address, true));
444 }
445 if let Some(program_address) = program_address {
446 metas.push(AccountMeta::new(*program_address, false));
447 }
448 Instruction::new_with_bincode(id(), &UpgradeableLoaderInstruction::Close, metas)
449}
450
451#[cfg(feature = "bincode")]
452pub fn extend_program(
455 program_address: &Pubkey,
456 payer_address: Option<&Pubkey>,
457 additional_bytes: u32,
458) -> Instruction {
459 let program_data_address = get_program_data_address(program_address);
460 let mut metas = vec![
461 AccountMeta::new(program_data_address, false),
462 AccountMeta::new(*program_address, false),
463 ];
464 if let Some(payer_address) = payer_address {
465 metas.push(AccountMeta::new_readonly(
466 solana_sdk_ids::system_program::id(),
467 false,
468 ));
469 metas.push(AccountMeta::new(*payer_address, true));
470 }
471 Instruction::new_with_bincode(
472 id(),
473 &UpgradeableLoaderInstruction::ExtendProgram { additional_bytes },
474 metas,
475 )
476}
477
478#[cfg(feature = "bincode")]
480pub fn migrate_program(
481 programdata_address: &Pubkey,
482 program_address: &Pubkey,
483 authority: &Pubkey,
484) -> Instruction {
485 let accounts = vec![
486 AccountMeta::new(*programdata_address, false),
487 AccountMeta::new(*program_address, false),
488 AccountMeta::new_readonly(*authority, true),
489 AccountMeta::new_readonly(loader_v4::id(), false),
490 ];
491
492 Instruction::new_with_bincode(id(), &UpgradeableLoaderInstruction::Migrate, accounts)
493}
494
495#[cfg(feature = "bincode")]
498pub fn extend_program_checked(
499 program_address: &Pubkey,
500 authority_address: &Pubkey,
501 payer_address: Option<&Pubkey>,
502 additional_bytes: u32,
503) -> Instruction {
504 let program_data_address = get_program_data_address(program_address);
505 let mut metas = vec![
506 AccountMeta::new(program_data_address, false),
507 AccountMeta::new(*program_address, false),
508 AccountMeta::new(*authority_address, true),
509 ];
510 if let Some(payer_address) = payer_address {
511 metas.push(AccountMeta::new_readonly(
512 solana_sdk_ids::system_program::id(),
513 false,
514 ));
515 metas.push(AccountMeta::new(*payer_address, true));
516 }
517 Instruction::new_with_bincode(
518 id(),
519 &UpgradeableLoaderInstruction::ExtendProgramChecked { additional_bytes },
520 metas,
521 )
522}
523
524#[cfg(test)]
525mod tests {
526 use super::*;
527
528 fn assert_is_instruction<F>(
529 is_instruction_fn: F,
530 expected_instruction: UpgradeableLoaderInstruction,
531 ) where
532 F: Fn(&[u8]) -> bool,
533 {
534 let result = is_instruction_fn(
535 &bincode::serialize(&UpgradeableLoaderInstruction::InitializeBuffer).unwrap(),
536 );
537 let expected_result = matches!(
538 expected_instruction,
539 UpgradeableLoaderInstruction::InitializeBuffer
540 );
541 assert_eq!(expected_result, result);
542
543 let result = is_instruction_fn(
544 &bincode::serialize(&UpgradeableLoaderInstruction::Write {
545 offset: 0,
546 bytes: vec![],
547 })
548 .unwrap(),
549 );
550 let expected_result = matches!(
551 expected_instruction,
552 UpgradeableLoaderInstruction::Write {
553 offset: _,
554 bytes: _,
555 }
556 );
557 assert_eq!(expected_result, result);
558
559 let result = is_instruction_fn(
560 &bincode::serialize(&UpgradeableLoaderInstruction::DeployWithMaxDataLen {
561 max_data_len: 0,
562 })
563 .unwrap(),
564 );
565 let expected_result = matches!(
566 expected_instruction,
567 UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len: _ }
568 );
569 assert_eq!(expected_result, result);
570
571 let result =
572 is_instruction_fn(&bincode::serialize(&UpgradeableLoaderInstruction::Upgrade).unwrap());
573 let expected_result = matches!(expected_instruction, UpgradeableLoaderInstruction::Upgrade);
574 assert_eq!(expected_result, result);
575
576 let result = is_instruction_fn(
577 &bincode::serialize(&UpgradeableLoaderInstruction::SetAuthority).unwrap(),
578 );
579 let expected_result = matches!(
580 expected_instruction,
581 UpgradeableLoaderInstruction::SetAuthority
582 );
583 assert_eq!(expected_result, result);
584
585 let result =
586 is_instruction_fn(&bincode::serialize(&UpgradeableLoaderInstruction::Close).unwrap());
587 let expected_result = matches!(expected_instruction, UpgradeableLoaderInstruction::Close);
588 assert_eq!(expected_result, result);
589 }
590
591 #[test]
592 fn test_is_set_authority_instruction() {
593 assert!(!is_set_authority_instruction(&[]));
594 assert_is_instruction(
595 is_set_authority_instruction,
596 UpgradeableLoaderInstruction::SetAuthority {},
597 );
598 }
599
600 #[test]
601 fn test_is_set_authority_checked_instruction() {
602 assert!(!is_set_authority_checked_instruction(&[]));
603 assert_is_instruction(
604 is_set_authority_checked_instruction,
605 UpgradeableLoaderInstruction::SetAuthorityChecked {},
606 );
607 }
608
609 #[test]
610 fn test_is_upgrade_instruction() {
611 assert!(!is_upgrade_instruction(&[]));
612 assert_is_instruction(
613 is_upgrade_instruction,
614 UpgradeableLoaderInstruction::Upgrade {},
615 );
616 }
617
618 #[test]
619 fn test_is_migrate_instruction() {
620 assert!(!is_migrate_instruction(&[]));
621 assert_is_instruction(
622 is_migrate_instruction,
623 UpgradeableLoaderInstruction::Migrate {},
624 );
625 }
626
627 #[test]
628 fn test_is_extend_program_checked_instruction() {
629 assert!(!is_extend_program_checked_instruction(&[]));
630 assert_is_instruction(
631 is_extend_program_checked_instruction,
632 UpgradeableLoaderInstruction::ExtendProgramChecked {
633 additional_bytes: 0,
634 },
635 );
636 }
637}