Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions bin/ev-reth/src/builder.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -74,7 +74,8 @@ where
pub(crate) config: RollkitPayloadBuilderConfig,
}

impl<Node, Pool> PayloadBuilderBuilder<Node, Pool, EthEvmConfig> for RollkitPayloadBuilderBuilder
impl<Node, Pool> PayloadBuilderBuilder<Node, Pool, EthEvmConfig<ChainSpec, RollkitEvmFactory>>
for RollkitPayloadBuilderBuilder
where
Node: FullNodeTypes<
Types: NodeTypes<
Expand All @@ -93,7 +94,7 @@ where
self,
ctx: &BuilderContext<Node>,
pool: Pool,
evm_config: EthEvmConfig,
evm_config: EthEvmConfig<ChainSpec, RollkitEvmFactory>,
) -> eyre::Result<Self::PayloadBuilder> {
let rollkit_builder = Arc::new(RollkitPayloadBuilder::new(
Arc::new(ctx.provider().clone()),
Expand Down
7 changes: 4 additions & 3 deletions bin/ev-reth/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use clap::Parser;
use evolve_ev_reth::{
config::RollkitConfig,
consensus::RollkitConsensusBuilder,
executor::RollkitExecutorBuilder,
rpc::txpool::{RollkitTxpoolApiImpl, RollkitTxpoolApiServer},
};
use reth_ethereum::{
Expand All @@ -29,7 +30,7 @@ use reth_ethereum::{
rpc::RpcAddOns,
Node, NodeAdapter, NodeComponentsBuilder,
},
node::{EthereumExecutorBuilder, EthereumNetworkBuilder, EthereumPoolBuilder},
node::{EthereumNetworkBuilder, EthereumPoolBuilder},
EthereumEthApiBuilder,
},
primitives::SealedBlock,
Expand Down Expand Up @@ -124,7 +125,7 @@ where
EthereumPoolBuilder,
BasicPayloadServiceBuilder<RollkitPayloadBuilderBuilder>,
EthereumNetworkBuilder,
EthereumExecutorBuilder,
RollkitExecutorBuilder,
RollkitConsensusBuilder,
>;
type AddOns = RollkitNodeAddOns<
Expand All @@ -135,7 +136,7 @@ where
ComponentsBuilder::default()
.node_types::<N>()
.pool(EthereumPoolBuilder::default())
.executor(EthereumExecutorBuilder::default())
.executor(RollkitExecutorBuilder::default())
.payload(BasicPayloadServiceBuilder::new(
RollkitPayloadBuilderBuilder::new(&self.args),
))
Expand Down
65 changes: 65 additions & 0 deletions crates/evolve/src/evm.rs
Original file line number Diff line number Diff line change
@@ -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<DB: Database, I: Inspector<EthEvmContext<DB>, EthInterpreter>> =
EthEvm<DB, I, Self::Precompiles>;
type Context<DB: Database> = EthEvmContext<DB>;
type Tx = TxEnv;
type Error<DBError: core::error::Error + Send + Sync + 'static> = EVMError<DBError>;
type HaltReason = HaltReason;
type Spec = SpecId;
type Precompiles = PrecompilesMap;

fn create_evm<DB: Database>(&self, db: DB, input: EvmEnv) -> Self::Evm<DB, NoOpInspector> {
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,
));
Comment on lines +36 to +43
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current implementation incorrectly overrides spec-specific precompiles with those for the LATEST hardfork. The call to .with_precompiles(PrecompilesMap::from_static(EthPrecompiles::default().precompiles)) forces the use of LATEST precompiles, which is incorrect for other hardforks like Cancun. This can lead to consensus failures.

The fix is to remove this explicit with_precompiles call and let revm determine the correct precompiles based on the spec_id. The custom Prague precompiles should only be applied when the spec is indeed PRAGUE.

Suggested change
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,
));
let mut evm = Context::mainnet()
.with_db(db)
.with_cfg(input.cfg_env)
.with_block(input.block_env)
.build_mainnet_with_inspector(NoOpInspector {});


if spec == SpecId::PRAGUE {
evm = evm.with_precompiles(PrecompilesMap::from_static(custom_prague_precompiles()));
}

EthEvm::new(evm, false)
}

fn create_evm_with_inspector<DB: Database, I: Inspector<Self::Context<DB>, EthInterpreter>>(
&self,
db: DB,
input: EvmEnv,
inspector: I,
) -> Self::Evm<DB, I> {
EthEvm::new(
self.create_evm(db, input)
.into_inner()
.with_inspector(inspector),
true,
)
}
Comment on lines +52 to +64
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The create_evm_with_inspector function currently calls create_evm, unwraps the result with into_inner(), and then re-wraps it. This is slightly inefficient and introduces some code duplication.

Consider refactoring the EVM context creation into a private helper function. This helper could take an inspector as an argument and be used by both create_evm (with NoOpInspector) and create_evm_with_inspector. This would improve code clarity and remove the unnecessary wrap/unwrap cycle.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The interface can't be changed because we are implementing Reth's EvmFactory

}
28 changes: 28 additions & 0 deletions crates/evolve/src/executor.rs
Original file line number Diff line number Diff line change
@@ -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<Node> ExecutorBuilder<Node> for RollkitExecutorBuilder
where
Node: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec, Primitives = EthPrimitives>>,
{
type EVM = EthEvmConfig<ChainSpec, RollkitEvmFactory>;

async fn build_evm(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::EVM> {
let evm_config =
EthEvmConfig::new_with_evm_factory(ctx.chain_spec(), RollkitEvmFactory::default());
Ok(evm_config)
}
}
15 changes: 12 additions & 3 deletions crates/evolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;

Expand Down
14 changes: 14 additions & 0 deletions crates/evolve/src/precompiles.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use reth_ethereum::evm::revm::precompile::{secp256r1, Precompiles};
use std::sync::OnceLock;

pub(crate) fn custom_prague_precompiles() -> &'static Precompiles {
static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
INSTANCE.get_or_init(|| {
let mut precompiles = Precompiles::prague().clone();

// https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md
precompiles.extend(secp256r1::precompiles());

precompiles
})
}
12 changes: 8 additions & 4 deletions crates/node/src/builder.rs
Original file line number Diff line number Diff line change
@@ -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},
Expand All @@ -18,15 +19,18 @@ pub struct RollkitPayloadBuilder<Client> {
/// The client for state access
pub client: Arc<Client>,
/// EVM configuration
pub evm_config: EthEvmConfig,
pub evm_config: EthEvmConfig<ChainSpec, RollkitEvmFactory>,
}

impl<Client> RollkitPayloadBuilder<Client>
where
Client: StateProviderFactory + HeaderProvider<Header = Header> + Send + Sync + 'static,
{
/// Creates a new instance of `RollkitPayloadBuilder`
pub const fn new(client: Arc<Client>, evm_config: EthEvmConfig) -> Self {
pub const fn new(
client: Arc<Client>,
evm_config: EthEvmConfig<ChainSpec, RollkitEvmFactory>,
) -> Self {
Self { client, evm_config }
}

Expand Down Expand Up @@ -148,7 +152,7 @@ where
/// Creates a new payload builder service
pub const fn create_payload_builder_service<Client>(
client: Arc<Client>,
evm_config: EthEvmConfig,
evm_config: EthEvmConfig<ChainSpec, RollkitEvmFactory>,
) -> Option<RollkitPayloadBuilder<Client>>
where
Client: StateProviderFactory + HeaderProvider<Header = Header> + Send + Sync + 'static,
Expand Down
8 changes: 6 additions & 2 deletions crates/tests/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions etc/ev-reth-genesis.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"parisBlock": 0,
"shanghaiTime": 0,
"cancunTime": 0,
"pragueTime": 0,
"terminalTotalDifficulty": 0,
"terminalTotalDifficultyPassed": true
},
Expand Down