From 0f4914a9446263d3846830026c53cd9bb23d64cb Mon Sep 17 00:00:00 2001 From: Arsenii Kulikov Date: Sat, 15 Feb 2025 17:30:05 +0400 Subject: [PATCH] feat: use `SealedHeader` in `ChainSpec` (#14514) --- Cargo.lock | 2 + crates/chainspec/src/lib.rs | 5 +- crates/chainspec/src/spec.rs | 195 +++++++++--------- crates/ethereum/cli/src/lib.rs | 2 +- crates/optimism/chainspec/src/base.rs | 18 +- crates/optimism/chainspec/src/base_sepolia.rs | 18 +- crates/optimism/chainspec/src/dev.rs | 16 +- crates/optimism/chainspec/src/lib.rs | 8 +- crates/optimism/chainspec/src/op.rs | 22 +- crates/optimism/chainspec/src/op_sepolia.rs | 18 +- crates/optimism/cli/src/lib.rs | 2 +- .../optimism/consensus/src/validation/mod.rs | 2 +- crates/optimism/node/src/engine.rs | 2 +- crates/storage/db-common/src/init.rs | 1 - examples/bsc-p2p/Cargo.toml | 1 + examples/bsc-p2p/src/chainspec.rs | 29 +-- examples/polygon-p2p/Cargo.toml | 1 + examples/polygon-p2p/src/chain_cfg.rs | 33 +-- 18 files changed, 185 insertions(+), 190 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index be47e4b66..b4366f188 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2983,6 +2983,7 @@ dependencies = [ name = "example-bsc-p2p" version = "0.0.0" dependencies = [ + "alloy-genesis", "alloy-primitives", "reth-chainspec", "reth-discv4", @@ -3224,6 +3225,7 @@ dependencies = [ name = "example-polygon-p2p" version = "0.0.0" dependencies = [ + "alloy-genesis", "alloy-primitives", "reth-chainspec", "reth-discv4", diff --git a/crates/chainspec/src/lib.rs b/crates/chainspec/src/lib.rs index bd235b3f9..aa70706de 100644 --- a/crates/chainspec/src/lib.rs +++ b/crates/chainspec/src/lib.rs @@ -30,8 +30,9 @@ pub use info::ChainInfo; #[cfg(any(test, feature = "test-utils"))] pub use spec::test_fork_ids; pub use spec::{ - BaseFeeParams, BaseFeeParamsKind, ChainSpec, ChainSpecBuilder, ChainSpecProvider, - DepositContract, ForkBaseFeeParams, HardforkBlobParams, DEV, HOLESKY, MAINNET, SEPOLIA, + make_genesis_header, BaseFeeParams, BaseFeeParamsKind, ChainSpec, ChainSpecBuilder, + ChainSpecProvider, DepositContract, ForkBaseFeeParams, HardforkBlobParams, DEV, HOLESKY, + MAINNET, SEPOLIA, }; use reth_primitives_traits::sync::OnceLock; diff --git a/crates/chainspec/src/spec.rs b/crates/chainspec/src/spec.rs index 14019e1f7..7223d93b2 100644 --- a/crates/chainspec/src/spec.rs +++ b/crates/chainspec/src/spec.rs @@ -1,6 +1,6 @@ pub use alloy_eips::eip1559::BaseFeeParams; -use crate::{constants::MAINNET_DEPOSIT_CONTRACT, once_cell_set, EthChainSpec}; +use crate::{constants::MAINNET_DEPOSIT_CONTRACT, EthChainSpec}; use alloc::{boxed::Box, collections::BTreeMap, string::String, sync::Arc, vec::Vec}; use alloy_chains::{Chain, NamedChain}; use alloy_consensus::{ @@ -26,25 +26,79 @@ use reth_network_peers::{ base_nodes, base_testnet_nodes, holesky_nodes, mainnet_nodes, op_nodes, op_testnet_nodes, sepolia_nodes, NodeRecord, }; -use reth_primitives_traits::{ - sync::{LazyLock, OnceLock}, - SealedHeader, -}; +use reth_primitives_traits::{sync::LazyLock, SealedHeader}; + +/// Helper method building a [`Header`] given [`Genesis`] and [`ChainHardforks`]. +pub fn make_genesis_header(genesis: &Genesis, hardforks: &ChainHardforks) -> Header { + // If London is activated at genesis, we set the initial base fee as per EIP-1559. + let base_fee_per_gas = hardforks + .fork(EthereumHardfork::London) + .active_at_block(0) + .then(|| genesis.base_fee_per_gas.map(|fee| fee as u64).unwrap_or(INITIAL_BASE_FEE)); + + // If shanghai is activated, initialize the header with an empty withdrawals hash, and + // empty withdrawals list. + let withdrawals_root = hardforks + .fork(EthereumHardfork::Shanghai) + .active_at_timestamp(genesis.timestamp) + .then_some(EMPTY_WITHDRAWALS); + + // If Cancun is activated at genesis, we set: + // * parent beacon block root to 0x0 + // * blob gas used to provided genesis or 0x0 + // * excess blob gas to provided genesis or 0x0 + let (parent_beacon_block_root, blob_gas_used, excess_blob_gas) = + if hardforks.fork(EthereumHardfork::Cancun).active_at_timestamp(genesis.timestamp) { + let blob_gas_used = genesis.blob_gas_used.unwrap_or(0); + let excess_blob_gas = genesis.excess_blob_gas.unwrap_or(0); + (Some(B256::ZERO), Some(blob_gas_used), Some(excess_blob_gas)) + } else { + (None, None, None) + }; + + // If Prague is activated at genesis we set requests root to an empty trie root. + let requests_hash = hardforks + .fork(EthereumHardfork::Prague) + .active_at_timestamp(genesis.timestamp) + .then_some(EMPTY_REQUESTS_HASH); + + Header { + gas_limit: genesis.gas_limit, + difficulty: genesis.difficulty, + nonce: genesis.nonce.into(), + extra_data: genesis.extra_data.clone(), + state_root: state_root_ref_unhashed(&genesis.alloc), + timestamp: genesis.timestamp, + mix_hash: genesis.mix_hash, + beneficiary: genesis.coinbase, + base_fee_per_gas, + withdrawals_root, + parent_beacon_block_root, + blob_gas_used, + excess_blob_gas, + requests_hash, + ..Default::default() + } +} /// The Ethereum mainnet spec pub static MAINNET: LazyLock> = LazyLock::new(|| { + let genesis = serde_json::from_str(include_str!("../res/genesis/mainnet.json")) + .expect("Can't deserialize Mainnet genesis json"); + let hardforks = EthereumHardfork::mainnet().into(); let mut spec = ChainSpec { chain: Chain::mainnet(), - genesis: serde_json::from_str(include_str!("../res/genesis/mainnet.json")) - .expect("Can't deserialize Mainnet genesis json"), - genesis_hash: once_cell_set(MAINNET_GENESIS_HASH), - genesis_header: Default::default(), + genesis_header: SealedHeader::new( + make_genesis_header(&genesis, &hardforks), + MAINNET_GENESIS_HASH, + ), + genesis, // paris_block_and_final_difficulty: Some(( 15537394, U256::from(58_750_003_716_598_352_816_469u128), )), - hardforks: EthereumHardfork::mainnet().into(), + hardforks, // https://etherscan.io/tx/0xe75fb554e433e03763a1560646ee22dcb74e5274b34c5ad644e7c0f619a7e1d0 deposit_contract: Some(DepositContract::new( MAINNET_DEPOSIT_CONTRACT_ADDRESS, @@ -61,15 +115,19 @@ pub static MAINNET: LazyLock> = LazyLock::new(|| { /// The Sepolia spec pub static SEPOLIA: LazyLock> = LazyLock::new(|| { + let genesis = serde_json::from_str(include_str!("../res/genesis/sepolia.json")) + .expect("Can't deserialize Sepolia genesis json"); + let hardforks = EthereumHardfork::sepolia().into(); let mut spec = ChainSpec { chain: Chain::sepolia(), - genesis: serde_json::from_str(include_str!("../res/genesis/sepolia.json")) - .expect("Can't deserialize Sepolia genesis json"), - genesis_hash: once_cell_set(SEPOLIA_GENESIS_HASH), - genesis_header: Default::default(), + genesis_header: SealedHeader::new( + make_genesis_header(&genesis, &hardforks), + SEPOLIA_GENESIS_HASH, + ), + genesis, // paris_block_and_final_difficulty: Some((1450409, U256::from(17_000_018_015_853_232u128))), - hardforks: EthereumHardfork::sepolia().into(), + hardforks, // https://sepolia.etherscan.io/tx/0x025ecbf81a2f1220da6285d1701dc89fb5a956b62562ee922e1a9efd73eb4b14 deposit_contract: Some(DepositContract::new( address!("7f02c3e3c98b133055b8b348b2ac625669ed295d"), @@ -86,14 +144,18 @@ pub static SEPOLIA: LazyLock> = LazyLock::new(|| { /// The Holesky spec pub static HOLESKY: LazyLock> = LazyLock::new(|| { + let genesis = serde_json::from_str(include_str!("../res/genesis/holesky.json")) + .expect("Can't deserialize Holesky genesis json"); + let hardforks = EthereumHardfork::holesky().into(); let mut spec = ChainSpec { chain: Chain::holesky(), - genesis: serde_json::from_str(include_str!("../res/genesis/holesky.json")) - .expect("Can't deserialize Holesky genesis json"), - genesis_hash: once_cell_set(HOLESKY_GENESIS_HASH), - genesis_header: Default::default(), + genesis_header: SealedHeader::new( + make_genesis_header(&genesis, &hardforks), + HOLESKY_GENESIS_HASH, + ), + genesis, paris_block_and_final_difficulty: Some((0, U256::from(1))), - hardforks: EthereumHardfork::holesky().into(), + hardforks, deposit_contract: Some(DepositContract::new( address!("4242424242424242424242424242424242424242"), 0, @@ -112,11 +174,16 @@ pub static HOLESKY: LazyLock> = LazyLock::new(|| { /// Includes 20 prefunded accounts with `10_000` ETH each derived from mnemonic "test test test test /// test test test test test test test junk". pub static DEV: LazyLock> = LazyLock::new(|| { + let genesis = serde_json::from_str(include_str!("../res/genesis/dev.json")) + .expect("Can't deserialize Dev testnet genesis json"); + let hardforks = DEV_HARDFORKS.clone(); ChainSpec { chain: Chain::dev(), - genesis: serde_json::from_str(include_str!("../res/genesis/dev.json")) - .expect("Can't deserialize Dev testnet genesis json"), - genesis_hash: once_cell_set(DEV_GENESIS_HASH), + genesis_header: SealedHeader::new( + make_genesis_header(&genesis, &hardforks), + DEV_GENESIS_HASH, + ), + genesis, paris_block_and_final_difficulty: Some((0, U256::from(0))), hardforks: DEV_HARDFORKS.clone(), base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()), @@ -220,17 +287,8 @@ pub struct ChainSpec { /// The genesis block. pub genesis: Genesis, - /// The hash of the genesis block. - /// - /// This is either stored at construction time if it is known using [`once_cell_set`], or - /// computed once on the first access. - pub genesis_hash: OnceLock, - /// The header corresponding to the genesis block. - /// - /// This is either stored at construction time if it is known using [`once_cell_set`], or - /// computed once on the first access. - pub genesis_header: OnceLock
, + pub genesis_header: SealedHeader, /// The block at which [`EthereumHardfork::Paris`] was activated and the final difficulty at /// this block. @@ -256,7 +314,6 @@ impl Default for ChainSpec { fn default() -> Self { Self { chain: Default::default(), - genesis_hash: Default::default(), genesis: Default::default(), genesis_header: Default::default(), paris_block_and_final_difficulty: Default::default(), @@ -307,55 +364,7 @@ impl ChainSpec { /// Get the header for the genesis block. pub fn genesis_header(&self) -> &Header { - self.genesis_header.get_or_init(|| self.make_genesis_header()) - } - - fn make_genesis_header(&self) -> Header { - // If London is activated at genesis, we set the initial base fee as per EIP-1559. - let base_fee_per_gas = self.initial_base_fee(); - - // If shanghai is activated, initialize the header with an empty withdrawals hash, and - // empty withdrawals list. - let withdrawals_root = self - .fork(EthereumHardfork::Shanghai) - .active_at_timestamp(self.genesis.timestamp) - .then_some(EMPTY_WITHDRAWALS); - - // If Cancun is activated at genesis, we set: - // * parent beacon block root to 0x0 - // * blob gas used to provided genesis or 0x0 - // * excess blob gas to provided genesis or 0x0 - let (parent_beacon_block_root, blob_gas_used, excess_blob_gas) = - if self.is_cancun_active_at_timestamp(self.genesis.timestamp) { - let blob_gas_used = self.genesis.blob_gas_used.unwrap_or(0); - let excess_blob_gas = self.genesis.excess_blob_gas.unwrap_or(0); - (Some(B256::ZERO), Some(blob_gas_used), Some(excess_blob_gas)) - } else { - (None, None, None) - }; - - // If Prague is activated at genesis we set requests root to an empty trie root. - let requests_hash = self - .is_prague_active_at_timestamp(self.genesis.timestamp) - .then_some(EMPTY_REQUESTS_HASH); - - Header { - gas_limit: self.genesis.gas_limit, - difficulty: self.genesis.difficulty, - nonce: self.genesis.nonce.into(), - extra_data: self.genesis.extra_data.clone(), - state_root: state_root_ref_unhashed(&self.genesis.alloc), - timestamp: self.genesis.timestamp, - mix_hash: self.genesis.mix_hash, - beneficiary: self.genesis.coinbase, - base_fee_per_gas, - withdrawals_root, - parent_beacon_block_root, - blob_gas_used, - excess_blob_gas, - requests_hash, - ..Default::default() - } + &self.genesis_header } /// Get the sealed header for the genesis block. @@ -413,7 +422,7 @@ impl ChainSpec { /// Get the hash of the genesis block. pub fn genesis_hash(&self) -> B256 { - *self.genesis_hash.get_or_init(|| self.genesis_header().hash_slow()) + self.genesis_header.hash() } /// Get the timestamp of the genesis block. @@ -728,11 +737,13 @@ impl From for ChainSpec { DepositContract { address, block: 0, topic: MAINNET_DEPOSIT_CONTRACT.topic } }); + let hardforks = ChainHardforks::new(ordered_hardforks); + Self { chain: genesis.config.chain_id.into(), + genesis_header: SealedHeader::new_unhashed(make_genesis_header(&genesis, &hardforks)), genesis, - genesis_hash: OnceLock::new(), - hardforks: ChainHardforks::new(ordered_hardforks), + hardforks, paris_block_and_final_difficulty, deposit_contract, blob_params, @@ -974,10 +985,14 @@ impl ChainSpecBuilder { } }) }; + let genesis = self.genesis.expect("The genesis is required"); ChainSpec { chain: self.chain.expect("The chain is required"), - genesis: self.genesis.expect("The genesis is required"), - genesis_hash: OnceLock::new(), + genesis_header: SealedHeader::new_unhashed(make_genesis_header( + &genesis, + &self.hardforks, + )), + genesis, hardforks: self.hardforks, paris_block_and_final_difficulty, deposit_contract: None, @@ -1930,7 +1945,6 @@ Post-merge hard forks (timestamp based): assert_eq!(&alloy_rlp::encode(TrieAccount::from(account.clone())), expected_rlp); } - assert_eq!(chainspec.genesis_hash.get(), None); let expected_state_root: B256 = hex!("078dc6061b1d8eaa8493384b59c9c65ceb917201221d08b80c4de6770b6ec7e7").into(); assert_eq!(chainspec.genesis_header().state_root, expected_state_root); @@ -2003,7 +2017,6 @@ Post-merge hard forks (timestamp based): let genesis = serde_json::from_str::(hive_json).unwrap(); let chainspec: ChainSpec = genesis.into(); - assert_eq!(chainspec.genesis_hash.get(), None); assert_eq!(chainspec.chain, Chain::from_named(NamedChain::Optimism)); let expected_state_root: B256 = hex!("9a6049ac535e3dc7436c189eaa81c73f35abd7f282ab67c32944ff0301d63360").into(); @@ -2318,7 +2331,6 @@ Post-merge hard forks (timestamp based): let spec = ChainSpec { chain: Chain::mainnet(), genesis: Genesis::default(), - genesis_hash: OnceLock::new(), hardforks: ChainHardforks::new(vec![( EthereumHardfork::Frontier.boxed(), ForkCondition::Never, @@ -2336,7 +2348,6 @@ Post-merge hard forks (timestamp based): let spec = ChainSpec { chain: Chain::mainnet(), genesis: Genesis::default(), - genesis_hash: OnceLock::new(), hardforks: ChainHardforks::new(vec![( EthereumHardfork::Shanghai.boxed(), ForkCondition::Never, diff --git a/crates/ethereum/cli/src/lib.rs b/crates/ethereum/cli/src/lib.rs index 48d4b938e..7296e7c2d 100644 --- a/crates/ethereum/cli/src/lib.rs +++ b/crates/ethereum/cli/src/lib.rs @@ -23,7 +23,7 @@ mod test { let cmd: NodeCommand = NodeCommand::parse_from(["reth", "--dev"]); let chain = DEV.clone(); assert_eq!(cmd.chain.chain, chain.chain); - assert_eq!(cmd.chain.genesis_hash, chain.genesis_hash); + assert_eq!(cmd.chain.genesis_hash(), chain.genesis_hash()); assert_eq!( cmd.chain.paris_block_and_final_difficulty, chain.paris_block_and_final_difficulty diff --git a/crates/optimism/chainspec/src/base.rs b/crates/optimism/chainspec/src/base.rs index 8282c58f6..a6d302b50 100644 --- a/crates/optimism/chainspec/src/base.rs +++ b/crates/optimism/chainspec/src/base.rs @@ -4,24 +4,28 @@ use alloc::{sync::Arc, vec}; use alloy_chains::Chain; use alloy_primitives::{b256, U256}; -use reth_chainspec::{once_cell_set, BaseFeeParams, BaseFeeParamsKind, ChainSpec}; +use reth_chainspec::{make_genesis_header, BaseFeeParams, BaseFeeParamsKind, ChainSpec}; use reth_ethereum_forks::{EthereumHardfork, Hardfork}; use reth_optimism_forks::OpHardfork; +use reth_primitives_traits::SealedHeader; use crate::{LazyLock, OpChainSpec}; /// The Base mainnet spec pub static BASE_MAINNET: LazyLock> = LazyLock::new(|| { + let genesis = serde_json::from_str(include_str!("../res/genesis/base.json")) + .expect("Can't deserialize Base genesis json"); + let hardforks = OpHardfork::base_mainnet(); OpChainSpec { inner: ChainSpec { chain: Chain::base_mainnet(), - genesis: serde_json::from_str(include_str!("../res/genesis/base.json")) - .expect("Can't deserialize Base genesis json"), - genesis_hash: once_cell_set(b256!( - "f712aa9241cc24369b143cf6dce85f0902a9731e70d66818a3a5845b296c73dd" - )), + genesis_header: SealedHeader::new( + make_genesis_header(&genesis, &hardforks), + b256!("f712aa9241cc24369b143cf6dce85f0902a9731e70d66818a3a5845b296c73dd"), + ), + genesis, paris_block_and_final_difficulty: Some((0, U256::from(0))), - hardforks: OpHardfork::base_mainnet(), + hardforks, base_fee_params: BaseFeeParamsKind::Variable( vec![ (EthereumHardfork::London.boxed(), BaseFeeParams::optimism()), diff --git a/crates/optimism/chainspec/src/base_sepolia.rs b/crates/optimism/chainspec/src/base_sepolia.rs index 2b5434754..ef412f109 100644 --- a/crates/optimism/chainspec/src/base_sepolia.rs +++ b/crates/optimism/chainspec/src/base_sepolia.rs @@ -4,24 +4,28 @@ use alloc::{sync::Arc, vec}; use alloy_chains::Chain; use alloy_primitives::{b256, U256}; -use reth_chainspec::{once_cell_set, BaseFeeParams, BaseFeeParamsKind, ChainSpec, Hardfork}; +use reth_chainspec::{make_genesis_header, BaseFeeParams, BaseFeeParamsKind, ChainSpec, Hardfork}; use reth_ethereum_forks::EthereumHardfork; use reth_optimism_forks::OpHardfork; +use reth_primitives_traits::SealedHeader; use crate::{LazyLock, OpChainSpec}; /// The Base Sepolia spec pub static BASE_SEPOLIA: LazyLock> = LazyLock::new(|| { + let genesis = serde_json::from_str(include_str!("../res/genesis/sepolia_base.json")) + .expect("Can't deserialize Base Sepolia genesis json"); + let hardforks = OpHardfork::base_sepolia(); OpChainSpec { inner: ChainSpec { chain: Chain::base_sepolia(), - genesis: serde_json::from_str(include_str!("../res/genesis/sepolia_base.json")) - .expect("Can't deserialize Base Sepolia genesis json"), - genesis_hash: once_cell_set(b256!( - "0dcc9e089e30b90ddfc55be9a37dd15bc551aeee999d2e2b51414c54eaf934e4" - )), + genesis_header: SealedHeader::new( + make_genesis_header(&genesis, &hardforks), + b256!("0dcc9e089e30b90ddfc55be9a37dd15bc551aeee999d2e2b51414c54eaf934e4"), + ), + genesis, paris_block_and_final_difficulty: Some((0, U256::from(0))), - hardforks: OpHardfork::base_sepolia(), + hardforks, base_fee_params: BaseFeeParamsKind::Variable( vec![ (EthereumHardfork::London.boxed(), BaseFeeParams::base_sepolia()), diff --git a/crates/optimism/chainspec/src/dev.rs b/crates/optimism/chainspec/src/dev.rs index eae25f73e..f7614a8bc 100644 --- a/crates/optimism/chainspec/src/dev.rs +++ b/crates/optimism/chainspec/src/dev.rs @@ -5,8 +5,9 @@ use alloc::sync::Arc; use alloy_chains::Chain; use alloy_consensus::constants::DEV_GENESIS_HASH; use alloy_primitives::U256; -use reth_chainspec::{once_cell_set, BaseFeeParams, BaseFeeParamsKind, ChainSpec}; +use reth_chainspec::{make_genesis_header, BaseFeeParams, BaseFeeParamsKind, ChainSpec}; use reth_optimism_forks::DEV_HARDFORKS; +use reth_primitives_traits::SealedHeader; use crate::{LazyLock, OpChainSpec}; @@ -15,14 +16,19 @@ use crate::{LazyLock, OpChainSpec}; /// Includes 20 prefunded accounts with `10_000` ETH each derived from mnemonic "test test test test /// test test test test test test test junk". pub static OP_DEV: LazyLock> = LazyLock::new(|| { + let genesis = serde_json::from_str(include_str!("../res/genesis/dev.json")) + .expect("Can't deserialize Dev testnet genesis json"); + let hardforks = DEV_HARDFORKS.clone(); OpChainSpec { inner: ChainSpec { chain: Chain::dev(), - genesis: serde_json::from_str(include_str!("../res/genesis/dev.json")) - .expect("Can't deserialize Dev testnet genesis json"), - genesis_hash: once_cell_set(DEV_GENESIS_HASH), + genesis_header: SealedHeader::new( + make_genesis_header(&genesis, &hardforks), + DEV_GENESIS_HASH, + ), + genesis, paris_block_and_final_difficulty: Some((0, U256::from(0))), - hardforks: DEV_HARDFORKS.clone(), + hardforks, base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()), deposit_contract: None, // TODO: do we even have? ..Default::default() diff --git a/crates/optimism/chainspec/src/lib.rs b/crates/optimism/chainspec/src/lib.rs index 3387d06c2..2629119b1 100644 --- a/crates/optimism/chainspec/src/lib.rs +++ b/crates/optimism/chainspec/src/lib.rs @@ -443,8 +443,8 @@ mod tests { #[test] fn base_mainnet_forkids() { - let base_mainnet = OpChainSpecBuilder::base_mainnet().build(); - let _ = base_mainnet.genesis_hash.set(BASE_MAINNET.genesis_hash.get().copied().unwrap()); + let mut base_mainnet = OpChainSpecBuilder::base_mainnet().build(); + base_mainnet.inner.genesis_header.set_hash(BASE_MAINNET.genesis_hash()); test_fork_ids( &BASE_MAINNET, &[ @@ -539,10 +539,10 @@ mod tests { #[test] fn op_mainnet_forkids() { - let op_mainnet = OpChainSpecBuilder::optimism_mainnet().build(); + let mut op_mainnet = OpChainSpecBuilder::optimism_mainnet().build(); // for OP mainnet we have to do this because the genesis header can't be properly computed // from the genesis.json file - let _ = op_mainnet.genesis_hash.set(OP_MAINNET.genesis_hash()); + op_mainnet.inner.genesis_header.set_hash(OP_MAINNET.genesis_hash()); test_fork_ids( &op_mainnet, &[ diff --git a/crates/optimism/chainspec/src/op.rs b/crates/optimism/chainspec/src/op.rs index 9b2c98e61..2d6777d27 100644 --- a/crates/optimism/chainspec/src/op.rs +++ b/crates/optimism/chainspec/src/op.rs @@ -4,24 +4,28 @@ use crate::{LazyLock, OpChainSpec}; use alloc::{sync::Arc, vec}; use alloy_chains::Chain; use alloy_primitives::{b256, U256}; -use reth_chainspec::{once_cell_set, BaseFeeParams, BaseFeeParamsKind, ChainSpec, Hardfork}; +use reth_chainspec::{make_genesis_header, BaseFeeParams, BaseFeeParamsKind, ChainSpec, Hardfork}; use reth_ethereum_forks::EthereumHardfork; use reth_optimism_forks::OpHardfork; +use reth_primitives_traits::SealedHeader; /// The Optimism Mainnet spec pub static OP_MAINNET: LazyLock> = LazyLock::new(|| { + // genesis contains empty alloc field because state at first bedrock block is imported + // manually from trusted source + let genesis = serde_json::from_str(include_str!("../res/genesis/optimism.json")) + .expect("Can't deserialize Optimism Mainnet genesis json"); + let hardforks = OpHardfork::op_mainnet(); OpChainSpec { inner: ChainSpec { chain: Chain::optimism_mainnet(), - // genesis contains empty alloc field because state at first bedrock block is imported - // manually from trusted source - genesis: serde_json::from_str(include_str!("../res/genesis/optimism.json")) - .expect("Can't deserialize Optimism Mainnet genesis json"), - genesis_hash: once_cell_set(b256!( - "7ca38a1916c42007829c55e69d3e9a73265554b586a499015373241b8a3fa48b" - )), + genesis_header: SealedHeader::new( + make_genesis_header(&genesis, &hardforks), + b256!("7ca38a1916c42007829c55e69d3e9a73265554b586a499015373241b8a3fa48b"), + ), + genesis, paris_block_and_final_difficulty: Some((0, U256::from(0))), - hardforks: OpHardfork::op_mainnet(), + hardforks, base_fee_params: BaseFeeParamsKind::Variable( vec![ (EthereumHardfork::London.boxed(), BaseFeeParams::optimism()), diff --git a/crates/optimism/chainspec/src/op_sepolia.rs b/crates/optimism/chainspec/src/op_sepolia.rs index 99702e6a1..2c963d360 100644 --- a/crates/optimism/chainspec/src/op_sepolia.rs +++ b/crates/optimism/chainspec/src/op_sepolia.rs @@ -4,22 +4,26 @@ use crate::{LazyLock, OpChainSpec}; use alloc::{sync::Arc, vec}; use alloy_chains::{Chain, NamedChain}; use alloy_primitives::{b256, U256}; -use reth_chainspec::{once_cell_set, BaseFeeParams, BaseFeeParamsKind, ChainSpec, Hardfork}; +use reth_chainspec::{make_genesis_header, BaseFeeParams, BaseFeeParamsKind, ChainSpec, Hardfork}; use reth_ethereum_forks::EthereumHardfork; use reth_optimism_forks::OpHardfork; +use reth_primitives_traits::SealedHeader; /// The OP Sepolia spec pub static OP_SEPOLIA: LazyLock> = LazyLock::new(|| { + let genesis = serde_json::from_str(include_str!("../res/genesis/sepolia_op.json")) + .expect("Can't deserialize OP Sepolia genesis json"); + let hardforks = OpHardfork::op_sepolia(); OpChainSpec { inner: ChainSpec { chain: Chain::from_named(NamedChain::OptimismSepolia), - genesis: serde_json::from_str(include_str!("../res/genesis/sepolia_op.json")) - .expect("Can't deserialize OP Sepolia genesis json"), - genesis_hash: once_cell_set(b256!( - "102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d" - )), + genesis_header: SealedHeader::new( + make_genesis_header(&genesis, &hardforks), + b256!("102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d"), + ), + genesis, paris_block_and_final_difficulty: Some((0, U256::from(0))), - hardforks: OpHardfork::op_sepolia(), + hardforks, base_fee_params: BaseFeeParamsKind::Variable( vec![ (EthereumHardfork::London.boxed(), BaseFeeParams::optimism_sepolia()), diff --git a/crates/optimism/cli/src/lib.rs b/crates/optimism/cli/src/lib.rs index 21fb46b78..76c4d9a74 100644 --- a/crates/optimism/cli/src/lib.rs +++ b/crates/optimism/cli/src/lib.rs @@ -209,7 +209,7 @@ mod test { let cmd = NodeCommand::::parse_from(["op-reth", "--dev"]); let chain = OP_DEV.clone(); assert_eq!(cmd.chain.chain, chain.chain); - assert_eq!(cmd.chain.genesis_hash, chain.genesis_hash); + assert_eq!(cmd.chain.genesis_hash(), chain.genesis_hash()); assert_eq!( cmd.chain.paris_block_and_final_difficulty, chain.paris_block_and_final_difficulty diff --git a/crates/optimism/consensus/src/validation/mod.rs b/crates/optimism/consensus/src/validation/mod.rs index ccbe5ebc0..16f10a92b 100644 --- a/crates/optimism/consensus/src/validation/mod.rs +++ b/crates/optimism/consensus/src/validation/mod.rs @@ -160,7 +160,7 @@ mod tests { inner: ChainSpec { chain: BASE_SEPOLIA.inner.chain, genesis: BASE_SEPOLIA.inner.genesis.clone(), - genesis_hash: BASE_SEPOLIA.inner.genesis_hash.clone(), + genesis_header: BASE_SEPOLIA.inner.genesis_header.clone(), paris_block_and_final_difficulty: Some((0, U256::from(0))), hardforks, base_fee_params: BASE_SEPOLIA.inner.base_fee_params.clone(), diff --git a/crates/optimism/node/src/engine.rs b/crates/optimism/node/src/engine.rs index bfa2d86d8..e7cff087d 100644 --- a/crates/optimism/node/src/engine.rs +++ b/crates/optimism/node/src/engine.rs @@ -232,7 +232,7 @@ mod test { inner: ChainSpec { chain: BASE_SEPOLIA.inner.chain, genesis: BASE_SEPOLIA.inner.genesis.clone(), - genesis_hash: BASE_SEPOLIA.inner.genesis_hash.clone(), + genesis_header: BASE_SEPOLIA.inner.genesis_header.clone(), paris_block_and_final_difficulty: BASE_SEPOLIA .inner .paris_block_and_final_difficulty, diff --git a/crates/storage/db-common/src/init.rs b/crates/storage/db-common/src/init.rs index 605a36d25..1771527a7 100644 --- a/crates/storage/db-common/src/init.rs +++ b/crates/storage/db-common/src/init.rs @@ -724,7 +724,6 @@ mod tests { ..Default::default() }, hardforks: Default::default(), - genesis_hash: Default::default(), paris_block_and_final_difficulty: None, deposit_contract: None, ..Default::default() diff --git a/examples/bsc-p2p/Cargo.toml b/examples/bsc-p2p/Cargo.toml index 1a3093394..0bdee25a6 100644 --- a/examples/bsc-p2p/Cargo.toml +++ b/examples/bsc-p2p/Cargo.toml @@ -23,4 +23,5 @@ tokio-stream.workspace = true serde_json.workspace = true +alloy-genesis.workspace = true alloy-primitives.workspace = true diff --git a/examples/bsc-p2p/src/chainspec.rs b/examples/bsc-p2p/src/chainspec.rs index 106d96b56..715f69b36 100644 --- a/examples/bsc-p2p/src/chainspec.rs +++ b/examples/bsc-p2p/src/chainspec.rs @@ -1,33 +1,14 @@ -use alloy_primitives::{b256, B256}; -use reth_chainspec::{ - once_cell_set, BaseFeeParams, Chain, ChainHardforks, ChainSpec, EthereumHardfork, - ForkCondition, Hardfork, -}; +use alloy_genesis::Genesis; +use reth_chainspec::ChainSpec; use reth_network_peers::NodeRecord; - use std::sync::Arc; pub const SHANGHAI_TIME: u64 = 1705996800; pub(crate) fn bsc_chain_spec() -> Arc { - const GENESIS: B256 = b256!("0d21840abff46b96c84b2ac9e10e4f5cdaeb5693cb665db62a2f3b02d2d57b5b"); - - ChainSpec { - chain: Chain::from_id(56), - genesis: serde_json::from_str(include_str!("./genesis.json")).expect("deserialize genesis"), - genesis_hash: once_cell_set(GENESIS), - genesis_header: Default::default(), - paris_block_and_final_difficulty: None, - hardforks: ChainHardforks::new(vec![( - EthereumHardfork::Shanghai.boxed(), - ForkCondition::Timestamp(SHANGHAI_TIME), - )]), - deposit_contract: None, - base_fee_params: reth_chainspec::BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()), - prune_delete_limit: 0, - blob_params: Default::default(), - } - .into() + let genesis: Genesis = + serde_json::from_str(include_str!("./genesis.json")).expect("deserialize genesis"); + Arc::new(genesis.into()) } /// BSC mainnet bootnodes diff --git a/examples/polygon-p2p/Cargo.toml b/examples/polygon-p2p/Cargo.toml index b351da47d..5daa8149b 100644 --- a/examples/polygon-p2p/Cargo.toml +++ b/examples/polygon-p2p/Cargo.toml @@ -19,3 +19,4 @@ reth-tracing.workspace = true tokio-stream.workspace = true reth-discv4 = { workspace = true, features = ["test-utils"] } alloy-primitives.workspace = true +alloy-genesis.workspace = true diff --git a/examples/polygon-p2p/src/chain_cfg.rs b/examples/polygon-p2p/src/chain_cfg.rs index ea4a45a5d..fc0acb04e 100644 --- a/examples/polygon-p2p/src/chain_cfg.rs +++ b/examples/polygon-p2p/src/chain_cfg.rs @@ -1,8 +1,5 @@ -use alloy_primitives::{b256, B256}; -use reth_chainspec::{ - once_cell_set, BaseFeeParams, Chain, ChainHardforks, ChainSpec, EthereumHardfork, - ForkCondition, Hardfork, -}; +use alloy_genesis::Genesis; +use reth_chainspec::ChainSpec; use reth_discv4::NodeRecord; use reth_primitives::Head; @@ -11,29 +8,9 @@ use std::sync::Arc; const SHANGHAI_BLOCK: u64 = 50523000; pub(crate) fn polygon_chain_spec() -> Arc { - const GENESIS: B256 = b256!("a9c28ce2141b56c474f1dc504bee9b01eb1bd7d1a507580d5519d4437a97de1b"); - - ChainSpec { - chain: Chain::from_id(137), - // - genesis: serde_json::from_str(include_str!("./genesis.json")).expect("deserialize genesis"), - genesis_hash: once_cell_set(GENESIS), - genesis_header: Default::default(), - paris_block_and_final_difficulty: None, - hardforks: ChainHardforks::new(vec![ - (EthereumHardfork::Petersburg.boxed(), ForkCondition::Block(0)), - (EthereumHardfork::Istanbul.boxed(), ForkCondition::Block(3395000)), - (EthereumHardfork::MuirGlacier.boxed(), ForkCondition::Block(3395000)), - (EthereumHardfork::Berlin.boxed(), ForkCondition::Block(14750000)), - (EthereumHardfork::London.boxed(), ForkCondition::Block(23850000)), - (EthereumHardfork::Shanghai.boxed(), ForkCondition::Block(SHANGHAI_BLOCK)), - ]), - deposit_contract: None, - base_fee_params: reth_chainspec::BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()), - prune_delete_limit: 0, - blob_params: Default::default(), - } - .into() + let genesis: Genesis = + serde_json::from_str(include_str!("./genesis.json")).expect("deserialize genesis"); + Arc::new(genesis.into()) } /// Polygon mainnet boot nodes