1use crate::{invariant::RandomCallGenerator, strategies::EvmFuzzState};
2use revm::{
3 context::{ContextTr, Transaction},
4 inspector::JournalExt,
5 interpreter::{CallInput, CallInputs, CallOutcome, CallScheme, Interpreter},
6 Inspector,
7};
89/// An inspector that can fuzz and collect data for that effect.
10#[derive(Clone, Debug)]
11pub struct Fuzzer {
12/// Given a strategy, it generates a random call.
13pub call_generator: Option<RandomCallGenerator>,
14/// If set, it collects `stack` and `memory` values for fuzzing purposes.
15pub collect: bool,
16/// If `collect` is set, we store the collected values in this fuzz dictionary.
17pub fuzz_state: EvmFuzzState,
18}
1920impl<CTX> Inspector<CTX> for Fuzzer21where
22CTX: ContextTr<Journal: JournalExt>,
23{
24#[inline]
25fn step(&mut self, interp: &mut Interpreter, _context: &mut CTX) {
26// We only collect `stack` and `memory` data before and after calls.
27if self.collect {
28self.collect_data(interp);
29self.collect = false;
30 }
31 }
3233#[inline]
34fn call(&mut self, ecx: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {
35// We don't want to override the very first call made to the test contract.
36if self.call_generator.is_some() && ecx.tx().caller() != inputs.caller {
37self.override_call(inputs);
38 }
3940// We only collect `stack` and `memory` data before and after calls.
41 // this will be turned off on the next `step`
42self.collect = true;
4344None45 }
4647#[inline]
48fn call_end(&mut self, _context: &mut CTX, _inputs: &CallInputs, _outcome: &mut CallOutcome) {
49if let Some(ref mut call_generator) = self.call_generator {
50call_generator.used = false;
51 }
5253// We only collect `stack` and `memory` data before and after calls.
54 // this will be turned off on the next `step`
55self.collect = true;
56 }
57}
5859impl Fuzzer {
60/// Collects `stack` and `memory` values into the fuzz dictionary.
61fn collect_data(&mut self, interpreter: &Interpreter) {
62self.fuzz_state.collect_values(interpreter.stack.data().iter().copied().map(Into::into));
6364// TODO: disabled for now since it's flooding the dictionary
65 // for index in 0..interpreter.shared_memory.len() / 32 {
66 // let mut slot = [0u8; 32];
67 // slot.clone_from_slice(interpreter.shared_memory.get_slice(index * 32, 32));
6869 // state.insert(slot);
70 // }
71}
7273/// Overrides an external call and tries to call any method of msg.sender.
74fn override_call(&mut self, call: &mut CallInputs) {
75if let Some(ref mut call_generator) = self.call_generator {
76// We only override external calls which are not coming from the test contract.
77if call.caller != call_generator.test_address &&
78 call.scheme == CallScheme::Call &&
79 !call_generator.used
80 {
81// There's only a 30% chance that an override happens.
82if let Some(tx) = call_generator.next(call.caller, call.target_address) {
83call.input = CallInput::Bytes(tx.call_details.calldata.0.into());
84call.caller = tx.sender;
85call.target_address = tx.call_details.target;
8687// TODO: in what scenarios can the following be problematic
88call.bytecode_address = tx.call_details.target;
89call_generator.used = true;
90 }
91 }
92 }
93 }
94}