refactor: implement BlockExecutionStrategyFactory directly on EvmConfig (#14675)

This commit is contained in:
Arsenii Kulikov
2025-02-25 01:28:21 +04:00
committed by GitHub
parent a18b0fce7c
commit c40d059dd3
24 changed files with 250 additions and 436 deletions

View File

@@ -9,7 +9,7 @@ use alloy_consensus::{Header, Transaction};
use alloy_eips::{eip4895::Withdrawals, eip6110, eip7685::Requests};
use alloy_evm::FromRecoveredTx;
use alloy_primitives::{Address, B256};
use reth_chainspec::{ChainSpec, EthereumHardfork, EthereumHardforks, MAINNET};
use reth_chainspec::{ChainSpec, EthereumHardfork, EthereumHardforks};
use reth_evm::{
execute::{
balance_increment_state, BasicBlockExecutorProvider, BlockExecutionError,
@@ -17,54 +17,25 @@ use reth_evm::{
},
state_change::post_block_balance_increments,
system_calls::{OnStateHook, StateChangePostBlockSource, StateChangeSource, SystemCaller},
ConfigureEvm, Database, Evm,
ConfigureEvm, Database, Evm, EvmEnv, EvmFactory, TransactionEnv,
};
use reth_execution_types::BlockExecutionResult;
use reth_primitives::{
EthPrimitives, Receipt, Recovered, RecoveredBlock, SealedBlock, TransactionSigned,
};
use reth_primitives_traits::NodePrimitives;
use reth_revm::{context_interface::result::ResultAndState, db::State, DatabaseCommit};
use reth_revm::{
context_interface::result::ResultAndState, db::State, specification::hardfork::SpecId,
DatabaseCommit,
};
/// Factory for [`EthExecutionStrategy`].
#[derive(Debug, Clone)]
pub struct EthExecutionStrategyFactory<EvmConfig = EthEvmConfig> {
/// The chainspec
chain_spec: Arc<ChainSpec>,
/// How to create an EVM.
evm_config: EvmConfig,
}
impl EthExecutionStrategyFactory {
/// Creates a new default ethereum executor strategy factory.
pub fn ethereum(chain_spec: Arc<ChainSpec>) -> Self {
Self::new(chain_spec.clone(), EthEvmConfig::new(chain_spec))
}
/// Returns a new factory for the mainnet.
pub fn mainnet() -> Self {
Self::ethereum(MAINNET.clone())
}
}
impl<EvmConfig> EthExecutionStrategyFactory<EvmConfig> {
/// Creates a new executor strategy factory.
pub fn new(chain_spec: Arc<ChainSpec>, evm_config: EvmConfig) -> Self {
Self { chain_spec, evm_config }
}
}
impl<EvmConfig> BlockExecutionStrategyFactory for EthExecutionStrategyFactory<EvmConfig>
impl<EvmF> BlockExecutionStrategyFactory for EthEvmConfig<EvmF>
where
EvmConfig: Clone
+ Unpin
+ Sync
EvmF: EvmFactory<EvmEnv<SpecId>, Tx: TransactionEnv + FromRecoveredTx<TransactionSigned>>
+ Send
+ 'static
+ ConfigureEvm<
Header = alloy_consensus::Header,
Transaction = reth_primitives::TransactionSigned,
>,
+ Sync
+ Unpin
+ Clone,
{
type Primitives = EthPrimitives;
@@ -76,7 +47,7 @@ where
where
DB: Database,
{
let evm = self.evm_config.evm_for_block(db, block.header());
let evm = self.evm_for_block(db, block.header());
EthExecutionStrategy::new(evm, block.sealed_block(), &self.chain_spec)
}
}
@@ -287,15 +258,13 @@ pub struct EthExecutorProvider;
impl EthExecutorProvider {
/// Creates a new default ethereum executor provider.
pub fn ethereum(
chain_spec: Arc<ChainSpec>,
) -> BasicBlockExecutorProvider<EthExecutionStrategyFactory> {
BasicBlockExecutorProvider::new(EthExecutionStrategyFactory::ethereum(chain_spec))
pub fn ethereum(chain_spec: Arc<ChainSpec>) -> BasicBlockExecutorProvider<EthEvmConfig> {
BasicBlockExecutorProvider::new(EthEvmConfig::new(chain_spec))
}
/// Returns a new provider for the mainnet.
pub fn mainnet() -> BasicBlockExecutorProvider<EthExecutionStrategyFactory> {
BasicBlockExecutorProvider::new(EthExecutionStrategyFactory::mainnet())
pub fn mainnet() -> BasicBlockExecutorProvider<EthEvmConfig> {
BasicBlockExecutorProvider::new(EthEvmConfig::mainnet())
}
}
@@ -311,7 +280,7 @@ mod tests {
eip7685::EMPTY_REQUESTS_HASH,
};
use alloy_primitives::{b256, fixed_bytes, keccak256, Bytes, TxKind, B256, U256};
use reth_chainspec::{ChainSpecBuilder, ForkCondition};
use reth_chainspec::{ChainSpecBuilder, ForkCondition, MAINNET};
use reth_evm::execute::{BasicBlockExecutorProvider, BlockExecutorProvider, Executor};
use reth_execution_types::BlockExecutionResult;
use reth_primitives::{Account, Block, BlockBody, Transaction};
@@ -366,13 +335,8 @@ mod tests {
db
}
fn executor_provider(
chain_spec: Arc<ChainSpec>,
) -> BasicBlockExecutorProvider<EthExecutionStrategyFactory> {
let strategy_factory =
EthExecutionStrategyFactory::new(chain_spec.clone(), EthEvmConfig::new(chain_spec));
BasicBlockExecutorProvider::new(strategy_factory)
fn executor_provider(chain_spec: Arc<ChainSpec>) -> BasicBlockExecutorProvider<EthEvmConfig> {
BasicBlockExecutorProvider::new(EthEvmConfig::new(chain_spec))
}
#[test]

View File

@@ -20,14 +20,16 @@ extern crate alloc;
use alloc::sync::Arc;
use alloy_consensus::{BlockHeader, Header};
pub use alloy_evm::EthEvm;
use alloy_evm::EthEvmFactory;
use alloy_evm::{EthEvmFactory, FromRecoveredTx};
use alloy_primitives::U256;
use core::{convert::Infallible, fmt::Debug};
use reth_chainspec::{ChainSpec, EthChainSpec, MAINNET};
use reth_evm::{ConfigureEvm, ConfigureEvmEnv, EvmEnv, NextBlockEnvAttributes};
use reth_evm::{
ConfigureEvm, ConfigureEvmEnv, EvmEnv, EvmFactory, NextBlockEnvAttributes, TransactionEnv,
};
use reth_primitives::TransactionSigned;
use reth_revm::{
context::{BlockEnv, CfgEnv, TxEnv},
context::{BlockEnv, CfgEnv},
context_interface::block::BlobExcessGasAndPrice,
specification::hardfork::SpecId,
};
@@ -47,20 +49,32 @@ pub mod eip6110;
/// Ethereum-related EVM configuration.
#[derive(Debug, Clone)]
pub struct EthEvmConfig {
pub struct EthEvmConfig<EvmFactory = EthEvmFactory> {
chain_spec: Arc<ChainSpec>,
evm_factory: EthEvmFactory,
evm_factory: EvmFactory,
}
impl EthEvmConfig {
/// Creates a new Ethereum EVM configuration with the given chain spec.
pub fn new(chain_spec: Arc<ChainSpec>) -> Self {
Self { chain_spec, evm_factory: Default::default() }
Self::ethereum(chain_spec)
}
/// Creates a new Ethereum EVM configuration.
pub fn ethereum(chain_spec: Arc<ChainSpec>) -> Self {
Self::new_with_evm_factory(chain_spec, EthEvmFactory::default())
}
/// Creates a new Ethereum EVM configuration for the ethereum mainnet.
pub fn mainnet() -> Self {
Self::new(MAINNET.clone())
Self::ethereum(MAINNET.clone())
}
}
impl<EvmFactory> EthEvmConfig<EvmFactory> {
/// Creates a new Ethereum EVM configuration with the given chain spec and EVM factory.
pub fn new_with_evm_factory(chain_spec: Arc<ChainSpec>, evm_factory: EvmFactory) -> Self {
Self { chain_spec, evm_factory }
}
/// Returns the chain spec associated with this configuration.
@@ -69,11 +83,18 @@ impl EthEvmConfig {
}
}
impl ConfigureEvmEnv for EthEvmConfig {
impl<EvmF> ConfigureEvmEnv for EthEvmConfig<EvmF>
where
EvmF: EvmFactory<EvmEnv<SpecId>, Tx: TransactionEnv + FromRecoveredTx<TransactionSigned>>
+ Send
+ Sync
+ Unpin
+ Clone,
{
type Header = Header;
type Transaction = TransactionSigned;
type Error = Infallible;
type TxEnv = TxEnv;
type TxEnv = EvmF::Tx;
type Spec = SpecId;
fn evm_env(&self, header: &Self::Header) -> EvmEnv {
@@ -161,8 +182,15 @@ impl ConfigureEvmEnv for EthEvmConfig {
}
}
impl ConfigureEvm for EthEvmConfig {
type EvmFactory = EthEvmFactory;
impl<EvmF> ConfigureEvm for EthEvmConfig<EvmF>
where
EvmF: EvmFactory<EvmEnv<SpecId>, Tx: TransactionEnv + FromRecoveredTx<TransactionSigned>>
+ Send
+ Sync
+ Unpin
+ Clone,
{
type EvmFactory = EvmF;
fn evm_factory(&self) -> &Self::EvmFactory {
&self.evm_factory
@@ -174,7 +202,7 @@ mod tests {
use super::*;
use alloy_consensus::Header;
use alloy_genesis::Genesis;
use reth_chainspec::{Chain, ChainSpec, MAINNET};
use reth_chainspec::{Chain, ChainSpec};
use reth_evm::{execute::ProviderError, EvmEnv};
use reth_revm::{
context::{BlockEnv, CfgEnv},
@@ -210,7 +238,7 @@ mod tests {
#[test]
fn test_evm_with_env_default_spec() {
let evm_config = EthEvmConfig::new(MAINNET.clone());
let evm_config = EthEvmConfig::mainnet();
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
@@ -225,7 +253,7 @@ mod tests {
#[test]
fn test_evm_with_env_custom_cfg() {
let evm_config = EthEvmConfig::new(MAINNET.clone());
let evm_config = EthEvmConfig::mainnet();
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
@@ -242,7 +270,7 @@ mod tests {
#[test]
fn test_evm_with_env_custom_block_and_tx() {
let evm_config = EthEvmConfig::new(MAINNET.clone());
let evm_config = EthEvmConfig::mainnet();
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
@@ -263,7 +291,7 @@ mod tests {
#[test]
fn test_evm_with_spec_id() {
let evm_config = EthEvmConfig::new(MAINNET.clone());
let evm_config = EthEvmConfig::mainnet();
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
@@ -280,7 +308,7 @@ mod tests {
#[test]
fn test_evm_with_env_and_default_inspector() {
let evm_config = EthEvmConfig::new(MAINNET.clone());
let evm_config = EthEvmConfig::mainnet();
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
let evm_env = EvmEnv::default();
@@ -294,7 +322,7 @@ mod tests {
#[test]
fn test_evm_with_env_inspector_and_custom_cfg() {
let evm_config = EthEvmConfig::new(MAINNET.clone());
let evm_config = EthEvmConfig::mainnet();
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
let cfg_env = CfgEnv::default().with_chain_id(111);
@@ -310,7 +338,7 @@ mod tests {
#[test]
fn test_evm_with_env_inspector_and_custom_block_tx() {
let evm_config = EthEvmConfig::new(MAINNET.clone());
let evm_config = EthEvmConfig::mainnet();
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
// Create custom block and tx environment
@@ -327,7 +355,7 @@ mod tests {
#[test]
fn test_evm_with_env_inspector_and_spec_id() {
let evm_config = EthEvmConfig::new(MAINNET.clone());
let evm_config = EthEvmConfig::mainnet();
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
let evm_env = EvmEnv {

View File

@@ -3,6 +3,6 @@
#[doc(inline)]
pub use reth_evm::execute::BasicBlockExecutorProvider;
#[doc(inline)]
pub use reth_evm_ethereum::execute::{EthExecutionStrategyFactory, EthExecutorProvider};
pub use reth_evm_ethereum::execute::EthExecutorProvider;
#[doc(inline)]
pub use reth_evm_ethereum::{EthEvm, EthEvmConfig};

View File

@@ -17,9 +17,7 @@ use revm as _;
pub use reth_ethereum_engine_primitives::EthEngineTypes;
pub mod evm;
pub use evm::{
BasicBlockExecutorProvider, EthEvmConfig, EthExecutionStrategyFactory, EthExecutorProvider,
};
pub use evm::{BasicBlockExecutorProvider, EthEvmConfig, EthExecutorProvider};
pub use reth_ethereum_consensus as consensus;
pub mod node;

View File

@@ -11,7 +11,6 @@ use reth_ethereum_engine_primitives::{
};
use reth_ethereum_primitives::{EthPrimitives, PooledTransaction};
use reth_evm::{execute::BasicBlockExecutorProvider, ConfigureEvm};
use reth_evm_ethereum::execute::EthExecutionStrategyFactory;
use reth_network::{EthNetworkPrimitives, NetworkHandle, PeersInfo};
use reth_node_api::{AddOnsContext, FullNodeComponents, NodeAddOns, TxTy};
use reth_node_builder::{
@@ -241,16 +240,14 @@ where
Node: FullNodeTypes<Types = Types>,
{
type EVM = EthEvmConfig;
type Executor = BasicBlockExecutorProvider<EthExecutionStrategyFactory>;
type Executor = BasicBlockExecutorProvider<EthEvmConfig>;
async fn build_evm(
self,
ctx: &BuilderContext<Node>,
) -> eyre::Result<(Self::EVM, Self::Executor)> {
let chain_spec = ctx.chain_spec();
let evm_config = EthEvmConfig::new(ctx.chain_spec());
let strategy_factory = EthExecutionStrategyFactory::new(chain_spec, evm_config.clone());
let executor = BasicBlockExecutorProvider::new(strategy_factory);
let executor = BasicBlockExecutorProvider::new(evm_config.clone());
Ok((evm_config, executor))
}

View File

@@ -2,7 +2,7 @@
use alloy_consensus::BlockHeader;
// Re-export execution types
use crate::{system_calls::OnStateHook, Database};
use crate::{system_calls::OnStateHook, ConfigureEvmFor, Database};
use alloc::{boxed::Box, vec::Vec};
use alloy_primitives::{
map::{DefaultHashBuilder, HashMap},
@@ -191,7 +191,7 @@ pub trait BlockExecutionStrategy {
}
/// A strategy factory that can create block execution strategies.
pub trait BlockExecutionStrategyFactory: Send + Sync + Clone + Unpin + 'static {
pub trait BlockExecutionStrategyFactory: ConfigureEvmFor<Self::Primitives> {
/// Primitive types used by the strategy.
type Primitives: NodePrimitives;
@@ -229,7 +229,7 @@ impl<F> BasicBlockExecutorProvider<F> {
impl<F> BlockExecutorProvider for BasicBlockExecutorProvider<F>
where
F: BlockExecutionStrategyFactory,
F: BlockExecutionStrategyFactory + 'static,
{
type Primitives = F::Primitives;
@@ -359,10 +359,8 @@ where
mod tests {
use super::*;
use alloy_consensus::constants::KECCAK_EMPTY;
use alloy_eips::eip7685::Requests;
use alloy_primitives::{address, bytes, U256};
use alloy_primitives::{address, U256};
use core::marker::PhantomData;
use reth_ethereum_primitives::TransactionSigned;
use reth_primitives::EthPrimitives;
use revm::state::AccountInfo;
use revm_database::{CacheDB, EmptyDBTyped};
@@ -416,55 +414,6 @@ mod tests {
}
}
struct TestExecutorStrategy {
result: BlockExecutionResult<Receipt>,
}
#[derive(Clone)]
struct TestExecutorStrategyFactory {
result: BlockExecutionResult<Receipt>,
}
impl BlockExecutionStrategyFactory for TestExecutorStrategyFactory {
type Primitives = EthPrimitives;
fn create_strategy<'a, DB>(
&'a mut self,
_db: &'a mut State<DB>,
_block: &'a RecoveredBlock<<Self::Primitives as NodePrimitives>::Block>,
) -> impl BlockExecutionStrategy<Primitives = Self::Primitives, Error = BlockExecutionError> + 'a
where
DB: Database,
{
TestExecutorStrategy { result: self.result.clone() }
}
}
impl BlockExecutionStrategy for TestExecutorStrategy {
type Primitives = EthPrimitives;
type Error = BlockExecutionError;
fn apply_pre_execution_changes(&mut self) -> Result<(), Self::Error> {
Ok(())
}
fn execute_transaction(
&mut self,
_tx: Recovered<&TransactionSigned>,
) -> Result<u64, Self::Error> {
Ok(0)
}
fn apply_post_execution_changes(
self,
) -> Result<BlockExecutionResult<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>
{
Ok(self.result)
}
fn with_state_hook(&mut self, _hook: Option<Box<dyn OnStateHook>>) {}
}
#[test]
fn test_provider() {
let provider = TestExecutorProvider;
@@ -473,25 +422,6 @@ mod tests {
let _ = executor.execute(&Default::default());
}
#[test]
fn test_strategy() {
let expected_result = BlockExecutionResult {
receipts: vec![Receipt::default()],
gas_used: 10,
requests: Requests::new(vec![bytes!("deadbeef")]),
};
let strategy_factory = TestExecutorStrategyFactory { result: expected_result.clone() };
let provider = BasicBlockExecutorProvider::new(strategy_factory);
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
let executor = provider.executor(db);
let result = executor.execute(&Default::default());
assert!(result.is_ok());
let block_execution_output = result.unwrap();
assert_eq!(block_execution_output.result, expected_result);
}
fn setup_state_with_account(
addr: Address,
balance: u128,

View File

@@ -8,7 +8,7 @@ use crate::{
BuilderContext, FullNodeTypes,
};
use reth_consensus::{ConsensusError, FullConsensus};
use reth_evm::{execute::BlockExecutorProvider, ConfigureEvmFor};
use reth_evm::execute::{BlockExecutionStrategyFactory, BlockExecutorProvider};
use reth_network::NetworkPrimitives;
use reth_node_api::{BlockTy, BodyTy, HeaderTy, PrimitivesTy, TxTy};
use reth_transaction_pool::{PoolTransaction, TransactionPool};
@@ -409,7 +409,7 @@ where
Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
+ Unpin
+ 'static,
EVM: ConfigureEvmFor<PrimitivesTy<Node::Types>> + 'static,
EVM: BlockExecutionStrategyFactory<Primitives = PrimitivesTy<Node::Types>> + 'static,
Executor: BlockExecutorProvider<Primitives = PrimitivesTy<Node::Types>>,
Cons:
FullConsensus<PrimitivesTy<Node::Types>, Error = ConsensusError> + Clone + Unpin + 'static,

View File

@@ -1,6 +1,6 @@
//! EVM component for the node builder.
use crate::{BuilderContext, FullNodeTypes};
use reth_evm::{execute::BlockExecutorProvider, ConfigureEvmFor};
use reth_evm::execute::{BlockExecutionStrategyFactory, BlockExecutorProvider};
use reth_node_api::PrimitivesTy;
use std::future::Future;
@@ -9,7 +9,7 @@ pub trait ExecutorBuilder<Node: FullNodeTypes>: Send {
/// The EVM config to use.
///
/// This provides the node with the necessary configuration to configure an EVM.
type EVM: ConfigureEvmFor<PrimitivesTy<Node::Types>> + 'static;
type EVM: BlockExecutionStrategyFactory<Primitives = PrimitivesTy<Node::Types>> + 'static;
/// The type that knows how to execute blocks.
type Executor: BlockExecutorProvider<Primitives = PrimitivesTy<Node::Types>>;
@@ -24,7 +24,7 @@ pub trait ExecutorBuilder<Node: FullNodeTypes>: Send {
impl<Node, F, Fut, EVM, Executor> ExecutorBuilder<Node> for F
where
Node: FullNodeTypes,
EVM: ConfigureEvmFor<PrimitivesTy<Node::Types>> + 'static,
EVM: BlockExecutionStrategyFactory<Primitives = PrimitivesTy<Node::Types>> + 'static,
Executor: BlockExecutorProvider<Primitives = PrimitivesTy<Node::Types>>,
F: FnOnce(&BuilderContext<Node>) -> Fut + Send,
Fut: Future<Output = eyre::Result<(EVM, Executor)>> + Send,

View File

@@ -25,7 +25,7 @@ use reth_payload_builder::PayloadBuilderHandle;
use crate::{ConfigureEvm, FullNodeTypes};
use reth_consensus::{ConsensusError, FullConsensus};
use reth_evm::{execute::BlockExecutorProvider, ConfigureEvmFor};
use reth_evm::execute::{BlockExecutionStrategyFactory, BlockExecutorProvider};
use reth_network::{NetworkHandle, NetworkPrimitives};
use reth_network_api::FullNetwork;
use reth_node_api::{
@@ -44,7 +44,7 @@ pub trait NodeComponents<T: FullNodeTypes>: Clone + Unpin + Send + Sync + 'stati
type Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<T::Types>>> + Unpin;
/// The node's EVM configuration, defining settings for the Ethereum Virtual Machine.
type Evm: ConfigureEvmFor<<T::Types as NodeTypes>::Primitives>;
type Evm: BlockExecutionStrategyFactory<Primitives = <T::Types as NodeTypes>::Primitives>;
/// The type that knows how to execute blocks.
type Executor: BlockExecutorProvider<Primitives = <T::Types as NodeTypes>::Primitives>;
@@ -127,7 +127,7 @@ where
Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
+ Unpin
+ 'static,
EVM: ConfigureEvm<Header = HeaderTy<Node::Types>, Transaction = TxTy<Node::Types>> + 'static,
EVM: BlockExecutionStrategyFactory<Primitives = PrimitivesTy<Node::Types>> + 'static,
Executor: BlockExecutorProvider<Primitives = PrimitivesTy<Node::Types>>,
Cons:
FullConsensus<PrimitivesTy<Node::Types>, Error = ConsensusError> + Clone + Unpin + 'static,

View File

@@ -1,10 +1,10 @@
use alloy_consensus::Header;
use alloy_consensus::BlockHeader;
use reth_optimism_forks::OpHardforks;
use revm_optimism::OpSpecId;
/// Map the latest active hardfork at the given header to a revm [`OpSpecId`].
pub fn revm_spec(chain_spec: impl OpHardforks, header: &Header) -> OpSpecId {
revm_spec_by_timestamp_after_bedrock(chain_spec, header.timestamp)
pub fn revm_spec(chain_spec: impl OpHardforks, header: impl BlockHeader) -> OpSpecId {
revm_spec_by_timestamp_after_bedrock(chain_spec, header.timestamp())
}
/// Returns the revm [`OpSpecId`] at the given timestamp.
@@ -42,6 +42,7 @@ pub fn revm_spec_by_timestamp_after_bedrock(
#[cfg(test)]
mod tests {
use super::*;
use alloy_consensus::Header;
use reth_chainspec::ChainSpecBuilder;
use reth_optimism_chainspec::{OpChainSpec, OpChainSpecBuilder};
@@ -98,35 +99,32 @@ mod tests {
f(cs).build()
}
assert_eq!(
revm_spec(op_cs(|cs| cs.isthmus_activated()), &Default::default()),
revm_spec(op_cs(|cs| cs.isthmus_activated()), Header::default()),
OpSpecId::ISTHMUS
);
assert_eq!(
revm_spec(op_cs(|cs| cs.holocene_activated()), &Default::default()),
revm_spec(op_cs(|cs| cs.holocene_activated()), Header::default()),
OpSpecId::HOLOCENE
);
assert_eq!(
revm_spec(op_cs(|cs| cs.granite_activated()), &Default::default()),
revm_spec(op_cs(|cs| cs.granite_activated()), Header::default()),
OpSpecId::GRANITE
);
assert_eq!(revm_spec(op_cs(|cs| cs.fjord_activated()), Header::default()), OpSpecId::FJORD);
assert_eq!(
revm_spec(op_cs(|cs| cs.fjord_activated()), &Default::default()),
OpSpecId::FJORD
);
assert_eq!(
revm_spec(op_cs(|cs| cs.ecotone_activated()), &Default::default()),
revm_spec(op_cs(|cs| cs.ecotone_activated()), Header::default()),
OpSpecId::ECOTONE
);
assert_eq!(
revm_spec(op_cs(|cs| cs.canyon_activated()), &Default::default()),
revm_spec(op_cs(|cs| cs.canyon_activated()), Header::default()),
OpSpecId::CANYON
);
assert_eq!(
revm_spec(op_cs(|cs| cs.bedrock_activated()), &Default::default()),
revm_spec(op_cs(|cs| cs.bedrock_activated()), Header::default()),
OpSpecId::BEDROCK
);
assert_eq!(
revm_spec(op_cs(|cs| cs.regolith_activated()), &Default::default()),
revm_spec(op_cs(|cs| cs.regolith_activated()), Header::default()),
OpSpecId::REGOLITH
);
}

View File

@@ -10,6 +10,7 @@ use alloy_consensus::{
};
use alloy_evm::FromRecoveredTx;
use op_alloy_consensus::OpDepositReceipt;
use reth_chainspec::EthChainSpec;
use reth_evm::{
execute::{
balance_increment_state, BasicBlockExecutorProvider, BlockExecutionError,
@@ -17,70 +18,25 @@ use reth_evm::{
},
state_change::post_block_balance_increments,
system_calls::{OnStateHook, StateChangePostBlockSource, StateChangeSource, SystemCaller},
ConfigureEvm, ConfigureEvmFor, Database, Evm, HaltReasonFor,
ConfigureEvm, Database, Evm,
};
use reth_execution_types::BlockExecutionResult;
use reth_optimism_chainspec::OpChainSpec;
use reth_optimism_forks::OpHardforks;
use reth_optimism_primitives::{transaction::signed::OpTransaction, DepositReceipt, OpPrimitives};
use reth_optimism_primitives::{transaction::signed::OpTransaction, DepositReceipt};
use reth_primitives_traits::{
Block, NodePrimitives, RecoveredBlock, SealedBlock, SignedTransaction,
};
use revm::{context_interface::result::ResultAndState, DatabaseCommit};
use revm::{context::TxEnv, context_interface::result::ResultAndState, DatabaseCommit};
use revm_database::State;
use revm_primitives::{Address, B256};
use tracing::trace;
/// Factory for [`OpExecutionStrategy`].
#[derive(Debug, Clone)]
pub struct OpExecutionStrategyFactory<
N: NodePrimitives = OpPrimitives,
ChainSpec = OpChainSpec,
EvmConfig: ConfigureEvm = OpEvmConfig<ChainSpec>,
> {
/// The chainspec
chain_spec: Arc<ChainSpec>,
/// How to create an EVM.
evm_config: EvmConfig,
/// Receipt builder.
receipt_builder:
Arc<dyn OpReceiptBuilder<N::SignedTx, HaltReasonFor<EvmConfig>, Receipt = N::Receipt>>,
}
impl OpExecutionStrategyFactory<OpPrimitives> {
/// Creates a new default optimism executor strategy factory.
pub fn optimism(chain_spec: Arc<OpChainSpec>) -> Self {
Self::new(
chain_spec.clone(),
OpEvmConfig::new(chain_spec),
BasicOpReceiptBuilder::default(),
)
}
}
impl<N: NodePrimitives, ChainSpec, EvmConfig: ConfigureEvm>
OpExecutionStrategyFactory<N, ChainSpec, EvmConfig>
{
/// Creates a new executor strategy factory.
pub fn new(
chain_spec: Arc<ChainSpec>,
evm_config: EvmConfig,
receipt_builder: impl OpReceiptBuilder<
N::SignedTx,
HaltReasonFor<EvmConfig>,
Receipt = N::Receipt,
>,
) -> Self {
Self { chain_spec, evm_config, receipt_builder: Arc::new(receipt_builder) }
}
}
impl<N, ChainSpec, EvmConfig> BlockExecutionStrategyFactory
for OpExecutionStrategyFactory<N, ChainSpec, EvmConfig>
impl<ChainSpec, N> BlockExecutionStrategyFactory for OpEvmConfig<ChainSpec, N>
where
ChainSpec: EthChainSpec + OpHardforks,
N: NodePrimitives<SignedTx: OpTransaction, Receipt: DepositReceipt>,
ChainSpec: OpHardforks + Clone + Unpin + Sync + Send + 'static,
EvmConfig: ConfigureEvmFor<N> + Clone + Unpin + Sync + Send + 'static,
revm_optimism::OpTransaction<TxEnv>: FromRecoveredTx<N::SignedTx>,
{
type Primitives = N;
@@ -92,7 +48,7 @@ where
where
DB: Database,
{
let evm = self.evm_config.evm_for_block(db, block.header());
let evm = self.evm_for_block(db, block.header());
OpExecutionStrategy::new(
evm,
block.sealed_block(),
@@ -329,10 +285,11 @@ pub struct OpExecutorProvider;
impl OpExecutorProvider {
/// Creates a new default optimism executor strategy factory.
pub fn optimism(
chain_spec: Arc<OpChainSpec>,
) -> BasicBlockExecutorProvider<OpExecutionStrategyFactory<OpPrimitives>> {
BasicBlockExecutorProvider::new(OpExecutionStrategyFactory::optimism(chain_spec))
pub fn optimism(chain_spec: Arc<OpChainSpec>) -> BasicBlockExecutorProvider<OpEvmConfig> {
BasicBlockExecutorProvider::new(OpEvmConfig::new(
chain_spec,
BasicOpReceiptBuilder::default(),
))
}
}
@@ -381,12 +338,11 @@ mod tests {
db
}
fn executor_provider(
chain_spec: Arc<OpChainSpec>,
) -> BasicBlockExecutorProvider<OpExecutionStrategyFactory> {
let strategy_factory = OpExecutionStrategyFactory::optimism(chain_spec);
BasicBlockExecutorProvider::new(strategy_factory)
fn executor_provider(chain_spec: Arc<OpChainSpec>) -> BasicBlockExecutorProvider<OpEvmConfig> {
BasicBlockExecutorProvider::new(OpEvmConfig::new(
chain_spec,
BasicOpReceiptBuilder::default(),
))
}
#[test]

View File

@@ -11,7 +11,8 @@
extern crate alloc;
use alloc::sync::Arc;
use alloy_consensus::{BlockHeader, Header};
use alloy_consensus::BlockHeader;
use alloy_evm::FromRecoveredTx;
use alloy_op_evm::OpEvmFactory;
use alloy_primitives::U256;
use core::fmt::Debug;
@@ -21,13 +22,14 @@ use reth_evm::{ConfigureEvm, ConfigureEvmEnv, EvmEnv, NextBlockEnvAttributes};
use reth_optimism_chainspec::OpChainSpec;
use reth_optimism_consensus::next_block_base_fee;
use reth_optimism_forks::OpHardforks;
use reth_optimism_primitives::OpTransactionSigned;
use reth_optimism_primitives::OpPrimitives;
use reth_primitives_traits::NodePrimitives;
use revm::{
context::{BlockEnv, CfgEnv, TxEnv},
context_interface::block::BlobExcessGasAndPrice,
specification::hardfork::SpecId,
};
use revm_optimism::{OpSpecId, OpTransaction};
use revm_optimism::{OpHaltReason, OpSpecId, OpTransaction};
mod config;
pub use config::{revm_spec, revm_spec_by_timestamp_after_bedrock};
@@ -43,21 +45,40 @@ pub use error::OpBlockExecutionError;
/// Optimism-related EVM configuration.
#[derive(Debug)]
pub struct OpEvmConfig<ChainSpec = OpChainSpec> {
pub struct OpEvmConfig<ChainSpec = OpChainSpec, N: NodePrimitives = OpPrimitives> {
chain_spec: Arc<ChainSpec>,
evm_factory: OpEvmFactory,
receipt_builder: Arc<dyn OpReceiptBuilder<N::SignedTx, OpHaltReason, Receipt = N::Receipt>>,
}
impl<ChainSpec> Clone for OpEvmConfig<ChainSpec> {
impl<ChainSpec, N: NodePrimitives> Clone for OpEvmConfig<ChainSpec, N> {
fn clone(&self) -> Self {
Self { chain_spec: self.chain_spec.clone(), evm_factory: OpEvmFactory::default() }
Self {
chain_spec: self.chain_spec.clone(),
evm_factory: OpEvmFactory::default(),
receipt_builder: self.receipt_builder.clone(),
}
}
}
impl<ChainSpec> OpEvmConfig<ChainSpec> {
/// Creates a new [`OpEvmConfig`] with the given chain spec for OP chains.
pub fn optimism(chain_spec: Arc<ChainSpec>) -> Self {
Self::new(chain_spec, BasicOpReceiptBuilder::default())
}
}
impl<ChainSpec, N: NodePrimitives> OpEvmConfig<ChainSpec, N> {
/// Creates a new [`OpEvmConfig`] with the given chain spec.
pub fn new(chain_spec: Arc<ChainSpec>) -> Self {
Self { chain_spec, evm_factory: OpEvmFactory::default() }
pub fn new(
chain_spec: Arc<ChainSpec>,
receipt_builder: impl OpReceiptBuilder<N::SignedTx, OpHaltReason, Receipt = N::Receipt>,
) -> Self {
Self {
chain_spec,
evm_factory: OpEvmFactory::default(),
receipt_builder: Arc::new(receipt_builder),
}
}
/// Returns the chain spec associated with this configuration.
@@ -66,9 +87,14 @@ impl<ChainSpec> OpEvmConfig<ChainSpec> {
}
}
impl<ChainSpec: EthChainSpec + OpHardforks + 'static> ConfigureEvmEnv for OpEvmConfig<ChainSpec> {
type Header = Header;
type Transaction = OpTransactionSigned;
impl<ChainSpec, N> ConfigureEvmEnv for OpEvmConfig<ChainSpec, N>
where
ChainSpec: EthChainSpec + OpHardforks,
N: NodePrimitives,
OpTransaction<TxEnv>: FromRecoveredTx<N::SignedTx>,
{
type Header = N::BlockHeader;
type Transaction = N::SignedTx;
type Error = EIP1559ParamError;
type TxEnv = OpTransaction<TxEnv>;
type Spec = OpSpecId;
@@ -124,7 +150,7 @@ impl<ChainSpec: EthChainSpec + OpHardforks + 'static> ConfigureEvmEnv for OpEvmC
.map(|gas| BlobExcessGasAndPrice::new(gas, false));
let block_env = BlockEnv {
number: parent.number + 1,
number: parent.number() + 1,
beneficiary: attributes.suggested_fee_recipient,
timestamp: attributes.timestamp,
difficulty: U256::ZERO,
@@ -140,7 +166,12 @@ impl<ChainSpec: EthChainSpec + OpHardforks + 'static> ConfigureEvmEnv for OpEvmC
}
}
impl<ChainSpec: EthChainSpec + OpHardforks + 'static> ConfigureEvm for OpEvmConfig<ChainSpec> {
impl<ChainSpec, N> ConfigureEvm for OpEvmConfig<ChainSpec, N>
where
ChainSpec: EthChainSpec + OpHardforks,
N: NodePrimitives,
OpTransaction<TxEnv>: FromRecoveredTx<N::SignedTx>,
{
type EvmFactory = OpEvmFactory;
fn evm_factory(&self) -> &Self::EvmFactory {
@@ -170,7 +201,7 @@ mod tests {
use std::sync::Arc;
fn test_evm_config() -> OpEvmConfig {
OpEvmConfig::new(BASE_MAINNET.clone())
OpEvmConfig::optimism(BASE_MAINNET.clone())
}
#[test]
@@ -191,7 +222,8 @@ mod tests {
// Use the `OpEvmConfig` to create the `cfg_env` and `block_env` based on the ChainSpec,
// Header, and total difficulty
let EvmEnv { cfg_env, .. } =
OpEvmConfig::new(Arc::new(OpChainSpec { inner: chain_spec.clone() })).evm_env(&header);
OpEvmConfig::optimism(Arc::new(OpChainSpec { inner: chain_spec.clone() }))
.evm_env(&header);
// Assert that the chain ID in the `cfg_env` is correctly set to the chain ID of the
// ChainSpec

View File

@@ -26,7 +26,7 @@ use reth_node_builder::{
};
use reth_optimism_chainspec::OpChainSpec;
use reth_optimism_consensus::OpBeaconConsensus;
use reth_optimism_evm::{BasicOpReceiptBuilder, OpEvmConfig, OpExecutionStrategyFactory};
use reth_optimism_evm::{BasicOpReceiptBuilder, OpEvmConfig};
use reth_optimism_forks::OpHardforks;
use reth_optimism_payload_builder::{
builder::OpPayloadTransactions,
@@ -414,15 +414,14 @@ where
Node: FullNodeTypes<Types: NodeTypes<ChainSpec = OpChainSpec, Primitives = OpPrimitives>>,
{
type EVM = OpEvmConfig;
type Executor = BasicBlockExecutorProvider<OpExecutionStrategyFactory<OpPrimitives>>;
type Executor = BasicBlockExecutorProvider<Self::EVM>;
async fn build_evm(
self,
ctx: &BuilderContext<Node>,
) -> eyre::Result<(Self::EVM, Self::Executor)> {
let evm_config = OpEvmConfig::new(ctx.chain_spec());
let strategy_factory = OpExecutionStrategyFactory::optimism(ctx.chain_spec());
let executor = BasicBlockExecutorProvider::new(strategy_factory);
let evm_config = OpEvmConfig::optimism(ctx.chain_spec());
let executor = BasicBlockExecutorProvider::new(evm_config.clone());
Ok((evm_config, executor))
}
@@ -660,7 +659,7 @@ where
ctx: &BuilderContext<Node>,
pool: Pool,
) -> eyre::Result<Self::PayloadBuilder> {
self.build(OpEvmConfig::new(ctx.chain_spec()), ctx, pool)
self.build(OpEvmConfig::optimism(ctx.chain_spec()), ctx, pool)
}
}

View File

@@ -6,7 +6,7 @@ use reth_consensus::noop::NoopConsensus;
use reth_engine_primitives::BeaconConsensusEngineHandle;
use reth_ethereum_engine_primitives::{EthEngineTypes, EthereumEngineValidator};
use reth_evm::execute::BasicBlockExecutorProvider;
use reth_evm_ethereum::{execute::EthExecutionStrategyFactory, EthEvmConfig};
use reth_evm_ethereum::EthEvmConfig;
use reth_network_api::noop::NoopNetwork;
use reth_payload_builder::test_utils::spawn_test_payload_service;
use reth_provider::test_utils::NoopProvider;
@@ -124,7 +124,7 @@ pub fn test_rpc_builder() -> RpcModuleBuilder<
NoopNetwork,
TokioTaskExecutor,
EthEvmConfig,
BasicBlockExecutorProvider<EthExecutionStrategyFactory>,
BasicBlockExecutorProvider<EthEvmConfig>,
NoopConsensus,
> {
RpcModuleBuilder::default()
@@ -132,9 +132,7 @@ pub fn test_rpc_builder() -> RpcModuleBuilder<
.with_pool(TestPoolBuilder::default().into())
.with_network(NoopNetwork::default())
.with_executor(TokioTaskExecutor::default())
.with_evm_config(EthEvmConfig::new(MAINNET.clone()))
.with_block_executor(
BasicBlockExecutorProvider::new(EthExecutionStrategyFactory::mainnet()),
)
.with_evm_config(EthEvmConfig::mainnet())
.with_block_executor(BasicBlockExecutorProvider::new(EthEvmConfig::mainnet()))
.with_consensus(NoopConsensus::default())
}

View File

@@ -38,7 +38,6 @@ mod tests {
use super::*;
use alloy_eips::eip1559::ETHEREUM_BLOCK_GAS_LIMIT_30M;
use alloy_primitives::{Address, StorageKey, StorageValue, U256};
use reth_chainspec::MAINNET;
use reth_evm_ethereum::EthEvmConfig;
use reth_network_api::noop::NoopNetwork;
use reth_provider::test_utils::{ExtendedAccount, MockEthProvider, NoopProvider};
@@ -55,7 +54,7 @@ mod tests {
fn noop_eth_api() -> EthApi<NoopProvider, TestPool, NoopNetwork, EthEvmConfig> {
let pool = testing_pool();
let evm_config = EthEvmConfig::new(MAINNET.clone());
let evm_config = EthEvmConfig::mainnet();
let cache = EthStateCache::spawn(NoopProvider::default(), Default::default());
EthApi::new(

View File

@@ -680,7 +680,7 @@ mod tests {
};
use reth_ethereum_consensus::EthBeaconConsensus;
use reth_evm::execute::BasicBlockExecutorProvider;
use reth_evm_ethereum::execute::EthExecutionStrategyFactory;
use reth_evm_ethereum::EthEvmConfig;
use reth_primitives::{Account, Bytecode, SealedBlock, StorageEntry};
use reth_provider::{
test_utils::create_test_provider_factory, AccountReader, DatabaseProviderFactory,
@@ -691,10 +691,9 @@ mod tests {
use reth_stages_api::StageUnitCheckpoint;
use std::collections::BTreeMap;
fn stage() -> ExecutionStage<BasicBlockExecutorProvider<EthExecutionStrategyFactory>> {
let strategy_factory = EthExecutionStrategyFactory::ethereum(Arc::new(
ChainSpecBuilder::mainnet().berlin_activated().build(),
));
fn stage() -> ExecutionStage<BasicBlockExecutorProvider<EthEvmConfig>> {
let strategy_factory =
EthEvmConfig::new(Arc::new(ChainSpecBuilder::mainnet().berlin_activated().build()));
let executor_provider = BasicBlockExecutorProvider::new(strategy_factory);
let consensus = Arc::new(EthBeaconConsensus::new(Arc::new(
ChainSpecBuilder::mainnet().berlin_activated().build(),