foundry_cheatcodes/
state.rs1use crate::{
4 CheatcodeAnalysis, CheatsConfig, ExpectedCallTracker, Wallets,
5 evm::mock::{MockCallDataContext, MockCallReturnData},
6 inspector::ArbitraryStorage,
7};
8use alloy_primitives::{
9 Address, Bytes, U256,
10 map::{AddressHashMap, HashMap},
11};
12use alloy_rpc_types::AccessList;
13use alloy_signer_local::PrivateKeySigner;
14use foundry_common::mapping_slots::MappingSlots;
15use foundry_wallets::wallet_multi::MultiWallet;
16use proptest::test_runner::{RngAlgorithm, TestRng, TestRunner};
17use rand::Rng;
18use serde_json::Value;
19use std::{
20 collections::{BTreeMap, VecDeque},
21 fs::File,
22 io::BufReader,
23 path::PathBuf,
24 sync::Arc,
25};
26
27#[derive(Clone, Debug)]
29pub struct CheatcodesCore {
30 pub config: Arc<CheatsConfig>,
32 pub analysis: Option<CheatcodeAnalysis>,
34 pub labels: AddressHashMap<String>,
36 pub test_context: TestContext,
38 pub fs_commit: bool,
41 pub serialized_jsons: BTreeMap<String, BTreeMap<String, Value>>,
44 test_runner: Option<TestRunner>,
47 pub wallets: Option<Wallets>,
49 pub private_key_signers: HashMap<U256, PrivateKeySigner>,
51 pub mocked_calls: HashMap<Address, BTreeMap<MockCallDataContext, VecDeque<MockCallReturnData>>>,
54 pub mocked_functions: HashMap<Address, HashMap<Bytes, Address>>,
56 pub expected_calls: ExpectedCallTracker,
58 pub mapping_slots: Option<AddressHashMap<MappingSlots>>,
60 pub recorded_logs: Option<Vec<crate::Vm::Log>>,
62 pub access_list: Option<AccessList>,
64 pub intercept_next_create_call: bool,
66 pub arbitrary_storage: Option<ArbitraryStorage>,
68}
69
70impl Default for CheatcodesCore {
71 fn default() -> Self {
72 Self::new(Default::default())
73 }
74}
75
76impl CheatcodesCore {
77 pub fn new(config: Arc<CheatsConfig>) -> Self {
79 Self {
80 analysis: None,
81 labels: config.labels.clone(),
82 config,
83 test_context: Default::default(),
84 fs_commit: true,
85 serialized_jsons: Default::default(),
86 test_runner: Default::default(),
87 wallets: Default::default(),
88 private_key_signers: Default::default(),
89 mocked_calls: Default::default(),
90 mocked_functions: Default::default(),
91 expected_calls: Default::default(),
92 mapping_slots: Default::default(),
93 recorded_logs: Default::default(),
94 access_list: Default::default(),
95 intercept_next_create_call: Default::default(),
96 arbitrary_storage: Default::default(),
97 }
98 }
99
100 pub fn set_analysis(&mut self, analysis: CheatcodeAnalysis) {
102 self.analysis = Some(analysis);
103 }
104
105 pub fn wallets(&mut self) -> &Wallets {
107 self.wallets.get_or_insert_with(|| Wallets::new(MultiWallet::default(), None))
108 }
109
110 pub fn set_wallets(&mut self, wallets: Wallets) {
112 self.wallets = Some(wallets);
113 }
114
115 pub fn rng(&mut self) -> &mut impl Rng {
116 self.test_runner().rng()
117 }
118
119 pub fn test_runner(&mut self) -> &mut TestRunner {
120 self.test_runner.get_or_insert_with(|| match self.config.seed {
121 Some(seed) => TestRunner::new_with_rng(
122 proptest::test_runner::Config::default(),
123 TestRng::from_seed(RngAlgorithm::ChaCha, &seed.to_be_bytes::<32>()),
124 ),
125 None => TestRunner::new(proptest::test_runner::Config::default()),
126 })
127 }
128
129 pub fn set_seed(&mut self, seed: U256) {
130 self.test_runner = Some(TestRunner::new_with_rng(
131 proptest::test_runner::Config::default(),
132 TestRng::from_seed(RngAlgorithm::ChaCha, &seed.to_be_bytes::<32>()),
133 ));
134 }
135
136 pub fn struct_defs(&self) -> Option<&foundry_common::fmt::StructDefinitions> {
138 self.analysis.as_ref().and_then(|analysis| analysis.struct_defs().ok())
139 }
140
141 pub fn arbitrary_storage(&mut self) -> &mut ArbitraryStorage {
144 self.arbitrary_storage.get_or_insert_with(ArbitraryStorage::default)
145 }
146}
147
148#[derive(Debug, Default)]
150pub struct TestContext {
151 pub opened_read_files: HashMap<PathBuf, BufReader<File>>,
153}
154
155impl Clone for TestContext {
157 fn clone(&self) -> Self {
158 Default::default()
159 }
160}
161
162impl TestContext {
163 pub fn clear(&mut self) {
165 self.opened_read_files.clear();
166 }
167}