foundry_evm_core/backend/
cow.rs1use super::{BackendError, strategy::BackendStrategy};
4use crate::{
5 AsEnvMut, Env, EnvMut, InspectorExt,
6 backend::{
7 Backend, DatabaseExt, JournaledState, LocalForkId, RevertStateSnapshotAction,
8 diagnostic::RevertDiagnostic,
9 },
10 fork::{CreateFork, ForkId},
11};
12use alloy_genesis::GenesisAccount;
13use alloy_primitives::{Address, B256, U256};
14use alloy_rpc_types::TransactionRequest;
15use foundry_fork_db::DatabaseError;
16use revm::{
17 Database, DatabaseCommit,
18 bytecode::Bytecode,
19 context_interface::result::ResultAndState,
20 database::DatabaseRef,
21 primitives::{HashMap as Map, hardfork::SpecId},
22 state::{Account, AccountInfo},
23};
24use std::{any::Any, borrow::Cow, collections::BTreeMap};
25
26#[derive(Clone, Debug)]
43pub struct CowBackend<'a> {
44 pub backend: Cow<'a, Backend>,
48 is_initialized: bool,
50 spec_id: SpecId,
52}
53
54impl<'a> CowBackend<'a> {
55 pub fn new_borrowed(backend: &'a Backend) -> Self {
57 Self { backend: Cow::Borrowed(backend), is_initialized: false, spec_id: SpecId::default() }
58 }
59
60 #[instrument(name = "inspect", level = "debug", skip_all)]
65 pub fn inspect<I: InspectorExt>(
66 &mut self,
67 env: &mut Env,
68 inspector: &mut I,
69 inspect_ctx: Box<dyn Any>,
70 ) -> eyre::Result<ResultAndState> {
71 self.is_initialized = false;
74 self.spec_id = env.evm_env.cfg_env.spec;
75 self.backend.strategy.runner.inspect(self.backend.to_mut(), env, inspector, inspect_ctx)
76 }
77
78 pub fn has_state_snapshot_failure(&self) -> bool {
82 self.backend.has_state_snapshot_failure()
83 }
84
85 fn backend_mut(&mut self, env: &EnvMut<'_>) -> &mut Backend {
89 if !self.is_initialized {
90 let backend = self.backend.to_mut();
91 let mut env = env.to_owned();
92 env.evm_env.cfg_env.spec = self.spec_id;
93 backend.initialize(&env);
94 self.is_initialized = true;
95 return backend;
96 }
97 self.backend.to_mut()
98 }
99
100 fn initialized_backend_mut(&mut self) -> Option<&mut Backend> {
102 if self.is_initialized {
103 return Some(self.backend.to_mut());
104 }
105 None
106 }
107}
108
109impl DatabaseExt for CowBackend<'_> {
110 fn get_strategy(&mut self) -> &mut BackendStrategy {
111 &mut self.backend.to_mut().strategy
112 }
113
114 fn snapshot_state(&mut self, journaled_state: &JournaledState, env: &mut EnvMut<'_>) -> U256 {
115 self.backend_mut(env).snapshot_state(journaled_state, env)
116 }
117
118 fn revert_state(
119 &mut self,
120 id: U256,
121 journaled_state: &JournaledState,
122 current: &mut EnvMut<'_>,
123 action: RevertStateSnapshotAction,
124 ) -> Option<JournaledState> {
125 self.backend_mut(current).revert_state(id, journaled_state, current, action)
126 }
127
128 fn delete_state_snapshot(&mut self, id: U256) -> bool {
129 if let Some(backend) = self.initialized_backend_mut() {
131 return backend.delete_state_snapshot(id);
132 }
133 false
134 }
135
136 fn delete_state_snapshots(&mut self) {
137 if let Some(backend) = self.initialized_backend_mut() {
138 backend.delete_state_snapshots()
139 }
140 }
141
142 fn create_fork(&mut self, fork: CreateFork) -> eyre::Result<LocalForkId> {
143 self.backend.to_mut().create_fork(fork)
144 }
145
146 fn create_fork_at_transaction(
147 &mut self,
148 fork: CreateFork,
149 transaction: B256,
150 ) -> eyre::Result<LocalForkId> {
151 self.backend.to_mut().create_fork_at_transaction(fork, transaction)
152 }
153
154 fn select_fork(
155 &mut self,
156 id: LocalForkId,
157 env: &mut EnvMut<'_>,
158 journaled_state: &mut JournaledState,
159 ) -> eyre::Result<()> {
160 self.backend_mut(env).select_fork(id, env, journaled_state)
161 }
162
163 fn roll_fork(
164 &mut self,
165 id: Option<LocalForkId>,
166 block_number: u64,
167 env: &mut EnvMut<'_>,
168 journaled_state: &mut JournaledState,
169 ) -> eyre::Result<()> {
170 self.backend_mut(env).roll_fork(id, block_number, env, journaled_state)
171 }
172
173 fn roll_fork_to_transaction(
174 &mut self,
175 id: Option<LocalForkId>,
176 transaction: B256,
177 env: &mut EnvMut<'_>,
178 journaled_state: &mut JournaledState,
179 ) -> eyre::Result<()> {
180 self.backend_mut(env).roll_fork_to_transaction(id, transaction, env, journaled_state)
181 }
182
183 fn transact(
184 &mut self,
185 id: Option<LocalForkId>,
186 transaction: B256,
187 mut env: Env,
188 journaled_state: &mut JournaledState,
189 inspector: &mut dyn InspectorExt,
190 ) -> eyre::Result<()> {
191 self.backend_mut(&env.as_env_mut()).transact(
192 id,
193 transaction,
194 env,
195 journaled_state,
196 inspector,
197 )
198 }
199
200 fn transact_from_tx(
201 &mut self,
202 transaction: &TransactionRequest,
203 mut env: Env,
204 journaled_state: &mut JournaledState,
205 inspector: &mut dyn InspectorExt,
206 inspect_ctx: Box<dyn Any>,
207 ) -> eyre::Result<()> {
208 self.backend_mut(&env.as_env_mut()).transact_from_tx(
209 transaction,
210 env,
211 journaled_state,
212 inspector,
213 inspect_ctx,
214 )
215 }
216
217 fn active_fork_id(&self) -> Option<LocalForkId> {
218 self.backend.active_fork_id()
219 }
220
221 fn active_fork_url(&self) -> Option<String> {
222 self.backend.active_fork_url()
223 }
224
225 fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId> {
226 self.backend.ensure_fork(id)
227 }
228
229 fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {
230 self.backend.ensure_fork_id(id)
231 }
232
233 fn diagnose_revert(
234 &self,
235 callee: Address,
236 journaled_state: &JournaledState,
237 ) -> Option<RevertDiagnostic> {
238 self.backend.diagnose_revert(callee, journaled_state)
239 }
240
241 fn load_allocs(
242 &mut self,
243 allocs: &BTreeMap<Address, GenesisAccount>,
244 journaled_state: &mut JournaledState,
245 ) -> Result<(), BackendError> {
246 self.backend_mut(&Env::default().as_env_mut()).load_allocs(allocs, journaled_state)
247 }
248
249 fn clone_account(
250 &mut self,
251 source: &GenesisAccount,
252 target: &Address,
253 journaled_state: &mut JournaledState,
254 ) -> Result<(), BackendError> {
255 self.backend_mut(&Env::default().as_env_mut()).clone_account(
256 source,
257 target,
258 journaled_state,
259 )
260 }
261
262 fn is_persistent(&self, acc: &Address) -> bool {
263 self.backend.is_persistent(acc)
264 }
265
266 fn remove_persistent_account(&mut self, account: &Address) -> bool {
267 self.backend.to_mut().remove_persistent_account(account)
268 }
269
270 fn add_persistent_account(&mut self, account: Address) -> bool {
271 self.backend.to_mut().add_persistent_account(account)
272 }
273
274 fn persistent_accounts(&self) -> &std::collections::HashSet<Address> {
275 self.backend.persistent_accounts()
276 }
277
278 fn allow_cheatcode_access(&mut self, account: Address) -> bool {
279 self.backend.to_mut().allow_cheatcode_access(account)
280 }
281
282 fn revoke_cheatcode_access(&mut self, account: &Address) -> bool {
283 self.backend.to_mut().revoke_cheatcode_access(account)
284 }
285
286 fn has_cheatcode_access(&self, account: &Address) -> bool {
287 self.backend.has_cheatcode_access(account)
288 }
289
290 fn cached_accounts(&self) -> Vec<Address> {
291 self.backend.cached_accounts()
292 }
293
294 fn cached_storage(&self, address: Address) -> Option<Map<U256, U256>> {
295 self.backend.cached_storage(address)
296 }
297
298 fn set_blockhash(&mut self, block_number: U256, block_hash: B256) {
299 self.backend.to_mut().set_blockhash(block_number, block_hash);
300 }
301
302 fn get_test_contract_address(&self) -> Option<Address> {
303 self.backend.get_test_contract_address()
304 }
305}
306
307impl DatabaseRef for CowBackend<'_> {
308 type Error = DatabaseError;
309
310 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
311 DatabaseRef::basic_ref(self.backend.as_ref(), address)
312 }
313
314 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
315 DatabaseRef::code_by_hash_ref(self.backend.as_ref(), code_hash)
316 }
317
318 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
319 DatabaseRef::storage_ref(self.backend.as_ref(), address, index)
320 }
321
322 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
323 DatabaseRef::block_hash_ref(self.backend.as_ref(), number)
324 }
325}
326
327impl Database for CowBackend<'_> {
328 type Error = DatabaseError;
329
330 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
331 DatabaseRef::basic_ref(self, address)
332 }
333
334 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
335 DatabaseRef::code_by_hash_ref(self, code_hash)
336 }
337
338 fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
339 DatabaseRef::storage_ref(self, address, index)
340 }
341
342 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
343 DatabaseRef::block_hash_ref(self, number)
344 }
345}
346
347impl DatabaseCommit for CowBackend<'_> {
348 fn commit(&mut self, changes: Map<Address, Account>) {
349 self.backend.to_mut().commit(changes)
350 }
351}