From 68952b306409de61563384b36d5953f4495c3d3d Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Fri, 7 Feb 2025 03:41:37 +0400 Subject: [PATCH] feat: abstract op executor over chainspec (#14285) Co-authored-by: Georgios Konstantopoulos --- crates/optimism/evm/src/execute.rs | 71 ++++++++++++++---------------- crates/optimism/evm/src/l1.rs | 11 +++-- 2 files changed, 38 insertions(+), 44 deletions(-) diff --git a/crates/optimism/evm/src/execute.rs b/crates/optimism/evm/src/execute.rs index 2d11bd31c..d7e0d9df8 100644 --- a/crates/optimism/evm/src/execute.rs +++ b/crates/optimism/evm/src/execute.rs @@ -8,7 +8,6 @@ use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloy_consensus::{BlockHeader, Eip658Value, Receipt, Transaction as _}; use alloy_eips::eip7685::Requests; use op_alloy_consensus::OpDepositReceipt; -use reth_chainspec::EthereumHardforks; use reth_consensus::ConsensusError; use reth_evm::{ execute::{ @@ -21,10 +20,8 @@ use reth_evm::{ }; use reth_optimism_chainspec::OpChainSpec; use reth_optimism_consensus::validate_block_post_execution; -use reth_optimism_forks::OpHardfork; -use reth_optimism_primitives::{ - transaction::signed::OpTransaction, DepositReceipt, OpPrimitives, OpReceipt, -}; +use reth_optimism_forks::OpHardforks; +use reth_optimism_primitives::{transaction::signed::OpTransaction, DepositReceipt, OpPrimitives}; use reth_primitives::{NodePrimitives, RecoveredBlock}; use reth_primitives_traits::{BlockBody, SignedTransaction}; use reth_revm::State; @@ -33,9 +30,13 @@ use tracing::trace; /// Factory for [`OpExecutionStrategy`]. #[derive(Debug, Clone)] -pub struct OpExecutionStrategyFactory { +pub struct OpExecutionStrategyFactory< + N: NodePrimitives = OpPrimitives, + ChainSpec = OpChainSpec, + EvmConfig = OpEvmConfig, +> { /// The chainspec - chain_spec: Arc, + chain_spec: Arc, /// How to create an EVM. evm_config: EvmConfig, /// Receipt builder. @@ -53,10 +54,10 @@ impl OpExecutionStrategyFactory { } } -impl OpExecutionStrategyFactory { +impl OpExecutionStrategyFactory { /// Creates a new executor strategy factory. pub fn new( - chain_spec: Arc, + chain_spec: Arc, evm_config: EvmConfig, receipt_builder: impl OpReceiptBuilder, ) -> Self { @@ -64,17 +65,15 @@ impl OpExecutionStrategyFactory { } } -impl BlockExecutionStrategyFactory for OpExecutionStrategyFactory +impl BlockExecutionStrategyFactory + for OpExecutionStrategyFactory where - N: NodePrimitives< - BlockHeader = alloy_consensus::Header, - Receipt = OpReceipt, - SignedTx: OpTransaction, - >, + N: NodePrimitives, + ChainSpec: OpHardforks + Clone + Unpin + Sync + Send + 'static, EvmConfig: ConfigureEvmFor + Clone + Unpin + Sync + Send + 'static, { type Primitives = N; - type Strategy = OpExecutionStrategy; + type Strategy = OpExecutionStrategy; fn create_strategy(&self, db: DB) -> Self::Strategy where @@ -93,31 +92,32 @@ where /// Block execution strategy for Optimism. #[allow(missing_debug_implementations)] -pub struct OpExecutionStrategy +pub struct OpExecutionStrategy where EvmConfig: Clone, { /// The chainspec - chain_spec: Arc, + chain_spec: Arc, /// How to create an EVM. evm_config: EvmConfig, /// Current state for block execution. state: State, /// Utility to call system smart contracts. - system_caller: SystemCaller, + system_caller: SystemCaller, /// Receipt builder. receipt_builder: Arc>, } -impl OpExecutionStrategy +impl OpExecutionStrategy where N: NodePrimitives, + ChainSpec: OpHardforks, EvmConfig: Clone, { /// Creates a new [`OpExecutionStrategy`] pub fn new( state: State, - chain_spec: Arc, + chain_spec: Arc, evm_config: EvmConfig, receipt_builder: Arc>, ) -> Self { @@ -126,14 +126,12 @@ where } } -impl BlockExecutionStrategy for OpExecutionStrategy +impl BlockExecutionStrategy + for OpExecutionStrategy where DB: Database, - N: NodePrimitives< - BlockHeader = alloy_consensus::Header, - SignedTx: OpTransaction, - Receipt: DepositReceipt, - >, + N: NodePrimitives, + ChainSpec: OpHardforks, EvmConfig: ConfigureEvmFor, { type DB = DB; @@ -152,9 +150,9 @@ where let mut evm = self.evm_config.evm_for_block(&mut self.state, block.header()); self.system_caller.apply_beacon_root_contract_call( - block.header().timestamp, - block.header().number, - block.header().parent_beacon_block_root, + block.header().timestamp(), + block.header().number(), + block.header().parent_beacon_block_root(), &mut evm, )?; @@ -162,7 +160,7 @@ where // blocks will always have at least a single transaction in them (the L1 info transaction), // so we can safely assume that this will always be triggered upon the transition and that // the above check for empty blocks will never be hit on OP chains. - ensure_create2_deployer(self.chain_spec.clone(), block.header().timestamp, evm.db_mut()) + ensure_create2_deployer(self.chain_spec.clone(), block.header().timestamp(), evm.db_mut()) .map_err(|_| OpBlockExecutionError::ForceCreate2DeployerFail)?; Ok(()) @@ -174,8 +172,7 @@ where ) -> Result, Self::Error> { let mut evm = self.evm_config.evm_for_block(&mut self.state, block.header()); - let is_regolith = - self.chain_spec.fork(OpHardfork::Regolith).active_at_timestamp(block.timestamp()); + let is_regolith = self.chain_spec.is_regolith_active_at_timestamp(block.timestamp()); let mut cumulative_gas_used = 0; let mut receipts = Vec::with_capacity(block.body().transaction_count()); @@ -255,10 +252,8 @@ where // this is only set for post-Canyon deposit // transactions. deposit_receipt_version: (transaction.is_deposit() && - self.chain_spec.is_fork_active_at_timestamp( - OpHardfork::Canyon, - block.header().timestamp, - )) + self.chain_spec + .is_canyon_active_at_timestamp(block.timestamp())) .then_some(1), }) } @@ -333,7 +328,7 @@ mod tests { use reth_chainspec::MIN_TRANSACTION_GAS; use reth_evm::execute::{BasicBlockExecutorProvider, BatchExecutor, BlockExecutorProvider}; use reth_optimism_chainspec::OpChainSpecBuilder; - use reth_optimism_primitives::OpTransactionSigned; + use reth_optimism_primitives::{OpReceipt, OpTransactionSigned}; use reth_primitives::{Account, Block, BlockBody}; use reth_revm::{ database::StateProviderDatabase, test_utils::StateProviderTest, L1_BLOCK_CONTRACT, diff --git a/crates/optimism/evm/src/l1.rs b/crates/optimism/evm/src/l1.rs index ab09a6e7b..f5c0b7ba9 100644 --- a/crates/optimism/evm/src/l1.rs +++ b/crates/optimism/evm/src/l1.rs @@ -1,12 +1,11 @@ //! Optimism-specific implementation and utilities for the executor use crate::OpBlockExecutionError; -use alloc::{string::ToString, sync::Arc}; +use alloc::string::ToString; use alloy_consensus::Transaction; use alloy_primitives::{address, b256, hex, Address, Bytes, B256, U256}; use reth_execution_errors::BlockExecutionError; -use reth_optimism_chainspec::OpChainSpec; -use reth_optimism_forks::{OpHardfork, OpHardforks}; +use reth_optimism_forks::OpHardforks; use reth_primitives_traits::BlockBody; use revm::{ primitives::{Bytecode, HashMap, SpecId}, @@ -360,7 +359,7 @@ impl RethL1BlockInfo for L1BlockInfo { /// deployer contract. This is done by directly setting the code of the create2 deployer account /// prior to executing any transactions on the timestamp activation of the fork. pub fn ensure_create2_deployer( - chain_spec: Arc, + chain_spec: impl OpHardforks, timestamp: u64, db: &mut revm::State, ) -> Result<(), DB::Error> @@ -370,8 +369,8 @@ where // If the canyon hardfork is active at the current timestamp, and it was not active at the // previous block timestamp (heuristically, block time is not perfectly constant at 2s), and the // chain is an optimism chain, then we need to force-deploy the create2 deployer contract. - if chain_spec.is_fork_active_at_timestamp(OpHardfork::Canyon, timestamp) && - !chain_spec.is_fork_active_at_timestamp(OpHardfork::Canyon, timestamp.saturating_sub(2)) + if chain_spec.is_canyon_active_at_timestamp(timestamp) && + !chain_spec.is_canyon_active_at_timestamp(timestamp.saturating_sub(2)) { trace!(target: "evm", "Forcing create2 deployer contract deployment on Canyon transition");