chore: update genesis to chain spec conversion (#10764)

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
greged93
2024-09-14 11:36:30 +02:00
committed by GitHub
parent bff991dd0a
commit 646b72f342

View File

@ -6,8 +6,6 @@ use alloy_primitives::{address, b256, Address, BlockNumber, B256, U256};
use alloy_trie::EMPTY_ROOT_HASH;
use derive_more::From;
use once_cell::sync::{Lazy, OnceCell};
#[cfg(feature = "optimism")]
use reth_ethereum_forks::OptimismHardfork;
use reth_ethereum_forks::{
ChainHardforks, DisplayHardforks, EthereumHardfork, EthereumHardforks, ForkCondition,
ForkFilter, ForkFilterKey, ForkHash, ForkId, Hardfork, Head, DEV_HARDFORKS,
@ -256,7 +254,8 @@ impl ChainSpec {
#[inline]
#[cfg(feature = "optimism")]
pub fn is_optimism(&self) -> bool {
self.chain.is_optimism() || self.hardforks.get(OptimismHardfork::Bedrock).is_some()
self.chain.is_optimism() ||
self.hardforks.get(reth_ethereum_forks::OptimismHardfork::Bedrock).is_some()
}
/// Returns `true` if this chain contains Optimism configuration.
@ -605,119 +604,206 @@ impl ChainSpec {
impl From<Genesis> for ChainSpec {
fn from(genesis: Genesis) -> Self {
#[cfg(feature = "optimism")]
let optimism_genesis_info = OptimismGenesisInfo::extract_from(&genesis);
#[cfg(feature = "optimism")]
let genesis_info =
optimism_genesis_info.optimism_chain_info.genesis_info.unwrap_or_default();
// Block-based hardforks
let hardfork_opts = [
(EthereumHardfork::Homestead.boxed(), genesis.config.homestead_block),
(EthereumHardfork::Dao.boxed(), genesis.config.dao_fork_block),
(EthereumHardfork::Tangerine.boxed(), genesis.config.eip150_block),
(EthereumHardfork::SpuriousDragon.boxed(), genesis.config.eip155_block),
(EthereumHardfork::Byzantium.boxed(), genesis.config.byzantium_block),
(EthereumHardfork::Constantinople.boxed(), genesis.config.constantinople_block),
(EthereumHardfork::Petersburg.boxed(), genesis.config.petersburg_block),
(EthereumHardfork::Istanbul.boxed(), genesis.config.istanbul_block),
(EthereumHardfork::MuirGlacier.boxed(), genesis.config.muir_glacier_block),
(EthereumHardfork::Berlin.boxed(), genesis.config.berlin_block),
(EthereumHardfork::London.boxed(), genesis.config.london_block),
(EthereumHardfork::ArrowGlacier.boxed(), genesis.config.arrow_glacier_block),
(EthereumHardfork::GrayGlacier.boxed(), genesis.config.gray_glacier_block),
#[cfg(feature = "optimism")]
(OptimismHardfork::Bedrock.boxed(), genesis_info.bedrock_block),
];
let mut hardforks = hardfork_opts
.into_iter()
.filter_map(|(hardfork, opt)| opt.map(|block| (hardfork, ForkCondition::Block(block))))
.collect::<Vec<_>>();
// Paris
let paris_block_and_final_difficulty =
if let Some(ttd) = genesis.config.terminal_total_difficulty {
hardforks.push((
EthereumHardfork::Paris.boxed(),
ForkCondition::TTD {
total_difficulty: ttd,
fork_block: genesis.config.merge_netsplit_block,
},
));
genesis.config.merge_netsplit_block.map(|block| (block, ttd))
} else {
None
};
// Time-based hardforks
let time_hardfork_opts = [
(EthereumHardfork::Shanghai.boxed(), genesis.config.shanghai_time),
(EthereumHardfork::Cancun.boxed(), genesis.config.cancun_time),
(EthereumHardfork::Prague.boxed(), genesis.config.prague_time),
#[cfg(feature = "optimism")]
(OptimismHardfork::Regolith.boxed(), genesis_info.regolith_time),
#[cfg(feature = "optimism")]
(OptimismHardfork::Canyon.boxed(), genesis_info.canyon_time),
#[cfg(feature = "optimism")]
(OptimismHardfork::Ecotone.boxed(), genesis_info.ecotone_time),
#[cfg(feature = "optimism")]
(OptimismHardfork::Fjord.boxed(), genesis_info.fjord_time),
#[cfg(feature = "optimism")]
(OptimismHardfork::Granite.boxed(), genesis_info.granite_time),
];
let time_hardforks = time_hardfork_opts
.into_iter()
.filter_map(|(hardfork, opt)| {
opt.map(|time| (hardfork, ForkCondition::Timestamp(time)))
})
.collect::<Vec<_>>();
hardforks.extend(time_hardforks);
// Uses ethereum or optimism main chains to find proper order
#[cfg(not(feature = "optimism"))]
let mainnet_hardforks: ChainHardforks = EthereumHardfork::mainnet().into();
#[cfg(not(feature = "optimism"))]
let mainnet_order = mainnet_hardforks.forks_iter();
#[cfg(feature = "optimism")]
let mainnet_hardforks = OptimismHardfork::op_mainnet();
#[cfg(feature = "optimism")]
let mainnet_order = mainnet_hardforks.forks_iter();
let mut ordered_hardforks = Vec::with_capacity(hardforks.len());
for (hardfork, _) in mainnet_order {
if let Some(pos) = hardforks.iter().position(|(e, _)| **e == *hardfork) {
ordered_hardforks.push(hardforks.remove(pos));
}
{
into_ethereum_chain_spec(genesis)
}
// append the remaining unknown hardforks to ensure we don't filter any out
ordered_hardforks.extend(hardforks);
// NOTE: in full node, we prune all receipts except the deposit contract's. We do not
// have the deployment block in the genesis file, so we use block zero. We use the same
// deposit topic as the mainnet contract if we have the deposit contract address in the
// genesis json.
let deposit_contract = genesis.config.deposit_contract_address.map(|address| {
DepositContract { address, block: 0, topic: MAINNET_DEPOSIT_CONTRACT.topic }
});
Self {
chain: genesis.config.chain_id.into(),
genesis,
genesis_hash: OnceCell::new(),
hardforks: ChainHardforks::new(ordered_hardforks),
paris_block_and_final_difficulty,
deposit_contract,
#[cfg(feature = "optimism")]
base_fee_params: optimism_genesis_info.base_fee_params,
..Default::default()
#[cfg(feature = "optimism")]
{
into_optimism_chain_spec(genesis)
}
}
}
/// Convert the given [`Genesis`] into an Ethereum [`ChainSpec`].
#[cfg(not(feature = "optimism"))]
fn into_ethereum_chain_spec(genesis: Genesis) -> ChainSpec {
// Block-based hardforks
let hardfork_opts = [
(EthereumHardfork::Homestead.boxed(), genesis.config.homestead_block),
(EthereumHardfork::Dao.boxed(), genesis.config.dao_fork_block),
(EthereumHardfork::Tangerine.boxed(), genesis.config.eip150_block),
(EthereumHardfork::SpuriousDragon.boxed(), genesis.config.eip155_block),
(EthereumHardfork::Byzantium.boxed(), genesis.config.byzantium_block),
(EthereumHardfork::Constantinople.boxed(), genesis.config.constantinople_block),
(EthereumHardfork::Petersburg.boxed(), genesis.config.petersburg_block),
(EthereumHardfork::Istanbul.boxed(), genesis.config.istanbul_block),
(EthereumHardfork::MuirGlacier.boxed(), genesis.config.muir_glacier_block),
(EthereumHardfork::Berlin.boxed(), genesis.config.berlin_block),
(EthereumHardfork::London.boxed(), genesis.config.london_block),
(EthereumHardfork::ArrowGlacier.boxed(), genesis.config.arrow_glacier_block),
(EthereumHardfork::GrayGlacier.boxed(), genesis.config.gray_glacier_block),
];
let mut hardforks = hardfork_opts
.into_iter()
.filter_map(|(hardfork, opt)| opt.map(|block| (hardfork, ForkCondition::Block(block))))
.collect::<Vec<_>>();
// Paris
let paris_block_and_final_difficulty =
if let Some(ttd) = genesis.config.terminal_total_difficulty {
hardforks.push((
EthereumHardfork::Paris.boxed(),
ForkCondition::TTD {
total_difficulty: ttd,
fork_block: genesis.config.merge_netsplit_block,
},
));
genesis.config.merge_netsplit_block.map(|block| (block, ttd))
} else {
None
};
// Time-based hardforks
let time_hardfork_opts = [
(EthereumHardfork::Shanghai.boxed(), genesis.config.shanghai_time),
(EthereumHardfork::Cancun.boxed(), genesis.config.cancun_time),
(EthereumHardfork::Prague.boxed(), genesis.config.prague_time),
];
let mut time_hardforks = time_hardfork_opts
.into_iter()
.filter_map(|(hardfork, opt)| opt.map(|time| (hardfork, ForkCondition::Timestamp(time))))
.collect::<Vec<_>>();
hardforks.append(&mut time_hardforks);
// Ordered Hardforks
let mainnet_hardforks: ChainHardforks = EthereumHardfork::mainnet().into();
let mainnet_order = mainnet_hardforks.forks_iter();
let mut ordered_hardforks = Vec::with_capacity(hardforks.len());
for (hardfork, _) in mainnet_order {
if let Some(pos) = hardforks.iter().position(|(e, _)| **e == *hardfork) {
ordered_hardforks.push(hardforks.remove(pos));
}
}
// append the remaining unknown hardforks to ensure we don't filter any out
ordered_hardforks.append(&mut hardforks);
// NOTE: in full node, we prune all receipts except the deposit contract's. We do not
// have the deployment block in the genesis file, so we use block zero. We use the same
// deposit topic as the mainnet contract if we have the deposit contract address in the
// genesis json.
let deposit_contract = genesis.config.deposit_contract_address.map(|address| DepositContract {
address,
block: 0,
topic: MAINNET_DEPOSIT_CONTRACT.topic,
});
ChainSpec {
chain: genesis.config.chain_id.into(),
genesis,
genesis_hash: OnceCell::new(),
hardforks: ChainHardforks::new(ordered_hardforks),
paris_block_and_final_difficulty,
deposit_contract,
..Default::default()
}
}
#[cfg(feature = "optimism")]
/// Convert the given [`Genesis`] into an Optimism [`ChainSpec`].
fn into_optimism_chain_spec(genesis: Genesis) -> ChainSpec {
use reth_ethereum_forks::OptimismHardfork;
let optimism_genesis_info = OptimismGenesisInfo::extract_from(&genesis);
let genesis_info = optimism_genesis_info.optimism_chain_info.genesis_info.unwrap_or_default();
// Block-based hardforks
let hardfork_opts = [
(EthereumHardfork::Homestead.boxed(), genesis.config.homestead_block),
(EthereumHardfork::Tangerine.boxed(), genesis.config.eip150_block),
(EthereumHardfork::SpuriousDragon.boxed(), genesis.config.eip155_block),
(EthereumHardfork::Byzantium.boxed(), genesis.config.byzantium_block),
(EthereumHardfork::Constantinople.boxed(), genesis.config.constantinople_block),
(EthereumHardfork::Petersburg.boxed(), genesis.config.petersburg_block),
(EthereumHardfork::Istanbul.boxed(), genesis.config.istanbul_block),
(EthereumHardfork::MuirGlacier.boxed(), genesis.config.muir_glacier_block),
(EthereumHardfork::Berlin.boxed(), genesis.config.berlin_block),
(EthereumHardfork::London.boxed(), genesis.config.london_block),
(EthereumHardfork::ArrowGlacier.boxed(), genesis.config.arrow_glacier_block),
(EthereumHardfork::GrayGlacier.boxed(), genesis.config.gray_glacier_block),
(OptimismHardfork::Bedrock.boxed(), genesis_info.bedrock_block),
];
let mut block_hardforks = hardfork_opts
.into_iter()
.filter_map(|(hardfork, opt)| opt.map(|block| (hardfork, ForkCondition::Block(block))))
.collect::<Vec<_>>();
// Paris
let paris_block_and_final_difficulty =
if let Some(ttd) = genesis.config.terminal_total_difficulty {
block_hardforks.push((
EthereumHardfork::Paris.boxed(),
ForkCondition::TTD {
total_difficulty: ttd,
fork_block: genesis.config.merge_netsplit_block,
},
));
genesis.config.merge_netsplit_block.map(|block| (block, ttd))
} else {
None
};
// Time-based hardforks
let time_hardfork_opts = [
(EthereumHardfork::Shanghai.boxed(), genesis.config.shanghai_time),
(EthereumHardfork::Cancun.boxed(), genesis.config.cancun_time),
(EthereumHardfork::Prague.boxed(), genesis.config.prague_time),
(OptimismHardfork::Regolith.boxed(), genesis_info.regolith_time),
(OptimismHardfork::Canyon.boxed(), genesis_info.canyon_time),
(OptimismHardfork::Ecotone.boxed(), genesis_info.ecotone_time),
(OptimismHardfork::Fjord.boxed(), genesis_info.fjord_time),
(OptimismHardfork::Granite.boxed(), genesis_info.granite_time),
];
let mut time_hardforks = time_hardfork_opts
.into_iter()
.filter_map(|(hardfork, opt)| opt.map(|time| (hardfork, ForkCondition::Timestamp(time))))
.collect::<Vec<_>>();
block_hardforks.append(&mut time_hardforks);
// Ordered Hardforks
let mainnet_hardforks = OptimismHardfork::op_mainnet();
let mainnet_order = mainnet_hardforks.forks_iter();
let mut ordered_hardforks = Vec::with_capacity(block_hardforks.len());
for (hardfork, _) in mainnet_order {
if let Some(pos) = block_hardforks.iter().position(|(e, _)| **e == *hardfork) {
ordered_hardforks.push(block_hardforks.remove(pos));
}
}
// append the remaining unknown hardforks to ensure we don't filter any out
ordered_hardforks.append(&mut block_hardforks);
// NOTE: in full node, we prune all receipts except the deposit contract's. We do not
// have the deployment block in the genesis file, so we use block zero. We use the same
// deposit topic as the mainnet contract if we have the deposit contract address in the
// genesis json.
let deposit_contract = genesis.config.deposit_contract_address.map(|address| DepositContract {
address,
block: 0,
topic: MAINNET_DEPOSIT_CONTRACT.topic,
});
ChainSpec {
chain: genesis.config.chain_id.into(),
genesis,
genesis_hash: OnceCell::new(),
hardforks: ChainHardforks::new(ordered_hardforks),
paris_block_and_final_difficulty,
deposit_contract,
base_fee_params: optimism_genesis_info.base_fee_params,
..Default::default()
}
}
/// A trait for reading the current [`ChainSpec`].
#[auto_impl::auto_impl(&, Arc)]
pub trait ChainSpecProvider: Send + Sync {
@ -886,7 +972,7 @@ impl ChainSpecBuilder {
#[cfg(feature = "optimism")]
pub fn bedrock_activated(mut self) -> Self {
self = self.paris_activated();
self.hardforks.insert(OptimismHardfork::Bedrock, ForkCondition::Block(0));
self.hardforks.insert(crate::OptimismHardfork::Bedrock, ForkCondition::Block(0));
self
}
@ -894,7 +980,7 @@ impl ChainSpecBuilder {
#[cfg(feature = "optimism")]
pub fn regolith_activated(mut self) -> Self {
self = self.bedrock_activated();
self.hardforks.insert(OptimismHardfork::Regolith, ForkCondition::Timestamp(0));
self.hardforks.insert(crate::OptimismHardfork::Regolith, ForkCondition::Timestamp(0));
self
}
@ -904,7 +990,7 @@ impl ChainSpecBuilder {
self = self.regolith_activated();
// Canyon also activates changes from L1's Shanghai hardfork
self.hardforks.insert(EthereumHardfork::Shanghai, ForkCondition::Timestamp(0));
self.hardforks.insert(OptimismHardfork::Canyon, ForkCondition::Timestamp(0));
self.hardforks.insert(crate::OptimismHardfork::Canyon, ForkCondition::Timestamp(0));
self
}
@ -913,7 +999,7 @@ impl ChainSpecBuilder {
pub fn ecotone_activated(mut self) -> Self {
self = self.canyon_activated();
self.hardforks.insert(EthereumHardfork::Cancun, ForkCondition::Timestamp(0));
self.hardforks.insert(OptimismHardfork::Ecotone, ForkCondition::Timestamp(0));
self.hardforks.insert(crate::OptimismHardfork::Ecotone, ForkCondition::Timestamp(0));
self
}
@ -921,7 +1007,7 @@ impl ChainSpecBuilder {
#[cfg(feature = "optimism")]
pub fn fjord_activated(mut self) -> Self {
self = self.ecotone_activated();
self.hardforks.insert(OptimismHardfork::Fjord, ForkCondition::Timestamp(0));
self.hardforks.insert(crate::OptimismHardfork::Fjord, ForkCondition::Timestamp(0));
self
}
@ -929,7 +1015,7 @@ impl ChainSpecBuilder {
#[cfg(feature = "optimism")]
pub fn granite_activated(mut self) -> Self {
self = self.fjord_activated();
self.hardforks.insert(OptimismHardfork::Granite, ForkCondition::Timestamp(0));
self.hardforks.insert(crate::OptimismHardfork::Granite, ForkCondition::Timestamp(0));
self
}
@ -1024,7 +1110,7 @@ impl OptimismGenesisInfo {
BaseFeeParams::new(denominator as u128, elasticity as u128),
),
(
OptimismHardfork::Canyon.boxed(),
reth_ethereum_forks::OptimismHardfork::Canyon.boxed(),
BaseFeeParams::new(canyon_denominator as u128, elasticity as u128),
),
]
@ -1418,7 +1504,7 @@ Post-merge hard forks (timestamp based):
}
#[test]
fn mainnet_forkids() {
fn mainnet_fork_ids() {
test_fork_ids(
&MAINNET,
&[
@ -1494,7 +1580,7 @@ Post-merge hard forks (timestamp based):
}
#[test]
fn holesky_forkids() {
fn holesky_fork_ids() {
test_fork_ids(
&HOLESKY,
&[
@ -1532,7 +1618,7 @@ Post-merge hard forks (timestamp based):
}
#[test]
fn sepolia_forkids() {
fn sepolia_fork_ids() {
test_fork_ids(
&SEPOLIA,
&[
@ -1572,7 +1658,7 @@ Post-merge hard forks (timestamp based):
}
#[test]
fn dev_forkids() {
fn dev_fork_ids() {
test_fork_ids(
&DEV,
&[(
@ -2362,4 +2448,139 @@ Post-merge hard forks (timestamp based):
MAINNET.latest_fork_id()
)
}
#[test]
#[cfg(not(feature = "optimism"))]
fn test_fork_order_ethereum_mainnet() {
let genesis = Genesis {
config: ChainConfig {
chain_id: 0,
homestead_block: Some(0),
dao_fork_block: Some(0),
dao_fork_support: false,
eip150_block: Some(0),
eip155_block: Some(0),
eip158_block: Some(0),
byzantium_block: Some(0),
constantinople_block: Some(0),
petersburg_block: Some(0),
istanbul_block: Some(0),
muir_glacier_block: Some(0),
berlin_block: Some(0),
london_block: Some(0),
arrow_glacier_block: Some(0),
gray_glacier_block: Some(0),
merge_netsplit_block: Some(0),
shanghai_time: Some(0),
cancun_time: Some(0),
terminal_total_difficulty: Some(U256::ZERO),
..Default::default()
},
..Default::default()
};
let chain_spec = into_ethereum_chain_spec(genesis);
let hardforks: Vec<_> = chain_spec.hardforks.forks_iter().map(|(h, _)| h).collect();
let expected_hardforks = vec![
EthereumHardfork::Homestead.boxed(),
EthereumHardfork::Dao.boxed(),
EthereumHardfork::Tangerine.boxed(),
EthereumHardfork::SpuriousDragon.boxed(),
EthereumHardfork::Byzantium.boxed(),
EthereumHardfork::Constantinople.boxed(),
EthereumHardfork::Petersburg.boxed(),
EthereumHardfork::Istanbul.boxed(),
EthereumHardfork::MuirGlacier.boxed(),
EthereumHardfork::Berlin.boxed(),
EthereumHardfork::London.boxed(),
EthereumHardfork::ArrowGlacier.boxed(),
EthereumHardfork::GrayGlacier.boxed(),
EthereumHardfork::Paris.boxed(),
EthereumHardfork::Shanghai.boxed(),
EthereumHardfork::Cancun.boxed(),
];
assert!(expected_hardforks
.iter()
.zip(hardforks.iter())
.all(|(expected, actual)| &**expected == *actual));
assert_eq!(expected_hardforks.len(), hardforks.len());
}
#[test]
#[cfg(feature = "optimism")]
fn test_fork_order_optimism_mainnet() {
use crate::OptimismHardfork;
let genesis = Genesis {
config: ChainConfig {
chain_id: 0,
homestead_block: Some(0),
dao_fork_block: Some(0),
dao_fork_support: false,
eip150_block: Some(0),
eip155_block: Some(0),
eip158_block: Some(0),
byzantium_block: Some(0),
constantinople_block: Some(0),
petersburg_block: Some(0),
istanbul_block: Some(0),
muir_glacier_block: Some(0),
berlin_block: Some(0),
london_block: Some(0),
arrow_glacier_block: Some(0),
gray_glacier_block: Some(0),
merge_netsplit_block: Some(0),
shanghai_time: Some(0),
cancun_time: Some(0),
terminal_total_difficulty: Some(U256::ZERO),
extra_fields: [
(String::from("bedrockBlock"), 0.into()),
(String::from("regolithTime"), 0.into()),
(String::from("canyonTime"), 0.into()),
(String::from("ecotoneTime"), 0.into()),
(String::from("fjordTime"), 0.into()),
(String::from("graniteTime"), 0.into()),
]
.into_iter()
.collect(),
..Default::default()
},
..Default::default()
};
let chain_spec: ChainSpec = into_optimism_chain_spec(genesis);
let hardforks: Vec<_> = chain_spec.hardforks.forks_iter().map(|(h, _)| h).collect();
let expected_hardforks = vec![
EthereumHardfork::Homestead.boxed(),
EthereumHardfork::Tangerine.boxed(),
EthereumHardfork::SpuriousDragon.boxed(),
EthereumHardfork::Byzantium.boxed(),
EthereumHardfork::Constantinople.boxed(),
EthereumHardfork::Petersburg.boxed(),
EthereumHardfork::Istanbul.boxed(),
EthereumHardfork::MuirGlacier.boxed(),
EthereumHardfork::Berlin.boxed(),
EthereumHardfork::London.boxed(),
EthereumHardfork::ArrowGlacier.boxed(),
EthereumHardfork::GrayGlacier.boxed(),
EthereumHardfork::Paris.boxed(),
OptimismHardfork::Bedrock.boxed(),
OptimismHardfork::Regolith.boxed(),
EthereumHardfork::Shanghai.boxed(),
OptimismHardfork::Canyon.boxed(),
EthereumHardfork::Cancun.boxed(),
OptimismHardfork::Ecotone.boxed(),
OptimismHardfork::Fjord.boxed(),
OptimismHardfork::Granite.boxed(),
];
assert!(expected_hardforks
.iter()
.zip(hardforks.iter())
.all(|(expected, actual)| &**expected == *actual));
assert_eq!(expected_hardforks.len(), hardforks.len());
}
}