Skip to main content

foundry_evm_core/evm/
eth.rs

1use alloy_evm::{
2    EthEvm, EthEvmFactory, Evm, EvmEnv, EvmFactory, eth::EthEvmContext, precompiles::PrecompilesMap,
3};
4use foundry_fork_db::DatabaseError;
5use revm::{
6    context::{
7        BlockEnv, ContextTr, Evm as RevmEvm, Journal, LocalContextTr, TxEnv,
8        result::{EVMError, ResultAndState},
9    },
10    handler::{
11        EthFrame, EvmTr, FrameResult, Handler, MainnetHandler, instructions::EthInstructions,
12    },
13    inspector::InspectorHandler,
14    interpreter::{
15        FrameInput, GasTracker, SharedMemory, interpreter::EthInterpreter,
16        interpreter_action::FrameInit,
17    },
18    primitives::hardfork::SpecId,
19};
20
21use crate::{
22    FoundryContextExt, FoundryInspectorExt,
23    backend::{DatabaseExt, JournaledState},
24    evm::{FoundryEvmFactory, NestedEvm, NestedEvmFor},
25};
26
27type EthEvmHandler<'db, I> = MainnetHandler<EthRevmEvm<'db, I>, EVMError<DatabaseError>, EthFrame>;
28
29pub type EthRevmEvm<'db, I> = RevmEvm<
30    EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>,
31    I,
32    EthInstructions<EthInterpreter, EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>,
33    PrecompilesMap,
34    EthFrame,
35>;
36
37impl FoundryEvmFactory for EthEvmFactory {
38    type Chain = ();
39    type FoundryContext<'db> = EthEvmContext<&'db mut dyn DatabaseExt<Self>>;
40
41    type FoundryEvm<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>> =
42        EthEvm<&'db mut dyn DatabaseExt<Self>, I, Self::Precompiles>;
43
44    fn create_evm_with_context<DB: alloy_evm::Database>(
45        &self,
46        db: DB,
47        evm_env: EvmEnv,
48        _chain_context: Self::Chain,
49    ) -> Self::Evm<DB, revm::inspector::NoOpInspector> {
50        self.create_evm(db, evm_env)
51    }
52
53    fn create_foundry_evm_with_inspector<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>>(
54        &self,
55        db: &'db mut dyn DatabaseExt<Self>,
56        evm_env: EvmEnv,
57        _chain_context: Self::Chain,
58        inspector: I,
59    ) -> Self::FoundryEvm<'db, I> {
60        let chain_id = evm_env.cfg_env.chain_id;
61        let timestamp = evm_env.block_env.timestamp.saturating_to();
62        let mut eth_evm = Self::default().create_evm_with_inspector(db, evm_env, inspector);
63        eth_evm.cfg.tx_chain_id_check = true;
64        let networks = eth_evm.inspector().get_networks();
65        networks.inject_precompiles(eth_evm.precompiles_mut());
66        networks.inject_chain_precompiles(eth_evm.precompiles_mut(), chain_id, timestamp);
67        eth_evm
68    }
69
70    fn create_foundry_nested_evm<'db>(
71        &self,
72        db: &'db mut dyn DatabaseExt<Self>,
73        evm_env: EvmEnv,
74        chain_context: Self::Chain,
75        inspector: &'db mut dyn FoundryInspectorExt<Self::FoundryContext<'db>>,
76    ) -> NestedEvmFor<'db, Self> {
77        Box::new(
78            self.create_foundry_evm_with_inspector(db, evm_env, chain_context, inspector)
79                .into_inner(),
80        )
81    }
82}
83
84impl<'db, I: FoundryInspectorExt<EthEvmContext<&'db mut dyn DatabaseExt<EthEvmFactory>>>> NestedEvm
85    for EthRevmEvm<'db, I>
86{
87    type Spec = SpecId;
88    type Block = BlockEnv;
89    type Tx = TxEnv;
90    type Chain = ();
91    type Journal = Journal<&'db mut dyn DatabaseExt<EthEvmFactory>>;
92
93    fn tx_mut(&mut self) -> &mut Self::Tx {
94        self.ctx_mut().tx_mut()
95    }
96
97    fn journal_inner_mut(&mut self) -> &mut JournaledState {
98        &mut self.ctx_mut().journaled_state.inner
99    }
100
101    fn chain_mut(&mut self) -> &mut Self::Chain {
102        &mut self.ctx_mut().chain
103    }
104
105    fn journal_mut(&mut self) -> &mut Self::Journal {
106        &mut self.ctx_mut().journaled_state
107    }
108
109    fn run_execution(&mut self, frame: FrameInput) -> Result<FrameResult, EVMError<DatabaseError>> {
110        let mut handler = EthEvmHandler::<I>::default();
111        // Create first frame
112        let memory =
113            SharedMemory::new_with_buffer(self.ctx_ref().local().shared_memory_buffer().clone());
114        let first_frame_input = FrameInit { depth: 0, memory, frame_input: frame };
115
116        // Run execution loop
117        let mut frame_result = handler.inspect_run_exec_loop(self, first_frame_input)?;
118
119        // Handle last frame result
120        let mut parent_gas = GasTracker::new(
121            frame_result.gas().limit(),
122            frame_result.gas().remaining(),
123            frame_result.gas().reservoir(),
124        );
125        handler.last_frame_result(self, &mut frame_result, &mut parent_gas)?;
126
127        Ok(frame_result)
128    }
129
130    fn transact_raw(&mut self, tx: Self::Tx) -> eyre::Result<ResultAndState> {
131        self.set_tx(tx);
132
133        let result = EthEvmHandler::<I>::default().inspect_run(self)?;
134
135        Ok(ResultAndState::new(result, self.ctx.journaled_state.inner.state.clone()))
136    }
137
138    fn to_evm_env(&self) -> EvmEnv<Self::Spec, Self::Block> {
139        self.ctx_ref().evm_clone()
140    }
141}