diff --git a/examples/custom-node/src/evm/alloy.rs b/examples/custom-node/src/evm/alloy.rs index b79c4616bd0..bebecb2d6f0 100644 --- a/examples/custom-node/src/evm/alloy.rs +++ b/examples/custom-node/src/evm/alloy.rs @@ -1,21 +1,18 @@ use crate::evm::{CustomEvmTransaction, CustomTxEnv}; use alloy_evm::{precompiles::PrecompilesMap, Database, Evm, EvmEnv, EvmFactory}; -use alloy_primitives::{Address, Bytes, TxKind, U256}; -use op_alloy_consensus::OpTxType; +use alloy_op_evm::{OpEvm, OpEvmFactory}; +use alloy_primitives::{Address, Bytes}; use op_revm::{ - precompiles::OpPrecompiles, transaction::deposit::DepositTransactionParts, DefaultOp, - L1BlockInfo, OpBuilder, OpHaltReason, OpSpecId, OpTransaction, OpTransactionError, + precompiles::OpPrecompiles, L1BlockInfo, OpContext, OpHaltReason, OpSpecId, OpTransaction, + OpTransactionError, }; use reth_ethereum::evm::revm::{ - context::{result::ResultAndState, BlockEnv, CfgEnv, TxEnv}, - handler::{instructions::EthInstructions, PrecompileProvider}, - interpreter::{interpreter::EthInterpreter, InterpreterResult}, + context::{result::ResultAndState, BlockEnv, CfgEnv}, + handler::PrecompileProvider, + interpreter::InterpreterResult, Context, Inspector, Journal, }; -use revm::{ - context_interface::result::EVMError, handler::EvmTr, inspector::NoOpInspector, ExecuteEvm, - InspectEvm, -}; +use revm::{context_interface::result::EVMError, inspector::NoOpInspector}; use std::error::Error; /// EVM context contains data that EVM needs for execution of [`CustomEvmTransaction`]. @@ -23,16 +20,20 @@ pub type CustomContext = Context, CfgEnv, DB, Journal, L1BlockInfo>; pub struct CustomEvm { - inner: - op_revm::OpEvm, I, EthInstructions>, P>, - inspect: bool, + inner: OpEvm, +} + +impl CustomEvm { + pub fn new(op: OpEvm) -> Self { + Self { inner: op } + } } impl Evm for CustomEvm where DB: Database, - I: Inspector>, - P: PrecompileProvider, Output = InterpreterResult>, + I: Inspector>, + P: PrecompileProvider, Output = InterpreterResult>, { type DB = DB; type Tx = CustomEvmTransaction; @@ -43,22 +44,20 @@ where type Inspector = I; fn block(&self) -> &BlockEnv { - &self.inner.ctx_ref().block + self.inner.block() } fn chain_id(&self) -> u64 { - self.inner.ctx_ref().cfg.chain_id + self.inner.chain_id() } fn transact_raw( &mut self, tx: Self::Tx, ) -> Result, Self::Error> { - if self.inspect { - self.inner.set_tx(tx.0); - self.inner.inspect_replay() - } else { - self.inner.transact(tx.0) + match tx { + CustomEvmTransaction::Op(tx) => self.inner.transact_raw(tx), + CustomEvmTransaction::Payment(..) => todo!(), } } @@ -68,116 +67,43 @@ where contract: Address, data: Bytes, ) -> Result, Self::Error> { - let tx = CustomEvmTransaction(OpTransaction { - base: CustomTxEnv(TxEnv { - caller, - kind: TxKind::Call(contract), - // Explicitly set nonce to 0 so revm does not do any nonce checks - nonce: 0, - gas_limit: 30_000_000, - value: U256::ZERO, - data, - // Setting the gas price to zero enforces that no value is transferred as part of - // the call, and that the call will not count against the block's - // gas limit - gas_price: 0, - // The chain ID check is not relevant here and is disabled if set to None - chain_id: None, - // Setting the gas priority fee to None ensures the effective gas price is derived - // from the `gas_price` field, which we need to be zero - gas_priority_fee: None, - access_list: Default::default(), - // blob fields can be None for this tx - blob_hashes: Vec::new(), - max_fee_per_blob_gas: 0, - tx_type: OpTxType::Deposit as u8, - authorization_list: Default::default(), - }), - // The L1 fee is not charged for the EIP-4788 transaction, submit zero bytes for the - // enveloped tx size. - enveloped_tx: Some(Bytes::default()), - deposit: Default::default(), - }); - - let mut gas_limit = tx.0.base.0.gas_limit; - let mut basefee = 0; - let mut disable_nonce_check = true; - - // ensure the block gas limit is >= the tx - core::mem::swap(&mut self.inner.ctx().block.gas_limit, &mut gas_limit); - // disable the base fee check for this call by setting the base fee to zero - core::mem::swap(&mut self.inner.ctx().block.basefee, &mut basefee); - // disable the nonce check - core::mem::swap(&mut self.inner.ctx().cfg.disable_nonce_check, &mut disable_nonce_check); - - let mut res = self.transact(tx); - - // swap back to the previous gas limit - core::mem::swap(&mut self.inner.ctx().block.gas_limit, &mut gas_limit); - // swap back to the previous base fee - core::mem::swap(&mut self.inner.ctx().block.basefee, &mut basefee); - // swap back to the previous nonce check flag - core::mem::swap(&mut self.inner.ctx().cfg.disable_nonce_check, &mut disable_nonce_check); - - // NOTE: We assume that only the contract storage is modified. Revm currently marks the - // caller and block beneficiary accounts as "touched" when we do the above transact calls, - // and includes them in the result. - // - // We're doing this state cleanup to make sure that changeset only includes the changed - // contract storage. - if let Ok(res) = &mut res { - res.state.retain(|addr, _| *addr == contract); - } - - res + self.inner.transact_system_call(caller, contract, data) } fn db_mut(&mut self) -> &mut Self::DB { - &mut self.inner.ctx().journaled_state.database + self.inner.db_mut() } fn finish(self) -> (Self::DB, EvmEnv) { - let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.0.ctx; - - (journaled_state.database, EvmEnv { block_env, cfg_env }) + self.inner.finish() } fn set_inspector_enabled(&mut self, enabled: bool) { - self.inspect = enabled; + self.inner.set_inspector_enabled(enabled) } fn precompiles(&self) -> &Self::Precompiles { - &self.inner.0.precompiles + self.inner.precompiles() } fn precompiles_mut(&mut self) -> &mut Self::Precompiles { - &mut self.inner.0.precompiles + self.inner.precompiles_mut() } fn inspector(&self) -> &Self::Inspector { - &self.inner.0.inspector + self.inner.inspector() } fn inspector_mut(&mut self) -> &mut Self::Inspector { - &mut self.inner.0.inspector + self.inner.inspector_mut() } } -pub struct CustomEvmFactory; - -impl CustomEvmFactory { - fn default_tx() -> CustomEvmTransaction { - CustomEvmTransaction(OpTransaction { - base: CustomTxEnv::default(), - enveloped_tx: Some(vec![0x00].into()), - deposit: DepositTransactionParts::default(), - }) - } -} +pub struct CustomEvmFactory(OpEvmFactory); impl EvmFactory for CustomEvmFactory { - type Evm>> = CustomEvm; - type Context = CustomContext; + type Evm>> = CustomEvm; + type Context = OpContext; type Tx = CustomEvmTransaction; type Error = EVMError; type HaltReason = OpHaltReason; @@ -189,19 +115,7 @@ impl EvmFactory for CustomEvmFactory { db: DB, input: EvmEnv, ) -> Self::Evm { - let spec_id = input.cfg_env.spec; - CustomEvm { - inner: Context::op() - .with_tx(Self::default_tx().0) - .with_db(db) - .with_block(input.block_env) - .with_cfg(input.cfg_env) - .build_op_with_inspector(NoOpInspector {}) - .with_precompiles(PrecompilesMap::from_static( - OpPrecompiles::new_with_spec(spec_id).precompiles(), - )), - inspect: false, - } + CustomEvm::new(self.0.create_evm(db, input)) } fn create_evm_with_inspector>>( @@ -210,18 +124,6 @@ impl EvmFactory for CustomEvmFactory { input: EvmEnv, inspector: I, ) -> Self::Evm { - let spec_id = input.cfg_env.spec; - CustomEvm { - inner: Context::op() - .with_tx(Self::default_tx().0) - .with_db(db) - .with_block(input.block_env) - .with_cfg(input.cfg_env) - .build_op_with_inspector(inspector) - .with_precompiles(PrecompilesMap::from_static( - OpPrecompiles::new_with_spec(spec_id).precompiles(), - )), - inspect: true, - } + CustomEvm::new(self.0.create_evm_with_inspector(db, input, inspector)) } } diff --git a/examples/custom-node/src/evm/env.rs b/examples/custom-node/src/evm/env.rs index d59c8e78b95..36b42f20ad7 100644 --- a/examples/custom-node/src/evm/env.rs +++ b/examples/custom-node/src/evm/env.rs @@ -1,9 +1,5 @@ use crate::primitives::{CustomTransaction, CustomTransactionEnvelope, TxPayment}; -use alloy_eips::{ - eip2718::{EIP2930_TX_TYPE_ID, LEGACY_TX_TYPE_ID}, - eip2930::AccessList, - Typed2718, -}; +use alloy_eips::{eip2930::AccessList, Typed2718}; use alloy_evm::{FromRecoveredTx, FromTxWithEncoded, IntoTxEnv}; use alloy_primitives::{Address, Bytes, TxKind, B256, U256}; use op_revm::OpTransaction; @@ -14,7 +10,10 @@ use reth_ethereum::evm::{primitives::TransactionEnv, revm::context::TxEnv}; /// /// [`Evm`]: alloy_evm::Evm #[derive(Clone, Debug)] -pub struct CustomEvmTransaction(pub OpTransaction); +pub enum CustomEvmTransaction { + Op(OpTransaction), + Payment(CustomTxEnv), +} /// A transaction environment is a set of information related to an Ethereum transaction that can be /// fed to [`Evm`] for execution. @@ -34,63 +33,108 @@ impl revm::context::Transaction for CustomEvmTransaction { Self: 'a; fn tx_type(&self) -> u8 { - self.0.tx_type() + match self { + CustomEvmTransaction::Op(tx) => tx.tx_type(), + CustomEvmTransaction::Payment(tx) => tx.tx_type(), + } } fn caller(&self) -> Address { - self.0.caller() + match self { + CustomEvmTransaction::Op(tx) => tx.caller(), + CustomEvmTransaction::Payment(tx) => tx.caller(), + } } fn gas_limit(&self) -> u64 { - self.0.gas_limit() + match self { + CustomEvmTransaction::Op(tx) => tx.gas_limit(), + CustomEvmTransaction::Payment(tx) => tx.gas_limit(), + } } fn value(&self) -> U256 { - self.0.value() + match self { + CustomEvmTransaction::Op(tx) => tx.value(), + CustomEvmTransaction::Payment(tx) => tx.value(), + } } fn input(&self) -> &Bytes { - self.0.input() + match self { + CustomEvmTransaction::Op(tx) => tx.input(), + CustomEvmTransaction::Payment(tx) => tx.input(), + } } fn nonce(&self) -> u64 { - revm::context::Transaction::nonce(&self.0) + match self { + CustomEvmTransaction::Op(tx) => revm::context::Transaction::nonce(tx), + CustomEvmTransaction::Payment(tx) => revm::context::Transaction::nonce(tx), + } } fn kind(&self) -> TxKind { - self.0.kind() + match self { + CustomEvmTransaction::Op(tx) => tx.kind(), + CustomEvmTransaction::Payment(tx) => tx.kind(), + } } fn chain_id(&self) -> Option { - self.0.chain_id() + match self { + CustomEvmTransaction::Op(tx) => tx.chain_id(), + CustomEvmTransaction::Payment(tx) => tx.chain_id(), + } } fn gas_price(&self) -> u128 { - self.0.gas_price() + match self { + CustomEvmTransaction::Op(tx) => tx.gas_price(), + CustomEvmTransaction::Payment(tx) => tx.gas_price(), + } } fn access_list(&self) -> Option>> { - self.0.access_list() + Some(match self { + CustomEvmTransaction::Op(tx) => tx.base.access_list.iter(), + CustomEvmTransaction::Payment(tx) => tx.0.access_list.iter(), + }) } fn blob_versioned_hashes(&self) -> &[B256] { - self.0.blob_versioned_hashes() + match self { + CustomEvmTransaction::Op(tx) => tx.blob_versioned_hashes(), + CustomEvmTransaction::Payment(tx) => tx.blob_versioned_hashes(), + } } fn max_fee_per_blob_gas(&self) -> u128 { - self.0.max_fee_per_blob_gas() + match self { + CustomEvmTransaction::Op(tx) => tx.max_fee_per_blob_gas(), + CustomEvmTransaction::Payment(tx) => tx.max_fee_per_blob_gas(), + } } fn authorization_list_len(&self) -> usize { - self.0.authorization_list_len() + match self { + CustomEvmTransaction::Op(tx) => tx.authorization_list_len(), + CustomEvmTransaction::Payment(tx) => tx.authorization_list_len(), + } } fn authorization_list(&self) -> impl Iterator> { - self.0.authorization_list() + match self { + CustomEvmTransaction::Op(tx) => tx.base.authorization_list.iter(), + CustomEvmTransaction::Payment(tx) => tx.0.authorization_list.iter(), + } } fn max_priority_fee_per_gas(&self) -> Option { - self.0.max_priority_fee_per_gas() + match self { + CustomEvmTransaction::Op(tx) => tx.max_priority_fee_per_gas(), + CustomEvmTransaction::Payment(tx) => tx.max_priority_fee_per_gas(), + } } } @@ -167,43 +211,49 @@ impl revm::context::Transaction for CustomTxEnv { impl TransactionEnv for CustomTxEnv { fn set_gas_limit(&mut self, gas_limit: u64) { - self.0.gas_limit = gas_limit; + self.0.set_gas_limit(gas_limit); } fn nonce(&self) -> u64 { - self.0.nonce + self.0.nonce() } fn set_nonce(&mut self, nonce: u64) { - self.0.nonce = nonce; + self.0.set_nonce(nonce); } fn set_access_list(&mut self, access_list: AccessList) { - self.0.access_list = access_list; - - if self.0.tx_type == LEGACY_TX_TYPE_ID { - // if this was previously marked as legacy tx, this must be upgraded to eip2930 with an - // accesslist - self.0.tx_type = EIP2930_TX_TYPE_ID; - } + self.0.set_access_list(access_list); } } impl TransactionEnv for CustomEvmTransaction { fn set_gas_limit(&mut self, gas_limit: u64) { - self.0.base.set_gas_limit(gas_limit) + match self { + CustomEvmTransaction::Op(tx) => tx.set_gas_limit(gas_limit), + CustomEvmTransaction::Payment(tx) => tx.set_gas_limit(gas_limit), + } } fn nonce(&self) -> u64 { - self.0.base.nonce() + match self { + CustomEvmTransaction::Op(tx) => tx.nonce(), + CustomEvmTransaction::Payment(tx) => tx.nonce(), + } } fn set_nonce(&mut self, nonce: u64) { - self.0.base.set_nonce(nonce) + match self { + CustomEvmTransaction::Op(tx) => tx.set_nonce(nonce), + CustomEvmTransaction::Payment(tx) => tx.set_nonce(nonce), + } } fn set_access_list(&mut self, access_list: AccessList) { - self.0.base.set_access_list(access_list) + match self { + CustomEvmTransaction::Op(tx) => tx.set_access_list(access_list), + CustomEvmTransaction::Payment(tx) => tx.set_access_list(access_list), + } } } @@ -269,33 +319,27 @@ impl FromTxWithEncoded for TxEnv { impl FromRecoveredTx for CustomEvmTransaction { fn from_recovered_tx(tx: &CustomTransaction, sender: Address) -> Self { - Self(match tx { + match tx { CustomTransaction::BuiltIn(tx) => { - let tx = OpTransaction::::from_recovered_tx(tx, sender); - let base = CustomTxEnv(tx.base); - - OpTransaction { base, enveloped_tx: tx.enveloped_tx, deposit: tx.deposit } + Self::Op(OpTransaction::from_recovered_tx(tx, sender)) } CustomTransaction::Other(tx) => { - OpTransaction::new(CustomTxEnv(TxEnv::from_recovered_tx(tx, sender))) + Self::Payment(CustomTxEnv(TxEnv::from_recovered_tx(tx, sender))) } - }) + } } } impl FromTxWithEncoded for CustomEvmTransaction { fn from_encoded_tx(tx: &CustomTransaction, sender: Address, encoded: Bytes) -> Self { - Self(match tx { + match tx { CustomTransaction::BuiltIn(tx) => { - let tx = OpTransaction::::from_encoded_tx(tx, sender, encoded); - let base = CustomTxEnv(tx.base); - - OpTransaction { base, enveloped_tx: tx.enveloped_tx, deposit: tx.deposit } + Self::Op(OpTransaction::from_encoded_tx(tx, sender, encoded)) } CustomTransaction::Other(tx) => { - OpTransaction::new(CustomTxEnv(TxEnv::from_encoded_tx(tx, sender, encoded))) + Self::Payment(CustomTxEnv(TxEnv::from_encoded_tx(tx, sender, encoded))) } - }) + } } }