Skip to content

Commit 3c6b1d8

Browse files
committed
2nd attempt at trace configuration
1 parent 4129ea5 commit 3c6b1d8

File tree

4 files changed

+149
-99
lines changed

4 files changed

+149
-99
lines changed

harness/src/lib.rs

Lines changed: 86 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -506,8 +506,11 @@ pub struct Mollusk {
506506
#[cfg(feature = "invocation-inspect-callback")]
507507
pub invocation_inspect_callback: Box<dyn InvocationInspectCallback>,
508508

509-
#[cfg(feature = "register-tracing")]
510-
pub enable_register_tracing: bool,
509+
/// Dictates whether or not register tracing was enabled.
510+
/// Provided as input to the invocation inspect callback for potential
511+
/// register trace consumption.
512+
#[cfg(feature = "invocation-inspect-callback")]
513+
enable_register_tracing: bool,
511514

512515
/// This field stores the slot only to be able to convert to and from FD
513516
/// fixtures and a Mollusk instance, since FD fixtures have a
@@ -528,7 +531,7 @@ pub trait InvocationInspectCallback {
528531
invoke_context: &InvokeContext,
529532
);
530533

531-
fn after_invocation(&self, invoke_context: &InvokeContext);
534+
fn after_invocation(&self, invoke_context: &InvokeContext, register_tracing_enabled: bool);
532535
}
533536

534537
#[cfg(feature = "invocation-inspect-callback")]
@@ -539,71 +542,12 @@ impl InvocationInspectCallback for EmptyInvocationInspectCallback {
539542
fn before_invocation(&self, _: &Pubkey, _: &[u8], _: &[InstructionAccount], _: &InvokeContext) {
540543
}
541544

542-
fn after_invocation(&self, _: &InvokeContext) {}
545+
fn after_invocation(&self, _: &InvokeContext, _register_tracing_enabled: bool) {}
543546
}
544547

545548
impl Default for Mollusk {
546549
fn default() -> Self {
547-
#[rustfmt::skip]
548-
solana_logger::setup_with_default(
549-
"solana_rbpf::vm=debug,\
550-
solana_runtime::message_processor=debug,\
551-
solana_runtime::system_instruction_processor=trace",
552-
);
553-
let compute_budget = ComputeBudget::new_with_defaults(true, true);
554-
555-
#[cfg(feature = "fuzz")]
556-
let feature_set = {
557-
// Omit "test features" (they have the same u64 ID).
558-
let mut fs = FeatureSet::all_enabled();
559-
fs.active_mut()
560-
.remove(&agave_feature_set::disable_sbpf_v0_execution::id());
561-
fs.active_mut()
562-
.remove(&agave_feature_set::reenable_sbpf_v0_execution::id());
563-
fs
564-
};
565-
#[cfg(not(feature = "fuzz"))]
566-
let feature_set = FeatureSet::all_enabled();
567-
568-
let program_cache = ProgramCache::new(
569-
&feature_set,
570-
&compute_budget,
571-
#[cfg(feature = "register-tracing")]
572-
{
573-
true
574-
},
575-
#[cfg(not(feature = "register-tracing"))]
576-
{
577-
false
578-
},
579-
);
580-
581-
Self {
582-
config: Config::default(),
583-
compute_budget,
584-
epoch_stake: EpochStake::default(),
585-
feature_set,
586-
logger: None,
587-
program_cache,
588-
sysvars: Sysvars::default(),
589-
590-
// Register tracing feature requires `invocation-inspect-callback`.
591-
// Use tracing callback when both are active.
592-
#[cfg(all(feature = "invocation-inspect-callback", feature = "register-tracing"))]
593-
invocation_inspect_callback: Box::new(DefaultRegisterTracingCallback::default()),
594-
// Use empty callback when only `invocation-inspect-callback` is active.
595-
#[cfg(all(
596-
feature = "invocation-inspect-callback",
597-
not(feature = "register-tracing"),
598-
))]
599-
invocation_inspect_callback: Box::new(EmptyInvocationInspectCallback {}),
600-
601-
#[cfg(feature = "register-tracing")]
602-
enable_register_tracing: true,
603-
604-
#[cfg(feature = "fuzz-fd")]
605-
slot: 0,
606-
}
550+
Self::new_inner(/* enable_register_tracing */ false)
607551
}
608552
}
609553

@@ -669,6 +613,61 @@ impl InvokeContextCallback for MolluskInvokeContextCallback<'_> {
669613
}
670614

671615
impl Mollusk {
616+
fn new_inner(#[allow(unused)] enable_register_tracing: bool) -> Self {
617+
#[rustfmt::skip]
618+
solana_logger::setup_with_default(
619+
"solana_rbpf::vm=debug,\
620+
solana_runtime::message_processor=debug,\
621+
solana_runtime::system_instruction_processor=trace",
622+
);
623+
let compute_budget = ComputeBudget::new_with_defaults(true, true);
624+
625+
#[cfg(feature = "fuzz")]
626+
let feature_set = {
627+
// Omit "test features" (they have the same u64 ID).
628+
let mut fs = FeatureSet::all_enabled();
629+
fs.active_mut()
630+
.remove(&agave_feature_set::disable_sbpf_v0_execution::id());
631+
fs.active_mut()
632+
.remove(&agave_feature_set::reenable_sbpf_v0_execution::id());
633+
fs
634+
};
635+
#[cfg(not(feature = "fuzz"))]
636+
let feature_set = FeatureSet::all_enabled();
637+
638+
let program_cache =
639+
ProgramCache::new(&feature_set, &compute_budget, enable_register_tracing);
640+
641+
#[allow(unused_mut)]
642+
let mut me = Self {
643+
config: Config::default(),
644+
compute_budget,
645+
epoch_stake: EpochStake::default(),
646+
feature_set,
647+
logger: None,
648+
program_cache,
649+
sysvars: Sysvars::default(),
650+
651+
#[cfg(feature = "invocation-inspect-callback")]
652+
invocation_inspect_callback: Box::new(EmptyInvocationInspectCallback {}),
653+
654+
#[cfg(feature = "invocation-inspect-callback")]
655+
enable_register_tracing,
656+
657+
#[cfg(feature = "fuzz-fd")]
658+
slot: 0,
659+
};
660+
661+
#[cfg(feature = "register-tracing")]
662+
if enable_register_tracing {
663+
// Have a default register tracing callback if register tracing is
664+
// enabled.
665+
me.invocation_inspect_callback = Box::new(DefaultRegisterTracingCallback::default());
666+
}
667+
668+
me
669+
}
670+
672671
/// Create a new Mollusk instance containing the provided program.
673672
///
674673
/// Attempts to load the program's ELF file from the default search paths.
@@ -689,6 +688,28 @@ impl Mollusk {
689688
mollusk
690689
}
691690

691+
/// Create a new Mollusk instance with configurable debugging features.
692+
///
693+
/// This constructor allows enabling low-level VM debugging capabilities,
694+
/// such as register tracing, which are baked into program executables at
695+
/// load time and cannot be changed afterwards.
696+
///
697+
/// When `enable_register_tracing` is `true`:
698+
/// - Programs are compiled with register tracing support
699+
/// - A default [`DefaultRegisterTracingCallback`] is installed
700+
/// - Trace data is written to `SBF_TRACE_DIR` (or `target/sbf/trace` by
701+
/// default)
702+
#[cfg(feature = "register-tracing")]
703+
pub fn new_debuggable(
704+
program_id: &Pubkey,
705+
program_name: &str,
706+
enable_register_tracing: bool,
707+
) -> Self {
708+
let mut mollusk = Self::new_inner(enable_register_tracing);
709+
mollusk.add_program(program_id, program_name, &DEFAULT_LOADER_KEY);
710+
mollusk
711+
}
712+
692713
/// Add a program to the test environment.
693714
///
694715
/// If you intend to CPI to a program, this is likely what you want to use.
@@ -822,7 +843,7 @@ impl Mollusk {
822843

823844
#[cfg(feature = "invocation-inspect-callback")]
824845
self.invocation_inspect_callback
825-
.after_invocation(&invoke_context);
846+
.after_invocation(&invoke_context, self.enable_register_tracing);
826847

827848
result
828849
};

harness/src/register_tracing.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,19 @@ impl InvocationInspectCallback for DefaultRegisterTracingCallback {
8282
fn before_invocation(&self, _: &Pubkey, _: &[u8], _: &[InstructionAccount], _: &InvokeContext) {
8383
}
8484

85-
fn after_invocation(&self, invoke_context: &InvokeContext) {
86-
invoke_context.iterate_vm_traces(
87-
&|instruction_context: InstructionContext,
88-
executable: &Executable,
89-
register_trace: RegisterTrace| {
90-
if let Err(e) = self.handler(instruction_context, executable, register_trace) {
91-
eprintln!("Error collecting the register tracing: {}", e);
92-
}
93-
},
94-
);
85+
fn after_invocation(&self, invoke_context: &InvokeContext, register_tracing_enabled: bool) {
86+
if register_tracing_enabled {
87+
// Only read the register traces if they were actually enabled.
88+
invoke_context.iterate_vm_traces(
89+
&|instruction_context: InstructionContext,
90+
executable: &Executable,
91+
register_trace: RegisterTrace| {
92+
if let Err(e) = self.handler(instruction_context, executable, register_trace) {
93+
eprintln!("Error collecting the register tracing: {}", e);
94+
}
95+
},
96+
);
97+
}
9598
}
9699
}
97100

harness/tests/fd_test_vectors.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,10 @@ fn test_load_firedancer_fixtures() {
6262
},
6363
result,
6464
) = load_firedancer_fixture(&loaded_fixture);
65-
let mollusk = Mollusk {
66-
compute_budget,
67-
feature_set,
68-
slot,
69-
..Default::default()
70-
};
65+
let mut mollusk = Mollusk::default();
66+
mollusk.compute_budget = compute_budget;
67+
mollusk.feature_set = feature_set;
68+
mollusk.slot = slot;
7169
let generated_fixture =
7270
build_fixture_from_mollusk_test(&mollusk, &instruction, &accounts, &result);
7371

harness/tests/register_tracing.rs

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -69,24 +69,34 @@ fn test_custom_register_tracing_callback() {
6969
) {
7070
}
7171

72-
fn after_invocation(&self, invoke_context: &InvokeContext) {
73-
invoke_context.iterate_vm_traces(
74-
&|instruction_context: InstructionContext,
75-
executable: &Executable,
76-
register_trace: RegisterTrace| {
77-
if let Err(e) = self.handler(instruction_context, executable, register_trace) {
78-
eprintln!("Error collecting the register tracing: {}", e);
79-
}
80-
},
81-
);
72+
fn after_invocation(&self, invoke_context: &InvokeContext, register_tracing_enabled: bool) {
73+
// Only process traces if register tracing was enabled.
74+
if register_tracing_enabled {
75+
invoke_context.iterate_vm_traces(
76+
&|instruction_context: InstructionContext,
77+
executable: &Executable,
78+
register_trace: RegisterTrace| {
79+
if let Err(e) =
80+
self.handler(instruction_context, executable, register_trace)
81+
{
82+
eprintln!("Error collecting the register tracing: {}", e);
83+
}
84+
},
85+
);
86+
}
8287
}
8388
}
8489

8590
std::env::set_var("SBF_OUT_DIR", "../target/deploy");
8691

8792
let program_id = Pubkey::new_unique();
8893
let payer_pk = Pubkey::new_unique();
89-
let mut mollusk = Mollusk::new(&program_id, "test_program_primary");
94+
// Use new_debuggable with register tracing enabled.
95+
let mut mollusk = Mollusk::new_debuggable(
96+
&program_id,
97+
"test_program_primary",
98+
/* enable_register_tracing */ true,
99+
);
90100

91101
// Phase 1 - basic register tracing test.
92102

@@ -136,31 +146,49 @@ fn test_custom_register_tracing_callback() {
136146
collected_data.executed_jump_instructions_count;
137147
}
138148

139-
// Phase 2 - check we can stop register tracing for this instance of Mollusk.
149+
// Phase 2 - check that register tracing is disabled when constructing
150+
// Mollusk with enable_register_tracing=false.
140151
{
141152
// Clear the tracing data collected so far.
142153
{
143154
let mut td = tracing_data.borrow_mut();
144155
td.clear();
145156
}
146157

147-
mollusk.enable_register_tracing = false;
158+
// Create a new Mollusk instance with register tracing disabled.
159+
let mut mollusk_no_tracing = Mollusk::new_debuggable(
160+
&program_id,
161+
"test_program_primary",
162+
/* enable_register_tracing */ false,
163+
);
164+
mollusk_no_tracing.invocation_inspect_callback = Box::new(CustomRegisterTracingCallback {
165+
tracing_data: Rc::clone(&tracing_data),
166+
});
148167

149168
// Execute the same instruction again.
150-
let _ = mollusk.process_instruction(&instruction, &accounts);
169+
let _ = mollusk_no_tracing.process_instruction(&instruction, &accounts);
151170

152171
let td = tracing_data.borrow();
153-
// We expect it to be empty!
172+
// We expect it to be empty since tracing was disabled!
154173
assert!(td.is_empty());
155174
}
156175

157-
// Phase 3 - check we can have register tracing back for this instance of
176+
// Phase 3 - check we can have register tracing enabled for a new instance of
158177
// Mollusk.
159178
{
160-
mollusk.enable_register_tracing = true;
179+
// Create a new Mollusk instance with register tracing enabled.
180+
let mut mollusk_with_tracing = Mollusk::new_debuggable(
181+
&program_id,
182+
"test_program_primary",
183+
/* enable_register_tracing */ true,
184+
);
185+
mollusk_with_tracing.invocation_inspect_callback =
186+
Box::new(CustomRegisterTracingCallback {
187+
tracing_data: Rc::clone(&tracing_data),
188+
});
161189

162190
// Execute the same instruction again.
163-
let _ = mollusk.process_instruction(&instruction, &accounts);
191+
let _ = mollusk_with_tracing.process_instruction(&instruction, &accounts);
164192

165193
let td = tracing_data.borrow();
166194
let collected_data = td.get(&program_id).unwrap();

0 commit comments

Comments
 (0)