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