foundry_evm_fuzz/
inspector.rs1use crate::{invariant::RandomCallGenerator, strategies::EvmFuzzState};
2use revm::{
3 Inspector,
4 context::{ContextTr, Transaction},
5 inspector::JournalExt,
6 interpreter::{CallInput, CallInputs, CallOutcome, CallScheme, Interpreter},
7};
8
9#[derive(Clone, Debug)]
11pub struct Fuzzer {
12 pub call_generator: Option<RandomCallGenerator>,
14 pub collect: bool,
16 pub fuzz_state: EvmFuzzState,
18}
19
20impl<CTX> Inspector<CTX> for Fuzzer
21where
22 CTX: ContextTr<Journal: JournalExt>,
23{
24 #[inline]
25 fn step(&mut self, interp: &mut Interpreter, _context: &mut CTX) {
26 if self.collect {
28 self.collect_data(interp);
29 self.collect = false;
30 }
31 }
32
33 #[inline]
34 fn call(&mut self, ecx: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {
35 if self.call_generator.is_some() && ecx.tx().caller() != inputs.caller {
37 self.override_call(inputs);
38 }
39
40 self.collect = true;
43
44 None
45 }
46
47 #[inline]
48 fn call_end(&mut self, _context: &mut CTX, _inputs: &CallInputs, _outcome: &mut CallOutcome) {
49 if let Some(ref mut call_generator) = self.call_generator {
50 call_generator.used = false;
51 }
52
53 self.collect = true;
56 }
57}
58
59impl Fuzzer {
60 fn collect_data(&mut self, interpreter: &Interpreter) {
62 self.fuzz_state.collect_values(interpreter.stack.data().iter().copied().map(Into::into));
63
64 }
72
73 fn override_call(&mut self, call: &mut CallInputs) {
75 if let Some(ref mut call_generator) = self.call_generator {
76 if call.caller != call_generator.test_address
78 && call.scheme == CallScheme::Call
79 && !call_generator.used
80 {
81 if let Some(tx) = call_generator.next(call.caller, call.target_address) {
83 call.input = CallInput::Bytes(tx.call_details.calldata.0.into());
84 call.caller = tx.sender;
85 call.target_address = tx.call_details.target;
86
87 call.bytecode_address = tx.call_details.target;
89 call_generator.used = true;
90 }
91 }
92 }
93 }
94}