foundry_evm_core/backend/
cow.rs
1use super::BackendError;
4use crate::{
5 backend::{
6 diagnostic::RevertDiagnostic, Backend, DatabaseExt, LocalForkId, RevertStateSnapshotAction,
7 },
8 fork::{CreateFork, ForkId},
9 InspectorExt,
10};
11use alloy_genesis::GenesisAccount;
12use alloy_primitives::{Address, B256, U256};
13use alloy_rpc_types::TransactionRequest;
14use eyre::WrapErr;
15use foundry_fork_db::DatabaseError;
16use revm::{
17 db::DatabaseRef,
18 primitives::{
19 Account, AccountInfo, Bytecode, Env, EnvWithHandlerCfg, HashMap as Map, ResultAndState,
20 SpecId,
21 },
22 Database, DatabaseCommit, JournaledState,
23};
24use std::{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::LATEST }
58 }
59
60 #[instrument(name = "inspect", level = "debug", skip_all)]
65 pub fn inspect<I: InspectorExt>(
66 &mut self,
67 env: &mut EnvWithHandlerCfg,
68 inspector: &mut I,
69 ) -> eyre::Result<ResultAndState> {
70 self.is_initialized = false;
73 self.spec_id = env.handler_cfg.spec_id;
74 let mut evm = crate::utils::new_evm_with_inspector(self, env.clone(), inspector);
75
76 let res = evm.transact().wrap_err("EVM error")?;
77
78 env.env = evm.context.evm.inner.env;
79
80 Ok(res)
81 }
82
83 pub fn has_state_snapshot_failure(&self) -> bool {
87 self.backend.has_state_snapshot_failure()
88 }
89
90 fn backend_mut(&mut self, env: &Env) -> &mut Backend {
94 if !self.is_initialized {
95 let backend = self.backend.to_mut();
96 let env = EnvWithHandlerCfg::new_with_spec_id(Box::new(env.clone()), self.spec_id);
97 backend.initialize(&env);
98 self.is_initialized = true;
99 return backend
100 }
101 self.backend.to_mut()
102 }
103
104 fn initialized_backend_mut(&mut self) -> Option<&mut Backend> {
106 if self.is_initialized {
107 return Some(self.backend.to_mut())
108 }
109 None
110 }
111}
112
113impl DatabaseExt for CowBackend<'_> {
114 fn snapshot_state(&mut self, journaled_state: &JournaledState, env: &Env) -> 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 Env,
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 Env,
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 Env,
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 Env,
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 env: Env,
188 journaled_state: &mut JournaledState,
189 inspector: &mut dyn InspectorExt,
190 ) -> eyre::Result<()> {
191 self.backend_mut(&env).transact(id, transaction, env, journaled_state, inspector)
192 }
193
194 fn transact_from_tx(
195 &mut self,
196 transaction: &TransactionRequest,
197 env: Env,
198 journaled_state: &mut JournaledState,
199 inspector: &mut dyn InspectorExt,
200 ) -> eyre::Result<()> {
201 self.backend_mut(&env).transact_from_tx(transaction, env, journaled_state, inspector)
202 }
203
204 fn active_fork_id(&self) -> Option<LocalForkId> {
205 self.backend.active_fork_id()
206 }
207
208 fn active_fork_url(&self) -> Option<String> {
209 self.backend.active_fork_url()
210 }
211
212 fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId> {
213 self.backend.ensure_fork(id)
214 }
215
216 fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {
217 self.backend.ensure_fork_id(id)
218 }
219
220 fn diagnose_revert(
221 &self,
222 callee: Address,
223 journaled_state: &JournaledState,
224 ) -> Option<RevertDiagnostic> {
225 self.backend.diagnose_revert(callee, journaled_state)
226 }
227
228 fn load_allocs(
229 &mut self,
230 allocs: &BTreeMap<Address, GenesisAccount>,
231 journaled_state: &mut JournaledState,
232 ) -> Result<(), BackendError> {
233 self.backend_mut(&Env::default()).load_allocs(allocs, journaled_state)
234 }
235
236 fn clone_account(
237 &mut self,
238 source: &GenesisAccount,
239 target: &Address,
240 journaled_state: &mut JournaledState,
241 ) -> Result<(), BackendError> {
242 self.backend_mut(&Env::default()).clone_account(source, target, journaled_state)
243 }
244
245 fn is_persistent(&self, acc: &Address) -> bool {
246 self.backend.is_persistent(acc)
247 }
248
249 fn remove_persistent_account(&mut self, account: &Address) -> bool {
250 self.backend.to_mut().remove_persistent_account(account)
251 }
252
253 fn add_persistent_account(&mut self, account: Address) -> bool {
254 self.backend.to_mut().add_persistent_account(account)
255 }
256
257 fn allow_cheatcode_access(&mut self, account: Address) -> bool {
258 self.backend.to_mut().allow_cheatcode_access(account)
259 }
260
261 fn revoke_cheatcode_access(&mut self, account: &Address) -> bool {
262 self.backend.to_mut().revoke_cheatcode_access(account)
263 }
264
265 fn has_cheatcode_access(&self, account: &Address) -> bool {
266 self.backend.has_cheatcode_access(account)
267 }
268
269 fn set_blockhash(&mut self, block_number: U256, block_hash: B256) {
270 self.backend.to_mut().set_blockhash(block_number, block_hash);
271 }
272}
273
274impl DatabaseRef for CowBackend<'_> {
275 type Error = DatabaseError;
276
277 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
278 DatabaseRef::basic_ref(self.backend.as_ref(), address)
279 }
280
281 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
282 DatabaseRef::code_by_hash_ref(self.backend.as_ref(), code_hash)
283 }
284
285 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
286 DatabaseRef::storage_ref(self.backend.as_ref(), address, index)
287 }
288
289 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
290 DatabaseRef::block_hash_ref(self.backend.as_ref(), number)
291 }
292}
293
294impl Database for CowBackend<'_> {
295 type Error = DatabaseError;
296
297 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
298 DatabaseRef::basic_ref(self, address)
299 }
300
301 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
302 DatabaseRef::code_by_hash_ref(self, code_hash)
303 }
304
305 fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
306 DatabaseRef::storage_ref(self, address, index)
307 }
308
309 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
310 DatabaseRef::block_hash_ref(self, number)
311 }
312}
313
314impl DatabaseCommit for CowBackend<'_> {
315 fn commit(&mut self, changes: Map<Address, Account>) {
316 self.backend.to_mut().commit(changes)
317 }
318}