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 fn step(&mut self, interp: &mut Interpreter, _context: &mut CTX) {
25 if self.collect {
27 self.collect_data(interp);
28 }
29 }
30
31 fn call(&mut self, ecx: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {
32 if self.call_generator.is_some() && ecx.tx().caller() != inputs.caller {
34 self.override_call(inputs);
35 }
36
37 self.collect = true;
40
41 None
42 }
43
44 fn call_end(&mut self, _context: &mut CTX, _inputs: &CallInputs, _outcome: &mut CallOutcome) {
45 if let Some(ref mut call_generator) = self.call_generator {
46 call_generator.used = false;
47 }
48
49 self.collect = true;
52 }
53}
54
55impl Fuzzer {
56 #[cold]
58 fn collect_data(&mut self, interpreter: &Interpreter) {
59 self.fuzz_state.collect_values(interpreter.stack.data().iter().copied().map(Into::into));
60
61 self.collect = false;
70 }
71
72 fn override_call(&mut self, call: &mut CallInputs) {
74 if let Some(ref mut call_generator) = self.call_generator {
75 if call.caller != call_generator.test_address
77 && call.scheme == CallScheme::Call
78 && !call_generator.used
79 {
80 if let Some(tx) = call_generator.next(call.caller, call.target_address) {
82 call.input = CallInput::Bytes(tx.call_details.calldata.0.into());
83 call.caller = tx.sender;
84 call.target_address = tx.call_details.target;
85
86 call.bytecode_address = tx.call_details.target;
88 call_generator.used = true;
89 }
90 }
91 }
92 }
93}