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::{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
87/// Get the precompiles for the given spec.
88fn 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
98/// Get the call inputs for the CREATE2 factory.
99fn 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    /// Consumes the EVM and returns the inner context.
131    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        // Create first frame
142        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        // Run execution loop
147        let mut frame_result = handler.inspect_run_exec_loop(&mut self.inner, first_frame_input)?;
148
149        // Handle last frame result
150        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
266// Blanket Handler implementation for FoundryHandler, needed for implementing the InspectorHandler
267// trait.
268impl<'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    /// Handles CREATE2 frame initialization, potentially transforming it to use the CREATE2
282    /// factory.
283    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                // Get CREATE2 deployer.
297                let create2_deployer = evm.inspector().create2_deployer();
298
299                // Generate call inputs for CREATE2 factory.
300                let call_inputs = get_create2_factory_call_inputs(salt, inputs, create2_deployer);
301
302                // Push data about current override to the stack.
303                self.create2_overrides.push((evm.journal().depth(), call_inputs.clone()));
304
305                // Sanity check that CREATE2 deployer exists.
306                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                // Rewrite the frame init
331                init.frame_input = FrameInput::Call(Box::new(call_inputs));
332            }
333        }
334        Ok(None)
335    }
336
337    /// Transforms CREATE2 factory call results back into CREATE outcomes.
338    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            // Decode address from output.
350            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                    // Handle CREATE/CREATE2 frame initialization
390                    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            // Handle CREATE2 override transformation if needed
403            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}