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 type BlockEnv = BlockEnv;
110
111 fn block(&self) -> &BlockEnv {
112 match self {
113 Self::Eth(evm) => evm.block(),
114 Self::Op(evm) => evm.block(),
115 }
116 }
117
118 fn chain_id(&self) -> u64 {
119 match self {
120 Self::Eth(evm) => evm.chain_id(),
121 Self::Op(evm) => evm.chain_id(),
122 }
123 }
124
125 fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) {
126 match self {
127 Self::Eth(evm) => evm.components(),
128 Self::Op(evm) => evm.components(),
129 }
130 }
131
132 fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) {
133 match self {
134 Self::Eth(evm) => evm.components_mut(),
135 Self::Op(evm) => evm.components_mut(),
136 }
137 }
138
139 fn db_mut(&mut self) -> &mut Self::DB {
140 match self {
141 Self::Eth(evm) => evm.db_mut(),
142 Self::Op(evm) => evm.db_mut(),
143 }
144 }
145
146 fn into_db(self) -> Self::DB
147 where
148 Self: Sized,
149 {
150 match self {
151 Self::Eth(evm) => evm.into_db(),
152 Self::Op(evm) => evm.into_db(),
153 }
154 }
155
156 fn finish(self) -> (Self::DB, EvmEnv<Self::Spec>)
157 where
158 Self: Sized,
159 {
160 match self {
161 Self::Eth(evm) => evm.finish(),
162 Self::Op(evm) => {
163 let (db, env) = evm.finish();
164 (db, map_env(env))
165 }
166 }
167 }
168
169 fn precompiles(&self) -> &Self::Precompiles {
170 match self {
171 Self::Eth(evm) => evm.precompiles(),
172 Self::Op(evm) => evm.precompiles(),
173 }
174 }
175
176 fn precompiles_mut(&mut self) -> &mut Self::Precompiles {
177 match self {
178 Self::Eth(evm) => evm.precompiles_mut(),
179 Self::Op(evm) => evm.precompiles_mut(),
180 }
181 }
182
183 fn inspector(&self) -> &Self::Inspector {
184 match self {
185 Self::Eth(evm) => evm.inspector(),
186 Self::Op(evm) => evm.inspector(),
187 }
188 }
189
190 fn inspector_mut(&mut self) -> &mut Self::Inspector {
191 match self {
192 Self::Eth(evm) => evm.inspector_mut(),
193 Self::Op(evm) => evm.inspector_mut(),
194 }
195 }
196
197 fn enable_inspector(&mut self) {
198 match self {
199 Self::Eth(evm) => evm.enable_inspector(),
200 Self::Op(evm) => evm.enable_inspector(),
201 }
202 }
203
204 fn disable_inspector(&mut self) {
205 match self {
206 Self::Eth(evm) => evm.disable_inspector(),
207 Self::Op(evm) => evm.disable_inspector(),
208 }
209 }
210
211 fn set_inspector_enabled(&mut self, enabled: bool) {
212 match self {
213 Self::Eth(evm) => evm.set_inspector_enabled(enabled),
214 Self::Op(evm) => evm.set_inspector_enabled(enabled),
215 }
216 }
217
218 fn into_env(self) -> EvmEnv<Self::Spec>
219 where
220 Self: Sized,
221 {
222 match self {
223 Self::Eth(evm) => evm.into_env(),
224 Self::Op(evm) => map_env(evm.into_env()),
225 }
226 }
227
228 fn transact(
229 &mut self,
230 tx: impl alloy_evm::IntoTxEnv<Self::Tx>,
231 ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
232 match self {
233 Self::Eth(evm) => {
234 let eth = evm.transact(tx.into_tx_env().base);
235 self.map_eth_result(eth)
236 }
237 Self::Op(evm) => evm.transact(tx),
238 }
239 }
240
241 fn transact_commit(
242 &mut self,
243 tx: impl alloy_evm::IntoTxEnv<Self::Tx>,
244 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error>
245 where
246 Self::DB: DatabaseCommit,
247 {
248 match self {
249 Self::Eth(evm) => {
250 let eth = evm.transact_commit(tx.into_tx_env().base);
251 self.map_exec_result(eth)
252 }
253 Self::Op(evm) => evm.transact_commit(tx),
254 }
255 }
256
257 fn transact_raw(
258 &mut self,
259 tx: Self::Tx,
260 ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
261 match self {
262 Self::Eth(evm) => {
263 let res = evm.transact_raw(tx.base);
264 self.map_eth_result(res)
265 }
266 Self::Op(evm) => evm.transact_raw(tx),
267 }
268 }
269
270 fn transact_system_call(
271 &mut self,
272 caller: Address,
273 contract: Address,
274 data: Bytes,
275 ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
276 match self {
277 Self::Eth(evm) => {
278 let eth = evm.transact_system_call(caller, contract, data);
279 self.map_eth_result(eth)
280 }
281 Self::Op(evm) => evm.transact_system_call(caller, contract, data),
282 }
283 }
284}
285
286fn map_env(env: EvmEnv<OpSpecId>) -> EvmEnv {
288 let eth_spec_id = env.spec_id().into_eth_spec();
289 let cfg = env.cfg_env.with_spec(eth_spec_id);
290 EvmEnv { cfg_env: cfg, block_env: env.block_env }
291}