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 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 let mut frame_result = handler.inspect_run_exec_loop(self, first_frame_input)?;
118
119 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}