foundry_evm_core/
evm.rs

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