Skip to content
Merged
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
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 9 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ publish = false
[workspace]
resolver = "3"
members = [
"crates/chainspec",
"crates/evm",
"crates/payload/builder",
"crates/payload/types",
"crates/primitives",
"crates/revm",
"crates/chainspec",
"crates/evm",
"crates/payload/builder",
"crates/payload/types",
"crates/primitives",
"crates/revm",
]

[workspace.lints]
Expand Down Expand Up @@ -95,7 +95,9 @@ reth-revm = { git = "https://github.com/paradigmxyz/reth", rev = "64909d3", feat
"std",
"optional-checks",
] }
revm = { version = "33.1.0", features = ["optional_fee_charge"] }
revm = { version = "33.1.0", features = [
"optional_fee_charge",
], default-features = false }

alloy = { version = "1.1.3", default-features = false }
alloy-consensus = { version = "1.1.3", default-features = false }
Expand Down Expand Up @@ -156,6 +158,5 @@ tracing = "0.1.41"
tracing-subscriber = "0.3.19"
criterion = "0.7.0"
test-case = "3"
secp256k1 = "0.30.0"
pyroscope = "0.5.8"
pyroscope_pprofrs = "0.2.10"
2 changes: 1 addition & 1 deletion crates/chainspec/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ serde.workspace = true
serde_json.workspace = true

[features]
default = ["serde", "cli"]
default = ["serde"]
serde = [
"alloy-eips/serde",
"alloy-hardforks/serde",
Expand Down
1 change: 1 addition & 0 deletions crates/chainspec/src/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use reth_chainspec::{
Head,
};
use reth_network_peers::NodeRecord;
#[cfg(feature = "cli")]
use std::sync::Arc;

pub const MORPH_BASE_FEE: u64 = 10_000_000_000;
Expand Down
9 changes: 5 additions & 4 deletions crates/evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ morph-chainspec.workspace = true
morph-primitives.workspace = true
morph-revm.workspace = true

reth-chainspec.workspace = true
reth-chainspec = { workspace = true, optional = true }
reth-evm.workspace = true
reth-evm-ethereum.workspace = true
reth-revm.workspace = true
reth-primitives-traits.workspace = true
reth-primitives-traits = { workspace = true, optional = true }
reth-rpc-eth-api = { workspace = true, optional = true }

alloy-evm.workspace = true
alloy-consensus.workspace = true
alloy-consensus = { workspace = true, optional = true }
Comment on lines +19 to +27
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Jan 19, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the Cargo.toml file for crates/evm to see dependencies and features
cat -n crates/evm/Cargo.toml

Repository: morph-l2/morph-reth

Length of output: 1346


🏁 Script executed:

# Find and examine config.rs in crates/evm
find crates/evm -name "config.rs" -type f

Repository: morph-l2/morph-reth

Length of output: 87


🏁 Script executed:

# Check the structure of crates/evm
ls -la crates/evm/src/ 2>/dev/null || echo "Directory not found"

Repository: morph-l2/morph-reth

Length of output: 641


🏁 Script executed:

# Now examine config.rs to check for cfg attributes and imports
cat -n crates/evm/src/config.rs

Repository: morph-l2/morph-reth

Length of output: 4611


🏁 Script executed:

# Check lib.rs to see if config.rs is exposed and how
cat -n crates/evm/src/lib.rs

Repository: morph-l2/morph-reth

Length of output: 5989


reth-codec feature doesn't enable required optional dependencies
config.rs is gated by #[cfg(feature = "reth-codec")] and imports reth-chainspec, reth-primitives-traits, and alloy-consensus, which are optional dependencies. The feature must enable them, or builds with reth-codec will fail.

💡 Proposed fix
 [features]
 default = []
-reth-codec = ["morph-primitives/reth-codec"]
+reth-codec = [
+  "morph-primitives/reth-codec",
+  "dep:reth-chainspec",
+  "dep:reth-primitives-traits",
+  "dep:alloy-consensus",
+]
 rpc = ["dep:reth-rpc-eth-api", "morph-revm/rpc"]
 engine = []
🤖 Prompt for AI Agents
In `@crates/evm/Cargo.toml` around lines 19 - 27, The reth-codec feature is
declared but does not enable the optional dependencies used by config.rs; update
Cargo.toml so the feature "reth-codec" explicitly enables the optional crates
reth-chainspec, reth-primitives-traits, and alloy-consensus (ensure those
dependencies remain marked optional = true) so that enabling feature
"reth-codec" pulls in those crates and allows the code behind #[cfg(feature =
"reth-codec")] (e.g., config.rs) to compile.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@anylots cc, you should check the compilation with all features

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

alloy-primitives.workspace = true

derive_more.workspace = true
Expand All @@ -36,6 +36,7 @@ serde_json.workspace = true
alloy-genesis.workspace = true

[features]
default = ["rpc"]
default = []
reth-codec = ["morph-primitives/reth-codec"]
rpc = ["dep:reth-rpc-eth-api", "morph-revm/rpc"]
engine = []
110 changes: 110 additions & 0 deletions crates/evm/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use crate::{
MorphBlockAssembler, MorphBlockExecutionCtx, MorphEvmConfig, MorphEvmError,
MorphNextBlockEnvAttributes,
};
use alloy_consensus::BlockHeader;
use morph_chainspec::hardfork::MorphHardforks;
use morph_primitives::Block;
use morph_primitives::{MorphHeader, MorphPrimitives};
use morph_revm::MorphBlockEnv;
use reth_chainspec::EthChainSpec;
use reth_evm::{
ConfigureEvm, EvmEnv, EvmEnvFor,
eth::{EthBlockExecutionCtx, NextEvmEnvAttributes},
};
use reth_primitives_traits::{SealedBlock, SealedHeader};
use std::borrow::Cow;

impl ConfigureEvm for MorphEvmConfig {
type Primitives = MorphPrimitives;
type Error = MorphEvmError;
type NextBlockEnvCtx = MorphNextBlockEnvAttributes;
type BlockExecutorFactory = Self;
type BlockAssembler = MorphBlockAssembler;

fn block_executor_factory(&self) -> &Self::BlockExecutorFactory {
self
}

fn block_assembler(&self) -> &Self::BlockAssembler {
&self.block_assembler
}

fn evm_env(&self, header: &MorphHeader) -> Result<EvmEnvFor<Self>, Self::Error> {
let EvmEnv { cfg_env, block_env } = EvmEnv::for_eth_block(
header,
self.chain_spec(),
self.chain_spec().chain().id(),
self.chain_spec()
.blob_params_at_timestamp(header.timestamp()),
);

let spec = self.chain_spec().morph_hardfork_at(header.timestamp());

Ok(EvmEnv {
cfg_env: cfg_env.with_spec(spec),
block_env: MorphBlockEnv { inner: block_env },
})
}

fn next_evm_env(
&self,
parent: &MorphHeader,
attributes: &Self::NextBlockEnvCtx,
) -> Result<EvmEnvFor<Self>, Self::Error> {
let EvmEnv { cfg_env, block_env } = EvmEnv::for_eth_next_block(
parent,
NextEvmEnvAttributes {
timestamp: attributes.timestamp,
suggested_fee_recipient: attributes.suggested_fee_recipient,
prev_randao: attributes.prev_randao,
gas_limit: attributes.gas_limit,
},
self.chain_spec()
.next_block_base_fee(parent, attributes.timestamp)
.unwrap_or_default(),
self.chain_spec(),
self.chain_spec().chain().id(),
self.chain_spec()
.blob_params_at_timestamp(attributes.timestamp),
);

let spec = self.chain_spec().morph_hardfork_at(attributes.timestamp);

Ok(EvmEnv {
cfg_env: cfg_env.with_spec(spec),
block_env: MorphBlockEnv { inner: block_env },
})
}

fn context_for_block<'a>(
&self,
block: &'a SealedBlock<Block>,
) -> Result<MorphBlockExecutionCtx<'a>, Self::Error> {
Ok(MorphBlockExecutionCtx {
inner: EthBlockExecutionCtx {
parent_hash: block.header().parent_hash(),
parent_beacon_block_root: block.header().parent_beacon_block_root(),
ommers: &[],
withdrawals: block.body().withdrawals.as_ref().map(Cow::Borrowed),
extra_data: block.extra_data().clone(),
},
})
}

fn context_for_next_block(
&self,
parent: &SealedHeader<MorphHeader>,
attributes: Self::NextBlockEnvCtx,
) -> Result<MorphBlockExecutionCtx<'_>, Self::Error> {
Ok(MorphBlockExecutionCtx {
inner: EthBlockExecutionCtx {
parent_hash: parent.hash(),
parent_beacon_block_root: attributes.parent_beacon_block_root,
ommers: &[],
withdrawals: attributes.inner.withdrawals.map(Cow::Owned),
extra_data: attributes.inner.extra_data,
},
})
}
}
113 changes: 8 additions & 105 deletions crates/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
#![cfg_attr(docsrs, feature(doc_cfg))]

mod assemble;
#[cfg(feature = "reth-codec")]
mod config;
Comment on lines 6 to +8
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix cargo fmt failure (CI is red)
Pipeline reports cargo fmt --all -- --check failed due to module ordering near the engine/config declarations. Please run cargo fmt and commit the reformat.

🤖 Prompt for AI Agents
In `@crates/evm/src/lib.rs` around lines 6 - 10, The module declarations (mod
assemble, mod engine, mod config) are misordered causing cargo fmt to fail; run
rustfmt to fix and commit the result: either run cargo fmt --all (or cargo fmt
--all -- --check to verify) and commit the formatted changes, or manually
reorder the mod declarations to the canonical/rustfmt-preferred order (e.g.,
alphabetically: mod assemble, mod config, mod engine) so that rustfmt passes,
then commit.

#[cfg(feature = "engine")]
mod engine;
use alloy_consensus::BlockHeader as _;
pub use assemble::MorphBlockAssembler;
mod block;
mod context;
Expand All @@ -15,22 +16,17 @@ pub use context::{MorphBlockExecutionCtx, MorphNextBlockEnvAttributes};
mod error;
pub use error::MorphEvmError;
pub mod evm;
use std::{borrow::Cow, sync::Arc};
use std::sync::Arc;

use crate::{block::MorphBlockExecutor, evm::MorphEvm};
use alloy_evm::{
self, Database, EvmEnv,
self, Database,
block::{BlockExecutorFactory, BlockExecutorFor},
eth::{EthBlockExecutionCtx, NextEvmEnvAttributes},
revm::{Inspector, database::State},
};
pub use evm::MorphEvmFactory;
use morph_primitives::{Block, MorphHeader, MorphPrimitives, MorphReceipt, MorphTxEnvelope};
use reth_chainspec::EthChainSpec;
use reth_evm::{self, ConfigureEvm, EvmEnvFor};
use reth_primitives_traits::{SealedBlock, SealedHeader};

use crate::{block::MorphBlockExecutor, evm::MorphEvm};
use morph_chainspec::{MorphChainSpec, hardfork::MorphHardforks};
use morph_chainspec::MorphChainSpec;
use morph_primitives::{MorphReceipt, MorphTxEnvelope};
use morph_revm::evm::MorphContext;
use reth_evm_ethereum::EthEvmConfig;

Expand Down Expand Up @@ -95,100 +91,7 @@ impl BlockExecutorFactory for MorphEvmConfig {
}
}

impl ConfigureEvm for MorphEvmConfig {
type Primitives = MorphPrimitives;
type Error = MorphEvmError;
type NextBlockEnvCtx = MorphNextBlockEnvAttributes;
type BlockExecutorFactory = Self;
type BlockAssembler = MorphBlockAssembler;

fn block_executor_factory(&self) -> &Self::BlockExecutorFactory {
self
}

fn block_assembler(&self) -> &Self::BlockAssembler {
&self.block_assembler
}

fn evm_env(&self, header: &MorphHeader) -> Result<EvmEnvFor<Self>, Self::Error> {
let EvmEnv { cfg_env, block_env } = EvmEnv::for_eth_block(
header,
self.chain_spec(),
self.chain_spec().chain().id(),
self.chain_spec()
.blob_params_at_timestamp(header.timestamp()),
);

let spec = self.chain_spec().morph_hardfork_at(header.timestamp());

Ok(EvmEnv {
cfg_env: cfg_env.with_spec(spec),
block_env: MorphBlockEnv { inner: block_env },
})
}

fn next_evm_env(
&self,
parent: &MorphHeader,
attributes: &Self::NextBlockEnvCtx,
) -> Result<EvmEnvFor<Self>, Self::Error> {
let EvmEnv { cfg_env, block_env } = EvmEnv::for_eth_next_block(
parent,
NextEvmEnvAttributes {
timestamp: attributes.timestamp,
suggested_fee_recipient: attributes.suggested_fee_recipient,
prev_randao: attributes.prev_randao,
gas_limit: attributes.gas_limit,
},
self.chain_spec()
.next_block_base_fee(parent, attributes.timestamp)
.unwrap_or_default(),
self.chain_spec(),
self.chain_spec().chain().id(),
self.chain_spec()
.blob_params_at_timestamp(attributes.timestamp),
);

let spec = self.chain_spec().morph_hardfork_at(attributes.timestamp);

Ok(EvmEnv {
cfg_env: cfg_env.with_spec(spec),
block_env: MorphBlockEnv { inner: block_env },
})
}

fn context_for_block<'a>(
&self,
block: &'a SealedBlock<Block>,
) -> Result<MorphBlockExecutionCtx<'a>, Self::Error> {
Ok(MorphBlockExecutionCtx {
inner: EthBlockExecutionCtx {
parent_hash: block.header().parent_hash(),
parent_beacon_block_root: block.header().parent_beacon_block_root(),
ommers: &[],
withdrawals: block.body().withdrawals.as_ref().map(Cow::Borrowed),
extra_data: block.extra_data().clone(),
},
})
}

fn context_for_next_block(
&self,
parent: &SealedHeader<MorphHeader>,
attributes: Self::NextBlockEnvCtx,
) -> Result<MorphBlockExecutionCtx<'_>, Self::Error> {
Ok(MorphBlockExecutionCtx {
inner: EthBlockExecutionCtx {
parent_hash: parent.hash(),
parent_beacon_block_root: attributes.parent_beacon_block_root,
ommers: &[],
withdrawals: attributes.inner.withdrawals.map(Cow::Owned),
extra_data: attributes.inner.extra_data,
},
})
}
}

#[cfg(feature = "reth-codec")]
#[cfg(test)]
Comment on lines +94 to 95
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Jan 19, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, check the test code structure at lines 94-153
head -160 crates/evm/src/lib.rs | tail -70

Repository: morph-l2/morph-reth

Length of output: 2417


🏁 Script executed:

# Check if MorphEvmConfig is feature-gated in its definition
rg -n "struct MorphEvmConfig" --type rust -B 2 -A 5

Repository: morph-l2/morph-reth

Length of output: 509


🏁 Script executed:

# Search for from_genesis method in the codebase
rg -n "fn from_genesis" --type rust -B 1 -A 3 | head -40

Repository: morph-l2/morph-reth

Length of output: 462


🏁 Script executed:

# Check the chainspec crate Cargo.toml for feature definitions
find . -path "*/chainspec/Cargo.toml" -exec cat {} \;

Repository: morph-l2/morph-reth

Length of output: 855


🏁 Script executed:

# Check what features are required/optional in the evm crate
head -30 crates/evm/Cargo.toml

Repository: morph-l2/morph-reth

Length of output: 793


🏁 Script executed:

# Get the complete evm Cargo.toml
cat crates/evm/Cargo.toml

Repository: morph-l2/morph-reth

Length of output: 1052


🏁 Script executed:

# Search for all usages of reth-codec feature gate in the codebase
rg '#\[cfg\(feature = "reth-codec"\)' --type rust

Repository: morph-l2/morph-reth

Length of output: 381


🏁 Script executed:

# Check if reth-codec is defined in workspace Cargo.toml
cat Cargo.toml | grep -A 50 "\[features\]" | head -60

Repository: morph-l2/morph-reth

Length of output: 45


🏁 Script executed:

# Check what morph-primitives/reth-codec feature gates
rg '#\[cfg\(feature = "reth-codec"\)' --type rust crates/primitives/ -B 2 -A 3

Repository: morph-l2/morph-reth

Length of output: 1264


🏁 Script executed:

# Check if any of the test's dependencies are feature-gated on reth-codec
rg 'MorphChainSpec|MorphEvmConfig' --type rust crates/primitives/ | head -20

Repository: morph-l2/morph-reth

Length of output: 45


🏁 Script executed:

# Check both occurrences of reth-codec feature gate in evm/lib.rs
rg '#\[cfg\(feature = "reth-codec"\)' crates/evm/src/lib.rs -B 2 -A 10

Repository: morph-l2/morph-reth

Length of output: 712


🏁 Script executed:

# Find MorphEvmFactory definition to understand test dependencies
rg 'MorphEvmFactory|new_with_default_factory' --type rust -B 2 -A 5 | head -50

Repository: morph-l2/morph-reth

Length of output: 2699


🏁 Script executed:

# Check if MorphEvmConfig::new_with_default_factory uses any feature-gated types
ast-grep --pattern 'fn new_with_default_factory($_) { $$$ }'

Repository: morph-l2/morph-reth

Length of output: 45


🏁 Script executed:

# Check the config module which is feature-gated on reth-codec
cat crates/evm/src/config.rs

Repository: morph-l2/morph-reth

Length of output: 3841


🏁 Script executed:

# Check the full evm lib.rs module structure to understand dependencies
head -50 crates/evm/src/lib.rs

Repository: morph-l2/morph-reth

Length of output: 1501


Remove the reth-codec feature gate from the test module.

The test does not use any functionality that depends on the reth-codec feature. It only creates a MorphEvmConfig instance and queries hardfork information through the chain spec via public APIs that are unconditionally available. The reth-codec feature gates the config module (which implements the ConfigureEvm trait), but the test never invokes this trait. Since all test dependencies—including serde_json (available in dev-dependencies), MorphEvmConfig, and MorphChainSpec—are unconditionally compiled, the feature gate prevents the test from running in configurations where it could otherwise pass. Consider moving the test outside the feature gate to improve test coverage.

🤖 Prompt for AI Agents
In `@crates/evm/src/lib.rs` around lines 94 - 95, The test module is incorrectly
gated by #[cfg(feature = "reth-codec")] in addition to #[cfg(test)], preventing
it from running when the feature is disabled; remove the feature gate so only
#[cfg(test)] remains above the test module (i.e., drop #[cfg(feature =
"reth-codec")] and keep #[cfg(test)]), leaving the test to compile and run
unconditionally in test builds while still using the existing MorphEvmConfig and
MorphChainSpec APIs.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

remove the feature

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Task: Remove reth-codec feature gate from test module

  • Remove the #[cfg(feature = "reth-codec")] line before #[cfg(test)] in crates/evm/src/lib.rs
  • Keep the #[cfg(test)] attribute to ensure tests only compile in test builds

💡 For code changes across multiple files, use @coderabbitai plan in an issue comment

mod tests {
use super::*;
Expand Down
2 changes: 1 addition & 1 deletion crates/payload/types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ workspace = true

[dependencies]
# Morph
morph-primitives = { workspace = true, features = ["serde"] }
morph-primitives = { workspace = true, features = ["serde", "reth-codec"] }

# Reth
reth-payload-primitives.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ modular-bitfield = { version = "0.11.2", optional = true }
[dev-dependencies]

[features]
default = ["serde", "reth-codec"]
default = ["serde", "reth"]
serde = [
"dep:serde",
"dep:alloy-serde",
Expand Down
1 change: 1 addition & 0 deletions crates/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub use transaction::{
#[non_exhaustive]
pub struct MorphPrimitives;

#[cfg(feature = "reth-codec")]
impl NodePrimitives for MorphPrimitives {
type Block = Block;
type BlockHeader = MorphHeader;
Expand Down
18 changes: 17 additions & 1 deletion crates/primitives/src/transaction/envelope.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use alloy_consensus::{Signed, TransactionEnvelope, TxEip1559, TxEip2930, TxEip7702, TxLegacy};
use alloy_primitives::{B256, Bytes};
use alloy_primitives::{B256, Bytes, U256};
use alloy_rlp::BytesMut;

use crate::{TxAltFee, TxL1Msg};
Expand Down Expand Up @@ -70,6 +70,22 @@ impl MorphTxEnvelope {
}
Bytes(bytes.freeze())
}

/// Returns the fee token id if this is an AltFee transaction.
pub fn fee_token_id(&self) -> Option<u16> {
match self {
Self::AltFee(tx) => Some(tx.tx().fee_token_id),
_ => None,
}
}

/// Returns the fee limit if this is an AltFee transaction.
pub fn fee_limit(&self) -> Option<U256> {
match self {
Self::AltFee(tx) => Some(tx.tx().fee_limit),
_ => None,
}
}
}

impl reth_primitives_traits::InMemorySize for MorphTxEnvelope {
Expand Down
Loading