From 63db94dfa4527840a012d111c010c5786de99150 Mon Sep 17 00:00:00 2001 From: panos-xyz Date: Wed, 22 Apr 2026 18:44:36 +0800 Subject: [PATCH 1/3] refactor(evm): remove unused apply_curie_hard_fork dead code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every Morph chain config — mainnet, hoodi, devnet, and l2-genesis-generated configs — sets `curieBlock = 0` ("already on Curie"). The pre-execution handler guards on `ForkCondition::Block(0).transitions_at_block(block_number)`, which only fires when `block_number == 0`. Block 0 is genesis and never flows through `BlockExecutor::apply_pre_execution_changes`, so `apply_curie_hard_fork` is unreachable in every Morph environment. The L1GasPriceOracle Curie slots (6/7/8/9) are instead initialized by the contract owner via regular transactions after launch (e.g. mainnet block 863 calls the oracle's initializer via a standard tx), which already flow through `commit_transaction` and the normal state hook. This PR removes: - `crates/evm/src/block/curie.rs` (the function + its unit test) - the module declaration, import, and call site in `crates/evm/src/block/mod.rs` - `CURIE_L1_GAS_PRICE_ORACLE_STORAGE` and its `INITIAL_*`/`IS_CURIE` inputs in `crates/revm/src/l1block.rs`, plus the associated unit test - the re-exports in `crates/revm/src/lib.rs` `MorphHardfork::Curie`, `is_curie()`, the chainspec `curieBlock` parsing, and the Curie L1-fee formula branch in `L1BlockInfo::try_fetch` are all retained — those remain active code paths. No runtime behavior changes. Verified with `cargo check`, `cargo clippy --all --all-targets -- -D warnings`, `cargo fmt --all -- --check`, `cargo test --all`, `cargo test --doc --all`, and `make test-e2e` (77 integration tests passing). --- Cargo.lock | 4 + crates/evm/src/block/curie.rs | 149 ---------------------------------- crates/evm/src/block/mod.rs | 20 ----- crates/revm/src/l1block.rs | 48 ----------- crates/revm/src/lib.rs | 6 -- 5 files changed, 4 insertions(+), 223 deletions(-) delete mode 100644 crates/evm/src/block/curie.rs diff --git a/Cargo.lock b/Cargo.lock index 7e52838..7cce94f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4775,10 +4775,12 @@ dependencies = [ "async-trait", "auto_impl", "jsonrpsee", + "metrics", "morph-chainspec", "morph-payload-types", "morph-primitives", "parking_lot", + "reth-metrics", "reth-node-api", "reth-payload-builder", "reth-payload-primitives", @@ -4880,6 +4882,7 @@ dependencies = [ "alloy-eips", "alloy-primitives", "alloy-rlp", + "metrics", "morph-chainspec", "morph-evm", "morph-payload-types", @@ -4888,6 +4891,7 @@ dependencies = [ "reth-chainspec", "reth-evm", "reth-execution-types", + "reth-metrics", "reth-payload-builder", "reth-payload-primitives", "reth-payload-util", diff --git a/crates/evm/src/block/curie.rs b/crates/evm/src/block/curie.rs deleted file mode 100644 index 36c7358..0000000 --- a/crates/evm/src/block/curie.rs +++ /dev/null @@ -1,149 +0,0 @@ -//! Curie fork transition for Morph. -//! -//! The Curie hardfork introduced blob-based DA cost calculation for Morph L2. -//! -//! ## Changes -//! -//! 1. **Fee reduction** - Uses compressed blobs on L1 for lower DA costs. -//! 2. **Updated L1 gas oracle** - New storage slots for blob-based fee calculation: -//! - `l1BlobBaseFee` slot initialized to 1 -//! - `commitScalar` slot initialized to `InitialCommitScalar` -//! - `blobScalar` slot initialized to `InitialBlobScalar` -//! - `isCurie` slot set to 1 (true) -//! -//! ## DA Cost Formula -//! -//! - Pre-Curie: `(l1GasUsed(txRlp) + overhead) * l1BaseFee * scalar` -//! - Post-Curie: `l1BaseFee * commitScalar + len(txRlp) * l1BlobBaseFee * blobScalar` -//! -//! Reference: `consensus/misc/curie.go` in morph go-ethereum - -use morph_revm::{CURIE_L1_GAS_PRICE_ORACLE_STORAGE, L1_GAS_PRICE_ORACLE_ADDRESS}; -use revm::{ - Database, - database::{State, states::StorageSlot}, -}; - -/// Applies the Morph Curie hard fork to the state. -/// -/// Updates L1GasPriceOracle storage slots: -/// - Sets `l1BlobBaseFee` slot to 1 -/// - Sets `commitScalar` slot to initial value -/// - Sets `blobScalar` slot to initial value -/// - Sets `isCurie` slot to 1 (true) -/// -/// This function should only be called once at the Curie transition block. -pub(crate) fn apply_curie_hard_fork(state: &mut State) -> Result<(), DB::Error> { - tracing::info!(target: "morph::evm", "Applying Curie hard fork"); - - let oracle = state.load_cache_account(L1_GAS_PRICE_ORACLE_ADDRESS)?; - - // Create storage updates - let new_storage = CURIE_L1_GAS_PRICE_ORACLE_STORAGE - .into_iter() - .map(|(slot, present_value)| { - ( - slot, - StorageSlot { - present_value, - previous_or_original_value: oracle.storage_slot(slot).unwrap_or_default(), - }, - ) - }) - .collect(); - - // Get existing account info or use default - let oracle_info = oracle.account_info().unwrap_or_default(); - - // Create transition for oracle storage update - let transition = oracle.change(oracle_info, new_storage); - - // Add transition to state - if let Some(s) = state.transition_state.as_mut() { - s.add_transitions(vec![(L1_GAS_PRICE_ORACLE_ADDRESS, transition)]); - } - - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - use morph_revm::{ - GPO_BLOB_SCALAR_SLOT, GPO_COMMIT_SCALAR_SLOT, GPO_IS_CURIE_SLOT, GPO_L1_BASE_FEE_SLOT, - GPO_L1_BLOB_BASE_FEE_SLOT, GPO_OVERHEAD_SLOT, GPO_OWNER_SLOT, GPO_SCALAR_SLOT, - GPO_WHITELIST_SLOT, INITIAL_BLOB_SCALAR, INITIAL_COMMIT_SCALAR, INITIAL_L1_BLOB_BASE_FEE, - IS_CURIE, - }; - use revm::{ - database::{ - EmptyDB, State, - states::{StorageSlot, bundle_state::BundleRetention, plain_account::PlainStorage}, - }, - primitives::U256, - state::AccountInfo, - }; - - #[test] - fn test_apply_curie_fork() { - // init state - let db = EmptyDB::new(); - let mut state = State::builder() - .with_database(db) - .with_bundle_update() - .without_state_clear() - .build(); - - // oracle pre fork state - let oracle_pre_fork = AccountInfo::default(); - let oracle_storage_pre_fork = PlainStorage::from_iter([ - (GPO_OWNER_SLOT, U256::from(0x15f50e5eu64)), // placeholder owner - (GPO_L1_BASE_FEE_SLOT, U256::from(0x15f50e5eu64)), - (GPO_OVERHEAD_SLOT, U256::from(0x38u64)), - (GPO_SCALAR_SLOT, U256::from(0x3e95ba80u64)), - (GPO_WHITELIST_SLOT, U256::from(0x53u64)), // placeholder whitelist - ]); - state.insert_account_with_storage( - L1_GAS_PRICE_ORACLE_ADDRESS, - oracle_pre_fork, - oracle_storage_pre_fork, - ); - - // apply curie fork - apply_curie_hard_fork(&mut state).expect("should apply curie fork"); - - // merge transitions - state.merge_transitions(BundleRetention::Reverts); - let bundle = state.take_bundle(); - - // check oracle contract contains storage changeset - let oracle = bundle - .state - .get(&L1_GAS_PRICE_ORACLE_ADDRESS) - .unwrap() - .clone(); - let mut storage = oracle - .storage - .into_iter() - .collect::>(); - storage.sort_by(|(a, _), (b, _)| a.cmp(b)); - - let expected_storage = [ - (GPO_L1_BLOB_BASE_FEE_SLOT, INITIAL_L1_BLOB_BASE_FEE), - (GPO_COMMIT_SCALAR_SLOT, INITIAL_COMMIT_SCALAR), - (GPO_BLOB_SCALAR_SLOT, INITIAL_BLOB_SCALAR), - (GPO_IS_CURIE_SLOT, IS_CURIE), - ]; - - for (got, expected) in storage.into_iter().zip(expected_storage) { - assert_eq!(got.0, expected.0); - assert_eq!( - got.1, - StorageSlot { - present_value: expected.1, - ..Default::default() - } - ); - } - } -} diff --git a/crates/evm/src/block/mod.rs b/crates/evm/src/block/mod.rs index e45beaf..e6de9bd 100644 --- a/crates/evm/src/block/mod.rs +++ b/crates/evm/src/block/mod.rs @@ -4,9 +4,7 @@ //! - [`MorphBlockExecutor`]: The main block executor //! - [`MorphBlockExecutorFactory`]: Factory for creating block executors //! - [`MorphReceiptBuilder`]: Receipt construction for transactions -//! - Hardfork application logic (Curie, etc.) -pub(crate) mod curie; mod factory; mod receipt; @@ -26,7 +24,6 @@ use alloy_evm::{ }, }; use alloy_primitives::{Address, U256}; -use curie::apply_curie_hard_fork; use morph_chainspec::{MorphChainSpec, MorphHardfork, MorphHardforks}; use morph_primitives::{MorphReceipt, MorphTxEnvelope}; use morph_revm::{L1_GAS_PRICE_ORACLE_ADDRESS, MorphHaltReason, TokenFeeInfo, evm::MorphContext}; @@ -224,13 +221,9 @@ where /// 2. **L1 Gas Oracle Cache**: Loads the L1 Gas Price Oracle contract into the /// account cache to optimize L1 fee calculations for all transactions /// - /// 3. **Curie Hardfork**: At the exact Curie activation block, applies the - /// hardfork state changes (updates to L1 Gas Price Oracle contract) - /// /// # Errors /// Returns error if: /// - L1 Gas Price Oracle account cannot be loaded - /// - Curie hardfork application fails at transition block fn apply_pre_execution_changes(&mut self) -> Result<(), BlockExecutionError> { // 1. Set state clear flag if the block is after the Spurious Dragon hardfork let block_number: u64 = self.evm.block().number.to(); @@ -253,19 +246,6 @@ where .morph_hardfork_at(block_number, self.evm.block().timestamp.to::()); self.hardfork = hardfork; - // 3. Apply Curie hardfork at the transition block - // Only executes once at the exact block where Curie activates - if self - .spec - .morph_fork_activation(MorphHardfork::Curie) - .transitions_at_block(block_number) - && let Err(err) = apply_curie_hard_fork(self.evm.db_mut()) - { - return Err(BlockExecutionError::msg(format!( - "error occurred at Curie fork: {err:?}" - ))); - } - Ok(()) } diff --git a/crates/revm/src/l1block.rs b/crates/revm/src/l1block.rs index bdc5e05..e99f2f6 100644 --- a/crates/revm/src/l1block.rs +++ b/crates/revm/src/l1block.rs @@ -85,42 +85,10 @@ pub const GPO_BLOB_SCALAR_SLOT: U256 = U256::from_limbs([8, 0, 0, 0]); /// Added in the Curie hardfork. Set to 1 (true) after Curie activation. pub const GPO_IS_CURIE_SLOT: U256 = U256::from_limbs([9, 0, 0, 0]); -// ============================================================================= -// L1 Gas Price Oracle Initial Values (for Curie hardfork) -// ============================================================================= - -/// The initial blob base fee used by the oracle contract at Curie activation. -pub const INITIAL_L1_BLOB_BASE_FEE: U256 = U256::from_limbs([1, 0, 0, 0]); - -/// The initial commit scalar used by the oracle contract at Curie activation. -/// Reference: `rcfg.InitialCommitScalar` in go-ethereum (230759955285) -pub const INITIAL_COMMIT_SCALAR: U256 = U256::from_limbs([230759955285, 0, 0, 0]); - -/// The initial blob scalar used by the oracle contract at Curie activation. -/// Reference: `rcfg.InitialBlobScalar` in go-ethereum (417565260) -pub const INITIAL_BLOB_SCALAR: U256 = U256::from_limbs([417565260, 0, 0, 0]); - -/// Curie hardfork flag value (1 = true). -pub const IS_CURIE: U256 = U256::from_limbs([1, 0, 0, 0]); - /// Maximum L1 data fee cap for circuit compatibility. /// Matches go-ethereum's `CalculateL1DataFee` cap in `rollup/fees/rollup_fee.go`. const L1_FEE_CAP: U256 = U256::from_limbs([u64::MAX, 0, 0, 0]); -/// Storage updates for L1 gas price oracle Curie hardfork initialization. -/// -/// These storage slots are initialized when the Curie hardfork activates: -/// - l1BlobBaseFee = 1 -/// - commitScalar = InitialCommitScalar -/// - blobScalar = InitialBlobScalar -/// - isCurie = 1 (true) -pub const CURIE_L1_GAS_PRICE_ORACLE_STORAGE: [(U256, U256); 4] = [ - (GPO_L1_BLOB_BASE_FEE_SLOT, INITIAL_L1_BLOB_BASE_FEE), - (GPO_COMMIT_SCALAR_SLOT, INITIAL_COMMIT_SCALAR), - (GPO_BLOB_SCALAR_SLOT, INITIAL_BLOB_SCALAR), - (GPO_IS_CURIE_SLOT, IS_CURIE), -]; - // ============================================================================= // L1 Block Info // ============================================================================= @@ -423,22 +391,6 @@ mod tests { assert_eq!(cost, U256::ZERO); } - #[test] - fn test_curie_oracle_storage_constants() { - assert_eq!(CURIE_L1_GAS_PRICE_ORACLE_STORAGE.len(), 4); - // Verify the 4 slots are the expected ones - assert_eq!( - CURIE_L1_GAS_PRICE_ORACLE_STORAGE[0].0, - GPO_L1_BLOB_BASE_FEE_SLOT - ); - assert_eq!( - CURIE_L1_GAS_PRICE_ORACLE_STORAGE[1].0, - GPO_COMMIT_SCALAR_SLOT - ); - assert_eq!(CURIE_L1_GAS_PRICE_ORACLE_STORAGE[2].0, GPO_BLOB_SCALAR_SLOT); - assert_eq!(CURIE_L1_GAS_PRICE_ORACLE_STORAGE[3].0, GPO_IS_CURIE_SLOT); - } - #[test] fn test_gpo_storage_slot_ordering() { // Slots should be sequential per the contract layout diff --git a/crates/revm/src/lib.rs b/crates/revm/src/lib.rs index 75727d6..00aea49 100644 --- a/crates/revm/src/lib.rs +++ b/crates/revm/src/lib.rs @@ -58,7 +58,6 @@ pub use block::MorphBlockEnv; pub use error::{MorphHaltReason, MorphInvalidTransaction}; pub use evm::MorphEvm; pub use l1block::{ - CURIE_L1_GAS_PRICE_ORACLE_STORAGE, GPO_BLOB_SCALAR_SLOT, GPO_COMMIT_SCALAR_SLOT, GPO_IS_CURIE_SLOT, @@ -69,11 +68,6 @@ pub use l1block::{ GPO_OWNER_SLOT, GPO_SCALAR_SLOT, GPO_WHITELIST_SLOT, - INITIAL_BLOB_SCALAR, - INITIAL_COMMIT_SCALAR, - // Curie initial values - INITIAL_L1_BLOB_BASE_FEE, - IS_CURIE, L1_GAS_PRICE_ORACLE_ADDRESS, L1BlockInfo, }; From 0227bb6d2851d8b507e2949341c6b4cd75153f14 Mon Sep 17 00:00:00 2001 From: panos-xyz Date: Fri, 24 Apr 2026 21:55:53 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix(deps):=20bump=20rustls-webpki=200.103.1?= =?UTF-8?q?0=20=E2=86=92=200.103.13=20to=20fix=20RUSTSEC-2026-0104?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cargo-deny on this PR fails with: error[vulnerability]: Reachable panic in certificate revocation list parsing rustls-webpki 0.103.10 ID: RUSTSEC-2026-0104 Fix shipped in 0.103.13 (2026-04-21). cargo update is a clean patch bump (no other lockfile changes). Lets the cargo-deny CI step pass without us having to ignore the advisory. --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7cce94f..78e19f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2426,7 +2426,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ab67060fc6b8ef687992d439ca0fa36e7ed17e9a0b16b25b601e8757df720de" dependencies = [ "data-encoding", - "syn 2.0.117", + "syn 1.0.109", ] [[package]] @@ -9493,9 +9493,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.10" +version = "0.103.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ "ring", "rustls-pki-types", From cd6fa693cc3101c1181bb332021d38f81e51e22a Mon Sep 17 00:00:00 2001 From: panos-xyz Date: Fri, 24 Apr 2026 22:28:04 +0800 Subject: [PATCH 3/3] fix(deny): ignore RUSTSEC-2026-0105 (core2 unmaintained, all versions yanked) cargo-deny still failing after the rustls-webpki bump. New advisory: error[unmaintained]: core2 is unmaintained, all versions yanked ID: RUSTSEC-2026-0105 Maintainer stopped maintaining and yanked every published version, so `cargo update -p core2` can't pick a non-yanked one. core2 is a transitive dep we don't pull directly; the fix would be to drop whichever upstream crate still pulls it in. Until that lands, ignore the advisory with a note pointing at the upstream issue. --- deny.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/deny.toml b/deny.toml index 9000cea..45b052c 100644 --- a/deny.toml +++ b/deny.toml @@ -18,6 +18,9 @@ ignore = [ "RUSTSEC-2026-0098", # https://rustsec.org/advisories/RUSTSEC-2026-0099 rustls-webpki wildcard name constraints "RUSTSEC-2026-0099", + # https://rustsec.org/advisories/RUSTSEC-2026-0105 core2 unmaintained, all versions yanked + # transitive dep of (likely) reth fork; no upstream replacement, can't `cargo update` + "RUSTSEC-2026-0105", ] # This section is considered when running `cargo deny check bans`.