1use {
2 crate::parse_instruction::{
3 check_num_accounts, ParsableProgram, ParseInstructionError, ParsedInstructionEnum,
4 },
5 base64::{prelude::BASE64_STANDARD, Engine},
6 bincode::deserialize,
7 serde_json::json,
8 solana_loader_v2_interface::LoaderInstruction,
9 solana_loader_v3_interface::instruction::UpgradeableLoaderInstruction,
10 solana_message::{compiled_instruction::CompiledInstruction, AccountKeys},
11};
12
13pub fn parse_bpf_loader(
14 instruction: &CompiledInstruction,
15 account_keys: &AccountKeys,
16) -> Result<ParsedInstructionEnum, ParseInstructionError> {
17 let bpf_loader_instruction: LoaderInstruction = deserialize(&instruction.data)
18 .map_err(|_| ParseInstructionError::InstructionNotParsable(ParsableProgram::BpfLoader))?;
19 if instruction.accounts.is_empty() || instruction.accounts[0] as usize >= account_keys.len() {
20 return Err(ParseInstructionError::InstructionKeyMismatch(
21 ParsableProgram::BpfLoader,
22 ));
23 }
24 match bpf_loader_instruction {
25 LoaderInstruction::Write { offset, bytes } => {
26 check_num_bpf_loader_accounts(&instruction.accounts, 1)?;
27 Ok(ParsedInstructionEnum {
28 instruction_type: "write".to_string(),
29 info: json!({
30 "offset": offset,
31 "bytes": BASE64_STANDARD.encode(bytes),
32 "account": account_keys[instruction.accounts[0] as usize].to_string(),
33 }),
34 })
35 }
36 LoaderInstruction::Finalize => {
37 check_num_bpf_loader_accounts(&instruction.accounts, 2)?;
38 Ok(ParsedInstructionEnum {
39 instruction_type: "finalize".to_string(),
40 info: json!({
41 "account": account_keys[instruction.accounts[0] as usize].to_string(),
42 }),
43 })
44 }
45 }
46}
47
48pub fn parse_bpf_upgradeable_loader(
49 instruction: &CompiledInstruction,
50 account_keys: &AccountKeys,
51) -> Result<ParsedInstructionEnum, ParseInstructionError> {
52 let bpf_upgradeable_loader_instruction: UpgradeableLoaderInstruction =
53 deserialize(&instruction.data).map_err(|_| {
54 ParseInstructionError::InstructionNotParsable(ParsableProgram::BpfUpgradeableLoader)
55 })?;
56 match instruction.accounts.iter().max() {
57 Some(index) if (*index as usize) < account_keys.len() => {}
58 _ => {
59 return Err(ParseInstructionError::InstructionKeyMismatch(
61 ParsableProgram::BpfUpgradeableLoader,
62 ));
63 }
64 }
65 match bpf_upgradeable_loader_instruction {
66 UpgradeableLoaderInstruction::InitializeBuffer => {
67 check_num_bpf_upgradeable_loader_accounts(&instruction.accounts, 1)?;
68 let mut value = json!({
69 "account": account_keys[instruction.accounts[0] as usize].to_string(),
70 });
71 let map = value.as_object_mut().unwrap();
72 if instruction.accounts.len() > 1 {
73 map.insert(
74 "authority".to_string(),
75 json!(account_keys[instruction.accounts[1] as usize].to_string()),
76 );
77 }
78 Ok(ParsedInstructionEnum {
79 instruction_type: "initializeBuffer".to_string(),
80 info: value,
81 })
82 }
83 UpgradeableLoaderInstruction::Write { offset, bytes } => {
84 check_num_bpf_upgradeable_loader_accounts(&instruction.accounts, 2)?;
85 Ok(ParsedInstructionEnum {
86 instruction_type: "write".to_string(),
87 info: json!({
88 "offset": offset,
89 "bytes": BASE64_STANDARD.encode(bytes),
90 "account": account_keys[instruction.accounts[0] as usize].to_string(),
91 "authority": account_keys[instruction.accounts[1] as usize].to_string(),
92 }),
93 })
94 }
95 UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len } => {
96 check_num_bpf_upgradeable_loader_accounts(&instruction.accounts, 8)?;
97 Ok(ParsedInstructionEnum {
98 instruction_type: "deployWithMaxDataLen".to_string(),
99 info: json!({
100 "maxDataLen": max_data_len,
101 "payerAccount": account_keys[instruction.accounts[0] as usize].to_string(),
102 "programDataAccount": account_keys[instruction.accounts[1] as usize].to_string(),
103 "programAccount": account_keys[instruction.accounts[2] as usize].to_string(),
104 "bufferAccount": account_keys[instruction.accounts[3] as usize].to_string(),
105 "rentSysvar": account_keys[instruction.accounts[4] as usize].to_string(),
106 "clockSysvar": account_keys[instruction.accounts[5] as usize].to_string(),
107 "systemProgram": account_keys[instruction.accounts[6] as usize].to_string(),
108 "authority": account_keys[instruction.accounts[7] as usize].to_string(),
109 }),
110 })
111 }
112 UpgradeableLoaderInstruction::Upgrade => {
113 check_num_bpf_upgradeable_loader_accounts(&instruction.accounts, 7)?;
114 Ok(ParsedInstructionEnum {
115 instruction_type: "upgrade".to_string(),
116 info: json!({
117 "programDataAccount": account_keys[instruction.accounts[0] as usize].to_string(),
118 "programAccount": account_keys[instruction.accounts[1] as usize].to_string(),
119 "bufferAccount": account_keys[instruction.accounts[2] as usize].to_string(),
120 "spillAccount": account_keys[instruction.accounts[3] as usize].to_string(),
121 "rentSysvar": account_keys[instruction.accounts[4] as usize].to_string(),
122 "clockSysvar": account_keys[instruction.accounts[5] as usize].to_string(),
123 "authority": account_keys[instruction.accounts[6] as usize].to_string(),
124 }),
125 })
126 }
127 UpgradeableLoaderInstruction::SetAuthority => {
128 check_num_bpf_upgradeable_loader_accounts(&instruction.accounts, 2)?;
129 Ok(ParsedInstructionEnum {
130 instruction_type: "setAuthority".to_string(),
131 info: json!({
132 "account": account_keys[instruction.accounts[0] as usize].to_string(),
133 "authority": account_keys[instruction.accounts[1] as usize].to_string(),
134 "newAuthority": if instruction.accounts.len() > 2 {
135 Some(account_keys[instruction.accounts[2] as usize].to_string())
136 } else {
137 None
138 },
139 }),
140 })
141 }
142 UpgradeableLoaderInstruction::SetAuthorityChecked => {
143 check_num_bpf_upgradeable_loader_accounts(&instruction.accounts, 3)?;
144 Ok(ParsedInstructionEnum {
145 instruction_type: "setAuthorityChecked".to_string(),
146 info: json!({
147 "account": account_keys[instruction.accounts[0] as usize].to_string(),
148 "authority": account_keys[instruction.accounts[1] as usize].to_string(),
149 "newAuthority": account_keys[instruction.accounts[2] as usize].to_string(),
150 }),
151 })
152 }
153 UpgradeableLoaderInstruction::Close => {
154 check_num_bpf_upgradeable_loader_accounts(&instruction.accounts, 3)?;
155 Ok(ParsedInstructionEnum {
156 instruction_type: "close".to_string(),
157 info: json!({
158 "account": account_keys[instruction.accounts[0] as usize].to_string(),
159 "recipient": account_keys[instruction.accounts[1] as usize].to_string(),
160 "authority": account_keys[instruction.accounts[2] as usize].to_string(),
161 "programAccount": if instruction.accounts.len() > 3 {
162 Some(account_keys[instruction.accounts[3] as usize].to_string())
163 } else {
164 None
165 }
166 }),
167 })
168 }
169 UpgradeableLoaderInstruction::ExtendProgram { additional_bytes } => {
170 check_num_bpf_upgradeable_loader_accounts(&instruction.accounts, 2)?;
171 Ok(ParsedInstructionEnum {
172 instruction_type: "extendProgram".to_string(),
173 info: json!({
174 "additionalBytes": additional_bytes,
175 "programDataAccount": account_keys[instruction.accounts[0] as usize].to_string(),
176 "programAccount": account_keys[instruction.accounts[1] as usize].to_string(),
177 "systemProgram": if instruction.accounts.len() > 2 {
178 Some(account_keys[instruction.accounts[2] as usize].to_string())
179 } else {
180 None
181 },
182 "payerAccount": if instruction.accounts.len() > 3 {
183 Some(account_keys[instruction.accounts[3] as usize].to_string())
184 } else {
185 None
186 },
187 }),
188 })
189 }
190 UpgradeableLoaderInstruction::Migrate => {
191 check_num_bpf_upgradeable_loader_accounts(&instruction.accounts, 3)?;
192 Ok(ParsedInstructionEnum {
193 instruction_type: "migrate".to_string(),
194 info: json!({
195 "programDataAccount": account_keys[instruction.accounts[0] as usize].to_string(),
196 "programAccount": account_keys[instruction.accounts[1] as usize].to_string(),
197 "authority": account_keys[instruction.accounts[2] as usize].to_string(),
198 }),
199 })
200 }
201 UpgradeableLoaderInstruction::ExtendProgramChecked { additional_bytes } => {
202 check_num_bpf_upgradeable_loader_accounts(&instruction.accounts, 3)?;
203 Ok(ParsedInstructionEnum {
204 instruction_type: "extendProgramChecked".to_string(),
205 info: json!({
206 "additionalBytes": additional_bytes,
207 "programDataAccount": account_keys[instruction.accounts[0] as usize].to_string(),
208 "programAccount": account_keys[instruction.accounts[1] as usize].to_string(),
209 "authority": account_keys[instruction.accounts[2] as usize].to_string(),
210 "systemProgram": if instruction.accounts.len() > 3 {
211 Some(account_keys[instruction.accounts[3] as usize].to_string())
212 } else {
213 None
214 },
215 "payerAccount": if instruction.accounts.len() > 4 {
216 Some(account_keys[instruction.accounts[4] as usize].to_string())
217 } else {
218 None
219 },
220 }),
221 })
222 }
223 }
224}
225
226fn check_num_bpf_loader_accounts(accounts: &[u8], num: usize) -> Result<(), ParseInstructionError> {
227 check_num_accounts(accounts, num, ParsableProgram::BpfLoader)
228}
229
230fn check_num_bpf_upgradeable_loader_accounts(
231 accounts: &[u8],
232 num: usize,
233) -> Result<(), ParseInstructionError> {
234 check_num_accounts(accounts, num, ParsableProgram::BpfUpgradeableLoader)
235}
236
237#[cfg(test)]
238mod test {
239 use {
240 super::*,
241 serde_json::Value,
242 solana_loader_v3_interface::instruction as bpf_loader_upgradeable,
243 solana_message::Message,
244 solana_pubkey::{self as pubkey, Pubkey},
245 solana_sdk_ids::{system_program, sysvar},
246 };
247
248 #[test]
249 fn test_parse_bpf_loader_instructions() {
250 let account_pubkey = pubkey::new_rand();
251 let program_id = pubkey::new_rand();
252 let offset = 4242;
253 let bytes = vec![8; 99];
254 let fee_payer = pubkey::new_rand();
255 let account_keys = vec![fee_payer, account_pubkey];
256 let missing_account_keys = vec![account_pubkey];
257
258 #[allow(deprecated)]
259 let instruction =
260 solana_loader_v2_interface::write(&account_pubkey, &program_id, offset, bytes.clone());
261 let mut message = Message::new(&[instruction], Some(&fee_payer));
262 assert_eq!(
263 parse_bpf_loader(
264 &message.instructions[0],
265 &AccountKeys::new(&account_keys, None)
266 )
267 .unwrap(),
268 ParsedInstructionEnum {
269 instruction_type: "write".to_string(),
270 info: json!({
271 "offset": offset,
272 "bytes": BASE64_STANDARD.encode(&bytes),
273 "account": account_pubkey.to_string(),
274 }),
275 }
276 );
277 assert!(parse_bpf_loader(
278 &message.instructions[0],
279 &AccountKeys::new(&missing_account_keys, None)
280 )
281 .is_err());
282 message.instructions[0].accounts.pop();
283 assert!(parse_bpf_loader(
284 &message.instructions[0],
285 &AccountKeys::new(&account_keys, None)
286 )
287 .is_err());
288
289 #[allow(deprecated)]
290 let instruction = solana_loader_v2_interface::finalize(&account_pubkey, &program_id);
291 let mut message = Message::new(&[instruction], Some(&fee_payer));
292 assert_eq!(
293 parse_bpf_loader(
294 &message.instructions[0],
295 &AccountKeys::new(&account_keys, None)
296 )
297 .unwrap(),
298 ParsedInstructionEnum {
299 instruction_type: "finalize".to_string(),
300 info: json!({
301 "account": account_pubkey.to_string(),
302 }),
303 }
304 );
305 assert!(parse_bpf_loader(
306 &message.instructions[0],
307 &AccountKeys::new(&missing_account_keys, None)
308 )
309 .is_err());
310 message.instructions[0].accounts.pop();
311 assert!(parse_bpf_loader(
312 &message.instructions[0],
313 &AccountKeys::new(&account_keys, None)
314 )
315 .is_err());
316
317 let bad_compiled_instruction = CompiledInstruction {
318 program_id_index: 3,
319 accounts: vec![1, 2],
320 data: vec![2, 0, 0, 0], };
322 assert!(parse_bpf_loader(
323 &bad_compiled_instruction,
324 &AccountKeys::new(&account_keys, None)
325 )
326 .is_err());
327
328 let bad_compiled_instruction = CompiledInstruction {
329 program_id_index: 3,
330 accounts: vec![],
331 data: vec![1, 0, 0, 0],
332 };
333 assert!(parse_bpf_loader(
334 &bad_compiled_instruction,
335 &AccountKeys::new(&account_keys, None)
336 )
337 .is_err());
338 }
339
340 #[test]
341 fn test_parse_bpf_upgradeable_loader_create_buffer_ix() {
342 let max_data_len = 54321;
343
344 let payer_address = Pubkey::new_unique();
345 let buffer_address = Pubkey::new_unique();
346 let authority_address = Pubkey::new_unique();
347 let instructions = bpf_loader_upgradeable::create_buffer(
348 &payer_address,
349 &buffer_address,
350 &authority_address,
351 55,
352 max_data_len,
353 )
354 .unwrap();
355 let mut message = Message::new(&instructions, None);
356 assert_eq!(
357 parse_bpf_upgradeable_loader(
358 &message.instructions[1],
359 &AccountKeys::new(&message.account_keys, None)
360 )
361 .unwrap(),
362 ParsedInstructionEnum {
363 instruction_type: "initializeBuffer".to_string(),
364 info: json!({
365 "account": buffer_address.to_string(),
366 "authority": authority_address.to_string(),
367 }),
368 }
369 );
370 assert!(parse_bpf_upgradeable_loader(
371 &message.instructions[1],
372 &AccountKeys::new(&message.account_keys[0..2], None)
373 )
374 .is_err());
375 let keys = message.account_keys.clone();
376 message.instructions[1].accounts.pop();
377 message.instructions[1].accounts.pop();
378 assert!(parse_bpf_upgradeable_loader(
379 &message.instructions[1],
380 &AccountKeys::new(&keys, None)
381 )
382 .is_err());
383 }
384
385 #[test]
386 fn test_parse_bpf_upgradeable_loader_write_ix() {
387 let offset = 4242;
388 let bytes = vec![8; 99];
389
390 let buffer_address = Pubkey::new_unique();
391 let authority_address = Pubkey::new_unique();
392 let instruction = bpf_loader_upgradeable::write(
393 &buffer_address,
394 &authority_address,
395 offset,
396 bytes.clone(),
397 );
398 let mut message = Message::new(&[instruction], None);
399 assert_eq!(
400 parse_bpf_upgradeable_loader(
401 &message.instructions[0],
402 &AccountKeys::new(&message.account_keys, None)
403 )
404 .unwrap(),
405 ParsedInstructionEnum {
406 instruction_type: "write".to_string(),
407 info: json!({
408 "offset": offset,
409 "bytes": BASE64_STANDARD.encode(&bytes),
410 "account": buffer_address.to_string(),
411 "authority": authority_address.to_string(),
412 }),
413 }
414 );
415 assert!(parse_bpf_upgradeable_loader(
416 &message.instructions[0],
417 &AccountKeys::new(&message.account_keys[0..1], None)
418 )
419 .is_err());
420 let keys = message.account_keys.clone();
421 message.instructions[0].accounts.pop();
422 assert!(parse_bpf_upgradeable_loader(
423 &message.instructions[0],
424 &AccountKeys::new(&keys, None)
425 )
426 .is_err());
427 }
428
429 #[test]
430 fn test_parse_bpf_upgradeable_loader_deploy_ix() {
431 let max_data_len = 54321;
432
433 let payer_address = Pubkey::new_unique();
434 let program_address = Pubkey::new_unique();
435 let buffer_address = Pubkey::new_unique();
436 let upgrade_authority_address = Pubkey::new_unique();
437 let programdata_address = Pubkey::find_program_address(
438 &[program_address.as_ref()],
439 &solana_sdk_ids::bpf_loader_upgradeable::id(),
440 )
441 .0;
442 #[allow(deprecated)]
443 let instructions = bpf_loader_upgradeable::deploy_with_max_program_len(
444 &payer_address,
445 &program_address,
446 &buffer_address,
447 &upgrade_authority_address,
448 55,
449 max_data_len,
450 )
451 .unwrap();
452 let mut message = Message::new(&instructions, None);
453 assert_eq!(
454 parse_bpf_upgradeable_loader(
455 &message.instructions[1],
456 &AccountKeys::new(&message.account_keys, None)
457 )
458 .unwrap(),
459 ParsedInstructionEnum {
460 instruction_type: "deployWithMaxDataLen".to_string(),
461 info: json!({
462 "maxDataLen": max_data_len,
463 "payerAccount": payer_address.to_string(),
464 "programAccount": program_address.to_string(),
465 "authority": upgrade_authority_address.to_string(),
466 "programDataAccount": programdata_address.to_string(),
467 "bufferAccount": buffer_address.to_string(),
468 "rentSysvar": sysvar::rent::ID.to_string(),
469 "clockSysvar": sysvar::clock::ID.to_string(),
470 "systemProgram": system_program::ID.to_string(),
471 }),
472 }
473 );
474 assert!(parse_bpf_upgradeable_loader(
475 &message.instructions[1],
476 &AccountKeys::new(&message.account_keys[0..7], None)
477 )
478 .is_err());
479 let keys = message.account_keys.clone();
480 message.instructions[1].accounts.pop();
481 assert!(parse_bpf_upgradeable_loader(
482 &message.instructions[1],
483 &AccountKeys::new(&keys, None)
484 )
485 .is_err());
486 }
487
488 #[test]
489 fn test_parse_bpf_upgradeable_loader_upgrade_ix() {
490 let program_address = Pubkey::new_unique();
491 let buffer_address = Pubkey::new_unique();
492 let authority_address = Pubkey::new_unique();
493 let spill_address = Pubkey::new_unique();
494 let programdata_address = Pubkey::find_program_address(
495 &[program_address.as_ref()],
496 &solana_sdk_ids::bpf_loader_upgradeable::id(),
497 )
498 .0;
499 let instruction = bpf_loader_upgradeable::upgrade(
500 &program_address,
501 &buffer_address,
502 &authority_address,
503 &spill_address,
504 );
505 let mut message = Message::new(&[instruction], None);
506 assert_eq!(
507 parse_bpf_upgradeable_loader(
508 &message.instructions[0],
509 &AccountKeys::new(&message.account_keys, None)
510 )
511 .unwrap(),
512 ParsedInstructionEnum {
513 instruction_type: "upgrade".to_string(),
514 info: json!({
515 "authority": authority_address.to_string(),
516 "programDataAccount": programdata_address.to_string(),
517 "programAccount": program_address.to_string(),
518 "bufferAccount": buffer_address.to_string(),
519 "spillAccount": spill_address.to_string(),
520 "rentSysvar": sysvar::rent::ID.to_string(),
521 "clockSysvar": sysvar::clock::ID.to_string(),
522 }),
523 }
524 );
525 assert!(parse_bpf_upgradeable_loader(
526 &message.instructions[0],
527 &AccountKeys::new(&message.account_keys[0..6], None)
528 )
529 .is_err());
530 let keys = message.account_keys.clone();
531 message.instructions[0].accounts.pop();
532 assert!(parse_bpf_upgradeable_loader(
533 &message.instructions[0],
534 &AccountKeys::new(&keys, None)
535 )
536 .is_err());
537 }
538
539 #[test]
540 fn test_parse_bpf_upgradeable_loader_set_buffer_authority_ix() {
541 let buffer_address = Pubkey::new_unique();
542 let current_authority_address = Pubkey::new_unique();
543 let new_authority_address = Pubkey::new_unique();
544 let instruction = bpf_loader_upgradeable::set_buffer_authority(
545 &buffer_address,
546 ¤t_authority_address,
547 &new_authority_address,
548 );
549 let mut message = Message::new(&[instruction], None);
550 assert_eq!(
551 parse_bpf_upgradeable_loader(
552 &message.instructions[0],
553 &AccountKeys::new(&message.account_keys, None)
554 )
555 .unwrap(),
556 ParsedInstructionEnum {
557 instruction_type: "setAuthority".to_string(),
558 info: json!({
559 "account": buffer_address.to_string(),
560 "authority": current_authority_address.to_string(),
561 "newAuthority": new_authority_address.to_string(),
562 }),
563 }
564 );
565 assert!(parse_bpf_upgradeable_loader(
566 &message.instructions[0],
567 &AccountKeys::new(&message.account_keys[0..1], None)
568 )
569 .is_err());
570 let keys = message.account_keys.clone();
571 message.instructions[0].accounts.pop();
572 message.instructions[0].accounts.pop();
573 assert!(parse_bpf_upgradeable_loader(
574 &message.instructions[0],
575 &AccountKeys::new(&keys, None)
576 )
577 .is_err());
578 }
579
580 #[test]
581 fn test_parse_bpf_upgradeable_loader_set_buffer_authority_checked_ix() {
582 let buffer_address = Pubkey::new_unique();
583 let current_authority_address = Pubkey::new_unique();
584 let new_authority_address = Pubkey::new_unique();
585 let instruction = bpf_loader_upgradeable::set_buffer_authority_checked(
586 &buffer_address,
587 ¤t_authority_address,
588 &new_authority_address,
589 );
590 let message = Message::new(&[instruction], None);
591 assert_eq!(
592 parse_bpf_upgradeable_loader(
593 &message.instructions[0],
594 &AccountKeys::new(&message.account_keys, None)
595 )
596 .unwrap(),
597 ParsedInstructionEnum {
598 instruction_type: "setAuthorityChecked".to_string(),
599 info: json!({
600 "account": buffer_address.to_string(),
601 "authority": current_authority_address.to_string(),
602 "newAuthority": new_authority_address.to_string(),
603 }),
604 }
605 );
606 assert!(parse_bpf_upgradeable_loader(
607 &message.instructions[0],
608 &AccountKeys::new(&message.account_keys[0..2], None)
609 )
610 .is_err());
611 }
612
613 #[test]
614 fn test_parse_bpf_upgradeable_loader_set_upgrade_authority_ix() {
615 let program_address = Pubkey::new_unique();
616 let current_authority_address = Pubkey::new_unique();
617 let new_authority_address = Pubkey::new_unique();
618 let (programdata_address, _) = Pubkey::find_program_address(
619 &[program_address.as_ref()],
620 &solana_sdk_ids::bpf_loader_upgradeable::id(),
621 );
622 let instruction = bpf_loader_upgradeable::set_upgrade_authority(
623 &program_address,
624 ¤t_authority_address,
625 Some(&new_authority_address),
626 );
627 let mut message = Message::new(&[instruction], None);
628 assert_eq!(
629 parse_bpf_upgradeable_loader(
630 &message.instructions[0],
631 &AccountKeys::new(&message.account_keys, None)
632 )
633 .unwrap(),
634 ParsedInstructionEnum {
635 instruction_type: "setAuthority".to_string(),
636 info: json!({
637 "account": programdata_address.to_string(),
638 "authority": current_authority_address.to_string(),
639 "newAuthority": new_authority_address.to_string(),
640 }),
641 }
642 );
643 assert!(parse_bpf_upgradeable_loader(
644 &message.instructions[0],
645 &AccountKeys::new(&message.account_keys[0..1], None)
646 )
647 .is_err());
648 let keys = message.account_keys.clone();
649 message.instructions[0].accounts.pop();
650 message.instructions[0].accounts.pop();
651 assert!(parse_bpf_upgradeable_loader(
652 &message.instructions[0],
653 &AccountKeys::new(&keys, None)
654 )
655 .is_err());
656
657 let instruction = bpf_loader_upgradeable::set_upgrade_authority(
658 &program_address,
659 ¤t_authority_address,
660 None,
661 );
662 let mut message = Message::new(&[instruction], None);
663 assert_eq!(
664 parse_bpf_upgradeable_loader(
665 &message.instructions[0],
666 &AccountKeys::new(&message.account_keys, None)
667 )
668 .unwrap(),
669 ParsedInstructionEnum {
670 instruction_type: "setAuthority".to_string(),
671 info: json!({
672 "account": programdata_address.to_string(),
673 "authority": current_authority_address.to_string(),
674 "newAuthority": Value::Null,
675 }),
676 }
677 );
678 assert!(parse_bpf_upgradeable_loader(
679 &message.instructions[0],
680 &AccountKeys::new(&message.account_keys[0..1], None)
681 )
682 .is_err());
683 let keys = message.account_keys.clone();
684 message.instructions[0].accounts.pop();
685 assert!(parse_bpf_upgradeable_loader(
686 &message.instructions[0],
687 &AccountKeys::new(&keys, None)
688 )
689 .is_err());
690 }
691
692 #[test]
693 fn test_parse_bpf_upgradeable_loader_set_upgrade_authority_checked_ix() {
694 let program_address = Pubkey::new_unique();
695 let current_authority_address = Pubkey::new_unique();
696 let new_authority_address = Pubkey::new_unique();
697 let (programdata_address, _) = Pubkey::find_program_address(
698 &[program_address.as_ref()],
699 &solana_sdk_ids::bpf_loader_upgradeable::id(),
700 );
701 let instruction = bpf_loader_upgradeable::set_upgrade_authority_checked(
702 &program_address,
703 ¤t_authority_address,
704 &new_authority_address,
705 );
706 let message = Message::new(&[instruction], None);
707 assert_eq!(
708 parse_bpf_upgradeable_loader(
709 &message.instructions[0],
710 &AccountKeys::new(&message.account_keys, None)
711 )
712 .unwrap(),
713 ParsedInstructionEnum {
714 instruction_type: "setAuthorityChecked".to_string(),
715 info: json!({
716 "account": programdata_address.to_string(),
717 "authority": current_authority_address.to_string(),
718 "newAuthority": new_authority_address.to_string(),
719 }),
720 }
721 );
722
723 assert!(parse_bpf_upgradeable_loader(
724 &message.instructions[0],
725 &AccountKeys::new(&message.account_keys[0..2], None)
726 )
727 .is_err());
728 }
729
730 #[test]
731 fn test_parse_bpf_upgradeable_loader_close_buffer_ix() {
732 let close_address = Pubkey::new_unique();
733 let recipient_address = Pubkey::new_unique();
734 let authority_address = Pubkey::new_unique();
735 let instruction =
736 bpf_loader_upgradeable::close(&close_address, &recipient_address, &authority_address);
737 let mut message = Message::new(&[instruction], None);
738 assert_eq!(
739 parse_bpf_upgradeable_loader(
740 &message.instructions[0],
741 &AccountKeys::new(&message.account_keys, None)
742 )
743 .unwrap(),
744 ParsedInstructionEnum {
745 instruction_type: "close".to_string(),
746 info: json!({
747 "account": close_address.to_string(),
748 "recipient": recipient_address.to_string(),
749 "authority": authority_address.to_string(),
750 "programAccount": Value::Null
751 }),
752 }
753 );
754 assert!(parse_bpf_upgradeable_loader(
755 &message.instructions[0],
756 &AccountKeys::new(&message.account_keys[0..1], None)
757 )
758 .is_err());
759 let keys = message.account_keys.clone();
760 message.instructions[0].accounts.pop();
761 assert!(parse_bpf_upgradeable_loader(
762 &message.instructions[0],
763 &AccountKeys::new(&keys, None)
764 )
765 .is_err());
766 }
767
768 #[test]
769 fn test_parse_bpf_upgradeable_loader_close_program_ix() {
770 let close_address = Pubkey::new_unique();
771 let recipient_address = Pubkey::new_unique();
772 let authority_address = Pubkey::new_unique();
773 let program_address = Pubkey::new_unique();
774 let instruction = bpf_loader_upgradeable::close_any(
775 &close_address,
776 &recipient_address,
777 Some(&authority_address),
778 Some(&program_address),
779 );
780 let mut message = Message::new(&[instruction], None);
781 assert_eq!(
782 parse_bpf_upgradeable_loader(
783 &message.instructions[0],
784 &AccountKeys::new(&message.account_keys, None)
785 )
786 .unwrap(),
787 ParsedInstructionEnum {
788 instruction_type: "close".to_string(),
789 info: json!({
790 "account": close_address.to_string(),
791 "recipient": recipient_address.to_string(),
792 "authority": authority_address.to_string(),
793 "programAccount": program_address.to_string()
794 }),
795 }
796 );
797 assert!(parse_bpf_upgradeable_loader(
798 &message.instructions[0],
799 &AccountKeys::new(&message.account_keys[0..1], None)
800 )
801 .is_err());
802 let keys = message.account_keys.clone();
803 message.instructions[0].accounts.pop();
804 message.instructions[0].accounts.pop();
805 assert!(parse_bpf_upgradeable_loader(
806 &message.instructions[0],
807 &AccountKeys::new(&keys, None)
808 )
809 .is_err());
810 }
811}