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