@@ -452,6 +452,8 @@ pub mod sysvar;
452452pub use mollusk_svm_result as result;
453453#[ cfg( any( feature = "fuzz" , feature = "fuzz-fd" ) ) ]
454454use mollusk_svm_result:: Compare ;
455+ #[ cfg( feature = "invocation-inspect-callback" ) ]
456+ use solana_transaction_context:: InstructionAccount ;
455457use {
456458 crate :: {
457459 account_store:: AccountStore , compile_accounts:: CompiledAccounts , epoch_stake:: EpochStake ,
@@ -489,6 +491,12 @@ pub struct Mollusk {
489491 pub program_cache : ProgramCache ,
490492 pub sysvars : Sysvars ,
491493
494+ /// The callback which can be used to inspect invoke_context
495+ /// and extract low-level information such as bpf traces, transaction context,
496+ /// detailed timings, etc.
497+ #[ cfg( feature = "invocation-inspect-callback" ) ]
498+ pub invocation_inspect_callback : Box < dyn InvocationInspectCallback > ,
499+
492500 /// This field stores the slot only to be able to convert to and from FD
493501 /// fixtures and a Mollusk instance, since FD fixtures have a
494502 /// "slot context". However, this field is functionally irrelevant for
@@ -498,6 +506,36 @@ pub struct Mollusk {
498506 pub slot : u64 ,
499507}
500508
509+ #[ cfg( feature = "invocation-inspect-callback" ) ]
510+ pub trait InvocationInspectCallback {
511+ fn before_invocation (
512+ & self ,
513+ program_id : & Pubkey ,
514+ instruction_data : & [ u8 ] ,
515+ instruction_accounts : & [ InstructionAccount ] ,
516+ invoke_context : & InvokeContext ,
517+ ) ;
518+
519+ fn after_invocation ( & self , invoke_context : & InvokeContext ) ;
520+ }
521+
522+ #[ cfg( feature = "invocation-inspect-callback" ) ]
523+ pub struct EmptyInvocationInspectCallback ;
524+
525+ #[ cfg( feature = "invocation-inspect-callback" ) ]
526+ impl InvocationInspectCallback for EmptyInvocationInspectCallback {
527+ fn before_invocation (
528+ & self ,
529+ _: & Pubkey ,
530+ _: & [ u8 ] ,
531+ _: & [ InstructionAccount ] ,
532+ _: & InvokeContext ,
533+ ) {
534+ }
535+
536+ fn after_invocation ( & self , _: & InvokeContext ) { }
537+ }
538+
501539impl Default for Mollusk {
502540 fn default ( ) -> Self {
503541 #[ rustfmt:: skip]
@@ -528,6 +566,10 @@ impl Default for Mollusk {
528566 logger : None ,
529567 program_cache,
530568 sysvars : Sysvars :: default ( ) ,
569+
570+ #[ cfg( feature = "invocation-inspect-callback" ) ]
571+ invocation_inspect_callback : Box :: new ( EmptyInvocationInspectCallback { } ) ,
572+
531573 #[ cfg( feature = "fuzz-fd" ) ]
532574 slot : 0 ,
533575 }
@@ -678,7 +720,16 @@ impl Mollusk {
678720 self . compute_budget . to_budget ( ) ,
679721 self . compute_budget . to_cost ( ) ,
680722 ) ;
681- if invoke_context. is_precompile ( & instruction. program_id ) {
723+
724+ #[ cfg( feature = "invocation-inspect-callback" ) ]
725+ self . invocation_inspect_callback . before_invocation (
726+ & instruction. program_id ,
727+ & instruction. data ,
728+ & instruction_accounts,
729+ & invoke_context,
730+ ) ;
731+
732+ let result = if invoke_context. is_precompile ( & instruction. program_id ) {
682733 invoke_context. process_precompile (
683734 & instruction. program_id ,
684735 & instruction. data ,
@@ -694,7 +745,13 @@ impl Mollusk {
694745 & mut compute_units_consumed,
695746 & mut timings,
696747 )
697- }
748+ } ;
749+
750+ #[ cfg( feature = "invocation-inspect-callback" ) ]
751+ self . invocation_inspect_callback
752+ . after_invocation ( & invoke_context) ;
753+
754+ result
698755 } ;
699756
700757 let return_data = transaction_context. get_return_data ( ) . 1 . to_vec ( ) ;
0 commit comments