foundry_evm_fuzz/invariant/
call_override.rs1use crate::{BasicTxDetails, CallDetails};
2use alloy_primitives::Address;
3use parking_lot::{Mutex, RwLock};
4use proptest::{
5 option::weighted,
6 strategy::{SBoxedStrategy, Strategy, ValueTree},
7 test_runner::TestRunner,
8};
9use std::sync::Arc;
10
11#[derive(Clone, Debug)]
14pub struct RandomCallGenerator {
15 pub test_address: Address,
17 pub runner: Arc<Mutex<TestRunner>>,
19 pub strategy: SBoxedStrategy<Option<CallDetails>>,
21 pub target_reference: Arc<RwLock<Address>>,
23 pub used: bool,
25 pub replay: bool,
28 pub last_sequence: Arc<RwLock<Vec<Option<BasicTxDetails>>>>,
30}
31
32impl RandomCallGenerator {
33 pub fn new(
34 test_address: Address,
35 runner: TestRunner,
36 strategy: impl Strategy<Value = CallDetails> + Send + Sync + 'static,
37 target_reference: Arc<RwLock<Address>>,
38 ) -> Self {
39 Self {
40 test_address,
41 runner: Arc::new(Mutex::new(runner)),
42 strategy: weighted(0.9, strategy).sboxed(),
43 target_reference,
44 last_sequence: Arc::default(),
45 replay: false,
46 used: false,
47 }
48 }
49
50 pub fn set_replay(&mut self, status: bool) {
53 self.replay = status;
54 if status {
55 self.last_sequence.write().reverse();
57 }
58 }
59
60 pub fn next(
62 &mut self,
63 original_caller: Address,
64 original_target: Address,
65 ) -> Option<BasicTxDetails> {
66 if self.replay {
67 self.last_sequence.write().pop().expect(
68 "to have same size as the number of (unsafe) external calls of the sequence.",
69 )
70 } else {
71 let sender = original_target;
73
74 *self.target_reference.write() = original_caller;
76
77 let choice = self
79 .strategy
80 .new_tree(&mut self.runner.lock())
81 .unwrap()
82 .current()
83 .map(|call_details| BasicTxDetails { sender, call_details });
84
85 self.last_sequence.write().push(choice.clone());
86 choice
87 }
88 }
89}