Skip to main content

foundry_evm_core/evm/
op.rs

1use super::*;
2
3type OpEvmHandler<'db, I> = OpHandler<
4    OpRevmEvm<'db, I>,
5    EVMError<DatabaseError, OpTransactionError>,
6    EthFrame<EthInterpreter>,
7>;
8
9pub type OpRevmEvm<'db, I> = op_revm::OpEvm<
10    OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>,
11    I,
12    EthInstructions<EthInterpreter, OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>,
13    PrecompilesMap,
14>;
15
16/// Optimism counterpart of [`EthFoundryEvm`]. Wraps `op_revm::OpEvm` and routes execution
17/// through [`OpHandler`].
18pub struct OpFoundryEvm<
19    'db,
20    I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>,
21> {
22    pub inner: OpRevmEvm<'db, I>,
23}
24
25impl FoundryEvmFactory for OpEvmFactory {
26    type FoundryContext<'db> = OpContext<&'db mut dyn DatabaseExt<Self>>;
27
28    type FoundryEvm<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>> = OpFoundryEvm<'db, I>;
29
30    fn create_foundry_evm_with_inspector<'db, I: FoundryInspectorExt<Self::FoundryContext<'db>>>(
31        &self,
32        db: &'db mut dyn DatabaseExt<Self>,
33        evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
34        inspector: I,
35    ) -> Self::FoundryEvm<'db, I> {
36        let spec_id = *evm_env.spec_id();
37        let inner = Context::mainnet()
38            .with_tx(OpTx(OpTransaction::builder().build_fill()))
39            .with_cfg(CfgEnv::new_with_spec(OpSpecId::BEDROCK))
40            .with_chain(L1BlockInfo::default())
41            .with_db(db)
42            .with_block(evm_env.block_env)
43            .with_cfg(evm_env.cfg_env);
44        let mut inner = OpEvm::new(inner, inspector).with_precompiles(PrecompilesMap::from_static(
45            OpPrecompiles::new_with_spec(spec_id).precompiles(),
46        ));
47        inner.ctx_mut().cfg.tx_chain_id_check = true;
48
49        let mut evm: OpFoundryEvm<'_, I> = OpFoundryEvm { inner };
50        let networks = Evm::inspector(&evm).get_networks();
51        networks.inject_precompiles(evm.precompiles_mut());
52        evm
53    }
54
55    fn create_foundry_nested_evm<'db>(
56        &self,
57        db: &'db mut dyn DatabaseExt<Self>,
58        evm_env: EvmEnv<Self::Spec, Self::BlockEnv>,
59        inspector: &'db mut dyn FoundryInspectorExt<Self::FoundryContext<'db>>,
60    ) -> Box<dyn NestedEvm<Spec = OpSpecId, Block = BlockEnv, Tx = OpTx> + 'db> {
61        Box::new(self.create_foundry_evm_with_inspector(db, evm_env, inspector).inner)
62    }
63}
64
65impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>> Evm
66    for OpFoundryEvm<'db, I>
67{
68    type Precompiles = PrecompilesMap;
69    type Inspector = I;
70    type DB = &'db mut dyn DatabaseExt<OpEvmFactory>;
71    type Error = EVMError<DatabaseError>;
72    type HaltReason = OpHaltReason;
73    type Spec = OpSpecId;
74    type Tx = OpTx;
75    type BlockEnv = BlockEnv;
76
77    fn block(&self) -> &BlockEnv {
78        &self.inner.ctx_ref().block
79    }
80
81    fn chain_id(&self) -> u64 {
82        self.inner.ctx_ref().cfg.chain_id
83    }
84
85    fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) {
86        let (ctx, _, precompiles, _, inspector) = self.inner.all_inspector();
87        (&ctx.journaled_state.database, inspector, precompiles)
88    }
89
90    fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) {
91        let (ctx, _, precompiles, _, inspector) = self.inner.all_mut_inspector();
92        (&mut ctx.journaled_state.database, inspector, precompiles)
93    }
94
95    fn set_inspector_enabled(&mut self, _enabled: bool) {
96        unimplemented!("OpFoundryEvm is always inspecting")
97    }
98
99    fn transact_raw(
100        &mut self,
101        tx: Self::Tx,
102    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
103        self.inner.ctx().set_tx(tx);
104
105        let mut handler = OpEvmHandler::<I>::new();
106        // Convert OpTransactionError to InvalidTransaction due to missing InvalidTxError impl
107        let result = handler.inspect_run(&mut self.inner).map_err(|e| match e {
108            EVMError::Transaction(tx_error) => EVMError::Transaction(match tx_error {
109                OpTransactionError::Base(invalid_transaction) => invalid_transaction,
110                OpTransactionError::DepositSystemTxPostRegolith => {
111                    InvalidTransaction::Str("DepositSystemTxPostRegolith".into())
112                }
113                OpTransactionError::HaltedDepositPostRegolith => {
114                    InvalidTransaction::Str("HaltedDepositPostRegolith".into())
115                }
116                OpTransactionError::MissingEnvelopedTx => {
117                    InvalidTransaction::Str("MissingEnvelopedTx".into())
118                }
119            }),
120            EVMError::Header(invalid_header) => EVMError::Header(invalid_header),
121            EVMError::Database(db_error) => EVMError::Database(db_error),
122            EVMError::Custom(custom_error) => EVMError::Custom(custom_error),
123            EVMError::CustomAny(custom_any_error) => EVMError::CustomAny(custom_any_error),
124        })?;
125
126        Ok(ResultAndState::new(result, self.inner.ctx_ref().journaled_state.inner.state.clone()))
127    }
128
129    fn transact_system_call(
130        &mut self,
131        _caller: Address,
132        _contract: Address,
133        _data: Bytes,
134    ) -> Result<ExecResultAndState<ExecutionResult<Self::HaltReason>>, Self::Error> {
135        unimplemented!()
136    }
137
138    fn finish(self) -> (Self::DB, EvmEnv<Self::Spec>)
139    where
140        Self: Sized,
141    {
142        let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.0.ctx;
143        (journaled_state.database, EvmEnv { block_env, cfg_env })
144    }
145}
146
147impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>> Deref
148    for OpFoundryEvm<'db, I>
149{
150    type Target = OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>;
151
152    fn deref(&self) -> &Self::Target {
153        &self.inner.0.ctx
154    }
155}
156
157impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>> DerefMut
158    for OpFoundryEvm<'db, I>
159{
160    fn deref_mut(&mut self) -> &mut Self::Target {
161        &mut self.inner.0.ctx
162    }
163}
164
165/// Maps an OP [`EVMError`] to the common `EVMError<DatabaseError>` used by [`NestedEvm`].
166fn map_op_error(e: EVMError<DatabaseError, OpTransactionError>) -> EVMError<DatabaseError> {
167    match e {
168        EVMError::Database(db) => EVMError::Database(db),
169        EVMError::Header(h) => EVMError::Header(h),
170        EVMError::Custom(s) => EVMError::Custom(s),
171        EVMError::Transaction(t) => EVMError::Custom(format!("op transaction error: {t}")),
172        EVMError::CustomAny(custom_any_error) => EVMError::CustomAny(custom_any_error),
173    }
174}
175
176impl<'db, I: FoundryInspectorExt<OpContext<&'db mut dyn DatabaseExt<OpEvmFactory>>>> NestedEvm
177    for OpRevmEvm<'db, I>
178{
179    type Spec = OpSpecId;
180    type Block = BlockEnv;
181    type Tx = OpTx;
182
183    fn journal_inner_mut(&mut self) -> &mut JournaledState {
184        &mut self.ctx().journaled_state.inner
185    }
186
187    fn run_execution(&mut self, frame: FrameInput) -> Result<FrameResult, EVMError<DatabaseError>> {
188        let mut handler = OpEvmHandler::<I>::new();
189
190        let memory =
191            SharedMemory::new_with_buffer(self.ctx_ref().local.shared_memory_buffer().clone());
192        let first_frame_input = FrameInit { depth: 0, memory, frame_input: frame };
193
194        let mut frame_result =
195            handler.inspect_run_exec_loop(self, first_frame_input).map_err(map_op_error)?;
196
197        handler.last_frame_result(self, &mut frame_result).map_err(map_op_error)?;
198
199        Ok(frame_result)
200    }
201
202    fn transact_raw(
203        &mut self,
204        tx: Self::Tx,
205    ) -> Result<ResultAndState<HaltReason>, EVMError<DatabaseError>> {
206        self.ctx().set_tx(tx);
207
208        let mut handler = OpEvmHandler::<I>::new();
209        let result = handler.inspect_run(self).map_err(map_op_error)?;
210
211        let result = result.map_haltreason(|h| match h {
212            OpHaltReason::Base(eth) => eth,
213            _ => HaltReason::PrecompileError,
214        });
215
216        Ok(ResultAndState::new(result, self.ctx_ref().journaled_state.inner.state.clone()))
217    }
218
219    fn to_evm_env(&self) -> EvmEnv<Self::Spec, Self::Block> {
220        EvmEnv::new(self.ctx_ref().cfg.clone(), self.ctx_ref().block.clone())
221    }
222}