mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
chore(op): Add OpChainSpec (#10516)
This commit is contained in:
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -6568,7 +6568,6 @@ version = "1.0.5"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"eyre",
|
||||
"reth-chainspec",
|
||||
"reth-cli-runner",
|
||||
]
|
||||
|
||||
@ -7344,6 +7343,7 @@ dependencies = [
|
||||
"reth-evm",
|
||||
"reth-execution-errors",
|
||||
"reth-execution-types",
|
||||
"reth-optimism-chainspec",
|
||||
"reth-optimism-consensus",
|
||||
"reth-primitives",
|
||||
"reth-prune-types",
|
||||
@ -7971,6 +7971,7 @@ dependencies = [
|
||||
"alloy-chains",
|
||||
"alloy-genesis",
|
||||
"alloy-primitives",
|
||||
"derive_more 1.0.0",
|
||||
"once_cell",
|
||||
"op-alloy-rpc-types",
|
||||
"reth-chainspec",
|
||||
@ -7983,7 +7984,6 @@ dependencies = [
|
||||
name = "reth-optimism-cli"
|
||||
version = "1.0.5"
|
||||
dependencies = [
|
||||
"alloy-genesis",
|
||||
"alloy-primitives",
|
||||
"alloy-rlp",
|
||||
"clap",
|
||||
@ -8013,8 +8013,6 @@ dependencies = [
|
||||
"reth-stages-types",
|
||||
"reth-static-file",
|
||||
"reth-static-file-types",
|
||||
"serde_json",
|
||||
"shellexpand",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
|
||||
@ -14,7 +14,6 @@ workspace = true
|
||||
[dependencies]
|
||||
# reth
|
||||
reth-cli-runner.workspace = true
|
||||
reth-chainspec.workspace = true
|
||||
|
||||
# misc
|
||||
clap.workspace = true
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
use clap::builder::TypedValueParser;
|
||||
use reth_chainspec::ChainSpec;
|
||||
use std::sync::Arc;
|
||||
|
||||
use clap::builder::TypedValueParser;
|
||||
|
||||
/// Trait for parsing chain specifications.
|
||||
///
|
||||
/// This trait extends [`clap::builder::TypedValueParser`] to provide a parser for chain
|
||||
/// specifications. Implementers of this trait must provide a list of supported chains and a
|
||||
/// function to parse a given string into a [`ChainSpec`].
|
||||
pub trait ChainSpecParser: TypedValueParser<Value = Arc<ChainSpec>> + Default {
|
||||
/// function to parse a given string into a chain spec.
|
||||
pub trait ChainSpecParser<ChainSpec>: TypedValueParser<Value = Arc<ChainSpec>> + Default {
|
||||
/// List of supported chains.
|
||||
const SUPPORTED_CHAINS: &'static [&'static str];
|
||||
|
||||
/// Parses the given string into a [`ChainSpec`].
|
||||
/// Parses the given string into a chain spec.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
@ -20,6 +20,6 @@ pub trait ChainSpecParser: TypedValueParser<Value = Arc<ChainSpec>> + Default {
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if the input string cannot be parsed into a valid
|
||||
/// [`ChainSpec`].
|
||||
/// chain spec.
|
||||
fn parse(s: &str) -> eyre::Result<Arc<ChainSpec>>;
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ fn chain_value_parser(s: &str) -> eyre::Result<Arc<ChainSpec>, eyre::Error> {
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct EthChainSpecParser;
|
||||
|
||||
impl ChainSpecParser for EthChainSpecParser {
|
||||
impl ChainSpecParser<ChainSpec> for EthChainSpecParser {
|
||||
const SUPPORTED_CHAINS: &'static [&'static str] = &["mainnet", "sepolia", "holesky", "dev"];
|
||||
|
||||
fn parse(s: &str) -> eyre::Result<Arc<ChainSpec>> {
|
||||
@ -59,7 +59,7 @@ impl TypedValueParser for EthChainSpecParser {
|
||||
) -> Result<Self::Value, clap::Error> {
|
||||
let val =
|
||||
value.to_str().ok_or_else(|| clap::Error::new(clap::error::ErrorKind::InvalidUtf8))?;
|
||||
<Self as ChainSpecParser>::parse(val).map_err(|err| {
|
||||
<Self as ChainSpecParser<ChainSpec>>::parse(val).map_err(|err| {
|
||||
let arg = arg.map(|a| a.to_string()).unwrap_or_else(|| "...".to_owned());
|
||||
let possible_values = Self::SUPPORTED_CHAINS.join(",");
|
||||
let msg = format!(
|
||||
@ -84,7 +84,7 @@ mod tests {
|
||||
#[test]
|
||||
fn parse_known_chain_spec() {
|
||||
for &chain in EthChainSpecParser::SUPPORTED_CHAINS {
|
||||
assert!(<EthChainSpecParser as ChainSpecParser>::parse(chain).is_ok());
|
||||
assert!(<EthChainSpecParser as ChainSpecParser<ChainSpec>>::parse(chain).is_ok());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ reth-network-peers.workspace = true
|
||||
reth-consensus-common.workspace = true
|
||||
reth-prune-types.workspace = true
|
||||
reth-stages-types.workspace = true
|
||||
reth-optimism-chainspec = { workspace = true, features = ["optimism"], optional = true }
|
||||
reth-optimism-chainspec = { workspace = true, optional = true }
|
||||
|
||||
# ethereum
|
||||
alloy-genesis.workspace = true
|
||||
|
||||
@ -3,16 +3,17 @@
|
||||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
use alloy_genesis::Genesis;
|
||||
use reth_chainspec::{ChainSpec, DEV};
|
||||
use reth_chainspec::ChainSpec;
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
use reth_chainspec::{HOLESKY, MAINNET, SEPOLIA};
|
||||
use reth_chainspec::{DEV, HOLESKY, MAINNET, SEPOLIA};
|
||||
use reth_fs_util as fs;
|
||||
#[cfg(feature = "optimism")]
|
||||
use reth_optimism_chainspec::{BASE_MAINNET, BASE_SEPOLIA, OP_MAINNET, OP_SEPOLIA};
|
||||
use reth_optimism_chainspec::{BASE_MAINNET, BASE_SEPOLIA, OP_DEV, OP_MAINNET, OP_SEPOLIA};
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
/// Chains supported by op-reth. First value should be used as the default.
|
||||
pub const SUPPORTED_CHAINS: &[&str] = &["optimism", "optimism-sepolia", "base", "base-sepolia"];
|
||||
pub const SUPPORTED_CHAINS: &[&str] =
|
||||
&["optimism", "optimism-sepolia", "base", "base-sepolia", "dev"];
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
/// Chains supported by reth. First value should be used as the default.
|
||||
pub const SUPPORTED_CHAINS: &[&str] = &["mainnet", "sepolia", "holesky", "dev"];
|
||||
@ -26,45 +27,54 @@ pub fn chain_help() -> String {
|
||||
///
|
||||
/// The value parser matches either a known chain, the path
|
||||
/// to a json file, or a json formatted string in-memory. The json needs to be a Genesis struct.
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
pub fn chain_value_parser(s: &str) -> eyre::Result<Arc<ChainSpec>, eyre::Error> {
|
||||
Ok(match s {
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
"mainnet" => MAINNET.clone(),
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
"sepolia" => SEPOLIA.clone(),
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
"holesky" => HOLESKY.clone(),
|
||||
"dev" => DEV.clone(),
|
||||
#[cfg(feature = "optimism")]
|
||||
"optimism" => OP_MAINNET.clone(),
|
||||
#[cfg(feature = "optimism")]
|
||||
"optimism_sepolia" | "optimism-sepolia" => OP_SEPOLIA.clone(),
|
||||
#[cfg(feature = "optimism")]
|
||||
"base" => BASE_MAINNET.clone(),
|
||||
#[cfg(feature = "optimism")]
|
||||
"base_sepolia" | "base-sepolia" => BASE_SEPOLIA.clone(),
|
||||
_ => {
|
||||
// try to read json from path first
|
||||
let raw = match fs::read_to_string(PathBuf::from(shellexpand::full(s)?.into_owned())) {
|
||||
Ok(raw) => raw,
|
||||
Err(io_err) => {
|
||||
// valid json may start with "\n", but must contain "{"
|
||||
if s.contains('{') {
|
||||
s.to_string()
|
||||
} else {
|
||||
return Err(io_err.into()) // assume invalid path
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// both serialized Genesis and ChainSpec structs supported
|
||||
let genesis: Genesis = serde_json::from_str(&raw)?;
|
||||
|
||||
Arc::new(genesis.into())
|
||||
}
|
||||
_ => Arc::new(parse_custom_chain_spec(s)?),
|
||||
})
|
||||
}
|
||||
|
||||
/// Clap value parser for [`OpChainSpec`](reth_optimism_chainspec::OpChainSpec)s.
|
||||
///
|
||||
/// The value parser matches either a known chain, the path
|
||||
/// to a json file, or a json formatted string in-memory. The json needs to be a Genesis struct.
|
||||
#[cfg(feature = "optimism")]
|
||||
pub fn chain_value_parser(s: &str) -> eyre::Result<Arc<ChainSpec>, eyre::Error> {
|
||||
Ok(Arc::new(match s {
|
||||
"optimism" => OP_MAINNET.inner.clone(),
|
||||
"optimism_sepolia" | "optimism-sepolia" => OP_SEPOLIA.inner.clone(),
|
||||
"base" => BASE_MAINNET.inner.clone(),
|
||||
"base_sepolia" | "base-sepolia" => BASE_SEPOLIA.inner.clone(),
|
||||
"dev" => OP_DEV.inner.clone(),
|
||||
_ => parse_custom_chain_spec(s)?,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Parses a custom [`ChainSpec`].
|
||||
pub fn parse_custom_chain_spec(s: &str) -> eyre::Result<ChainSpec, eyre::Error> {
|
||||
// try to read json from path first
|
||||
let raw = match fs::read_to_string(PathBuf::from(shellexpand::full(s)?.into_owned())) {
|
||||
Ok(raw) => raw,
|
||||
Err(io_err) => {
|
||||
// valid json may start with "\n", but must contain "{"
|
||||
if s.contains('{') {
|
||||
s.to_string()
|
||||
} else {
|
||||
return Err(io_err.into()) // assume invalid path
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// both serialized Genesis and ChainSpec structs supported
|
||||
let genesis: Genesis = serde_json::from_str(&raw)?;
|
||||
|
||||
Ok(genesis.into())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@ -26,6 +26,7 @@ serde_json.workspace = true
|
||||
|
||||
# misc
|
||||
once_cell.workspace = true
|
||||
derive_more.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
reth-chainspec = { workspace = true, features = ["test-utils"] }
|
||||
@ -34,5 +35,4 @@ op-alloy-rpc-types.workspace = true
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = []
|
||||
optimism = []
|
||||
std = []
|
||||
1
crates/optimism/chainspec/res/genesis/dev.json
Normal file
1
crates/optimism/chainspec/res/genesis/dev.json
Normal file
@ -0,0 +1 @@
|
||||
{"nonce":"0x0","timestamp":"0x6490fdd2","extraData":"0x","gasLimit":"0x1c9c380","difficulty":"0x0","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","coinbase":"0x0000000000000000000000000000000000000000","stateRoot":"0x5eb6e371a698b8d68f665192350ffcecbbbf322916f4b51bd79bb6887da3f494","alloc":{"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266":{"balance":"0xD3C21BCECCEDA1000000"},"0x70997970C51812dc3A010C7d01b50e0d17dc79C8":{"balance":"0xD3C21BCECCEDA1000000"},"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC":{"balance":"0xD3C21BCECCEDA1000000"},"0x90F79bf6EB2c4f870365E785982E1f101E93b906":{"balance":"0xD3C21BCECCEDA1000000"},"0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65":{"balance":"0xD3C21BCECCEDA1000000"},"0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc":{"balance":"0xD3C21BCECCEDA1000000"},"0x976EA74026E726554dB657fA54763abd0C3a0aa9":{"balance":"0xD3C21BCECCEDA1000000"},"0x14dC79964da2C08b23698B3D3cc7Ca32193d9955":{"balance":"0xD3C21BCECCEDA1000000"},"0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f":{"balance":"0xD3C21BCECCEDA1000000"},"0xa0Ee7A142d267C1f36714E4a8F75612F20a79720":{"balance":"0xD3C21BCECCEDA1000000"},"0xBcd4042DE499D14e55001CcbB24a551F3b954096":{"balance":"0xD3C21BCECCEDA1000000"},"0x71bE63f3384f5fb98995898A86B02Fb2426c5788":{"balance":"0xD3C21BCECCEDA1000000"},"0xFABB0ac9d68B0B445fB7357272Ff202C5651694a":{"balance":"0xD3C21BCECCEDA1000000"},"0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec":{"balance":"0xD3C21BCECCEDA1000000"},"0xdF3e18d64BC6A983f673Ab319CCaE4f1a57C7097":{"balance":"0xD3C21BCECCEDA1000000"},"0xcd3B766CCDd6AE721141F452C550Ca635964ce71":{"balance":"0xD3C21BCECCEDA1000000"},"0x2546BcD3c84621e976D8185a91A922aE77ECEc30":{"balance":"0xD3C21BCECCEDA1000000"},"0xbDA5747bFD65F08deb54cb465eB87D40e51B197E":{"balance":"0xD3C21BCECCEDA1000000"},"0xdD2FD4581271e230360230F9337D5c0430Bf44C0":{"balance":"0xD3C21BCECCEDA1000000"},"0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199":{"balance":"0xD3C21BCECCEDA1000000"}},"number":"0x0","gasUsed":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}
|
||||
@ -11,27 +11,31 @@ use once_cell::sync::Lazy;
|
||||
use reth_chainspec::{BaseFeeParams, BaseFeeParamsKind, ChainSpec};
|
||||
use reth_ethereum_forks::{EthereumHardfork, OptimismHardfork};
|
||||
|
||||
use crate::OpChainSpec;
|
||||
|
||||
/// The Base mainnet spec
|
||||
pub static BASE_MAINNET: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
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: Some(b256!(
|
||||
"f712aa9241cc24369b143cf6dce85f0902a9731e70d66818a3a5845b296c73dd"
|
||||
)),
|
||||
paris_block_and_final_difficulty: Some((0, U256::from(0))),
|
||||
hardforks: OptimismHardfork::base_mainnet(),
|
||||
base_fee_params: BaseFeeParamsKind::Variable(
|
||||
vec![
|
||||
(EthereumHardfork::London.boxed(), BaseFeeParams::optimism()),
|
||||
(OptimismHardfork::Canyon.boxed(), BaseFeeParams::optimism_canyon()),
|
||||
]
|
||||
.into(),
|
||||
),
|
||||
max_gas_limit: crate::constants::BASE_MAINNET_MAX_GAS_LIMIT,
|
||||
prune_delete_limit: 10000,
|
||||
..Default::default()
|
||||
pub static BASE_MAINNET: Lazy<Arc<OpChainSpec>> = Lazy::new(|| {
|
||||
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: Some(b256!(
|
||||
"f712aa9241cc24369b143cf6dce85f0902a9731e70d66818a3a5845b296c73dd"
|
||||
)),
|
||||
paris_block_and_final_difficulty: Some((0, U256::from(0))),
|
||||
hardforks: OptimismHardfork::base_mainnet(),
|
||||
base_fee_params: BaseFeeParamsKind::Variable(
|
||||
vec![
|
||||
(EthereumHardfork::London.boxed(), BaseFeeParams::optimism()),
|
||||
(OptimismHardfork::Canyon.boxed(), BaseFeeParams::optimism_canyon()),
|
||||
]
|
||||
.into(),
|
||||
),
|
||||
max_gas_limit: crate::constants::BASE_MAINNET_MAX_GAS_LIMIT,
|
||||
prune_delete_limit: 10000,
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
.into()
|
||||
});
|
||||
|
||||
@ -11,27 +11,31 @@ use once_cell::sync::Lazy;
|
||||
use reth_chainspec::{BaseFeeParams, BaseFeeParamsKind, ChainSpec};
|
||||
use reth_ethereum_forks::{EthereumHardfork, OptimismHardfork};
|
||||
|
||||
use crate::OpChainSpec;
|
||||
|
||||
/// The Base Sepolia spec
|
||||
pub static BASE_SEPOLIA: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
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: Some(b256!(
|
||||
"0dcc9e089e30b90ddfc55be9a37dd15bc551aeee999d2e2b51414c54eaf934e4"
|
||||
)),
|
||||
paris_block_and_final_difficulty: Some((0, U256::from(0))),
|
||||
hardforks: OptimismHardfork::base_sepolia(),
|
||||
base_fee_params: BaseFeeParamsKind::Variable(
|
||||
vec![
|
||||
(EthereumHardfork::London.boxed(), BaseFeeParams::base_sepolia()),
|
||||
(OptimismHardfork::Canyon.boxed(), BaseFeeParams::base_sepolia_canyon()),
|
||||
]
|
||||
.into(),
|
||||
),
|
||||
max_gas_limit: crate::constants::BASE_SEPOLIA_MAX_GAS_LIMIT,
|
||||
prune_delete_limit: 10000,
|
||||
..Default::default()
|
||||
pub static BASE_SEPOLIA: Lazy<Arc<OpChainSpec>> = Lazy::new(|| {
|
||||
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: Some(b256!(
|
||||
"0dcc9e089e30b90ddfc55be9a37dd15bc551aeee999d2e2b51414c54eaf934e4"
|
||||
)),
|
||||
paris_block_and_final_difficulty: Some((0, U256::from(0))),
|
||||
hardforks: OptimismHardfork::base_sepolia(),
|
||||
base_fee_params: BaseFeeParamsKind::Variable(
|
||||
vec![
|
||||
(EthereumHardfork::London.boxed(), BaseFeeParams::base_sepolia()),
|
||||
(OptimismHardfork::Canyon.boxed(), BaseFeeParams::base_sepolia_canyon()),
|
||||
]
|
||||
.into(),
|
||||
),
|
||||
max_gas_limit: crate::constants::BASE_SEPOLIA_MAX_GAS_LIMIT,
|
||||
prune_delete_limit: 10000,
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
.into()
|
||||
});
|
||||
|
||||
38
crates/optimism/chainspec/src/dev.rs
Normal file
38
crates/optimism/chainspec/src/dev.rs
Normal file
@ -0,0 +1,38 @@
|
||||
//! Chain specification in dev mode for custom chain.
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::sync::Arc;
|
||||
#[cfg(feature = "std")]
|
||||
use std::sync::Arc;
|
||||
|
||||
use alloy_chains::Chain;
|
||||
use alloy_primitives::U256;
|
||||
use once_cell::sync::Lazy;
|
||||
use reth_chainspec::{BaseFeeParams, BaseFeeParamsKind, ChainSpec};
|
||||
use reth_ethereum_forks::DEV_HARDFORKS;
|
||||
use reth_primitives_traits::constants::DEV_GENESIS_HASH;
|
||||
|
||||
use crate::OpChainSpec;
|
||||
|
||||
/// OP dev testnet specification
|
||||
///
|
||||
/// 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: Lazy<Arc<OpChainSpec>> = Lazy::new(|| {
|
||||
{
|
||||
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: Some(DEV_GENESIS_HASH),
|
||||
paris_block_and_final_difficulty: Some((0, U256::from(0))),
|
||||
hardforks: DEV_HARDFORKS.clone(),
|
||||
base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()),
|
||||
deposit_contract: None, // TODO: do we even have?
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
.into()
|
||||
});
|
||||
@ -5,10 +5,7 @@
|
||||
html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
|
||||
issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
|
||||
)]
|
||||
#![cfg_attr(all(not(test), feature = "optimism"), warn(unused_crate_dependencies))]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||
// The `optimism` feature must be enabled to use this crate.
|
||||
#![cfg(feature = "optimism")]
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
extern crate alloc;
|
||||
@ -17,14 +14,26 @@ pub mod constants;
|
||||
|
||||
mod base;
|
||||
mod base_sepolia;
|
||||
mod dev;
|
||||
mod op;
|
||||
mod op_sepolia;
|
||||
|
||||
pub use base::BASE_MAINNET;
|
||||
pub use base_sepolia::BASE_SEPOLIA;
|
||||
pub use dev::OP_DEV;
|
||||
pub use op::OP_MAINNET;
|
||||
pub use op_sepolia::OP_SEPOLIA;
|
||||
|
||||
use derive_more::{Constructor, Deref, Into};
|
||||
use reth_chainspec::ChainSpec;
|
||||
|
||||
/// OP stack chain spec type.
|
||||
#[derive(Debug, Deref, Into, Constructor)]
|
||||
pub struct OpChainSpec {
|
||||
/// [`ChainSpec`].
|
||||
pub inner: ChainSpec,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use alloy_genesis::Genesis;
|
||||
|
||||
@ -12,29 +12,33 @@ use reth_chainspec::{BaseFeeParams, BaseFeeParamsKind, ChainSpec};
|
||||
use reth_ethereum_forks::{EthereumHardfork, OptimismHardfork};
|
||||
use reth_primitives_traits::constants::ETHEREUM_BLOCK_GAS_LIMIT;
|
||||
|
||||
use crate::OpChainSpec;
|
||||
|
||||
/// The Optimism Mainnet spec
|
||||
pub static OP_MAINNET: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
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: Some(b256!(
|
||||
"7ca38a1916c42007829c55e69d3e9a73265554b586a499015373241b8a3fa48b"
|
||||
)),
|
||||
paris_block_and_final_difficulty: Some((0, U256::from(0))),
|
||||
hardforks: OptimismHardfork::op_mainnet(),
|
||||
base_fee_params: BaseFeeParamsKind::Variable(
|
||||
vec![
|
||||
(EthereumHardfork::London.boxed(), BaseFeeParams::optimism()),
|
||||
(OptimismHardfork::Canyon.boxed(), BaseFeeParams::optimism_canyon()),
|
||||
]
|
||||
.into(),
|
||||
),
|
||||
max_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT,
|
||||
prune_delete_limit: 10000,
|
||||
..Default::default()
|
||||
pub static OP_MAINNET: Lazy<Arc<OpChainSpec>> = Lazy::new(|| {
|
||||
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: Some(b256!(
|
||||
"7ca38a1916c42007829c55e69d3e9a73265554b586a499015373241b8a3fa48b"
|
||||
)),
|
||||
paris_block_and_final_difficulty: Some((0, U256::from(0))),
|
||||
hardforks: OptimismHardfork::op_mainnet(),
|
||||
base_fee_params: BaseFeeParamsKind::Variable(
|
||||
vec![
|
||||
(EthereumHardfork::London.boxed(), BaseFeeParams::optimism()),
|
||||
(OptimismHardfork::Canyon.boxed(), BaseFeeParams::optimism_canyon()),
|
||||
]
|
||||
.into(),
|
||||
),
|
||||
max_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT,
|
||||
prune_delete_limit: 10000,
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
.into()
|
||||
});
|
||||
|
||||
@ -12,27 +12,31 @@ use reth_chainspec::{BaseFeeParams, BaseFeeParamsKind, ChainSpec};
|
||||
use reth_ethereum_forks::{EthereumHardfork, OptimismHardfork};
|
||||
use reth_primitives_traits::constants::ETHEREUM_BLOCK_GAS_LIMIT;
|
||||
|
||||
use crate::OpChainSpec;
|
||||
|
||||
/// The OP Sepolia spec
|
||||
pub static OP_SEPOLIA: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
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: Some(b256!(
|
||||
"102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d"
|
||||
)),
|
||||
paris_block_and_final_difficulty: Some((0, U256::from(0))),
|
||||
hardforks: OptimismHardfork::op_sepolia(),
|
||||
base_fee_params: BaseFeeParamsKind::Variable(
|
||||
vec![
|
||||
(EthereumHardfork::London.boxed(), BaseFeeParams::optimism_sepolia()),
|
||||
(OptimismHardfork::Canyon.boxed(), BaseFeeParams::optimism_sepolia_canyon()),
|
||||
]
|
||||
.into(),
|
||||
),
|
||||
max_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT,
|
||||
prune_delete_limit: 10000,
|
||||
..Default::default()
|
||||
pub static OP_SEPOLIA: Lazy<Arc<OpChainSpec>> = Lazy::new(|| {
|
||||
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: Some(b256!(
|
||||
"102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d"
|
||||
)),
|
||||
paris_block_and_final_difficulty: Some((0, U256::from(0))),
|
||||
hardforks: OptimismHardfork::op_sepolia(),
|
||||
base_fee_params: BaseFeeParamsKind::Variable(
|
||||
vec![
|
||||
(EthereumHardfork::London.boxed(), BaseFeeParams::optimism_sepolia()),
|
||||
(OptimismHardfork::Canyon.boxed(), BaseFeeParams::optimism_sepolia_canyon()),
|
||||
]
|
||||
.into(),
|
||||
),
|
||||
max_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT,
|
||||
prune_delete_limit: 10000,
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
.into()
|
||||
});
|
||||
|
||||
@ -27,7 +27,7 @@ reth-primitives.workspace = true
|
||||
|
||||
## optimisim
|
||||
reth-optimism-primitives.workspace = true
|
||||
reth-optimism-chainspec = { workspace = true, features = ["optimism"] }
|
||||
reth-optimism-chainspec.workspace = true
|
||||
|
||||
reth-chainspec.workspace = true
|
||||
reth-stages-types.workspace = true
|
||||
@ -39,14 +39,11 @@ reth-evm-optimism.workspace = true
|
||||
reth-cli.workspace = true
|
||||
|
||||
# eth
|
||||
alloy-genesis.workspace = true
|
||||
alloy-primitives.workspace = true
|
||||
alloy-rlp.workspace = true
|
||||
|
||||
|
||||
# misc
|
||||
shellexpand.workspace = true
|
||||
serde_json.workspace = true
|
||||
futures-util.workspace = true
|
||||
clap = { workspace = true, features = ["derive", "env"] }
|
||||
|
||||
|
||||
@ -1,41 +1,24 @@
|
||||
use std::{ffi::OsStr, fs, path::PathBuf, sync::Arc};
|
||||
use std::{ffi::OsStr, sync::Arc};
|
||||
|
||||
use alloy_genesis::Genesis;
|
||||
use clap::{builder::TypedValueParser, error::Result, Arg, Command};
|
||||
use reth_chainspec::{ChainSpec, DEV};
|
||||
use reth_cli::chainspec::ChainSpecParser;
|
||||
use reth_optimism_chainspec::{BASE_MAINNET, BASE_SEPOLIA, OP_MAINNET, OP_SEPOLIA};
|
||||
use reth_node_core::args::utils::parse_custom_chain_spec;
|
||||
use reth_optimism_chainspec::{
|
||||
OpChainSpec, BASE_MAINNET, BASE_SEPOLIA, OP_DEV, OP_MAINNET, OP_SEPOLIA,
|
||||
};
|
||||
|
||||
/// Clap value parser for [`ChainSpec`]s.
|
||||
/// Clap value parser for [`OpChainSpec`]s.
|
||||
///
|
||||
/// The value parser matches either a known chain, the path
|
||||
/// to a json file, or a json formatted string in-memory. The json needs to be a Genesis struct.
|
||||
fn chain_value_parser(s: &str) -> eyre::Result<Arc<ChainSpec>, eyre::Error> {
|
||||
fn chain_value_parser(s: &str) -> eyre::Result<Arc<OpChainSpec>, eyre::Error> {
|
||||
Ok(match s {
|
||||
"dev" => DEV.clone(),
|
||||
"dev" => OP_DEV.clone(),
|
||||
"optimism" => OP_MAINNET.clone(),
|
||||
"optimism_sepolia" | "optimism-sepolia" => OP_SEPOLIA.clone(),
|
||||
"base" => BASE_MAINNET.clone(),
|
||||
"base_sepolia" | "base-sepolia" => BASE_SEPOLIA.clone(),
|
||||
_ => {
|
||||
// try to read json from path first
|
||||
let raw = match fs::read_to_string(PathBuf::from(shellexpand::full(s)?.into_owned())) {
|
||||
Ok(raw) => raw,
|
||||
Err(io_err) => {
|
||||
// valid json may start with "\n", but must contain "{"
|
||||
if s.contains('{') {
|
||||
s.to_string()
|
||||
} else {
|
||||
return Err(io_err.into()) // assume invalid path
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// both serialized Genesis and ChainSpec structs supported
|
||||
let genesis: Genesis = serde_json::from_str(&raw)?;
|
||||
|
||||
Arc::new(genesis.into())
|
||||
}
|
||||
_ => Arc::new(OpChainSpec { inner: parse_custom_chain_spec(s)? }),
|
||||
})
|
||||
}
|
||||
|
||||
@ -43,8 +26,9 @@ fn chain_value_parser(s: &str) -> eyre::Result<Arc<ChainSpec>, eyre::Error> {
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct OpChainSpecParser;
|
||||
|
||||
impl ChainSpecParser for OpChainSpecParser {
|
||||
impl ChainSpecParser<OpChainSpec> for OpChainSpecParser {
|
||||
const SUPPORTED_CHAINS: &'static [&'static str] = &[
|
||||
"dev",
|
||||
"optimism",
|
||||
"optimism_sepolia",
|
||||
"optimism-sepolia",
|
||||
@ -53,13 +37,13 @@ impl ChainSpecParser for OpChainSpecParser {
|
||||
"base-sepolia",
|
||||
];
|
||||
|
||||
fn parse(s: &str) -> eyre::Result<Arc<ChainSpec>> {
|
||||
fn parse(s: &str) -> eyre::Result<Arc<OpChainSpec>> {
|
||||
chain_value_parser(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl TypedValueParser for OpChainSpecParser {
|
||||
type Value = Arc<ChainSpec>;
|
||||
type Value = Arc<OpChainSpec>;
|
||||
|
||||
fn parse_ref(
|
||||
&self,
|
||||
@ -69,7 +53,7 @@ impl TypedValueParser for OpChainSpecParser {
|
||||
) -> Result<Self::Value, clap::Error> {
|
||||
let val =
|
||||
value.to_str().ok_or_else(|| clap::Error::new(clap::error::ErrorKind::InvalidUtf8))?;
|
||||
<Self as ChainSpecParser>::parse(val).map_err(|err| {
|
||||
<Self as ChainSpecParser<OpChainSpec>>::parse(val).map_err(|err| {
|
||||
let arg = arg.map(|a| a.to_string()).unwrap_or_else(|| "...".to_owned());
|
||||
let possible_values = Self::SUPPORTED_CHAINS.join(", ");
|
||||
clap::Error::raw(
|
||||
@ -96,7 +80,7 @@ mod tests {
|
||||
#[test]
|
||||
fn parse_known_chain_spec() {
|
||||
for &chain in OpChainSpecParser::SUPPORTED_CHAINS {
|
||||
assert!(<OpChainSpecParser as ChainSpecParser>::parse(chain).is_ok());
|
||||
assert!(<OpChainSpecParser as ChainSpecParser<OpChainSpec>>::parse(chain).is_ok());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,6 +34,7 @@ tracing.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
reth-revm = { workspace = true, features = ["test-utils"] }
|
||||
reth-optimism-chainspec.workspace = true
|
||||
|
||||
[features]
|
||||
optimism = [
|
||||
|
||||
@ -501,8 +501,11 @@ mod tests {
|
||||
let account = Account { balance: U256::MAX, ..Account::default() };
|
||||
db.insert_account(addr, account, None, HashMap::new());
|
||||
|
||||
let chain_spec =
|
||||
Arc::new(ChainSpecBuilder::from(&*BASE_MAINNET).regolith_activated().build());
|
||||
let chain_spec = Arc::new(
|
||||
ChainSpecBuilder::from(&Arc::new(BASE_MAINNET.inner.clone()))
|
||||
.regolith_activated()
|
||||
.build(),
|
||||
);
|
||||
|
||||
let tx = TransactionSigned::from_transaction_and_signature(
|
||||
Transaction::Eip1559(TxEip1559 {
|
||||
@ -582,8 +585,11 @@ mod tests {
|
||||
|
||||
db.insert_account(addr, account, None, HashMap::new());
|
||||
|
||||
let chain_spec =
|
||||
Arc::new(ChainSpecBuilder::from(&*BASE_MAINNET).canyon_activated().build());
|
||||
let chain_spec = Arc::new(
|
||||
ChainSpecBuilder::from(&Arc::new(BASE_MAINNET.inner.clone()))
|
||||
.canyon_activated()
|
||||
.build(),
|
||||
);
|
||||
|
||||
let tx = TransactionSigned::from_transaction_and_signature(
|
||||
Transaction::Eip1559(TxEip1559 {
|
||||
|
||||
@ -37,7 +37,7 @@ reth-rpc-eth-types.workspace = true
|
||||
reth-rpc-eth-api.workspace = true
|
||||
reth-optimism-rpc.workspace = true
|
||||
reth-rpc.workspace = true
|
||||
reth-optimism-chainspec = { workspace = true, features = ["optimism"] }
|
||||
reth-optimism-chainspec.workspace = true
|
||||
|
||||
# async
|
||||
async-trait.workspace = true
|
||||
|
||||
@ -20,7 +20,7 @@ reth-trie-common.workspace = true
|
||||
revm-primitives = { workspace = true, features = ["serde"] }
|
||||
reth-chainspec = { workspace = true, optional = true }
|
||||
reth-codecs = { workspace = true, optional = true }
|
||||
reth-optimism-chainspec = { workspace = true, optional = true, features = ["optimism"] }
|
||||
reth-optimism-chainspec = { workspace = true, optional = true }
|
||||
|
||||
# ethereum
|
||||
alloy-primitives = { workspace = true, features = ["rand", "rlp"] }
|
||||
|
||||
Reference in New Issue
Block a user