1use std::{
2 marker::PhantomData,
3 ops::{Deref, DerefMut},
4};
5
6use crate::{
7 Env, InspectorExt, backend::DatabaseExt, constants::DEFAULT_CREATE2_DEPLOYER_CODEHASH,
8};
9use alloy_consensus::constants::KECCAK_EMPTY;
10use alloy_evm::{Evm, EvmEnv, eth::EthEvmContext, precompiles::PrecompilesMap};
11use alloy_primitives::{Address, Bytes, U256};
12use foundry_fork_db::DatabaseError;
13use revm::{
14 Context, Journal,
15 context::{
16 BlockEnv, CfgEnv, ContextTr, CreateScheme, Evm as RevmEvm, JournalTr, LocalContext,
17 LocalContextTr, TxEnv,
18 result::{EVMError, ExecResultAndState, ExecutionResult, HaltReason, ResultAndState},
19 },
20 handler::{
21 EthFrame, EthPrecompiles, EvmTr, FrameResult, FrameTr, Handler, ItemOrResult,
22 instructions::EthInstructions,
23 },
24 inspector::{InspectorEvmTr, InspectorHandler},
25 interpreter::{
26 CallInput, CallInputs, CallOutcome, CallScheme, CallValue, CreateInputs, CreateOutcome,
27 FrameInput, Gas, InstructionResult, InterpreterResult, SharedMemory,
28 interpreter::EthInterpreter, interpreter_action::FrameInit, return_ok,
29 },
30 precompile::{PrecompileSpecId, Precompiles},
31 primitives::hardfork::SpecId,
32};
33
34pub fn new_evm_with_inspector<'db, I: InspectorExt>(
35 db: &'db mut dyn DatabaseExt,
36 env: Env,
37 inspector: I,
38) -> FoundryEvm<'db, I> {
39 let mut ctx = EthEvmContext {
40 journaled_state: {
41 let mut journal = Journal::new(db);
42 journal.set_spec_id(env.evm_env.cfg_env.spec);
43 journal
44 },
45 block: env.evm_env.block_env,
46 cfg: env.evm_env.cfg_env,
47 tx: env.tx,
48 chain: (),
49 local: LocalContext::default(),
50 error: Ok(()),
51 };
52 ctx.cfg.tx_chain_id_check = true;
53 let spec = ctx.cfg.spec;
54
55 let mut evm = FoundryEvm {
56 inner: RevmEvm::new_with_inspector(
57 ctx,
58 inspector,
59 EthInstructions::default(),
60 get_precompiles(spec),
61 ),
62 };
63
64 evm.inspector().get_networks().inject_precompiles(evm.precompiles_mut());
65 evm
66}
67
68pub fn new_evm_with_existing_context<'a>(
69 ctx: EthEvmContext<&'a mut dyn DatabaseExt>,
70 inspector: &'a mut dyn InspectorExt,
71) -> FoundryEvm<'a, &'a mut dyn InspectorExt> {
72 let spec = ctx.cfg.spec;
73
74 let mut evm = FoundryEvm {
75 inner: RevmEvm::new_with_inspector(
76 ctx,
77 inspector,
78 EthInstructions::default(),
79 get_precompiles(spec),
80 ),
81 };
82
83 evm.inspector().get_networks().inject_precompiles(evm.precompiles_mut());
84 evm
85}
86
87fn get_precompiles(spec: SpecId) -> PrecompilesMap {
89 PrecompilesMap::from_static(
90 EthPrecompiles {
91 precompiles: Precompiles::new(PrecompileSpecId::from_spec_id(spec)),
92 spec,
93 }
94 .precompiles,
95 )
96}
97
98fn get_create2_factory_call_inputs(
100 salt: U256,
101 inputs: &CreateInputs,
102 deployer: Address,
103) -> CallInputs {
104 let calldata = [&salt.to_be_bytes::<32>()[..], &inputs.init_code[..]].concat();
105 CallInputs {
106 caller: inputs.caller,
107 bytecode_address: deployer,
108 known_bytecode: None,
109 target_address: deployer,
110 scheme: CallScheme::Call,
111 value: CallValue::Transfer(inputs.value),
112 input: CallInput::Bytes(calldata.into()),
113 gas_limit: inputs.gas_limit,
114 is_static: false,
115 return_memory_offset: 0..0,
116 }
117}
118
119pub struct FoundryEvm<'db, I: InspectorExt> {
120 #[allow(clippy::type_complexity)]
121 inner: RevmEvm<
122 EthEvmContext<&'db mut dyn DatabaseExt>,
123 I,
124 EthInstructions<EthInterpreter, EthEvmContext<&'db mut dyn DatabaseExt>>,
125 PrecompilesMap,
126 EthFrame<EthInterpreter>,
127 >,
128}
129impl<'db, I: InspectorExt> FoundryEvm<'db, I> {
130 pub fn into_context(self) -> EthEvmContext<&'db mut dyn DatabaseExt> {
132 self.inner.ctx
133 }
134
135 pub fn run_execution(
136 &mut self,
137 frame: FrameInput,
138 ) -> Result<FrameResult, EVMError<DatabaseError>> {
139 let mut handler = FoundryHandler::<I>::default();
140
141 let memory =
143 SharedMemory::new_with_buffer(self.inner.ctx().local().shared_memory_buffer().clone());
144 let first_frame_input = FrameInit { depth: 0, memory, frame_input: frame };
145
146 let mut frame_result = handler.inspect_run_exec_loop(&mut self.inner, first_frame_input)?;
148
149 handler.last_frame_result(&mut self.inner, &mut frame_result)?;
151
152 Ok(frame_result)
153 }
154}
155
156impl<'db, I: InspectorExt> Evm for FoundryEvm<'db, I> {
157 type Precompiles = PrecompilesMap;
158 type Inspector = I;
159 type DB = &'db mut dyn DatabaseExt;
160 type Error = EVMError<DatabaseError>;
161 type HaltReason = HaltReason;
162 type Spec = SpecId;
163 type Tx = TxEnv;
164 type BlockEnv = BlockEnv;
165
166 fn block(&self) -> &BlockEnv {
167 &self.inner.block
168 }
169
170 fn chain_id(&self) -> u64 {
171 self.inner.ctx.cfg.chain_id
172 }
173
174 fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) {
175 (&self.inner.ctx.journaled_state.database, &self.inner.inspector, &self.inner.precompiles)
176 }
177
178 fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) {
179 (
180 &mut self.inner.ctx.journaled_state.database,
181 &mut self.inner.inspector,
182 &mut self.inner.precompiles,
183 )
184 }
185
186 fn db_mut(&mut self) -> &mut Self::DB {
187 &mut self.inner.ctx.journaled_state.database
188 }
189
190 fn precompiles(&self) -> &Self::Precompiles {
191 &self.inner.precompiles
192 }
193
194 fn precompiles_mut(&mut self) -> &mut Self::Precompiles {
195 &mut self.inner.precompiles
196 }
197
198 fn inspector(&self) -> &Self::Inspector {
199 &self.inner.inspector
200 }
201
202 fn inspector_mut(&mut self) -> &mut Self::Inspector {
203 &mut self.inner.inspector
204 }
205
206 fn set_inspector_enabled(&mut self, _enabled: bool) {
207 unimplemented!("FoundryEvm is always inspecting")
208 }
209
210 fn transact_raw(
211 &mut self,
212 tx: Self::Tx,
213 ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
214 self.inner.ctx.tx = tx;
215
216 let mut handler = FoundryHandler::<I>::default();
217 let result = handler.inspect_run(&mut self.inner)?;
218
219 Ok(ResultAndState::new(result, self.inner.ctx.journaled_state.inner.state.clone()))
220 }
221
222 fn transact_system_call(
223 &mut self,
224 _caller: Address,
225 _contract: Address,
226 _data: Bytes,
227 ) -> Result<ExecResultAndState<ExecutionResult>, Self::Error> {
228 unimplemented!()
229 }
230
231 fn finish(self) -> (Self::DB, EvmEnv<Self::Spec>)
232 where
233 Self: Sized,
234 {
235 let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.ctx;
236
237 (journaled_state.database, EvmEnv { block_env, cfg_env })
238 }
239}
240
241impl<'db, I: InspectorExt> Deref for FoundryEvm<'db, I> {
242 type Target = Context<BlockEnv, TxEnv, CfgEnv, &'db mut dyn DatabaseExt>;
243
244 fn deref(&self) -> &Self::Target {
245 &self.inner.ctx
246 }
247}
248
249impl<I: InspectorExt> DerefMut for FoundryEvm<'_, I> {
250 fn deref_mut(&mut self) -> &mut Self::Target {
251 &mut self.inner.ctx
252 }
253}
254
255pub struct FoundryHandler<'db, I: InspectorExt> {
256 create2_overrides: Vec<(usize, CallInputs)>,
257 _phantom: PhantomData<(&'db mut dyn DatabaseExt, I)>,
258}
259
260impl<I: InspectorExt> Default for FoundryHandler<'_, I> {
261 fn default() -> Self {
262 Self { create2_overrides: Vec::new(), _phantom: PhantomData }
263 }
264}
265
266impl<'db, I: InspectorExt> Handler for FoundryHandler<'db, I> {
269 type Evm = RevmEvm<
270 EthEvmContext<&'db mut dyn DatabaseExt>,
271 I,
272 EthInstructions<EthInterpreter, EthEvmContext<&'db mut dyn DatabaseExt>>,
273 PrecompilesMap,
274 EthFrame<EthInterpreter>,
275 >;
276 type Error = EVMError<DatabaseError>;
277 type HaltReason = HaltReason;
278}
279
280impl<'db, I: InspectorExt> FoundryHandler<'db, I> {
281 fn handle_create_frame(
284 &mut self,
285 evm: &mut <Self as Handler>::Evm,
286 init: &mut FrameInit,
287 ) -> Result<Option<FrameResult>, <Self as Handler>::Error> {
288 if let FrameInput::Create(inputs) = &init.frame_input
289 && let CreateScheme::Create2 { salt } = inputs.scheme
290 {
291 let (ctx, inspector) = evm.ctx_inspector();
292
293 if inspector.should_use_create2_factory(ctx, inputs) {
294 let gas_limit = inputs.gas_limit;
295
296 let create2_deployer = evm.inspector().create2_deployer();
298
299 let call_inputs = get_create2_factory_call_inputs(salt, inputs, create2_deployer);
301
302 self.create2_overrides.push((evm.journal().depth(), call_inputs.clone()));
304
305 let code_hash = evm.journal_mut().load_account(create2_deployer)?.info.code_hash;
307 if code_hash == KECCAK_EMPTY {
308 return Ok(Some(FrameResult::Call(CallOutcome {
309 result: InterpreterResult {
310 result: InstructionResult::Revert,
311 output: Bytes::from(
312 format!("missing CREATE2 deployer: {create2_deployer}")
313 .into_bytes(),
314 ),
315 gas: Gas::new(gas_limit),
316 },
317 memory_offset: 0..0,
318 })));
319 } else if code_hash != DEFAULT_CREATE2_DEPLOYER_CODEHASH {
320 return Ok(Some(FrameResult::Call(CallOutcome {
321 result: InterpreterResult {
322 result: InstructionResult::Revert,
323 output: "invalid CREATE2 deployer bytecode".into(),
324 gas: Gas::new(gas_limit),
325 },
326 memory_offset: 0..0,
327 })));
328 }
329
330 init.frame_input = FrameInput::Call(Box::new(call_inputs));
332 }
333 }
334 Ok(None)
335 }
336
337 fn handle_create2_override(
339 &mut self,
340 evm: &mut <Self as Handler>::Evm,
341 result: FrameResult,
342 ) -> FrameResult {
343 if self.create2_overrides.last().is_some_and(|(depth, _)| *depth == evm.journal().depth()) {
344 let (_, call_inputs) = self.create2_overrides.pop().unwrap();
345 let FrameResult::Call(mut call) = result else {
346 unreachable!("create2 override should be a call frame");
347 };
348
349 let address = match call.instruction_result() {
351 return_ok!() => Address::try_from(call.output().as_ref())
352 .map_err(|_| {
353 call.result = InterpreterResult {
354 result: InstructionResult::Revert,
355 output: "invalid CREATE2 factory output".into(),
356 gas: Gas::new(call_inputs.gas_limit),
357 };
358 })
359 .ok(),
360 _ => None,
361 };
362
363 FrameResult::Create(CreateOutcome { result: call.result, address })
364 } else {
365 result
366 }
367 }
368}
369
370impl<I: InspectorExt> InspectorHandler for FoundryHandler<'_, I> {
371 type IT = EthInterpreter;
372
373 fn inspect_run_exec_loop(
374 &mut self,
375 evm: &mut Self::Evm,
376 first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
377 ) -> Result<FrameResult, Self::Error> {
378 let res = evm.inspect_frame_init(first_frame_input)?;
379
380 if let ItemOrResult::Result(frame_result) = res {
381 return Ok(frame_result);
382 }
383
384 loop {
385 let call_or_result = evm.inspect_frame_run()?;
386
387 let result = match call_or_result {
388 ItemOrResult::Item(mut init) => {
389 if let Some(frame_result) = self.handle_create_frame(evm, &mut init)? {
391 return Ok(frame_result);
392 }
393
394 match evm.inspect_frame_init(init)? {
395 ItemOrResult::Item(_) => continue,
396 ItemOrResult::Result(result) => result,
397 }
398 }
399 ItemOrResult::Result(result) => result,
400 };
401
402 let result = self.handle_create2_override(evm, result);
404
405 if let Some(result) = evm.frame_return_result(result)? {
406 return Ok(result);
407 }
408 }
409 }
410}