foundry_evm_core/backend/
cow.rs1use super::BackendError;
4use crate::{
5 EthInspectorExt,
6 backend::{
7 Backend, DatabaseExt, JournaledState, LocalForkId, RevertStateSnapshotAction,
8 diagnostic::RevertDiagnostic,
9 },
10 fork::{CreateFork, ForkId},
11};
12use alloy_evm::{Evm, EvmEnv};
13use alloy_genesis::GenesisAccount;
14use alloy_primitives::{Address, B256, TxKind, U256};
15use eyre::WrapErr;
16use foundry_fork_db::DatabaseError;
17use revm::{
18 Database, DatabaseCommit,
19 bytecode::Bytecode,
20 context::TxEnv,
21 context_interface::result::ResultAndState,
22 database::DatabaseRef,
23 primitives::{HashMap as Map, hardfork::SpecId},
24 state::{Account, AccountInfo, EvmState},
25};
26use std::{borrow::Cow, collections::BTreeMap};
27
28#[derive(Clone, Debug)]
45pub struct CowBackend<'a> {
46 pub backend: Cow<'a, Backend>,
50 pending_init: Option<(SpecId, Address, TxKind)>,
53}
54
55impl<'a> CowBackend<'a> {
56 pub fn new_borrowed(backend: &'a Backend) -> Self {
58 Self { backend: Cow::Borrowed(backend), pending_init: None }
59 }
60
61 #[instrument(name = "inspect", level = "debug", skip_all)]
66 pub fn inspect<I: EthInspectorExt>(
67 &mut self,
68 evm_env: &mut EvmEnv,
69 tx_env: &mut TxEnv,
70 inspector: I,
71 ) -> eyre::Result<ResultAndState> {
72 self.pending_init = Some((evm_env.cfg_env.spec, tx_env.caller, tx_env.kind));
75
76 let mut evm = crate::evm::new_eth_evm_with_inspector(
77 self,
78 evm_env.clone(),
79 tx_env.clone(),
80 inspector,
81 );
82
83 let res = evm.transact(tx_env.clone()).wrap_err("EVM error")?;
84
85 *evm_env = EvmEnv::new(evm.cfg.clone(), evm.block.clone());
86 *tx_env = evm.tx.clone();
87
88 Ok(res)
89 }
90
91 pub fn has_state_snapshot_failure(&self) -> bool {
95 self.backend.has_state_snapshot_failure()
96 }
97
98 fn backend_mut(&mut self) -> &mut Backend {
102 if let Some((spec_id, caller, tx_kind)) = self.pending_init.take() {
103 let backend = self.backend.to_mut();
104 backend.initialize(spec_id, caller, tx_kind);
105 return backend;
106 }
107 self.backend.to_mut()
108 }
109
110 fn initialized_backend_mut(&mut self) -> Option<&mut Backend> {
112 if self.pending_init.is_none() {
113 return Some(self.backend.to_mut());
114 }
115 None
116 }
117}
118
119impl DatabaseExt for CowBackend<'_> {
120 fn snapshot_state(&mut self, journaled_state: &JournaledState, evm_env: &EvmEnv) -> U256 {
121 self.backend_mut().snapshot_state(journaled_state, evm_env)
122 }
123
124 fn revert_state(
125 &mut self,
126 id: U256,
127 journaled_state: &JournaledState,
128 evm_env: &mut EvmEnv,
129 tx_env: &mut TxEnv,
130 action: RevertStateSnapshotAction,
131 ) -> Option<JournaledState> {
132 self.backend_mut().revert_state(id, journaled_state, evm_env, tx_env, action)
133 }
134
135 fn delete_state_snapshot(&mut self, id: U256) -> bool {
136 if let Some(backend) = self.initialized_backend_mut() {
138 return backend.delete_state_snapshot(id);
139 }
140 false
141 }
142
143 fn delete_state_snapshots(&mut self) {
144 if let Some(backend) = self.initialized_backend_mut() {
145 backend.delete_state_snapshots()
146 }
147 }
148
149 fn create_fork(&mut self, fork: CreateFork) -> eyre::Result<LocalForkId> {
150 self.backend.to_mut().create_fork(fork)
151 }
152
153 fn create_fork_at_transaction(
154 &mut self,
155 fork: CreateFork,
156 transaction: B256,
157 ) -> eyre::Result<LocalForkId> {
158 self.backend.to_mut().create_fork_at_transaction(fork, transaction)
159 }
160
161 fn select_fork(
162 &mut self,
163 id: LocalForkId,
164 evm_env: &mut EvmEnv,
165 tx_env: &mut TxEnv,
166 journaled_state: &mut JournaledState,
167 ) -> eyre::Result<()> {
168 self.backend_mut().select_fork(id, evm_env, tx_env, journaled_state)
169 }
170
171 fn roll_fork(
172 &mut self,
173 id: Option<LocalForkId>,
174 block_number: u64,
175 evm_env: &mut EvmEnv,
176 tx_env: &mut TxEnv,
177 journaled_state: &mut JournaledState,
178 ) -> eyre::Result<()> {
179 self.backend_mut().roll_fork(id, block_number, evm_env, tx_env, journaled_state)
180 }
181
182 fn roll_fork_to_transaction(
183 &mut self,
184 id: Option<LocalForkId>,
185 transaction: B256,
186 evm_env: &mut EvmEnv,
187 tx_env: &mut TxEnv,
188 journaled_state: &mut JournaledState,
189 ) -> eyre::Result<()> {
190 self.backend_mut().roll_fork_to_transaction(
191 id,
192 transaction,
193 evm_env,
194 tx_env,
195 journaled_state,
196 )
197 }
198
199 fn transact(
200 &mut self,
201 id: Option<LocalForkId>,
202 transaction: B256,
203 evm_env: EvmEnv,
204 tx_env: TxEnv,
205 journaled_state: &mut JournaledState,
206 inspector: &mut dyn EthInspectorExt,
207 ) -> eyre::Result<()> {
208 self.backend_mut().transact(id, transaction, evm_env, tx_env, journaled_state, inspector)
209 }
210
211 fn transact_from_tx(
212 &mut self,
213 tx_env: &TxEnv,
214 evm_env: EvmEnv,
215 journaled_state: &mut JournaledState,
216 inspector: &mut dyn EthInspectorExt,
217 ) -> eyre::Result<()> {
218 self.backend_mut().transact_from_tx(tx_env, evm_env, journaled_state, inspector)
219 }
220
221 fn active_fork_id(&self) -> Option<LocalForkId> {
222 self.backend.active_fork_id()
223 }
224
225 fn active_fork_url(&self) -> Option<String> {
226 self.backend.active_fork_url()
227 }
228
229 fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId> {
230 self.backend.ensure_fork(id)
231 }
232
233 fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {
234 self.backend.ensure_fork_id(id)
235 }
236
237 fn diagnose_revert(&self, callee: Address, evm_state: &EvmState) -> Option<RevertDiagnostic> {
238 self.backend.diagnose_revert(callee, evm_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.to_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.to_mut().clone_account(source, target, journaled_state)
256 }
257
258 fn is_persistent(&self, acc: &Address) -> bool {
259 self.backend.is_persistent(acc)
260 }
261
262 fn remove_persistent_account(&mut self, account: &Address) -> bool {
263 self.backend.to_mut().remove_persistent_account(account)
264 }
265
266 fn add_persistent_account(&mut self, account: Address) -> bool {
267 self.backend.to_mut().add_persistent_account(account)
268 }
269
270 fn allow_cheatcode_access(&mut self, account: Address) -> bool {
271 self.backend.to_mut().allow_cheatcode_access(account)
272 }
273
274 fn revoke_cheatcode_access(&mut self, account: &Address) -> bool {
275 self.backend.to_mut().revoke_cheatcode_access(account)
276 }
277
278 fn has_cheatcode_access(&self, account: &Address) -> bool {
279 self.backend.has_cheatcode_access(account)
280 }
281
282 fn set_blockhash(&mut self, block_number: U256, block_hash: B256) {
283 self.backend.to_mut().set_blockhash(block_number, block_hash);
284 }
285}
286
287impl DatabaseRef for CowBackend<'_> {
288 type Error = DatabaseError;
289
290 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
291 DatabaseRef::basic_ref(self.backend.as_ref(), address)
292 }
293
294 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
295 DatabaseRef::code_by_hash_ref(self.backend.as_ref(), code_hash)
296 }
297
298 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
299 DatabaseRef::storage_ref(self.backend.as_ref(), address, index)
300 }
301
302 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
303 DatabaseRef::block_hash_ref(self.backend.as_ref(), number)
304 }
305}
306
307impl Database for CowBackend<'_> {
308 type Error = DatabaseError;
309
310 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
311 DatabaseRef::basic_ref(self, address)
312 }
313
314 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
315 DatabaseRef::code_by_hash_ref(self, code_hash)
316 }
317
318 fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
319 DatabaseRef::storage_ref(self, address, index)
320 }
321
322 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
323 DatabaseRef::block_hash_ref(self, number)
324 }
325}
326
327impl DatabaseCommit for CowBackend<'_> {
328 fn commit(&mut self, changes: Map<Address, Account>) {
329 self.backend.to_mut().commit(changes)
330 }
331}