feat: use SealedHeader in ChainSpec (#14514)

This commit is contained in:
Arsenii Kulikov
2025-02-15 17:30:05 +04:00
committed by GitHub
parent 8123d6bd3b
commit 0f4914a944
18 changed files with 185 additions and 190 deletions

2
Cargo.lock generated
View File

@ -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",

View File

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

View File

@ -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<Arc<ChainSpec>> = 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,
// <https://etherscan.io/block/15537394>
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<Arc<ChainSpec>> = LazyLock::new(|| {
/// The Sepolia spec
pub static SEPOLIA: LazyLock<Arc<ChainSpec>> = 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,
// <https://sepolia.etherscan.io/block/1450409>
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<Arc<ChainSpec>> = LazyLock::new(|| {
/// The Holesky spec
pub static HOLESKY: LazyLock<Arc<ChainSpec>> = 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<Arc<ChainSpec>> = 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<Arc<ChainSpec>> = 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<B256>,
/// 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<Header>,
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<Genesis> 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::<Genesis>(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,

View File

@ -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

View File

@ -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<Arc<OpChainSpec>> = 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()),

View File

@ -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<Arc<OpChainSpec>> = 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()),

View File

@ -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<Arc<OpChainSpec>> = 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()

View File

@ -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,
&[

View File

@ -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<Arc<OpChainSpec>> = 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()),

View File

@ -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<Arc<OpChainSpec>> = 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()),

View File

@ -209,7 +209,7 @@ mod test {
let cmd = NodeCommand::<OpChainSpecParser, NoArgs>::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

View File

@ -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(),

View File

@ -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,

View File

@ -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()

View File

@ -23,4 +23,5 @@ tokio-stream.workspace = true
serde_json.workspace = true
alloy-genesis.workspace = true
alloy-primitives.workspace = true

View File

@ -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<ChainSpec> {
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 <https://github.com/bnb-chain/bsc/blob/master/params/bootnodes.go#L23>

View File

@ -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

View File

@ -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<ChainSpec> {
const GENESIS: B256 = b256!("a9c28ce2141b56c474f1dc504bee9b01eb1bd7d1a507580d5519d4437a97de1b");
ChainSpec {
chain: Chain::from_id(137),
// <https://github.com/maticnetwork/bor/blob/d521b8e266b97efe9c8fdce8167e9dd77b04637d/builder/files/genesis-mainnet-v1.json>
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 <https://github.com/maticnetwork/bor/blob/master/params/bootnodes.go#L79>