1use alloy_evm::{Database, EthEvm, Evm, EvmEnv, eth::EthEvmContext};
2use alloy_op_evm::OpEvm;
3use alloy_primitives::{Address, Bytes};
4use op_revm::{OpContext, OpHaltReason, OpSpecId, OpTransaction, OpTransactionError};
5use revm::{
6 DatabaseCommit, Inspector,
7 context::{
8 BlockEnv, TxEnv,
9 result::{EVMError, ExecResultAndState, ExecutionResult, ResultAndState},
10 },
11 handler::PrecompileProvider,
12 interpreter::InterpreterResult,
13 primitives::hardfork::SpecId,
14};
15
16type EitherEvmResult<DBError, HaltReason, TxError> =
18 Result<ResultAndState<HaltReason>, EVMError<DBError, TxError>>;
19
20type EitherExecResult<DBError, HaltReason, TxError> =
22 Result<ExecutionResult<HaltReason>, EVMError<DBError, TxError>>;
23
24#[allow(clippy::large_enum_variant)]
37pub enum EitherEvm<DB, I, P>
38where
39 DB: Database,
40{
41 Eth(EthEvm<DB, I, P>),
43 Op(OpEvm<DB, I, P>),
45}
46
47impl<DB, I, P> EitherEvm<DB, I, P>
48where
49 DB: Database,
50 I: Inspector<EthEvmContext<DB>> + Inspector<OpContext<DB>>,
51 P: PrecompileProvider<EthEvmContext<DB>, Output = InterpreterResult>
52 + PrecompileProvider<OpContext<DB>, Output = InterpreterResult>,
53{
54 fn map_eth_result(
56 &self,
57 result: Result<ExecResultAndState<ExecutionResult>, EVMError<DB::Error>>,
58 ) -> EitherEvmResult<DB::Error, OpHaltReason, OpTransactionError> {
59 match result {
60 Ok(result) => Ok(ResultAndState {
61 result: result.result.map_haltreason(OpHaltReason::Base),
62 state: result.state,
63 }),
64 Err(e) => Err(self.map_eth_err(e)),
65 }
66 }
67
68 fn map_exec_result(
70 &self,
71 result: Result<ExecutionResult, EVMError<DB::Error>>,
72 ) -> EitherExecResult<DB::Error, OpHaltReason, OpTransactionError> {
73 match result {
74 Ok(result) => {
75 Ok(result.map_haltreason(OpHaltReason::Base))
77 }
78 Err(e) => Err(self.map_eth_err(e)),
79 }
80 }
81
82 fn map_eth_err(&self, err: EVMError<DB::Error>) -> EVMError<DB::Error, OpTransactionError> {
84 match err {
85 EVMError::Transaction(invalid_tx) => {
86 EVMError::Transaction(OpTransactionError::Base(invalid_tx))
87 }
88 EVMError::Database(e) => EVMError::Database(e),
89 EVMError::Header(e) => EVMError::Header(e),
90 EVMError::Custom(e) => EVMError::Custom(e),
91 }
92 }
93}
94
95impl<DB, I, P> Evm for EitherEvm<DB, I, P>
96where
97 DB: Database,
98 I: Inspector<EthEvmContext<DB>> + Inspector<OpContext<DB>>,
99 P: PrecompileProvider<EthEvmContext<DB>, Output = InterpreterResult>
100 + PrecompileProvider<OpContext<DB>, Output = InterpreterResult>,
101{
102 type DB = DB;
103 type Error = EVMError<DB::Error, OpTransactionError>;
104 type HaltReason = OpHaltReason;
105 type Tx = OpTransaction<TxEnv>;
106 type Inspector = I;
107 type Precompiles = P;
108 type Spec = SpecId;
109
110 fn block(&self) -> &BlockEnv {
111 match self {
112 Self::Eth(evm) => evm.block(),
113 Self::Op(evm) => evm.block(),
114 }
115 }
116
117 fn chain_id(&self) -> u64 {
118 match self {
119 Self::Eth(evm) => evm.chain_id(),
120 Self::Op(evm) => evm.chain_id(),
121 }
122 }
123
124 fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) {
125 match self {
126 Self::Eth(evm) => evm.components(),
127 Self::Op(evm) => evm.components(),
128 }
129 }
130
131 fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) {
132 match self {
133 Self::Eth(evm) => evm.components_mut(),
134 Self::Op(evm) => evm.components_mut(),
135 }
136 }
137
138 fn db_mut(&mut self) -> &mut Self::DB {
139 match self {
140 Self::Eth(evm) => evm.db_mut(),
141 Self::Op(evm) => evm.db_mut(),
142 }
143 }
144
145 fn into_db(self) -> Self::DB
146 where
147 Self: Sized,
148 {
149 match self {
150 Self::Eth(evm) => evm.into_db(),
151 Self::Op(evm) => evm.into_db(),
152 }
153 }
154
155 fn finish(self) -> (Self::DB, EvmEnv<Self::Spec>)
156 where
157 Self: Sized,
158 {
159 match self {
160 Self::Eth(evm) => evm.finish(),
161 Self::Op(evm) => {
162 let (db, env) = evm.finish();
163 (db, map_env(env))
164 }
165 }
166 }
167
168 fn precompiles(&self) -> &Self::Precompiles {
169 match self {
170 Self::Eth(evm) => evm.precompiles(),
171 Self::Op(evm) => evm.precompiles(),
172 }
173 }
174
175 fn precompiles_mut(&mut self) -> &mut Self::Precompiles {
176 match self {
177 Self::Eth(evm) => evm.precompiles_mut(),
178 Self::Op(evm) => evm.precompiles_mut(),
179 }
180 }
181
182 fn inspector(&self) -> &Self::Inspector {
183 match self {
184 Self::Eth(evm) => evm.inspector(),
185 Self::Op(evm) => evm.inspector(),
186 }
187 }
188
189 fn inspector_mut(&mut self) -> &mut Self::Inspector {
190 match self {
191 Self::Eth(evm) => evm.inspector_mut(),
192 Self::Op(evm) => evm.inspector_mut(),
193 }
194 }
195
196 fn enable_inspector(&mut self) {
197 match self {
198 Self::Eth(evm) => evm.enable_inspector(),
199 Self::Op(evm) => evm.enable_inspector(),
200 }
201 }
202
203 fn disable_inspector(&mut self) {
204 match self {
205 Self::Eth(evm) => evm.disable_inspector(),
206 Self::Op(evm) => evm.disable_inspector(),
207 }
208 }
209
210 fn set_inspector_enabled(&mut self, enabled: bool) {
211 match self {
212 Self::Eth(evm) => evm.set_inspector_enabled(enabled),
213 Self::Op(evm) => evm.set_inspector_enabled(enabled),
214 }
215 }
216
217 fn into_env(self) -> EvmEnv<Self::Spec>
218 where
219 Self: Sized,
220 {
221 match self {
222 Self::Eth(evm) => evm.into_env(),
223 Self::Op(evm) => map_env(evm.into_env()),
224 }
225 }
226
227 fn transact(
228 &mut self,
229 tx: impl alloy_evm::IntoTxEnv<Self::Tx>,
230 ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
231 match self {
232 Self::Eth(evm) => {
233 let eth = evm.transact(tx.into_tx_env().base);
234 self.map_eth_result(eth)
235 }
236 Self::Op(evm) => evm.transact(tx),
237 }
238 }
239
240 fn transact_commit(
241 &mut self,
242 tx: impl alloy_evm::IntoTxEnv<Self::Tx>,
243 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error>
244 where
245 Self::DB: DatabaseCommit,
246 {
247 match self {
248 Self::Eth(evm) => {
249 let eth = evm.transact_commit(tx.into_tx_env().base);
250 self.map_exec_result(eth)
251 }
252 Self::Op(evm) => evm.transact_commit(tx),
253 }
254 }
255
256 fn transact_raw(
257 &mut self,
258 tx: Self::Tx,
259 ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
260 match self {
261 Self::Eth(evm) => {
262 let res = evm.transact_raw(tx.base);
263 self.map_eth_result(res)
264 }
265 Self::Op(evm) => evm.transact_raw(tx),
266 }
267 }
268
269 fn transact_system_call(
270 &mut self,
271 caller: Address,
272 contract: Address,
273 data: Bytes,
274 ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
275 match self {
276 Self::Eth(evm) => {
277 let eth = evm.transact_system_call(caller, contract, data);
278 self.map_eth_result(eth)
279 }
280 Self::Op(evm) => evm.transact_system_call(caller, contract, data),
281 }
282 }
283}
284
285fn map_env(env: EvmEnv<OpSpecId>) -> EvmEnv {
287 let eth_spec_id = env.spec_id().into_eth_spec();
288 let cfg = env.cfg_env.with_spec(eth_spec_id);
289 EvmEnv { cfg_env: cfg, block_env: env.block_env }
290}