From 29f1e0f266c00ae2b0acec641c365958ee811c68 Mon Sep 17 00:00:00 2001 From: John Letey Date: Thu, 11 Sep 2025 11:48:30 +0200 Subject: [PATCH 1/2] feat: enable customization of evm --- bin/ev-reth/src/builder.rs | 7 ++-- bin/ev-reth/src/main.rs | 7 ++-- crates/evolve/src/evm.rs | 65 ++++++++++++++++++++++++++++++++ crates/evolve/src/executor.rs | 28 ++++++++++++++ crates/evolve/src/lib.rs | 15 ++++++-- crates/evolve/src/precompiles.rs | 13 +++++++ crates/node/src/builder.rs | 12 ++++-- crates/tests/src/common.rs | 8 +++- etc/ev-reth-genesis.json | 1 + 9 files changed, 141 insertions(+), 15 deletions(-) create mode 100644 crates/evolve/src/evm.rs create mode 100644 crates/evolve/src/executor.rs create mode 100644 crates/evolve/src/precompiles.rs diff --git a/bin/ev-reth/src/builder.rs b/bin/ev-reth/src/builder.rs index 4032e61..826e49c 100644 --- a/bin/ev-reth/src/builder.rs +++ b/bin/ev-reth/src/builder.rs @@ -1,7 +1,7 @@ use alloy_primitives::U256; use clap::Parser; use ev_node::{RollkitPayloadBuilder, RollkitPayloadBuilderConfig}; -use evolve_ev_reth::RollkitPayloadAttributes; +use evolve_ev_reth::{evm::RollkitEvmFactory, RollkitPayloadAttributes}; use reth_basic_payload_builder::{ BuildArguments, BuildOutcome, HeaderForPayload, MissingPayloadBehaviour, PayloadBuilder, PayloadConfig, @@ -74,7 +74,8 @@ where pub(crate) config: RollkitPayloadBuilderConfig, } -impl PayloadBuilderBuilder for RollkitPayloadBuilderBuilder +impl PayloadBuilderBuilder> + for RollkitPayloadBuilderBuilder where Node: FullNodeTypes< Types: NodeTypes< @@ -93,7 +94,7 @@ where self, ctx: &BuilderContext, pool: Pool, - evm_config: EthEvmConfig, + evm_config: EthEvmConfig, ) -> eyre::Result { let rollkit_builder = Arc::new(RollkitPayloadBuilder::new( Arc::new(ctx.provider().clone()), diff --git a/bin/ev-reth/src/main.rs b/bin/ev-reth/src/main.rs index e2e42a8..befef93 100644 --- a/bin/ev-reth/src/main.rs +++ b/bin/ev-reth/src/main.rs @@ -18,6 +18,7 @@ use clap::Parser; use evolve_ev_reth::{ config::RollkitConfig, consensus::RollkitConsensusBuilder, + executor::RollkitExecutorBuilder, rpc::txpool::{RollkitTxpoolApiImpl, RollkitTxpoolApiServer}, }; use reth_ethereum::{ @@ -29,7 +30,7 @@ use reth_ethereum::{ rpc::RpcAddOns, Node, NodeAdapter, NodeComponentsBuilder, }, - node::{EthereumExecutorBuilder, EthereumNetworkBuilder, EthereumPoolBuilder}, + node::{EthereumNetworkBuilder, EthereumPoolBuilder}, EthereumEthApiBuilder, }, primitives::SealedBlock, @@ -124,7 +125,7 @@ where EthereumPoolBuilder, BasicPayloadServiceBuilder, EthereumNetworkBuilder, - EthereumExecutorBuilder, + RollkitExecutorBuilder, RollkitConsensusBuilder, >; type AddOns = RollkitNodeAddOns< @@ -135,7 +136,7 @@ where ComponentsBuilder::default() .node_types::() .pool(EthereumPoolBuilder::default()) - .executor(EthereumExecutorBuilder::default()) + .executor(RollkitExecutorBuilder::default()) .payload(BasicPayloadServiceBuilder::new( RollkitPayloadBuilderBuilder::new(&self.args), )) diff --git a/crates/evolve/src/evm.rs b/crates/evolve/src/evm.rs new file mode 100644 index 0000000..d1616b2 --- /dev/null +++ b/crates/evolve/src/evm.rs @@ -0,0 +1,65 @@ +use reth_ethereum::evm::{ + primitives::{eth::EthEvmContext, precompiles::PrecompilesMap, Database, EvmEnv, EvmFactory}, + revm::{ + context::{ + result::{EVMError, HaltReason}, + TxEnv, + }, + handler::EthPrecompiles, + inspector::NoOpInspector, + interpreter::interpreter::EthInterpreter, + primitives::hardfork::SpecId, + Context, Inspector, MainBuilder, MainContext, + }, + EthEvm, +}; + +use crate::precompiles::custom_prague_precompiles; + +/// Rollkit EVM factory that allows custom precompiles. +#[derive(Debug, Clone, Default)] +#[non_exhaustive] +pub struct RollkitEvmFactory; + +impl EvmFactory for RollkitEvmFactory { + type Evm, EthInterpreter>> = + EthEvm; + type Context = EthEvmContext; + type Tx = TxEnv; + type Error = EVMError; + type HaltReason = HaltReason; + type Spec = SpecId; + type Precompiles = PrecompilesMap; + + fn create_evm(&self, db: DB, input: EvmEnv) -> Self::Evm { + let spec = input.cfg_env.spec; + let mut evm = Context::mainnet() + .with_db(db) + .with_cfg(input.cfg_env) + .with_block(input.block_env) + .build_mainnet_with_inspector(NoOpInspector {}) + .with_precompiles(PrecompilesMap::from_static( + EthPrecompiles::default().precompiles, + )); + + if spec == SpecId::PRAGUE { + evm = evm.with_precompiles(PrecompilesMap::from_static(custom_prague_precompiles())); + } + + EthEvm::new(evm, false) + } + + fn create_evm_with_inspector, EthInterpreter>>( + &self, + db: DB, + input: EvmEnv, + inspector: I, + ) -> Self::Evm { + EthEvm::new( + self.create_evm(db, input) + .into_inner() + .with_inspector(inspector), + true, + ) + } +} diff --git a/crates/evolve/src/executor.rs b/crates/evolve/src/executor.rs new file mode 100644 index 0000000..eb94cc7 --- /dev/null +++ b/crates/evolve/src/executor.rs @@ -0,0 +1,28 @@ +use crate::evm::RollkitEvmFactory; +use reth_ethereum::{ + chainspec::ChainSpec, + node::{ + api::{FullNodeTypes, NodeTypes}, + builder::{components::ExecutorBuilder, BuilderContext}, + EthEvmConfig, + }, + EthPrimitives, +}; + +/// Rollkit executor builder that utilizes the Rollkit EVM factory. +#[derive(Debug, Default, Clone, Copy)] +#[non_exhaustive] +pub struct RollkitExecutorBuilder; + +impl ExecutorBuilder for RollkitExecutorBuilder +where + Node: FullNodeTypes>, +{ + type EVM = EthEvmConfig; + + async fn build_evm(self, ctx: &BuilderContext) -> eyre::Result { + let evm_config = + EthEvmConfig::new_with_evm_factory(ctx.chain_spec(), RollkitEvmFactory::default()); + Ok(evm_config) + } +} diff --git a/crates/evolve/src/lib.rs b/crates/evolve/src/lib.rs index 679b575..058809f 100644 --- a/crates/evolve/src/lib.rs +++ b/crates/evolve/src/lib.rs @@ -5,9 +5,6 @@ //! - Rollkit-specific types and traits //! - Custom consensus implementation -/// Rollkit-specific types and related definitions. -pub mod types; - /// Configuration for Rollkit functionality. pub mod config; @@ -17,6 +14,18 @@ pub mod rpc; /// Custom consensus implementation for Rollkit. pub mod consensus; +/// Custom EVM implementation for Rollkit. +pub mod evm; + +/// Custom executor implementation for Rollkit. +pub mod executor; + +/// Custom precompiles for Rollkit. +mod precompiles; + +/// Rollkit-specific types and related definitions. +pub mod types; + #[cfg(test)] mod tests; diff --git a/crates/evolve/src/precompiles.rs b/crates/evolve/src/precompiles.rs new file mode 100644 index 0000000..2b0f6b8 --- /dev/null +++ b/crates/evolve/src/precompiles.rs @@ -0,0 +1,13 @@ +use reth_ethereum::evm::revm::precompile::Precompiles; +use std::sync::OnceLock; + +pub(crate) fn custom_prague_precompiles() -> &'static Precompiles { + static INSTANCE: OnceLock = OnceLock::new(); + INSTANCE.get_or_init(|| { + let precompiles = Precompiles::prague().clone(); + + // TODO: Add RIP-7212. + + precompiles + }) +} diff --git a/crates/node/src/builder.rs b/crates/node/src/builder.rs index 112e8c3..6f1da7a 100644 --- a/crates/node/src/builder.rs +++ b/crates/node/src/builder.rs @@ -1,5 +1,6 @@ use alloy_consensus::transaction::Transaction; -use evolve_ev_reth::RollkitPayloadAttributes; +use evolve_ev_reth::{evm::RollkitEvmFactory, RollkitPayloadAttributes}; +use reth_chainspec::ChainSpec; use reth_errors::RethError; use reth_evm::{ execute::{BlockBuilder, BlockBuilderOutcome}, @@ -18,7 +19,7 @@ pub struct RollkitPayloadBuilder { /// The client for state access pub client: Arc, /// EVM configuration - pub evm_config: EthEvmConfig, + pub evm_config: EthEvmConfig, } impl RollkitPayloadBuilder @@ -26,7 +27,10 @@ where Client: StateProviderFactory + HeaderProvider
+ Send + Sync + 'static, { /// Creates a new instance of `RollkitPayloadBuilder` - pub const fn new(client: Arc, evm_config: EthEvmConfig) -> Self { + pub const fn new( + client: Arc, + evm_config: EthEvmConfig, + ) -> Self { Self { client, evm_config } } @@ -148,7 +152,7 @@ where /// Creates a new payload builder service pub const fn create_payload_builder_service( client: Arc, - evm_config: EthEvmConfig, + evm_config: EthEvmConfig, ) -> Option> where Client: StateProviderFactory + HeaderProvider
+ Send + Sync + 'static, diff --git a/crates/tests/src/common.rs b/crates/tests/src/common.rs index b25cc5a..944a7a9 100644 --- a/crates/tests/src/common.rs +++ b/crates/tests/src/common.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use alloy_consensus::{transaction::SignerRecoverable, TxLegacy, TypedTransaction}; use alloy_primitives::{Address, Bytes, ChainId, Signature, TxKind, B256, U256}; +use evolve_ev_reth::evm::RollkitEvmFactory; use eyre::Result; use reth_chainspec::{ChainSpecBuilder, MAINNET}; use reth_ethereum_primitives::TransactionSigned; @@ -75,9 +76,12 @@ impl RollkitTestFixture { // Create a test chain spec with our test chain ID let test_chainspec = ChainSpecBuilder::from(&*MAINNET) .chain(reth_chainspec::Chain::from_id(TEST_CHAIN_ID)) - .cancun_activated() + .prague_activated() .build(); - let evm_config = EthEvmConfig::new(Arc::new(test_chainspec)); + let evm_config = EthEvmConfig::new_with_evm_factory( + Arc::new(test_chainspec), + RollkitEvmFactory::default(), + ); let builder = RollkitPayloadBuilder::new(Arc::new(provider.clone()), evm_config); diff --git a/etc/ev-reth-genesis.json b/etc/ev-reth-genesis.json index 7b7ee9d..6d8fb13 100644 --- a/etc/ev-reth-genesis.json +++ b/etc/ev-reth-genesis.json @@ -14,6 +14,7 @@ "parisBlock": 0, "shanghaiTime": 0, "cancunTime": 0, + "pragueTime": 0, "terminalTotalDifficulty": 0, "terminalTotalDifficultyPassed": true }, From 010deaaff5fcdc0da54e6317087cf18650d201c8 Mon Sep 17 00:00:00 2001 From: John Letey Date: Thu, 11 Sep 2025 12:01:00 +0200 Subject: [PATCH 2/2] feat: enable rip-7212 --- crates/evolve/src/precompiles.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/evolve/src/precompiles.rs b/crates/evolve/src/precompiles.rs index 2b0f6b8..af97f3d 100644 --- a/crates/evolve/src/precompiles.rs +++ b/crates/evolve/src/precompiles.rs @@ -1,12 +1,13 @@ -use reth_ethereum::evm::revm::precompile::Precompiles; +use reth_ethereum::evm::revm::precompile::{secp256r1, Precompiles}; use std::sync::OnceLock; pub(crate) fn custom_prague_precompiles() -> &'static Precompiles { static INSTANCE: OnceLock = OnceLock::new(); INSTANCE.get_or_init(|| { - let precompiles = Precompiles::prague().clone(); + let mut precompiles = Precompiles::prague().clone(); - // TODO: Add RIP-7212. + // https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md + precompiles.extend(secp256r1::precompiles()); precompiles })