1use super::BackendError;
4use crate::{
5 FoundryInspectorExt,
6 backend::{
7 Backend, ContextUpdateFor, DatabaseExt, ForkAccountField, JournaledState, LocalForkId,
8 RevertStateSnapshotAction, diagnostic::RevertDiagnostic, existing_account,
9 },
10 evm::{
11 ChainFor, EvmEnvFor, FoundryContextFor, FoundryEvmFactory, FoundryEvmNetwork,
12 HaltReasonFor, SpecFor, TxEnvFor,
13 },
14 fork::{CreateFork, ForkId},
15};
16use alloy_evm::Evm;
17use alloy_genesis::GenesisAccount;
18use alloy_primitives::{Address, B256, TxKind, U256};
19use eyre::WrapErr;
20use foundry_fork_db::DatabaseError;
21use revm::{
22 Database, DatabaseCommit,
23 bytecode::Bytecode,
24 context::{ContextTr, Transaction},
25 context_interface::result::ResultAndState,
26 database::DatabaseRef,
27 primitives::AddressMap,
28 state::{Account, AccountInfo, EvmState},
29};
30use std::{borrow::Cow, collections::BTreeMap, fmt::Debug};
31
32#[cfg(feature = "monad")]
33use crate::evm::MonadEvmNetwork;
34#[cfg(feature = "monad")]
35use alloy_evm::EvmEnv;
36#[cfg(feature = "monad")]
37use alloy_monad_evm::MonadEvmFactory;
38#[cfg(feature = "monad")]
39use monad_revm::{MonadChainContext, MonadHardfork};
40#[cfg(feature = "monad")]
41use revm::context::TxEnv;
42
43pub struct CowBackend<'a, FEN: FoundryEvmNetwork> {
60 pub backend: Cow<'a, Backend<FEN>>,
64 pending_init: Option<(SpecFor<FEN>, Address, TxKind)>,
67}
68
69impl<FEN: FoundryEvmNetwork> Clone for CowBackend<'_, FEN> {
70 fn clone(&self) -> Self {
71 Self { backend: self.backend.clone(), pending_init: self.pending_init }
72 }
73}
74
75impl<FEN: FoundryEvmNetwork> Debug for CowBackend<'_, FEN> {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 f.debug_struct("CowBackend")
78 .field("backend", &self.backend)
79 .field("pending_init", &self.pending_init)
80 .finish()
81 }
82}
83
84impl<'a, FEN: FoundryEvmNetwork> CowBackend<'a, FEN> {
85 pub const fn new_borrowed(backend: &'a Backend<FEN>) -> Self {
87 Self { backend: Cow::Borrowed(backend), pending_init: None }
88 }
89
90 #[instrument(name = "inspect", level = "debug", skip_all)]
95 pub fn inspect<I: for<'db> FoundryInspectorExt<FoundryContextFor<'db, FEN>>>(
96 &mut self,
97 evm_env: &mut EvmEnvFor<FEN>,
98 tx_env: &mut TxEnvFor<FEN>,
99 inspector: I,
100 ) -> eyre::Result<ResultAndState<HaltReasonFor<FEN>>> {
101 let chain_context = self.chain_context_for_synthetic_transaction(tx_env)?;
102 self.inspect_with_context(evm_env, tx_env, chain_context, inspector)
103 }
104
105 #[instrument(name = "inspect", level = "debug", skip_all)]
107 pub fn inspect_with_context<I: for<'db> FoundryInspectorExt<FoundryContextFor<'db, FEN>>>(
108 &mut self,
109 evm_env: &mut EvmEnvFor<FEN>,
110 tx_env: &mut TxEnvFor<FEN>,
111 chain_context: ChainFor<FEN>,
112 inspector: I,
113 ) -> eyre::Result<ResultAndState<HaltReasonFor<FEN>>> {
114 self.pending_init = Some((evm_env.cfg_env.spec, tx_env.caller(), tx_env.kind()));
117
118 let factory = FEN::EvmFactory::default();
119 let mut evm = factory.create_foundry_evm_with_inspector(self, evm_env.clone(), inspector);
120 *evm.chain_mut() = chain_context;
121
122 let res = evm.transact(tx_env.clone()).wrap_err("EVM error")?;
123
124 *tx_env = evm.tx().clone();
125 *evm_env = evm.finish().1;
126
127 Ok(res)
128 }
129
130 pub fn has_state_snapshot_failure(&self) -> bool {
134 self.backend.has_state_snapshot_failure()
135 }
136
137 fn backend_mut(&mut self) -> &mut Backend<FEN> {
141 if let Some((spec_id, caller, tx_kind)) = self.pending_init.take() {
142 let backend = self.backend.to_mut();
143 backend.initialize(spec_id, caller, tx_kind);
144 return backend;
145 }
146 self.backend.to_mut()
147 }
148}
149
150#[cfg(feature = "monad")]
151impl CowBackend<'_, MonadEvmNetwork> {
152 #[instrument(name = "inspect_system_replay", level = "debug", skip_all)]
154 pub fn try_inspect_system_replay_with_context<
155 I: for<'db> FoundryInspectorExt<FoundryContextFor<'db, MonadEvmNetwork>>,
156 >(
157 &mut self,
158 evm_env: &mut EvmEnv<MonadHardfork>,
159 tx_env: &mut TxEnv,
160 chain_context: MonadChainContext,
161 inspector: &mut I,
162 ) -> eyre::Result<Option<ResultAndState<revm::context_interface::result::HaltReason>>> {
163 if crate::evm::protocol_system_call(tx_env)?.is_none() {
164 return Ok(None);
165 }
166
167 self.pending_init = Some((evm_env.cfg_env.spec, tx_env.caller(), tx_env.kind()));
168
169 let factory = MonadEvmFactory::default();
170 let mut evm = factory.create_nested_evm_with_inspector(self, evm_env.clone(), inspector);
171 *evm.chain_mut() = chain_context;
172 let result = evm.transact_raw(tx_env.clone())?;
173
174 *evm_env = evm.to_evm_env();
178
179 Ok(Some(result))
180 }
181}
182
183impl<FEN: FoundryEvmNetwork> DatabaseExt<FEN::EvmFactory> for CowBackend<'_, FEN> {
184 fn chain_context_for_synthetic_transaction(
185 &self,
186 tx: &TxEnvFor<FEN>,
187 ) -> eyre::Result<ChainFor<FEN>> {
188 self.backend.chain_context_for_synthetic_transaction(tx)
189 }
190
191 fn snapshot_state(
192 &mut self,
193 journaled_state: &JournaledState,
194 evm_env: &EvmEnvFor<FEN>,
195 ) -> U256 {
196 self.backend_mut().snapshot_state(journaled_state, evm_env)
197 }
198
199 fn revert_state(
200 &mut self,
201 id: U256,
202 journaled_state: &JournaledState,
203 evm_env: &mut EvmEnvFor<FEN>,
204 caller: Address,
205 action: RevertStateSnapshotAction,
206 ) -> Option<JournaledState> {
207 self.backend_mut().revert_state(id, journaled_state, evm_env, caller, action)
208 }
209
210 fn delete_state_snapshot(&mut self, id: U256) -> bool {
211 if self.backend.state_snapshots().get(id).is_none() {
213 return false;
214 }
215 self.backend_mut().delete_state_snapshot(id)
216 }
217
218 fn delete_state_snapshots(&mut self) {
219 if self.backend.state_snapshots().is_empty() {
221 return;
222 }
223 self.backend_mut().delete_state_snapshots()
224 }
225
226 fn create_fork(&mut self, fork: CreateFork) -> eyre::Result<LocalForkId> {
227 self.backend.to_mut().create_fork(fork)
228 }
229
230 fn create_fork_at_transaction(
231 &mut self,
232 fork: CreateFork,
233 transaction: B256,
234 ) -> eyre::Result<LocalForkId> {
235 self.backend.to_mut().create_fork_at_transaction(fork, transaction)
236 }
237
238 fn select_fork(
239 &mut self,
240 id: LocalForkId,
241 evm_env: &mut EvmEnvFor<FEN>,
242 tx_env: &mut TxEnvFor<FEN>,
243 journaled_state: &mut JournaledState,
244 ) -> eyre::Result<ContextUpdateFor<FEN::EvmFactory>> {
245 self.backend_mut().select_fork(id, evm_env, tx_env, journaled_state)
246 }
247
248 fn roll_fork(
249 &mut self,
250 id: Option<LocalForkId>,
251 block_number: u64,
252 evm_env: &mut EvmEnvFor<FEN>,
253 tx_env: &TxEnvFor<FEN>,
254 journaled_state: &mut JournaledState,
255 ) -> eyre::Result<ContextUpdateFor<FEN::EvmFactory>> {
256 self.backend_mut().roll_fork(id, block_number, evm_env, tx_env, journaled_state)
257 }
258
259 fn roll_fork_to_transaction(
260 &mut self,
261 id: Option<LocalForkId>,
262 transaction: B256,
263 evm_env: &mut EvmEnvFor<FEN>,
264 tx_env: &TxEnvFor<FEN>,
265 journaled_state: &mut JournaledState,
266 ) -> eyre::Result<ContextUpdateFor<FEN::EvmFactory>> {
267 self.backend_mut().roll_fork_to_transaction(
268 id,
269 transaction,
270 evm_env,
271 tx_env,
272 journaled_state,
273 )
274 }
275
276 fn transact(
277 &mut self,
278 id: Option<LocalForkId>,
279 transaction: B256,
280 evm_env: EvmEnvFor<FEN>,
281 outer_tx_env: &TxEnvFor<FEN>,
282 journaled_state: &mut JournaledState,
283 inspector: &mut dyn for<'db> FoundryInspectorExt<
284 <FEN::EvmFactory as FoundryEvmFactory>::FoundryContext<'db>,
285 >,
286 ) -> eyre::Result<ContextUpdateFor<FEN::EvmFactory>> {
287 self.backend_mut().transact(
288 id,
289 transaction,
290 evm_env,
291 outer_tx_env,
292 journaled_state,
293 inspector,
294 )
295 }
296
297 fn transact_from_tx(
298 &mut self,
299 tx_env: TxEnvFor<FEN>,
300 evm_env: EvmEnvFor<FEN>,
301 journaled_state: &mut JournaledState,
302 inspector: &mut dyn for<'db> FoundryInspectorExt<
303 <FEN::EvmFactory as FoundryEvmFactory>::FoundryContext<'db>,
304 >,
305 ) -> eyre::Result<()> {
306 self.backend_mut().transact_from_tx(tx_env, evm_env, journaled_state, inspector)
307 }
308
309 fn active_fork_id(&self) -> Option<LocalForkId> {
310 self.backend.active_fork_id()
311 }
312
313 fn active_fork_url(&self) -> Option<String> {
314 self.backend.active_fork_url()
315 }
316
317 fn active_fork_options(&self) -> Option<CreateFork> {
318 self.backend.active_fork_options()
319 }
320
321 fn active_fork_source_chain_id(&self) -> Option<u64> {
322 self.backend.active_fork_source_chain_id()
323 }
324
325 fn active_fork_block_number(&self) -> Option<u64> {
326 self.backend.active_fork_block_number()
327 }
328
329 fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId> {
330 self.backend.ensure_fork(id)
331 }
332
333 fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {
334 self.backend.ensure_fork_id(id)
335 }
336
337 fn diagnose_revert(&self, callee: Address, evm_state: &EvmState) -> Option<RevertDiagnostic> {
338 self.backend.diagnose_revert(callee, evm_state)
339 }
340
341 fn load_allocs(
342 &mut self,
343 allocs: &BTreeMap<Address, GenesisAccount>,
344 journaled_state: &mut JournaledState,
345 ) -> Result<(), BackendError> {
346 self.backend.to_mut().load_allocs(allocs, journaled_state)
347 }
348
349 fn clone_account(
350 &mut self,
351 source: &GenesisAccount,
352 target: &Address,
353 journaled_state: &mut JournaledState,
354 ) -> Result<(), BackendError> {
355 self.backend.to_mut().clone_account(source, target, journaled_state)
356 }
357
358 fn is_persistent(&self, acc: &Address) -> bool {
359 self.backend.is_persistent(acc)
360 }
361
362 fn refresh_fork_account(
363 &mut self,
364 address: Address,
365 field: ForkAccountField,
366 journaled_state: &mut JournaledState,
367 ) -> Result<(), BackendError> {
368 self.backend.to_mut().refresh_fork_account(address, field, journaled_state)
369 }
370
371 fn refresh_fork_storage(
372 &mut self,
373 address: Address,
374 slot: U256,
375 journaled_state: &mut JournaledState,
376 ) -> Result<(), BackendError> {
377 self.backend.to_mut().refresh_fork_storage(address, slot, journaled_state)
378 }
379
380 fn remove_persistent_account(&mut self, account: &Address) -> bool {
381 self.backend.to_mut().remove_persistent_account(account)
382 }
383
384 fn add_persistent_account(&mut self, account: Address) -> bool {
385 self.backend.to_mut().add_persistent_account(account)
386 }
387
388 fn allow_cheatcode_access(&mut self, account: Address) -> bool {
389 self.backend.to_mut().allow_cheatcode_access(account)
390 }
391
392 fn revoke_cheatcode_access(&mut self, account: &Address) -> bool {
393 self.backend.to_mut().revoke_cheatcode_access(account)
394 }
395
396 fn has_cheatcode_access(&self, account: &Address) -> bool {
397 self.backend.has_cheatcode_access(account)
398 }
399
400 fn set_blockhash(&mut self, block_number: U256, block_hash: B256) {
401 self.backend.to_mut().set_blockhash(block_number, block_hash);
402 }
403}
404
405impl<FEN: FoundryEvmNetwork> DatabaseRef for CowBackend<'_, FEN> {
406 type Error = DatabaseError;
407
408 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
409 DatabaseRef::basic_ref(self.backend.as_ref(), address)
410 }
411
412 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
413 DatabaseRef::code_by_hash_ref(self.backend.as_ref(), code_hash)
414 }
415
416 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
417 DatabaseRef::storage_ref(self.backend.as_ref(), address, index)
418 }
419
420 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
421 DatabaseRef::block_hash_ref(self.backend.as_ref(), number)
422 }
423}
424
425impl<FEN: FoundryEvmNetwork> Database for CowBackend<'_, FEN> {
426 type Error = DatabaseError;
427
428 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
429 let spec = self.pending_init.map_or(self.backend.inner.spec_id, |(spec, ..)| spec);
430 Ok(existing_account(spec, DatabaseRef::basic_ref(self, address)?))
431 }
432
433 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
434 DatabaseRef::code_by_hash_ref(self, code_hash)
435 }
436
437 fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
438 DatabaseRef::storage_ref(self, address, index)
439 }
440
441 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
442 DatabaseRef::block_hash_ref(self, number)
443 }
444}
445
446impl<FEN: FoundryEvmNetwork> DatabaseCommit for CowBackend<'_, FEN> {
447 fn commit(&mut self, changes: AddressMap<Account>) {
448 self.backend.to_mut().commit(changes)
449 }
450}