mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
chore: op chainspec (#11415)
This commit is contained in:
@ -26,12 +26,15 @@ alloy-chains.workspace = true
|
||||
alloy-genesis.workspace = true
|
||||
alloy-primitives.workspace = true
|
||||
|
||||
# op
|
||||
op-alloy-rpc-types.workspace = true
|
||||
|
||||
# io
|
||||
serde_json.workspace = true
|
||||
|
||||
# misc
|
||||
once_cell.workspace = true
|
||||
derive_more.workspace = true
|
||||
once_cell.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
reth-chainspec = { workspace = true, features = ["test-utils"] }
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
//! OP stack variation of chain spec constants.
|
||||
|
||||
use alloy_primitives::{address, b256};
|
||||
use reth_chainspec::DepositContract;
|
||||
|
||||
//------------------------------- BASE MAINNET -------------------------------//
|
||||
|
||||
/// Max gas limit on Base: <https://basescan.org/block/17208876>
|
||||
@ -9,3 +12,10 @@ pub const BASE_MAINNET_MAX_GAS_LIMIT: u64 = 105_000_000;
|
||||
|
||||
/// Max gas limit on Base Sepolia: <https://sepolia.basescan.org/block/12506483>
|
||||
pub const BASE_SEPOLIA_MAX_GAS_LIMIT: u64 = 45_000_000;
|
||||
|
||||
/// Deposit contract address: `0x00000000219ab540356cbb839cbe05303d7705fa`
|
||||
pub(crate) const MAINNET_DEPOSIT_CONTRACT: DepositContract = DepositContract::new(
|
||||
address!("00000000219ab540356cbb839cbe05303d7705fa"),
|
||||
11052984,
|
||||
b256!("649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5"),
|
||||
);
|
||||
|
||||
@ -26,11 +26,14 @@ pub use dev::OP_DEV;
|
||||
pub use op::OP_MAINNET;
|
||||
pub use op_sepolia::OP_SEPOLIA;
|
||||
|
||||
use crate::constants::MAINNET_DEPOSIT_CONTRACT;
|
||||
use derive_more::{Constructor, Deref, Into};
|
||||
use once_cell::sync::OnceCell;
|
||||
use reth_chainspec::{
|
||||
BaseFeeParams, ChainSpec, DepositContract, EthChainSpec, EthereumHardforks, ForkFilter, ForkId,
|
||||
Hardforks, Head,
|
||||
BaseFeeParams, BaseFeeParamsKind, ChainSpec, DepositContract, EthChainSpec, EthereumHardforks,
|
||||
ForkFilter, ForkId, Hardforks, Head,
|
||||
};
|
||||
use reth_ethereum_forks::{ChainHardforks, EthereumHardfork, ForkCondition};
|
||||
use reth_network_peers::NodeRecord;
|
||||
use reth_primitives_traits::Header;
|
||||
|
||||
@ -52,14 +55,14 @@ impl EthChainSpec for OpChainSpec {
|
||||
self.inner.chain()
|
||||
}
|
||||
|
||||
fn base_fee_params_at_timestamp(&self, timestamp: u64) -> BaseFeeParams {
|
||||
self.inner.base_fee_params_at_timestamp(timestamp)
|
||||
}
|
||||
|
||||
fn base_fee_params_at_block(&self, block_number: u64) -> BaseFeeParams {
|
||||
self.inner.base_fee_params_at_block(block_number)
|
||||
}
|
||||
|
||||
fn base_fee_params_at_timestamp(&self, timestamp: u64) -> BaseFeeParams {
|
||||
self.inner.base_fee_params_at_timestamp(timestamp)
|
||||
}
|
||||
|
||||
fn deposit_contract(&self) -> Option<&DepositContract> {
|
||||
self.inner.deposit_contract()
|
||||
}
|
||||
@ -118,20 +121,170 @@ impl Hardforks for OpChainSpec {
|
||||
}
|
||||
|
||||
impl EthereumHardforks for OpChainSpec {
|
||||
fn get_final_paris_total_difficulty(&self) -> Option<U256> {
|
||||
self.inner.get_final_paris_total_difficulty()
|
||||
}
|
||||
|
||||
fn final_paris_total_difficulty(&self, block_number: u64) -> Option<U256> {
|
||||
self.inner.final_paris_total_difficulty(block_number)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_final_paris_total_difficulty(&self) -> Option<U256> {
|
||||
self.inner.get_final_paris_total_difficulty()
|
||||
impl From<Genesis> for OpChainSpec {
|
||||
fn from(genesis: Genesis) -> Self {
|
||||
use reth_optimism_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 }
|
||||
});
|
||||
|
||||
Self {
|
||||
inner: 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()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct OptimismGenesisInfo {
|
||||
optimism_chain_info: op_alloy_rpc_types::genesis::OptimismChainInfo,
|
||||
base_fee_params: BaseFeeParamsKind,
|
||||
}
|
||||
|
||||
impl OptimismGenesisInfo {
|
||||
fn extract_from(genesis: &Genesis) -> Self {
|
||||
let mut info = Self {
|
||||
optimism_chain_info: op_alloy_rpc_types::genesis::OptimismChainInfo::extract_from(
|
||||
&genesis.config.extra_fields,
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
..Default::default()
|
||||
};
|
||||
if let Some(optimism_base_fee_info) = &info.optimism_chain_info.base_fee_info {
|
||||
if let (Some(elasticity), Some(denominator)) = (
|
||||
optimism_base_fee_info.eip1559_elasticity,
|
||||
optimism_base_fee_info.eip1559_denominator,
|
||||
) {
|
||||
let base_fee_params = if let Some(canyon_denominator) =
|
||||
optimism_base_fee_info.eip1559_denominator_canyon
|
||||
{
|
||||
BaseFeeParamsKind::Variable(
|
||||
vec![
|
||||
(
|
||||
EthereumHardfork::London.boxed(),
|
||||
BaseFeeParams::new(denominator as u128, elasticity as u128),
|
||||
),
|
||||
(
|
||||
reth_optimism_forks::OptimismHardfork::Canyon.boxed(),
|
||||
BaseFeeParams::new(canyon_denominator as u128, elasticity as u128),
|
||||
),
|
||||
]
|
||||
.into(),
|
||||
)
|
||||
} else {
|
||||
BaseFeeParams::new(denominator as u128, elasticity as u128).into()
|
||||
};
|
||||
|
||||
info.base_fee_params = base_fee_params;
|
||||
}
|
||||
}
|
||||
|
||||
info
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use alloy_genesis::Genesis;
|
||||
use alloy_genesis::{ChainConfig, Genesis};
|
||||
use alloy_primitives::b256;
|
||||
use reth_chainspec::{test_fork_ids, BaseFeeParams, BaseFeeParamsKind, ChainSpec};
|
||||
use reth_chainspec::{test_fork_ids, BaseFeeParams, BaseFeeParamsKind};
|
||||
use reth_ethereum_forks::{EthereumHardfork, ForkCondition, ForkHash, ForkId, Head};
|
||||
use reth_optimism_forks::{OptimismHardfork, OptimismHardforks};
|
||||
|
||||
@ -383,7 +536,7 @@ mod tests {
|
||||
})
|
||||
);
|
||||
|
||||
let chain_spec: ChainSpec = genesis.into();
|
||||
let chain_spec: OpChainSpec = genesis.into();
|
||||
|
||||
assert_eq!(
|
||||
chain_spec.base_fee_params,
|
||||
@ -449,7 +602,7 @@ mod tests {
|
||||
})
|
||||
);
|
||||
|
||||
let chain_spec: ChainSpec = genesis.into();
|
||||
let chain_spec: OpChainSpec = genesis.into();
|
||||
|
||||
assert_eq!(
|
||||
chain_spec.base_fee_params,
|
||||
@ -511,7 +664,7 @@ mod tests {
|
||||
}
|
||||
"#;
|
||||
let genesis: Genesis = serde_json::from_str(geth_genesis).unwrap();
|
||||
let chainspec = ChainSpec::from(genesis.clone());
|
||||
let chainspec = OpChainSpec::from(genesis.clone());
|
||||
|
||||
let actual_chain_id = genesis.config.chain_id;
|
||||
assert_eq!(actual_chain_id, 8453);
|
||||
@ -552,4 +705,79 @@ mod tests {
|
||||
|
||||
assert!(chainspec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, 20));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fork_order_optimism_mainnet() {
|
||||
use reth_optimism_forks::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: OpChainSpec = genesis.into();
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user