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<'db, I: InspectorExt>(
42    db: &'db mut dyn DatabaseExt,
43    env: Env,
44    inspector: I,
45) -> FoundryEvm<'db, 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 block(&self) -> &BlockEnv {
182        &self.inner.block
183    }
184
185    fn chain_id(&self) -> u64 {
186        self.inner.ctx.cfg.chain_id
187    }
188
189    fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) {
190        (&self.inner.ctx.journaled_state.database, &self.inner.inspector, &self.inner.precompiles)
191    }
192
193    fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) {
194        (
195            &mut self.inner.ctx.journaled_state.database,
196            &mut self.inner.inspector,
197            &mut self.inner.precompiles,
198        )
199    }
200
201    fn db_mut(&mut self) -> &mut Self::DB {
202        &mut self.inner.ctx.journaled_state.database
203    }
204
205    fn precompiles(&self) -> &Self::Precompiles {
206        &self.inner.precompiles
207    }
208
209    fn precompiles_mut(&mut self) -> &mut Self::Precompiles {
210        &mut self.inner.precompiles
211    }
212
213    fn inspector(&self) -> &Self::Inspector {
214        &self.inner.inspector
215    }
216
217    fn inspector_mut(&mut self) -> &mut Self::Inspector {
218        &mut self.inner.inspector
219    }
220
221    fn set_inspector_enabled(&mut self, _enabled: bool) {
222        unimplemented!("FoundryEvm is always inspecting")
223    }
224
225    fn transact_raw(
226        &mut self,
227        tx: Self::Tx,
228    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
229        self.inner.ctx.tx = tx;
230
231        let mut handler = FoundryHandler::<I>::default();
232        let result = handler.inspect_run(&mut self.inner)?;
233
234        Ok(ResultAndState::new(result, self.inner.ctx.journaled_state.inner.state.clone()))
235    }
236
237    fn transact_system_call(
238        &mut self,
239        _caller: Address,
240        _contract: Address,
241        _data: Bytes,
242    ) -> Result<ExecResultAndState<ExecutionResult>, Self::Error> {
243        unimplemented!()
244    }
245
246    fn finish(self) -> (Self::DB, EvmEnv<Self::Spec>)
247    where
248        Self: Sized,
249    {
250        let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.ctx;
251
252        (journaled_state.database, EvmEnv { block_env, cfg_env })
253    }
254}
255
256impl<'db, I: InspectorExt> Deref for FoundryEvm<'db, I> {
257    type Target = Context<BlockEnv, TxEnv, CfgEnv, &'db mut dyn DatabaseExt>;
258
259    fn deref(&self) -> &Self::Target {
260        &self.inner.ctx
261    }
262}
263
264impl<I: InspectorExt> DerefMut for FoundryEvm<'_, I> {
265    fn deref_mut(&mut self) -> &mut Self::Target {
266        &mut self.inner.ctx
267    }
268}
269
270pub struct FoundryHandler<'db, I: InspectorExt> {
271    create2_overrides: Vec<(usize, CallInputs)>,
272    _phantom: PhantomData<(&'db mut dyn DatabaseExt, I)>,
273}
274
275impl<I: InspectorExt> Default for FoundryHandler<'_, I> {
276    fn default() -> Self {
277        Self { create2_overrides: Vec::new(), _phantom: PhantomData }
278    }
279}
280
281// Blanket Handler implementation for FoundryHandler, needed for implementing the InspectorHandler
282// trait.
283impl<'db, I: InspectorExt> Handler for FoundryHandler<'db, I> {
284    type Evm = RevmEvm<
285        EthEvmContext<&'db mut dyn DatabaseExt>,
286        I,
287        EthInstructions<EthInterpreter, EthEvmContext<&'db mut dyn DatabaseExt>>,
288        PrecompilesMap,
289        EthFrame<EthInterpreter>,
290    >;
291    type Error = EVMError<DatabaseError>;
292    type HaltReason = HaltReason;
293}
294
295impl<'db, I: InspectorExt> FoundryHandler<'db, I> {
296    /// Handles CREATE2 frame initialization, potentially transforming it to use the CREATE2
297    /// factory.
298    fn handle_create_frame(
299        &mut self,
300        evm: &mut <Self as Handler>::Evm,
301        init: &mut FrameInit,
302    ) -> Result<Option<FrameResult>, <Self as Handler>::Error> {
303        if let FrameInput::Create(inputs) = &init.frame_input
304            && let CreateScheme::Create2 { salt } = inputs.scheme
305        {
306            let (ctx, inspector) = evm.ctx_inspector();
307
308            if inspector.should_use_create2_factory(ctx, inputs) {
309                let gas_limit = inputs.gas_limit;
310
311                // Get CREATE2 deployer.
312                let create2_deployer = evm.inspector().create2_deployer();
313
314                // Generate call inputs for CREATE2 factory.
315                let call_inputs = get_create2_factory_call_inputs(salt, inputs, create2_deployer);
316
317                // Push data about current override to the stack.
318                self.create2_overrides.push((evm.journal().depth(), call_inputs.clone()));
319
320                // Sanity check that CREATE2 deployer exists.
321                let code_hash = evm.journal_mut().load_account(create2_deployer)?.info.code_hash;
322                if code_hash == KECCAK_EMPTY {
323                    return Ok(Some(FrameResult::Call(CallOutcome {
324                        result: InterpreterResult {
325                            result: InstructionResult::Revert,
326                            output: Bytes::from(
327                                format!("missing CREATE2 deployer: {create2_deployer}")
328                                    .into_bytes(),
329                            ),
330                            gas: Gas::new(gas_limit),
331                        },
332                        memory_offset: 0..0,
333                    })));
334                } else if code_hash != DEFAULT_CREATE2_DEPLOYER_CODEHASH {
335                    return Ok(Some(FrameResult::Call(CallOutcome {
336                        result: InterpreterResult {
337                            result: InstructionResult::Revert,
338                            output: "invalid CREATE2 deployer bytecode".into(),
339                            gas: Gas::new(gas_limit),
340                        },
341                        memory_offset: 0..0,
342                    })));
343                }
344
345                // Rewrite the frame init
346                init.frame_input = FrameInput::Call(Box::new(call_inputs));
347            }
348        }
349        Ok(None)
350    }
351
352    /// Transforms CREATE2 factory call results back into CREATE outcomes.
353    fn handle_create2_override(
354        &mut self,
355        evm: &mut <Self as Handler>::Evm,
356        result: FrameResult,
357    ) -> FrameResult {
358        if self.create2_overrides.last().is_some_and(|(depth, _)| *depth == evm.journal().depth()) {
359            let (_, call_inputs) = self.create2_overrides.pop().unwrap();
360            let FrameResult::Call(mut call) = result else {
361                unreachable!("create2 override should be a call frame");
362            };
363
364            // Decode address from output.
365            let address = match call.instruction_result() {
366                return_ok!() => Address::try_from(call.output().as_ref())
367                    .map_err(|_| {
368                        call.result = InterpreterResult {
369                            result: InstructionResult::Revert,
370                            output: "invalid CREATE2 factory output".into(),
371                            gas: Gas::new(call_inputs.gas_limit),
372                        };
373                    })
374                    .ok(),
375                _ => None,
376            };
377
378            FrameResult::Create(CreateOutcome { result: call.result, address })
379        } else {
380            result
381        }
382    }
383}
384
385impl<I: InspectorExt> InspectorHandler for FoundryHandler<'_, I> {
386    type IT = EthInterpreter;
387
388    fn inspect_run_exec_loop(
389        &mut self,
390        evm: &mut Self::Evm,
391        first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
392    ) -> Result<FrameResult, Self::Error> {
393        let res = evm.inspect_frame_init(first_frame_input)?;
394
395        if let ItemOrResult::Result(frame_result) = res {
396            return Ok(frame_result);
397        }
398
399        loop {
400            let call_or_result = evm.inspect_frame_run()?;
401
402            let result = match call_or_result {
403                ItemOrResult::Item(mut init) => {
404                    // Handle CREATE/CREATE2 frame initialization
405                    if let Some(frame_result) = self.handle_create_frame(evm, &mut init)? {
406                        return Ok(frame_result);
407                    }
408
409                    match evm.inspect_frame_init(init)? {
410                        ItemOrResult::Item(_) => continue,
411                        ItemOrResult::Result(result) => result,
412                    }
413                }
414                ItemOrResult::Result(result) => result,
415            };
416
417            // Handle CREATE2 override transformation if needed
418            let result = self.handle_create2_override(evm, result);
419
420            if let Some(result) = evm.frame_return_result(result)? {
421                return Ok(result);
422            }
423        }
424    }
425}