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