foundry_evm_fuzz/
inspector.rs1use crate::{invariant::RandomCallGenerator, strategies::EvmFuzzState};
2use foundry_common::mapping_slots::step as mapping_step;
3use revm::{
4 Inspector,
5 context::{ContextTr, Transaction},
6 inspector::JournalExt,
7 interpreter::{CallInput, CallInputs, CallOutcome, CallScheme, Interpreter},
8};
9
10#[derive(Clone, Debug)]
12pub struct Fuzzer {
13 pub collect: bool,
15 pub call_generator: Option<RandomCallGenerator>,
17 pub fuzz_state: EvmFuzzState,
19}
20
21impl<CTX> Inspector<CTX> for Fuzzer
22where
23 CTX: ContextTr<Journal: JournalExt>,
24{
25 #[inline]
26 fn step(&mut self, interp: &mut Interpreter, _context: &mut CTX) {
27 if self.collect {
29 self.collect_data(interp);
30 if let Some(mapping_slots) = &mut self.fuzz_state.mapping_slots {
31 mapping_step(mapping_slots, interp);
32 }
33 }
34 }
35
36 fn call(&mut self, ecx: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {
37 if self.call_generator.is_some() && ecx.tx().caller() != inputs.caller {
39 self.override_call(inputs);
40 }
41
42 self.collect = true;
45
46 None
47 }
48
49 fn call_end(&mut self, _context: &mut CTX, _inputs: &CallInputs, _outcome: &mut CallOutcome) {
50 if let Some(ref mut call_generator) = self.call_generator {
51 call_generator.used = false;
52 }
53
54 self.collect = true;
57 }
58}
59
60impl Fuzzer {
61 #[cold]
63 fn collect_data(&mut self, interpreter: &Interpreter) {
64 self.fuzz_state.collect_values(interpreter.stack.data().iter().copied().map(Into::into));
65
66 self.collect = false;
75 }
76
77 fn override_call(&mut self, call: &mut CallInputs) {
79 if let Some(ref mut call_generator) = self.call_generator {
80 if call.caller != call_generator.test_address
82 && call.scheme == CallScheme::Call
83 && !call_generator.used
84 {
85 if let Some(tx) = call_generator.next(call.caller, call.target_address) {
87 call.input = CallInput::Bytes(tx.call_details.calldata.0.into());
88 call.caller = tx.sender;
89 call.target_address = tx.call_details.target;
90
91 call.bytecode_address = tx.call_details.target;
93 call_generator.used = true;
94 }
95 }
96 }
97 }
98}