From acc318efe4fa2e7a3e78f87bc186188f3960753f Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 8 Aug 2025 16:19:20 -0300 Subject: [PATCH 01/13] first step change Signed-off-by: Ignacio Hagopian --- crates/stateless/src/fork_spec.rs | 109 ------------------------------ crates/stateless/src/lib.rs | 12 ---- testing/ef-tests/src/models.rs | 100 ++++++++++++++------------- 3 files changed, 53 insertions(+), 168 deletions(-) delete mode 100644 crates/stateless/src/fork_spec.rs diff --git a/crates/stateless/src/fork_spec.rs b/crates/stateless/src/fork_spec.rs deleted file mode 100644 index 107a4fb71c6..00000000000 --- a/crates/stateless/src/fork_spec.rs +++ /dev/null @@ -1,109 +0,0 @@ -use alloy_eips::{eip6110::MAINNET_DEPOSIT_CONTRACT_ADDRESS, BlobScheduleBlobParams}; -use alloy_genesis::Genesis; -// This is here so we don't pull in the EF-tests. -// We need to think more about how we will parse in the chain-spec -use reth_chainspec::{Chain, ChainSpecBuilder}; -use serde::{Deserialize, Serialize}; - -use crate::chain_spec::ChainSpec; - -/// Fork specification. -#[derive(Debug, PartialEq, Eq, PartialOrd, Hash, Ord, Clone, Copy, Serialize, Deserialize)] -pub enum ForkSpec { - /// Frontier - Frontier, - /// Frontier to Homestead - FrontierToHomesteadAt5, - /// Homestead - Homestead, - /// Homestead to Tangerine - HomesteadToDaoAt5, - /// Homestead to Tangerine - HomesteadToEIP150At5, - /// Tangerine - EIP150, - /// Spurious Dragon - EIP158, // EIP-161: State trie clearing - /// Spurious Dragon to Byzantium - EIP158ToByzantiumAt5, - /// Byzantium - Byzantium, - /// Byzantium to Constantinople - ByzantiumToConstantinopleAt5, // SKIPPED - /// Byzantium to Constantinople - ByzantiumToConstantinopleFixAt5, - /// Constantinople - Constantinople, // SKIPPED - /// Constantinople fix - ConstantinopleFix, - /// Istanbul - Istanbul, - /// Berlin - Berlin, - /// Berlin to London - BerlinToLondonAt5, - /// London - London, - /// Paris aka The Merge - Merge, - /// Shanghai - Shanghai, - /// Merge EOF test - #[serde(alias = "Merge+3540+3670")] - MergeEOF, - /// After Merge Init Code test - #[serde(alias = "Merge+3860")] - MergeMeterInitCode, - /// After Merge plus new PUSH0 opcode - #[serde(alias = "Merge+3855")] - MergePush0, - /// Cancun - Cancun, - /// Prague - Prague, -} - -impl From for ChainSpec { - fn from(fork_spec: ForkSpec) -> Self { - // We initialize with empty genesis since we only use hardforks from the constructed ChainSpec. - let spec_builder = - ChainSpecBuilder::default().genesis(Genesis::default()).chain(Chain::mainnet()); - - let hardforks = match fork_spec { - ForkSpec::Frontier => spec_builder.frontier_activated(), - ForkSpec::Homestead | ForkSpec::FrontierToHomesteadAt5 => { - spec_builder.homestead_activated() - } - ForkSpec::EIP150 | ForkSpec::HomesteadToDaoAt5 | ForkSpec::HomesteadToEIP150At5 => { - spec_builder.tangerine_whistle_activated() - } - ForkSpec::EIP158 => spec_builder.spurious_dragon_activated(), - ForkSpec::Byzantium - | ForkSpec::EIP158ToByzantiumAt5 - | ForkSpec::ConstantinopleFix - | ForkSpec::ByzantiumToConstantinopleFixAt5 => spec_builder.byzantium_activated(), - ForkSpec::Istanbul => spec_builder.istanbul_activated(), - ForkSpec::Berlin => spec_builder.berlin_activated(), - ForkSpec::London | ForkSpec::BerlinToLondonAt5 => spec_builder.london_activated(), - ForkSpec::Merge - | ForkSpec::MergeEOF - | ForkSpec::MergeMeterInitCode - | ForkSpec::MergePush0 => spec_builder.paris_activated(), - ForkSpec::Shanghai => spec_builder.shanghai_activated(), - ForkSpec::Cancun => spec_builder.cancun_activated(), - ForkSpec::ByzantiumToConstantinopleAt5 | ForkSpec::Constantinople => { - panic!("Overridden with PETERSBURG") - } - ForkSpec::Prague => spec_builder.prague_activated(), - } - .build() - .hardforks; - - Self { - chain: Chain::mainnet(), - hardforks, - deposit_contract_address: Some(MAINNET_DEPOSIT_CONTRACT_ADDRESS), - blob_params: BlobScheduleBlobParams::default(), - } - } -} diff --git a/crates/stateless/src/lib.rs b/crates/stateless/src/lib.rs index 47da72c7cb7..041c82f1666 100644 --- a/crates/stateless/src/lib.rs +++ b/crates/stateless/src/lib.rs @@ -48,18 +48,6 @@ pub mod validation; pub(crate) mod witness_db; pub mod chain_spec; -/// ForkSpec module -/// This is needed because ChainSpec is not serializable (neither is genesis) -/// -/// Note: There is an exact copy of ForkSpec in `ef-tests` but since ef-tests is not no_std -/// we cannot pull that in since we need ForkSpec in the guest program. -/// -/// We convert the ef-tests version of ForkSpec in the host into the one located in here. -/// -/// When we parse execution spec tests, we get back a ForkSpec, that we then pass into -/// the guest program and convert it into a ChainSpec. If someone is using Hoodi/Mainnet -/// etc, then this may not be needed, as you can just do ChainSpec::mainnet() in the guest program -pub mod fork_spec; #[doc(inline)] pub use alloy_rpc_types_debug::ExecutionWitness; diff --git a/testing/ef-tests/src/models.rs b/testing/ef-tests/src/models.rs index 53d99da7dfb..76e9d69fdcd 100644 --- a/testing/ef-tests/src/models.rs +++ b/testing/ef-tests/src/models.rs @@ -2,10 +2,12 @@ use crate::{assert::assert_equal, Error}; use alloy_consensus::Header as RethHeader; -use alloy_eips::eip4895::Withdrawals; -use alloy_genesis::GenesisAccount; +use alloy_eips::{ + eip4895::Withdrawals, eip6110::MAINNET_DEPOSIT_CONTRACT_ADDRESS, BlobScheduleBlobParams, +}; +use alloy_genesis::{Genesis, GenesisAccount}; use alloy_primitives::{keccak256, Address, Bloom, Bytes, B256, B64, U256}; -use reth_chainspec::{ChainSpec, ChainSpecBuilder}; +use reth_chainspec::{Chain, ChainSpec, ChainSpecBuilder}; use reth_db_api::{cursor::DbDupCursorRO, tables, transaction::DbTx}; use reth_primitives_traits::SealedHeader; use serde::Deserialize; @@ -243,12 +245,12 @@ impl Account { } else { return Err(Error::Assertion(format!( "Slot {slot:?} is missing from the database. Expected {value:?}" - ))) + ))); } } else { return Err(Error::Assertion(format!( "Slot {slot:?} is missing from the database. Expected {value:?}" - ))) + ))); } } @@ -325,17 +327,17 @@ impl From for ChainSpec { spec_builder.tangerine_whistle_activated() } ForkSpec::EIP158 => spec_builder.spurious_dragon_activated(), - ForkSpec::Byzantium | - ForkSpec::EIP158ToByzantiumAt5 | - ForkSpec::ConstantinopleFix | - ForkSpec::ByzantiumToConstantinopleFixAt5 => spec_builder.byzantium_activated(), + ForkSpec::Byzantium + | ForkSpec::EIP158ToByzantiumAt5 + | ForkSpec::ConstantinopleFix + | ForkSpec::ByzantiumToConstantinopleFixAt5 => spec_builder.byzantium_activated(), ForkSpec::Istanbul => spec_builder.istanbul_activated(), ForkSpec::Berlin => spec_builder.berlin_activated(), ForkSpec::London | ForkSpec::BerlinToLondonAt5 => spec_builder.london_activated(), - ForkSpec::Merge | - ForkSpec::MergeEOF | - ForkSpec::MergeMeterInitCode | - ForkSpec::MergePush0 => spec_builder.paris_activated(), + ForkSpec::Merge + | ForkSpec::MergeEOF + | ForkSpec::MergeMeterInitCode + | ForkSpec::MergePush0 => spec_builder.paris_activated(), ForkSpec::Shanghai => spec_builder.shanghai_activated(), ForkSpec::Cancun => spec_builder.cancun_activated(), ForkSpec::ByzantiumToConstantinopleAt5 | ForkSpec::Constantinople => { @@ -347,43 +349,47 @@ impl From for ChainSpec { } } -impl From for reth_stateless::fork_spec::ForkSpec { - fn from(value: ForkSpec) -> Self { - match value { - ForkSpec::Frontier => reth_stateless::fork_spec::ForkSpec::Frontier, - ForkSpec::FrontierToHomesteadAt5 => { - reth_stateless::fork_spec::ForkSpec::FrontierToHomesteadAt5 - } - ForkSpec::Homestead => reth_stateless::fork_spec::ForkSpec::Homestead, - ForkSpec::HomesteadToDaoAt5 => reth_stateless::fork_spec::ForkSpec::HomesteadToDaoAt5, - ForkSpec::HomesteadToEIP150At5 => { - reth_stateless::fork_spec::ForkSpec::HomesteadToEIP150At5 - } - ForkSpec::EIP150 => reth_stateless::fork_spec::ForkSpec::EIP150, - ForkSpec::EIP158 => reth_stateless::fork_spec::ForkSpec::EIP158, - ForkSpec::EIP158ToByzantiumAt5 => { - reth_stateless::fork_spec::ForkSpec::EIP158ToByzantiumAt5 +impl From for reth_stateless::chain_spec::ChainSpec { + fn from(fork_spec: ForkSpec) -> Self { + // We initialize with empty genesis since we only use hardforks from the constructed ChainSpec. + let spec_builder = + ChainSpecBuilder::default().genesis(Genesis::default()).chain(Chain::mainnet()); + + let hardforks = match fork_spec { + ForkSpec::Frontier => spec_builder.frontier_activated(), + ForkSpec::Homestead | ForkSpec::FrontierToHomesteadAt5 => { + spec_builder.homestead_activated() } - ForkSpec::Byzantium => reth_stateless::fork_spec::ForkSpec::Byzantium, - ForkSpec::ByzantiumToConstantinopleAt5 => { - reth_stateless::fork_spec::ForkSpec::ByzantiumToConstantinopleAt5 + ForkSpec::EIP150 | ForkSpec::HomesteadToDaoAt5 | ForkSpec::HomesteadToEIP150At5 => { + spec_builder.tangerine_whistle_activated() } - ForkSpec::ByzantiumToConstantinopleFixAt5 => { - reth_stateless::fork_spec::ForkSpec::ByzantiumToConstantinopleFixAt5 + ForkSpec::EIP158 => spec_builder.spurious_dragon_activated(), + ForkSpec::Byzantium + | ForkSpec::EIP158ToByzantiumAt5 + | ForkSpec::ConstantinopleFix + | ForkSpec::ByzantiumToConstantinopleFixAt5 => spec_builder.byzantium_activated(), + ForkSpec::Istanbul => spec_builder.istanbul_activated(), + ForkSpec::Berlin => spec_builder.berlin_activated(), + ForkSpec::London | ForkSpec::BerlinToLondonAt5 => spec_builder.london_activated(), + ForkSpec::Merge + | ForkSpec::MergeEOF + | ForkSpec::MergeMeterInitCode + | ForkSpec::MergePush0 => spec_builder.paris_activated(), + ForkSpec::Shanghai => spec_builder.shanghai_activated(), + ForkSpec::Cancun => spec_builder.cancun_activated(), + ForkSpec::ByzantiumToConstantinopleAt5 | ForkSpec::Constantinople => { + panic!("Overridden with PETERSBURG") } - ForkSpec::Constantinople => reth_stateless::fork_spec::ForkSpec::Constantinople, - ForkSpec::ConstantinopleFix => reth_stateless::fork_spec::ForkSpec::ConstantinopleFix, - ForkSpec::Istanbul => reth_stateless::fork_spec::ForkSpec::Istanbul, - ForkSpec::Berlin => reth_stateless::fork_spec::ForkSpec::Berlin, - ForkSpec::BerlinToLondonAt5 => reth_stateless::fork_spec::ForkSpec::BerlinToLondonAt5, - ForkSpec::London => reth_stateless::fork_spec::ForkSpec::London, - ForkSpec::Merge => reth_stateless::fork_spec::ForkSpec::Merge, - ForkSpec::Shanghai => reth_stateless::fork_spec::ForkSpec::Shanghai, - ForkSpec::MergeEOF => reth_stateless::fork_spec::ForkSpec::MergeEOF, - ForkSpec::MergeMeterInitCode => reth_stateless::fork_spec::ForkSpec::MergeMeterInitCode, - ForkSpec::MergePush0 => reth_stateless::fork_spec::ForkSpec::MergePush0, - ForkSpec::Cancun => reth_stateless::fork_spec::ForkSpec::Cancun, - ForkSpec::Prague => reth_stateless::fork_spec::ForkSpec::Prague, + ForkSpec::Prague => spec_builder.prague_activated(), + } + .build() + .hardforks; + + Self { + chain: Chain::mainnet(), + hardforks, + deposit_contract_address: Some(MAINNET_DEPOSIT_CONTRACT_ADDRESS), + blob_params: BlobScheduleBlobParams::default(), } } } From 8cee4ee6fa64d1cd6492cf6a0eeb392cca3b02d2 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 8 Aug 2025 16:27:44 -0300 Subject: [PATCH 02/13] fill chainconfig for tests Signed-off-by: Ignacio Hagopian --- testing/ef-tests/src/models.rs | 70 ++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 4 deletions(-) diff --git a/testing/ef-tests/src/models.rs b/testing/ef-tests/src/models.rs index 76e9d69fdcd..656be290b25 100644 --- a/testing/ef-tests/src/models.rs +++ b/testing/ef-tests/src/models.rs @@ -5,9 +5,11 @@ use alloy_consensus::Header as RethHeader; use alloy_eips::{ eip4895::Withdrawals, eip6110::MAINNET_DEPOSIT_CONTRACT_ADDRESS, BlobScheduleBlobParams, }; -use alloy_genesis::{Genesis, GenesisAccount}; +use alloy_genesis::{ChainConfig, Genesis, GenesisAccount}; use alloy_primitives::{keccak256, Address, Bloom, Bytes, B256, B64, U256}; -use reth_chainspec::{Chain, ChainSpec, ChainSpecBuilder}; +use reth_chainspec::{ + Chain, ChainHardforks, ChainSpec, ChainSpecBuilder, EthereumHardfork, ForkCondition, +}; use reth_db_api::{cursor::DbDupCursorRO, tables, transaction::DbTx}; use reth_primitives_traits::SealedHeader; use serde::Deserialize; @@ -318,7 +320,7 @@ impl From for ChainSpec { fn from(fork_spec: ForkSpec) -> Self { let spec_builder = ChainSpecBuilder::mainnet(); - match fork_spec { + let mut chain_spec = match fork_spec { ForkSpec::Frontier => spec_builder.frontier_activated(), ForkSpec::Homestead | ForkSpec::FrontierToHomesteadAt5 => { spec_builder.homestead_activated() @@ -345,8 +347,68 @@ impl From for ChainSpec { } ForkSpec::Prague => spec_builder.prague_activated(), } - .build() + .build(); + + fill_genesis_config( + &mut chain_spec.genesis.config, + &chain_spec.hardforks, + Chain::mainnet().id(), + ); + + chain_spec + } +} + +fn fill_genesis_config(cfg: &mut ChainConfig, hardforks: &ChainHardforks, chain_id: u64) { + cfg.chain_id = chain_id; + // Helpers to extract activation values from ForkCondition + let get_block = |hf: EthereumHardfork| -> Option { + match hardforks.fork(hf) { + ForkCondition::Block(b) => Some(b), + ForkCondition::TTD { activation_block_number, .. } => Some(activation_block_number), + _ => None, + } + }; + let get_time = |hf: EthereumHardfork| -> Option { + match hardforks.fork(hf) { + ForkCondition::Timestamp(t) => Some(t), + _ => None, + } + }; + + // Legacy block-based forks + cfg.homestead_block = get_block(EthereumHardfork::Homestead); + cfg.dao_fork_block = get_block(EthereumHardfork::Dao); + cfg.dao_fork_support = cfg.dao_fork_block.is_some(); + cfg.eip150_block = get_block(EthereumHardfork::Tangerine); + // Spurious Dragon covers both eip155 and eip158 + let spurious = get_block(EthereumHardfork::SpuriousDragon); + cfg.eip155_block = spurious; + cfg.eip158_block = spurious; + cfg.byzantium_block = get_block(EthereumHardfork::Byzantium); + cfg.constantinople_block = get_block(EthereumHardfork::Constantinople); + cfg.petersburg_block = get_block(EthereumHardfork::Petersburg); + cfg.istanbul_block = get_block(EthereumHardfork::Istanbul); + cfg.muir_glacier_block = get_block(EthereumHardfork::MuirGlacier); + cfg.berlin_block = get_block(EthereumHardfork::Berlin); + cfg.london_block = get_block(EthereumHardfork::London); + cfg.arrow_glacier_block = get_block(EthereumHardfork::ArrowGlacier); + cfg.gray_glacier_block = get_block(EthereumHardfork::GrayGlacier); + + // Merge (Paris) via TTD + if let ForkCondition::TTD { total_difficulty, fork_block, .. } = + hardforks.fork(EthereumHardfork::Paris) + { + cfg.terminal_total_difficulty = Some(total_difficulty); + cfg.terminal_total_difficulty_passed = true; + cfg.merge_netsplit_block = fork_block; } + + // Timestamp-based forks + cfg.shanghai_time = get_time(EthereumHardfork::Shanghai); + cfg.cancun_time = get_time(EthereumHardfork::Cancun); + cfg.prague_time = get_time(EthereumHardfork::Prague); + cfg.osaka_time = get_time(EthereumHardfork::Osaka); } impl From for reth_stateless::chain_spec::ChainSpec { From ca2e722fba73a34aecedbd493f416cd05f8e0dbe Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 8 Aug 2025 17:01:20 -0300 Subject: [PATCH 03/13] add chain config Signed-off-by: Ignacio Hagopian --- crates/stateless/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/stateless/src/lib.rs b/crates/stateless/src/lib.rs index 041c82f1666..f572d514292 100644 --- a/crates/stateless/src/lib.rs +++ b/crates/stateless/src/lib.rs @@ -38,6 +38,7 @@ extern crate alloc; /// Sparse trie implementation for stateless validation pub mod trie; +use alloy_genesis::ChainConfig; #[doc(inline)] pub use trie::StatelessTrie; #[doc(inline)] @@ -66,6 +67,8 @@ pub struct StatelessInput { pub block: Block, /// `ExecutionWitness` for the stateless validation function pub witness: ExecutionWitness, + /// Chain configuration + pub chain_config: ChainConfig, } /// Tracks the amount of cycles a region of code takes up From 39c7e546d45a1064162a83e45e080c3d5a1f6e45 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 8 Aug 2025 17:45:13 -0300 Subject: [PATCH 04/13] export genesis Signed-off-by: Ignacio Hagopian --- crates/stateless/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/stateless/src/lib.rs b/crates/stateless/src/lib.rs index f572d514292..08502a54704 100644 --- a/crates/stateless/src/lib.rs +++ b/crates/stateless/src/lib.rs @@ -44,6 +44,8 @@ pub use trie::StatelessTrie; #[doc(inline)] pub use validation::stateless_validation_with_trie; +pub use alloy_genesis::Genesis; + /// Implementation of stateless validation pub mod validation; pub(crate) mod witness_db; From 4c51e81b7f74acbc278c57eb4aa66ecac07ac5f7 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 8 Aug 2025 17:53:55 -0300 Subject: [PATCH 05/13] update Signed-off-by: Ignacio Hagopian --- crates/stateless/Cargo.toml | 2 +- crates/stateless/src/lib.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/stateless/Cargo.toml b/crates/stateless/Cargo.toml index 738c6e5460f..15cc8e2e046 100644 --- a/crates/stateless/Cargo.toml +++ b/crates/stateless/Cargo.toml @@ -19,7 +19,7 @@ alloy-trie.workspace = true alloy-consensus.workspace = true alloy-rpc-types-debug.workspace = true alloy-eips.workspace = true -alloy-genesis.workspace = true +alloy-genesis = { workspace = true, features = ["serde-bincode-compat"] } # reth reth-ethereum-consensus.workspace = true diff --git a/crates/stateless/src/lib.rs b/crates/stateless/src/lib.rs index 08502a54704..e5bd22a4d30 100644 --- a/crates/stateless/src/lib.rs +++ b/crates/stateless/src/lib.rs @@ -69,7 +69,8 @@ pub struct StatelessInput { pub block: Block, /// `ExecutionWitness` for the stateless validation function pub witness: ExecutionWitness, - /// Chain configuration + /// Chain configuration for the stateless validation function + #[serde_as(as = "alloy_genesis::serde_bincode_compat::ChainConfig<'_>")] pub chain_config: ChainConfig, } From 65a6585d715b93ca07804bd44e89f81dd049abf2 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 8 Aug 2025 18:12:00 -0300 Subject: [PATCH 06/13] more changes Signed-off-by: Ignacio Hagopian --- testing/ef-tests/src/models.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/testing/ef-tests/src/models.rs b/testing/ef-tests/src/models.rs index 656be290b25..346afda357d 100644 --- a/testing/ef-tests/src/models.rs +++ b/testing/ef-tests/src/models.rs @@ -380,11 +380,12 @@ fn fill_genesis_config(cfg: &mut ChainConfig, hardforks: &ChainHardforks, chain_ cfg.homestead_block = get_block(EthereumHardfork::Homestead); cfg.dao_fork_block = get_block(EthereumHardfork::Dao); cfg.dao_fork_support = cfg.dao_fork_block.is_some(); + // TODO: why there isn't a consolidated Tangerine Whistle fork? cfg.eip150_block = get_block(EthereumHardfork::Tangerine); - // Spurious Dragon covers both eip155 and eip158 - let spurious = get_block(EthereumHardfork::SpuriousDragon); - cfg.eip155_block = spurious; - cfg.eip158_block = spurious; + cfg.eip158_block = get_block(EthereumHardfork::Tangerine); + // TODO: why there isn't a Spurious Dragon fork? + // More EIPs than EIP-155 were activated there, see: https://ethereum.org/en/history/#spurious-dragon + cfg.eip155_block = get_block(EthereumHardfork::SpuriousDragon); cfg.byzantium_block = get_block(EthereumHardfork::Byzantium); cfg.constantinople_block = get_block(EthereumHardfork::Constantinople); cfg.petersburg_block = get_block(EthereumHardfork::Petersburg); From 8d348c8c5f2bf136e71d92fde7da3373842b7eb6 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 8 Aug 2025 18:36:13 -0300 Subject: [PATCH 07/13] more work Signed-off-by: Ignacio Hagopian --- crates/chainspec/src/spec.rs | 61 ++++++++++++++++++++++++++++++++-- testing/ef-tests/src/models.rs | 61 +--------------------------------- 2 files changed, 59 insertions(+), 63 deletions(-) diff --git a/crates/chainspec/src/spec.rs b/crates/chainspec/src/spec.rs index 2800640b708..5e4d7f63942 100644 --- a/crates/chainspec/src/spec.rs +++ b/crates/chainspec/src/spec.rs @@ -17,7 +17,7 @@ use alloy_consensus::{ use alloy_eips::{ eip1559::INITIAL_BASE_FEE, eip7685::EMPTY_REQUESTS_HASH, eip7892::BlobScheduleBlobParams, }; -use alloy_genesis::Genesis; +use alloy_genesis::{ChainConfig, Genesis}; use alloy_primitives::{address, b256, Address, BlockNumber, B256, U256}; use alloy_trie::root::state_root_ref_unhashed; use core::fmt::Debug; @@ -87,9 +87,10 @@ pub fn make_genesis_header(genesis: &Genesis, hardforks: &ChainHardforks) -> Hea /// The Ethereum mainnet spec pub static MAINNET: LazyLock> = LazyLock::new(|| { - let genesis = serde_json::from_str(include_str!("../res/genesis/mainnet.json")) + let mut genesis: Genesis = serde_json::from_str(include_str!("../res/genesis/mainnet.json")) .expect("Can't deserialize Mainnet genesis json"); let hardforks = EthereumHardfork::mainnet().into(); +fill_genesis_config(&mut genesis.config, &hardforks, Some(Chain::mainnet())); let mut spec = ChainSpec { chain: Chain::mainnet(), genesis_header: SealedHeader::new( @@ -965,7 +966,8 @@ impl ChainSpecBuilder { } }) }; - let genesis = self.genesis.expect("The genesis is required"); + let mut genesis = self.genesis.expect("The genesis is required"); + fill_genesis_config(&mut genesis.config, &self.hardforks, self.chain); ChainSpec { chain: self.chain.expect("The chain is required"), genesis_header: SealedHeader::new_unhashed(make_genesis_header( @@ -981,6 +983,59 @@ impl ChainSpecBuilder { } } +fn fill_genesis_config(cfg: &mut ChainConfig, hardforks: &ChainHardforks, chain: Option) { + cfg.chain_id = chain.map(|c| c.id()).unwrap_or_default(); + // Helpers to extract activation values from ForkCondition + let get_block = |hf: EthereumHardfork| -> Option { + match hardforks.fork(hf) { + ForkCondition::Block(b) => Some(b), + ForkCondition::TTD { activation_block_number, .. } => Some(activation_block_number), + _ => None, + } + }; + let get_time = |hf: EthereumHardfork| -> Option { + match hardforks.fork(hf) { + ForkCondition::Timestamp(t) => Some(t), + _ => None, + } + }; + + // Legacy block-based forks + cfg.homestead_block = get_block(EthereumHardfork::Homestead); + cfg.dao_fork_block = get_block(EthereumHardfork::Dao); + cfg.dao_fork_support = cfg.dao_fork_block.is_some(); + // TODO: why there isn't a consolidated Tangerine Whistle fork? + cfg.eip150_block = get_block(EthereumHardfork::Tangerine); + cfg.eip158_block = get_block(EthereumHardfork::Tangerine); + // TODO: why there isn't a Spurious Dragon fork? + // More EIPs than EIP-155 were activated there, see: https://ethereum.org/en/history/#spurious-dragon + cfg.eip155_block = get_block(EthereumHardfork::SpuriousDragon); + cfg.byzantium_block = get_block(EthereumHardfork::Byzantium); + cfg.constantinople_block = get_block(EthereumHardfork::Constantinople); + cfg.petersburg_block = get_block(EthereumHardfork::Petersburg); + cfg.istanbul_block = get_block(EthereumHardfork::Istanbul); + cfg.muir_glacier_block = get_block(EthereumHardfork::MuirGlacier); + cfg.berlin_block = get_block(EthereumHardfork::Berlin); + cfg.london_block = get_block(EthereumHardfork::London); + cfg.arrow_glacier_block = get_block(EthereumHardfork::ArrowGlacier); + cfg.gray_glacier_block = get_block(EthereumHardfork::GrayGlacier); + + // Merge (Paris) via TTD + if let ForkCondition::TTD { total_difficulty, fork_block, .. } = + hardforks.fork(EthereumHardfork::Paris) + { + cfg.terminal_total_difficulty = Some(total_difficulty); + cfg.terminal_total_difficulty_passed = true; + cfg.merge_netsplit_block = fork_block; + } + + // Timestamp-based forks + cfg.shanghai_time = get_time(EthereumHardfork::Shanghai); + cfg.cancun_time = get_time(EthereumHardfork::Cancun); + cfg.prague_time = get_time(EthereumHardfork::Prague); + cfg.osaka_time = get_time(EthereumHardfork::Osaka); +} + impl From<&Arc> for ChainSpecBuilder { fn from(value: &Arc) -> Self { Self { diff --git a/testing/ef-tests/src/models.rs b/testing/ef-tests/src/models.rs index 346afda357d..56d413901ee 100644 --- a/testing/ef-tests/src/models.rs +++ b/testing/ef-tests/src/models.rs @@ -320,7 +320,7 @@ impl From for ChainSpec { fn from(fork_spec: ForkSpec) -> Self { let spec_builder = ChainSpecBuilder::mainnet(); - let mut chain_spec = match fork_spec { + let chain_spec = match fork_spec { ForkSpec::Frontier => spec_builder.frontier_activated(), ForkSpec::Homestead | ForkSpec::FrontierToHomesteadAt5 => { spec_builder.homestead_activated() @@ -349,69 +349,10 @@ impl From for ChainSpec { } .build(); - fill_genesis_config( - &mut chain_spec.genesis.config, - &chain_spec.hardforks, - Chain::mainnet().id(), - ); - chain_spec } } -fn fill_genesis_config(cfg: &mut ChainConfig, hardforks: &ChainHardforks, chain_id: u64) { - cfg.chain_id = chain_id; - // Helpers to extract activation values from ForkCondition - let get_block = |hf: EthereumHardfork| -> Option { - match hardforks.fork(hf) { - ForkCondition::Block(b) => Some(b), - ForkCondition::TTD { activation_block_number, .. } => Some(activation_block_number), - _ => None, - } - }; - let get_time = |hf: EthereumHardfork| -> Option { - match hardforks.fork(hf) { - ForkCondition::Timestamp(t) => Some(t), - _ => None, - } - }; - - // Legacy block-based forks - cfg.homestead_block = get_block(EthereumHardfork::Homestead); - cfg.dao_fork_block = get_block(EthereumHardfork::Dao); - cfg.dao_fork_support = cfg.dao_fork_block.is_some(); - // TODO: why there isn't a consolidated Tangerine Whistle fork? - cfg.eip150_block = get_block(EthereumHardfork::Tangerine); - cfg.eip158_block = get_block(EthereumHardfork::Tangerine); - // TODO: why there isn't a Spurious Dragon fork? - // More EIPs than EIP-155 were activated there, see: https://ethereum.org/en/history/#spurious-dragon - cfg.eip155_block = get_block(EthereumHardfork::SpuriousDragon); - cfg.byzantium_block = get_block(EthereumHardfork::Byzantium); - cfg.constantinople_block = get_block(EthereumHardfork::Constantinople); - cfg.petersburg_block = get_block(EthereumHardfork::Petersburg); - cfg.istanbul_block = get_block(EthereumHardfork::Istanbul); - cfg.muir_glacier_block = get_block(EthereumHardfork::MuirGlacier); - cfg.berlin_block = get_block(EthereumHardfork::Berlin); - cfg.london_block = get_block(EthereumHardfork::London); - cfg.arrow_glacier_block = get_block(EthereumHardfork::ArrowGlacier); - cfg.gray_glacier_block = get_block(EthereumHardfork::GrayGlacier); - - // Merge (Paris) via TTD - if let ForkCondition::TTD { total_difficulty, fork_block, .. } = - hardforks.fork(EthereumHardfork::Paris) - { - cfg.terminal_total_difficulty = Some(total_difficulty); - cfg.terminal_total_difficulty_passed = true; - cfg.merge_netsplit_block = fork_block; - } - - // Timestamp-based forks - cfg.shanghai_time = get_time(EthereumHardfork::Shanghai); - cfg.cancun_time = get_time(EthereumHardfork::Cancun); - cfg.prague_time = get_time(EthereumHardfork::Prague); - cfg.osaka_time = get_time(EthereumHardfork::Osaka); -} - impl From for reth_stateless::chain_spec::ChainSpec { fn from(fork_spec: ForkSpec) -> Self { // We initialize with empty genesis since we only use hardforks from the constructed ChainSpec. From b4bde84f11e2592fd8215f69a6ebc555f42057c7 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Fri, 8 Aug 2025 19:23:23 -0300 Subject: [PATCH 08/13] more changes Signed-off-by: Ignacio Hagopian --- crates/chainspec/src/spec.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/crates/chainspec/src/spec.rs b/crates/chainspec/src/spec.rs index 5e4d7f63942..5bfef2111b7 100644 --- a/crates/chainspec/src/spec.rs +++ b/crates/chainspec/src/spec.rs @@ -15,7 +15,8 @@ use alloy_consensus::{ Header, }; use alloy_eips::{ - eip1559::INITIAL_BASE_FEE, eip7685::EMPTY_REQUESTS_HASH, eip7892::BlobScheduleBlobParams, + eip1559::INITIAL_BASE_FEE, eip6110::MAINNET_DEPOSIT_CONTRACT_ADDRESS, +eip7685::EMPTY_REQUESTS_HASH, eip7892::BlobScheduleBlobParams, }; use alloy_genesis::{ChainConfig, Genesis}; use alloy_primitives::{address, b256, Address, BlockNumber, B256, U256}; @@ -90,7 +91,12 @@ pub static MAINNET: LazyLock> = LazyLock::new(|| { let mut genesis: Genesis = serde_json::from_str(include_str!("../res/genesis/mainnet.json")) .expect("Can't deserialize Mainnet genesis json"); let hardforks = EthereumHardfork::mainnet().into(); -fill_genesis_config(&mut genesis.config, &hardforks, Some(Chain::mainnet())); +fill_genesis_config( +&mut genesis.config, +&hardforks, +Some(Chain::mainnet()), + Some(MAINNET_DEPOSIT_CONTRACT_ADDRESS), +); let mut spec = ChainSpec { chain: Chain::mainnet(), genesis_header: SealedHeader::new( @@ -967,7 +973,7 @@ impl ChainSpecBuilder { }) }; let mut genesis = self.genesis.expect("The genesis is required"); - fill_genesis_config(&mut genesis.config, &self.hardforks, self.chain); + fill_genesis_config(&mut genesis.config, &self.hardforks, self.chain, None); ChainSpec { chain: self.chain.expect("The chain is required"), genesis_header: SealedHeader::new_unhashed(make_genesis_header( @@ -983,8 +989,14 @@ impl ChainSpecBuilder { } } -fn fill_genesis_config(cfg: &mut ChainConfig, hardforks: &ChainHardforks, chain: Option) { +fn fill_genesis_config( + cfg: &mut ChainConfig, + hardforks: &ChainHardforks, + chain: Option, + deposit_contract: Option
, +) { cfg.chain_id = chain.map(|c| c.id()).unwrap_or_default(); + cfg.deposit_contract_address = deposit_contract; // Helpers to extract activation values from ForkCondition let get_block = |hf: EthereumHardfork| -> Option { match hardforks.fork(hf) { From 6eda062b5f178ff919da1ec5d282690a83bc31fd Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 11 Aug 2025 09:32:29 -0300 Subject: [PATCH 09/13] remove stateless chainspec Signed-off-by: Ignacio Hagopian --- crates/stateless/src/chain_spec.rs | 122 ----------------------------- crates/stateless/src/lib.rs | 2 - testing/ef-tests/src/models.rs | 55 +------------ 3 files changed, 3 insertions(+), 176 deletions(-) delete mode 100644 crates/stateless/src/chain_spec.rs diff --git a/crates/stateless/src/chain_spec.rs b/crates/stateless/src/chain_spec.rs deleted file mode 100644 index 457d6fa856e..00000000000 --- a/crates/stateless/src/chain_spec.rs +++ /dev/null @@ -1,122 +0,0 @@ -use core::fmt::Display; - -use alloc::{boxed::Box, vec::Vec}; -use alloy_consensus::Header; -use alloy_eips::BlobScheduleBlobParams; -use alloy_genesis::Genesis; -use alloy_primitives::{Address, B256, U256}; -use reth_chainspec::{ - BaseFeeParams, Chain, ChainHardforks, DepositContract, EthChainSpec, EthereumHardfork, - EthereumHardforks, ForkCondition, ForkFilter, ForkId, Hardfork, Hardforks, Head, -}; -use reth_evm::eth::spec::EthExecutorSpec; - -#[derive(Debug, Clone)] -pub struct ChainSpec { - pub chain: Chain, - pub hardforks: ChainHardforks, - pub deposit_contract_address: Option
, - pub blob_params: BlobScheduleBlobParams, -} - -impl EthereumHardforks for ChainSpec { - fn ethereum_fork_activation(&self, fork: EthereumHardfork) -> ForkCondition { - self.hardforks.get(fork).unwrap_or_default() - } -} - -impl EthExecutorSpec for ChainSpec { - fn deposit_contract_address(&self) -> Option
{ - self.deposit_contract_address - } -} - -impl Hardforks for ChainSpec { - fn fork(&self, fork: H) -> ForkCondition { - self.hardforks.fork(fork) - } - - fn forks_iter(&self) -> impl Iterator { - self.hardforks.forks_iter() - } - - fn fork_id(&self, _head: &Head) -> ForkId { - unimplemented!(); - } - - fn latest_fork_id(&self) -> ForkId { - unimplemented!() - } - - fn fork_filter(&self, _head: Head) -> ForkFilter { - unimplemented!(); - } -} - -impl EthChainSpec for ChainSpec { - type Header = Header; - - fn chain(&self) -> Chain { - self.chain - } - - fn base_fee_params_at_block(&self, _: u64) -> BaseFeeParams { - unimplemented!() - } - - fn base_fee_params_at_timestamp(&self, _: u64) -> BaseFeeParams { - unimplemented!() - } - - fn blob_params_at_timestamp(&self, timestamp: u64) -> Option { - if let Some(blob_param) = self.blob_params.active_scheduled_params_at_timestamp(timestamp) { - Some(*blob_param) - } else if self.is_osaka_active_at_timestamp(timestamp) { - Some(self.blob_params.osaka) - } else if self.is_prague_active_at_timestamp(timestamp) { - Some(self.blob_params.prague) - } else if self.is_cancun_active_at_timestamp(timestamp) { - Some(self.blob_params.cancun) - } else { - None - } - } - - fn deposit_contract(&self) -> Option<&DepositContract> { - unimplemented!() - } - - fn genesis_hash(&self) -> B256 { - unimplemented!() - } - - fn prune_delete_limit(&self) -> usize { - unimplemented!() - } - - fn display_hardforks(&self) -> Box { - unimplemented!() - } - - fn genesis_header(&self) -> &Self::Header { - unimplemented!() - } - - fn genesis(&self) -> &Genesis { - unimplemented!() - } - - fn bootnodes(&self) -> Option> { - unimplemented!() - } - - fn final_paris_total_difficulty(&self) -> Option { - if let ForkCondition::TTD { total_difficulty, .. } = - self.ethereum_fork_activation(EthereumHardfork::Paris) - { - Some(total_difficulty) - } else { - None - } - } -} diff --git a/crates/stateless/src/lib.rs b/crates/stateless/src/lib.rs index e5bd22a4d30..4d68ff01364 100644 --- a/crates/stateless/src/lib.rs +++ b/crates/stateless/src/lib.rs @@ -50,8 +50,6 @@ pub use alloy_genesis::Genesis; pub mod validation; pub(crate) mod witness_db; -pub mod chain_spec; - #[doc(inline)] pub use alloy_rpc_types_debug::ExecutionWitness; diff --git a/testing/ef-tests/src/models.rs b/testing/ef-tests/src/models.rs index 56d413901ee..19a67e94eca 100644 --- a/testing/ef-tests/src/models.rs +++ b/testing/ef-tests/src/models.rs @@ -2,14 +2,10 @@ use crate::{assert::assert_equal, Error}; use alloy_consensus::Header as RethHeader; -use alloy_eips::{ - eip4895::Withdrawals, eip6110::MAINNET_DEPOSIT_CONTRACT_ADDRESS, BlobScheduleBlobParams, -}; -use alloy_genesis::{ChainConfig, Genesis, GenesisAccount}; +use alloy_eips::eip4895::Withdrawals; +use alloy_genesis::GenesisAccount; use alloy_primitives::{keccak256, Address, Bloom, Bytes, B256, B64, U256}; -use reth_chainspec::{ - Chain, ChainHardforks, ChainSpec, ChainSpecBuilder, EthereumHardfork, ForkCondition, -}; +use reth_chainspec::{ChainSpec, ChainSpecBuilder}; use reth_db_api::{cursor::DbDupCursorRO, tables, transaction::DbTx}; use reth_primitives_traits::SealedHeader; use serde::Deserialize; @@ -353,51 +349,6 @@ impl From for ChainSpec { } } -impl From for reth_stateless::chain_spec::ChainSpec { - fn from(fork_spec: ForkSpec) -> Self { - // We initialize with empty genesis since we only use hardforks from the constructed ChainSpec. - let spec_builder = - ChainSpecBuilder::default().genesis(Genesis::default()).chain(Chain::mainnet()); - - let hardforks = match fork_spec { - ForkSpec::Frontier => spec_builder.frontier_activated(), - ForkSpec::Homestead | ForkSpec::FrontierToHomesteadAt5 => { - spec_builder.homestead_activated() - } - ForkSpec::EIP150 | ForkSpec::HomesteadToDaoAt5 | ForkSpec::HomesteadToEIP150At5 => { - spec_builder.tangerine_whistle_activated() - } - ForkSpec::EIP158 => spec_builder.spurious_dragon_activated(), - ForkSpec::Byzantium - | ForkSpec::EIP158ToByzantiumAt5 - | ForkSpec::ConstantinopleFix - | ForkSpec::ByzantiumToConstantinopleFixAt5 => spec_builder.byzantium_activated(), - ForkSpec::Istanbul => spec_builder.istanbul_activated(), - ForkSpec::Berlin => spec_builder.berlin_activated(), - ForkSpec::London | ForkSpec::BerlinToLondonAt5 => spec_builder.london_activated(), - ForkSpec::Merge - | ForkSpec::MergeEOF - | ForkSpec::MergeMeterInitCode - | ForkSpec::MergePush0 => spec_builder.paris_activated(), - ForkSpec::Shanghai => spec_builder.shanghai_activated(), - ForkSpec::Cancun => spec_builder.cancun_activated(), - ForkSpec::ByzantiumToConstantinopleAt5 | ForkSpec::Constantinople => { - panic!("Overridden with PETERSBURG") - } - ForkSpec::Prague => spec_builder.prague_activated(), - } - .build() - .hardforks; - - Self { - chain: Chain::mainnet(), - hardforks, - deposit_contract_address: Some(MAINNET_DEPOSIT_CONTRACT_ADDRESS), - blob_params: BlobScheduleBlobParams::default(), - } - } -} - /// Possible seal engines. #[derive(Debug, PartialEq, Eq, Default, Deserialize)] pub enum SealEngine { From cb47abfdbc2f2f92dd1f0db6058b58740e6e4607 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 11 Aug 2025 09:47:39 -0300 Subject: [PATCH 10/13] improvements Signed-off-by: Ignacio Hagopian --- crates/chainspec/src/spec.rs | 46 ++++++++++++++++++++-------------- crates/stateless/Cargo.toml | 1 - testing/ef-tests/src/models.rs | 1 + 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/crates/chainspec/src/spec.rs b/crates/chainspec/src/spec.rs index 5bfef2111b7..1a855442a00 100644 --- a/crates/chainspec/src/spec.rs +++ b/crates/chainspec/src/spec.rs @@ -16,7 +16,7 @@ use alloy_consensus::{ }; use alloy_eips::{ eip1559::INITIAL_BASE_FEE, eip6110::MAINNET_DEPOSIT_CONTRACT_ADDRESS, -eip7685::EMPTY_REQUESTS_HASH, eip7892::BlobScheduleBlobParams, + eip7685::EMPTY_REQUESTS_HASH, eip7892::BlobScheduleBlobParams, }; use alloy_genesis::{ChainConfig, Genesis}; use alloy_primitives::{address, b256, Address, BlockNumber, B256, U256}; @@ -91,12 +91,12 @@ pub static MAINNET: LazyLock> = LazyLock::new(|| { let mut genesis: Genesis = serde_json::from_str(include_str!("../res/genesis/mainnet.json")) .expect("Can't deserialize Mainnet genesis json"); let hardforks = EthereumHardfork::mainnet().into(); -fill_genesis_config( -&mut genesis.config, -&hardforks, -Some(Chain::mainnet()), + fill_chainconfig( + &mut genesis.config, + &hardforks, + Some(Chain::mainnet()), Some(MAINNET_DEPOSIT_CONTRACT_ADDRESS), -); + ); let mut spec = ChainSpec { chain: Chain::mainnet(), genesis_header: SealedHeader::new( @@ -391,7 +391,7 @@ impl ChainSpec { // given timestamp. for (fork, params) in bf_params.iter().rev() { if self.hardforks.is_fork_active_at_timestamp(fork.clone(), timestamp) { - return *params + return *params; } } @@ -410,7 +410,7 @@ impl ChainSpec { // given timestamp. for (fork, params) in bf_params.iter().rev() { if self.hardforks.is_fork_active_at_block(fork.clone(), block_number) { - return *params + return *params; } } @@ -484,8 +484,8 @@ impl ChainSpec { // We filter out TTD-based forks w/o a pre-known block since those do not show up in the // fork filter. Some(match condition { - ForkCondition::Block(block) | - ForkCondition::TTD { fork_block: Some(block), .. } => ForkFilterKey::Block(block), + ForkCondition::Block(block) + | ForkCondition::TTD { fork_block: Some(block), .. } => ForkFilterKey::Block(block), ForkCondition::Timestamp(time) => ForkFilterKey::Time(time), _ => return None, }) @@ -512,8 +512,8 @@ impl ChainSpec { for (_, cond) in self.hardforks.forks_iter() { // handle block based forks and the sepolia merge netsplit block edge case (TTD // ForkCondition with Some(block)) - if let ForkCondition::Block(block) | - ForkCondition::TTD { fork_block: Some(block), .. } = cond + if let ForkCondition::Block(block) + | ForkCondition::TTD { fork_block: Some(block), .. } = cond { if head.number >= block { // skip duplicated hardforks: hardforks enabled at genesis block @@ -524,7 +524,7 @@ impl ChainSpec { } else { // we can return here because this block fork is not active, so we set the // `next` value - return ForkId { hash: forkhash, next: block } + return ForkId { hash: forkhash, next: block }; } } } @@ -546,7 +546,7 @@ impl ChainSpec { // can safely return here because we have already handled all block forks and // have handled all active timestamp forks, and set the next value to the // timestamp that is known but not active yet - return ForkId { hash: forkhash, next: timestamp } + return ForkId { hash: forkhash, next: timestamp }; } } @@ -791,6 +791,7 @@ pub struct ChainSpecBuilder { chain: Option, genesis: Option, hardforks: ChainHardforks, + fill_genesis_config: bool, } impl ChainSpecBuilder { @@ -800,6 +801,7 @@ impl ChainSpecBuilder { chain: Some(MAINNET.chain), genesis: Some(MAINNET.genesis.clone()), hardforks: MAINNET.hardforks.clone(), + fill_genesis_config: true, } } } @@ -956,6 +958,12 @@ impl ChainSpecBuilder { self } + /// Enable overriding genesis chain configuration from defined hardforks. + pub const fn fill_genesis_config(mut self, enable: bool) -> Self { + self.fill_genesis_config = enable; + self + } + /// Build the resulting [`ChainSpec`]. /// /// # Panics @@ -973,7 +981,9 @@ impl ChainSpecBuilder { }) }; let mut genesis = self.genesis.expect("The genesis is required"); - fill_genesis_config(&mut genesis.config, &self.hardforks, self.chain, None); + if self.fill_genesis_config { + fill_chainconfig(&mut genesis.config, &self.hardforks, self.chain, None); + } ChainSpec { chain: self.chain.expect("The chain is required"), genesis_header: SealedHeader::new_unhashed(make_genesis_header( @@ -989,7 +999,7 @@ impl ChainSpecBuilder { } } -fn fill_genesis_config( +fn fill_chainconfig( cfg: &mut ChainConfig, hardforks: &ChainHardforks, chain: Option, @@ -1016,11 +1026,8 @@ fn fill_genesis_config( cfg.homestead_block = get_block(EthereumHardfork::Homestead); cfg.dao_fork_block = get_block(EthereumHardfork::Dao); cfg.dao_fork_support = cfg.dao_fork_block.is_some(); - // TODO: why there isn't a consolidated Tangerine Whistle fork? cfg.eip150_block = get_block(EthereumHardfork::Tangerine); cfg.eip158_block = get_block(EthereumHardfork::Tangerine); - // TODO: why there isn't a Spurious Dragon fork? - // More EIPs than EIP-155 were activated there, see: https://ethereum.org/en/history/#spurious-dragon cfg.eip155_block = get_block(EthereumHardfork::SpuriousDragon); cfg.byzantium_block = get_block(EthereumHardfork::Byzantium); cfg.constantinople_block = get_block(EthereumHardfork::Constantinople); @@ -1054,6 +1061,7 @@ impl From<&Arc> for ChainSpecBuilder { chain: Some(value.chain), genesis: Some(value.genesis.clone()), hardforks: value.hardforks.clone(), + fill_genesis_config: false, } } } diff --git a/crates/stateless/Cargo.toml b/crates/stateless/Cargo.toml index 15cc8e2e046..2e431c5fd5c 100644 --- a/crates/stateless/Cargo.toml +++ b/crates/stateless/Cargo.toml @@ -18,7 +18,6 @@ alloy-rlp.workspace = true alloy-trie.workspace = true alloy-consensus.workspace = true alloy-rpc-types-debug.workspace = true -alloy-eips.workspace = true alloy-genesis = { workspace = true, features = ["serde-bincode-compat"] } # reth diff --git a/testing/ef-tests/src/models.rs b/testing/ef-tests/src/models.rs index 19a67e94eca..81e867b99dd 100644 --- a/testing/ef-tests/src/models.rs +++ b/testing/ef-tests/src/models.rs @@ -343,6 +343,7 @@ impl From for ChainSpec { } ForkSpec::Prague => spec_builder.prague_activated(), } + .fill_genesis_config(true) .build(); chain_spec From e5eac83c9a623a9b18557dbf875ff4595ea98fd1 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 11 Aug 2025 10:03:32 -0300 Subject: [PATCH 11/13] add glacier forks Signed-off-by: Ignacio Hagopian --- crates/chainspec/src/spec.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/crates/chainspec/src/spec.rs b/crates/chainspec/src/spec.rs index 1a855442a00..661905cedd6 100644 --- a/crates/chainspec/src/spec.rs +++ b/crates/chainspec/src/spec.rs @@ -902,9 +902,16 @@ impl ChainSpecBuilder { self } + /// Enable Muir Glacier at genesis. + pub fn muirglacier_activated(mut self) -> Self { + self = self.istanbul_activated(); + self.hardforks.insert(EthereumHardfork::MuirGlacier, ForkCondition::Block(0)); + self + } + /// Enable Berlin at genesis. pub fn berlin_activated(mut self) -> Self { - self = self.istanbul_activated(); + self = self.muirglacier_activated(); self.hardforks.insert(EthereumHardfork::Berlin, ForkCondition::Block(0)); self } @@ -916,9 +923,23 @@ impl ChainSpecBuilder { self } + /// Enable Arrow Glacier at genesis. + pub fn arrowglacier_activated(mut self) -> Self { + self = self.london_activated(); + self.hardforks.insert(EthereumHardfork::ArrowGlacier, ForkCondition::Block(0)); + self + } + + /// Enable Gray Glacier at genesis. + pub fn grayglacier_activated(mut self) -> Self { + self = self.arrowglacier_activated(); + self.hardforks.insert(EthereumHardfork::GrayGlacier, ForkCondition::Block(0)); + self + } + /// Enable Paris at genesis. pub fn paris_activated(mut self) -> Self { - self = self.london_activated(); + self = self.grayglacier_activated(); self.hardforks.insert( EthereumHardfork::Paris, ForkCondition::TTD { From 8444a3ea99d960e2f6e054e8ec1d71c0f198534c Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 11 Aug 2025 10:05:56 -0300 Subject: [PATCH 12/13] add missing dao fork Signed-off-by: Ignacio Hagopian --- crates/chainspec/src/spec.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/chainspec/src/spec.rs b/crates/chainspec/src/spec.rs index 661905cedd6..4217cce4784 100644 --- a/crates/chainspec/src/spec.rs +++ b/crates/chainspec/src/spec.rs @@ -853,9 +853,16 @@ impl ChainSpecBuilder { self } + /// Enable Dao at genesis. + pub fn dao_activated(mut self) -> Self { + self = self.frontier_activated(); + self.hardforks.insert(EthereumHardfork::Dao, ForkCondition::Block(0)); + self + } + /// Enable Homestead at genesis. pub fn homestead_activated(mut self) -> Self { - self = self.frontier_activated(); + self = self.dao_activated(); self.hardforks.insert(EthereumHardfork::Homestead, ForkCondition::Block(0)); self } From f17c70c23056cadd7f42ee7c4502f72078d2a118 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Mon, 11 Aug 2025 10:32:24 -0300 Subject: [PATCH 13/13] not required activation since we build from mainnet Signed-off-by: Ignacio Hagopian --- testing/ef-tests/src/models.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/testing/ef-tests/src/models.rs b/testing/ef-tests/src/models.rs index 81e867b99dd..19a67e94eca 100644 --- a/testing/ef-tests/src/models.rs +++ b/testing/ef-tests/src/models.rs @@ -343,7 +343,6 @@ impl From for ChainSpec { } ForkSpec::Prague => spec_builder.prague_activated(), } - .fill_genesis_config(true) .build(); chain_spec