mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
refactor: extract Chainspec type from primitives (#8055)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de> Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com> Co-authored-by: joshieDo <93316087+joshieDo@users.noreply.github.com>
This commit is contained in:
26
Cargo.lock
generated
26
Cargo.lock
generated
@ -6498,6 +6498,29 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reth-chainspec"
|
||||
version = "1.0.0-rc.1"
|
||||
dependencies = [
|
||||
"alloy-chains",
|
||||
"alloy-eips 0.1.0",
|
||||
"alloy-genesis",
|
||||
"alloy-primitives",
|
||||
"alloy-rlp",
|
||||
"alloy-trie",
|
||||
"derive_more",
|
||||
"nybbles",
|
||||
"once_cell",
|
||||
"rand 0.8.5",
|
||||
"reth-ethereum-forks",
|
||||
"reth-network-peers",
|
||||
"reth-primitives-traits",
|
||||
"reth-rpc-types",
|
||||
"reth-trie-common",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reth-cli-runner"
|
||||
version = "1.0.0-rc.1"
|
||||
@ -7660,7 +7683,6 @@ dependencies = [
|
||||
name = "reth-primitives"
|
||||
version = "1.0.0-rc.1"
|
||||
dependencies = [
|
||||
"alloy-chains",
|
||||
"alloy-consensus 0.1.0",
|
||||
"alloy-eips 0.1.0",
|
||||
"alloy-genesis",
|
||||
@ -7683,9 +7705,9 @@ dependencies = [
|
||||
"proptest-derive",
|
||||
"rand 0.8.5",
|
||||
"rayon",
|
||||
"reth-chainspec",
|
||||
"reth-codecs",
|
||||
"reth-ethereum-forks",
|
||||
"reth-network-peers",
|
||||
"reth-primitives-traits",
|
||||
"reth-static-file-types",
|
||||
"reth-trie-common",
|
||||
|
||||
@ -13,6 +13,7 @@ members = [
|
||||
"bin/reth/",
|
||||
"crates/blockchain-tree/",
|
||||
"crates/blockchain-tree-api/",
|
||||
"crates/chainspec/",
|
||||
"crates/cli/runner/",
|
||||
"crates/config/",
|
||||
"crates/consensus/auto-seal/",
|
||||
@ -246,6 +247,7 @@ reth-basic-payload-builder = { path = "crates/payload/basic" }
|
||||
reth-beacon-consensus = { path = "crates/consensus/beacon" }
|
||||
reth-blockchain-tree = { path = "crates/blockchain-tree" }
|
||||
reth-blockchain-tree-api = { path = "crates/blockchain-tree-api" }
|
||||
reth-chainspec = { path = "crates/chainspec" }
|
||||
reth-cli-runner = { path = "crates/cli/runner" }
|
||||
reth-codecs = { path = "crates/storage/codecs" }
|
||||
reth-codecs-derive = { path = "crates/storage/codecs/derive" }
|
||||
|
||||
53
crates/chainspec/Cargo.toml
Normal file
53
crates/chainspec/Cargo.toml
Normal file
@ -0,0 +1,53 @@
|
||||
[package]
|
||||
name = "reth-chainspec"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
homepage.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
# reth
|
||||
reth-ethereum-forks.workspace = true
|
||||
reth-network-peers.workspace = true
|
||||
reth-trie-common.workspace = true
|
||||
reth-primitives-traits.workspace = true
|
||||
|
||||
# ethereum
|
||||
alloy-chains = { workspace = true, features = ["serde", "rlp"] }
|
||||
alloy-eips = { workspace = true, features = ["serde"] }
|
||||
alloy-genesis.workspace = true
|
||||
alloy-primitives = { workspace = true, features = ["rand", "rlp"] }
|
||||
alloy-trie.workspace = true
|
||||
|
||||
# misc
|
||||
once_cell.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
derive_more.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
# eth
|
||||
nybbles = { workspace = true, features = ["arbitrary"] }
|
||||
alloy-trie = { workspace = true, features = ["arbitrary"] }
|
||||
alloy-eips = { workspace = true, features = ["arbitrary"] }
|
||||
alloy-rlp = { workspace = true, features = ["arrayvec"] }
|
||||
alloy-genesis.workspace = true
|
||||
reth-rpc-types.workspace = true
|
||||
rand.workspace = true
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
optimism = [
|
||||
"reth-ethereum-forks/optimism"
|
||||
]
|
||||
std = []
|
||||
arbitrary = [
|
||||
"alloy-chains/arbitrary"
|
||||
]
|
||||
|
||||
|
||||
49
crates/chainspec/src/constants/mod.rs
Normal file
49
crates/chainspec/src/constants/mod.rs
Normal file
@ -0,0 +1,49 @@
|
||||
use crate::spec::DepositContract;
|
||||
use alloy_primitives::{address, b256};
|
||||
|
||||
/// Deposit contract address: `0x00000000219ab540356cbb839cbe05303d7705fa`
|
||||
pub(crate) const MAINNET_DEPOSIT_CONTRACT: DepositContract = DepositContract::new(
|
||||
address!("00000000219ab540356cbb839cbe05303d7705fa"),
|
||||
11052984,
|
||||
b256!("649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5"),
|
||||
);
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
pub(crate) mod optimism;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use alloy_eips::calc_next_block_base_fee;
|
||||
|
||||
#[test]
|
||||
fn calculate_base_fee_success() {
|
||||
let base_fee = [
|
||||
1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
|
||||
1, 2,
|
||||
];
|
||||
let gas_used = [
|
||||
10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
|
||||
10000000,
|
||||
];
|
||||
let gas_limit = [
|
||||
10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
|
||||
18000000, 18000000,
|
||||
];
|
||||
let next_base_fee = [
|
||||
1125000000, 1083333333, 1053571428, 1179939062, 1116028649, 918084097, 1063811730, 1,
|
||||
2, 3,
|
||||
];
|
||||
|
||||
for i in 0..base_fee.len() {
|
||||
assert_eq!(
|
||||
next_base_fee[i],
|
||||
calc_next_block_base_fee(
|
||||
gas_used[i] as u128,
|
||||
gas_limit[i] as u128,
|
||||
base_fee[i] as u128,
|
||||
crate::BaseFeeParams::ethereum(),
|
||||
) as u64
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
148
crates/chainspec/src/constants/optimism.rs
Normal file
148
crates/chainspec/src/constants/optimism.rs
Normal file
@ -0,0 +1,148 @@
|
||||
use alloy_eips::eip1559::BaseFeeParams;
|
||||
use reth_primitives_traits::constants::{
|
||||
BASE_SEPOLIA_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
|
||||
OP_MAINNET_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_CANYON,
|
||||
OP_MAINNET_EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR,
|
||||
OP_MAINNET_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
|
||||
OP_SEPOLIA_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_CANYON,
|
||||
OP_SEPOLIA_EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR,
|
||||
OP_SEPOLIA_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
|
||||
};
|
||||
|
||||
/// Get the base fee parameters for Base Sepolia.
|
||||
pub(crate) const BASE_SEPOLIA_BASE_FEE_PARAMS: BaseFeeParams = BaseFeeParams {
|
||||
max_change_denominator: OP_SEPOLIA_EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR,
|
||||
elasticity_multiplier: BASE_SEPOLIA_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
|
||||
};
|
||||
|
||||
/// Get the base fee parameters for Base Sepolia (post Canyon).
|
||||
pub(crate) const BASE_SEPOLIA_CANYON_BASE_FEE_PARAMS: BaseFeeParams = BaseFeeParams {
|
||||
max_change_denominator: OP_SEPOLIA_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_CANYON,
|
||||
elasticity_multiplier: BASE_SEPOLIA_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
|
||||
};
|
||||
|
||||
/// Get the base fee parameters for Optimism Sepolia.
|
||||
pub(crate) const OP_SEPOLIA_BASE_FEE_PARAMS: BaseFeeParams = BaseFeeParams {
|
||||
max_change_denominator: OP_SEPOLIA_EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR,
|
||||
elasticity_multiplier: OP_SEPOLIA_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
|
||||
};
|
||||
|
||||
/// Get the base fee parameters for Optimism Sepolia (post Canyon).
|
||||
pub(crate) const OP_SEPOLIA_CANYON_BASE_FEE_PARAMS: BaseFeeParams = BaseFeeParams {
|
||||
max_change_denominator: OP_SEPOLIA_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_CANYON,
|
||||
elasticity_multiplier: OP_SEPOLIA_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
|
||||
};
|
||||
|
||||
/// Get the base fee parameters for Optimism Mainnet.
|
||||
pub(crate) const OP_BASE_FEE_PARAMS: BaseFeeParams = BaseFeeParams {
|
||||
max_change_denominator: OP_MAINNET_EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR,
|
||||
elasticity_multiplier: OP_MAINNET_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
|
||||
};
|
||||
|
||||
/// Get the base fee parameters for Optimism Mainnet (post Canyon).
|
||||
pub(crate) const OP_CANYON_BASE_FEE_PARAMS: BaseFeeParams = BaseFeeParams {
|
||||
max_change_denominator: OP_MAINNET_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_CANYON,
|
||||
elasticity_multiplier: OP_MAINNET_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use alloy_eips::calc_next_block_base_fee;
|
||||
|
||||
#[test]
|
||||
fn calculate_optimism_base_fee_success() {
|
||||
let base_fee = [
|
||||
1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
|
||||
1, 2,
|
||||
];
|
||||
let gas_used = [
|
||||
10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
|
||||
10000000,
|
||||
];
|
||||
let gas_limit = [
|
||||
10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
|
||||
18000000, 18000000,
|
||||
];
|
||||
let next_base_fee = [
|
||||
1100000048, 1080000000, 1065714297, 1167067046, 1128881311, 1028254188, 1098203452, 1,
|
||||
2, 3,
|
||||
];
|
||||
|
||||
for i in 0..base_fee.len() {
|
||||
assert_eq!(
|
||||
next_base_fee[i],
|
||||
calc_next_block_base_fee(
|
||||
gas_used[i] as u128,
|
||||
gas_limit[i] as u128,
|
||||
base_fee[i] as u128,
|
||||
OP_BASE_FEE_PARAMS,
|
||||
) as u64
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn calculate_optimism_sepolia_base_fee_success() {
|
||||
let base_fee = [
|
||||
1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
|
||||
1, 2,
|
||||
];
|
||||
let gas_used = [
|
||||
10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
|
||||
10000000,
|
||||
];
|
||||
let gas_limit = [
|
||||
10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
|
||||
18000000, 18000000,
|
||||
];
|
||||
let next_base_fee = [
|
||||
1100000048, 1080000000, 1065714297, 1167067046, 1128881311, 1028254188, 1098203452, 1,
|
||||
2, 3,
|
||||
];
|
||||
|
||||
for i in 0..base_fee.len() {
|
||||
assert_eq!(
|
||||
next_base_fee[i],
|
||||
calc_next_block_base_fee(
|
||||
gas_used[i] as u128,
|
||||
gas_limit[i] as u128,
|
||||
base_fee[i] as u128,
|
||||
OP_SEPOLIA_BASE_FEE_PARAMS,
|
||||
) as u64
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn calculate_base_sepolia_base_fee_success() {
|
||||
let base_fee = [
|
||||
1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
|
||||
1, 2,
|
||||
];
|
||||
let gas_used = [
|
||||
10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
|
||||
10000000,
|
||||
];
|
||||
let gas_limit = [
|
||||
10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
|
||||
18000000, 18000000,
|
||||
];
|
||||
let next_base_fee = [
|
||||
1180000000, 1146666666, 1122857142, 1244299375, 1189416692, 1028254188, 1144836295, 1,
|
||||
2, 3,
|
||||
];
|
||||
|
||||
for i in 0..base_fee.len() {
|
||||
assert_eq!(
|
||||
next_base_fee[i],
|
||||
calc_next_block_base_fee(
|
||||
gas_used[i] as u128,
|
||||
gas_limit[i] as u128,
|
||||
base_fee[i] as u128,
|
||||
BASE_SEPOLIA_BASE_FEE_PARAMS,
|
||||
) as u64
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
use crate::{BlockNumHash, BlockNumber, B256};
|
||||
use alloy_eips::BlockNumHash;
|
||||
use alloy_primitives::{BlockNumber, B256};
|
||||
|
||||
/// Current status of the blockchain's head.
|
||||
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
|
||||
@ -1,3 +1,13 @@
|
||||
//! The spec of an Ethereum network
|
||||
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
|
||||
html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
|
||||
issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
|
||||
)]
|
||||
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||
|
||||
pub use alloy_chains::{Chain, ChainKind, NamedChain};
|
||||
pub use info::ChainInfo;
|
||||
pub use spec::{
|
||||
@ -8,21 +18,24 @@ pub use spec::{
|
||||
#[cfg(feature = "optimism")]
|
||||
pub use spec::{BASE_MAINNET, BASE_SEPOLIA, OP_MAINNET, OP_SEPOLIA};
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
#[cfg(test)]
|
||||
pub(crate) use spec::{
|
||||
BASE_SEPOLIA_BASE_FEE_PARAMS, OP_BASE_FEE_PARAMS, OP_SEPOLIA_BASE_FEE_PARAMS,
|
||||
};
|
||||
|
||||
// The chain spec module.
|
||||
mod spec;
|
||||
// The chain info module.
|
||||
// /// The config info module namely spec id.
|
||||
// pub mod config;
|
||||
/// The chain info module.
|
||||
mod info;
|
||||
|
||||
/// Network related constants
|
||||
pub mod net;
|
||||
|
||||
/// The chain spec module.
|
||||
mod spec;
|
||||
|
||||
/// Chain specific constants
|
||||
pub(crate) mod constants;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::U256;
|
||||
use alloy_primitives::U256;
|
||||
use alloy_rlp::Encodable;
|
||||
use std::str::FromStr;
|
||||
|
||||
@ -1,24 +1,4 @@
|
||||
use crate::{
|
||||
constants::{
|
||||
EIP1559_INITIAL_BASE_FEE, EMPTY_RECEIPTS, EMPTY_ROOT_HASH, EMPTY_TRANSACTIONS,
|
||||
EMPTY_WITHDRAWALS,
|
||||
},
|
||||
holesky_nodes,
|
||||
net::{goerli_nodes, mainnet_nodes, sepolia_nodes},
|
||||
revm_primitives::{address, b256},
|
||||
Address, BlockNumber, Chain, ChainKind, ForkFilter, ForkFilterKey, ForkHash, ForkId, Genesis,
|
||||
Hardfork, Head, Header, NamedChain, NodeRecord, SealedHeader, B256, EMPTY_OMMER_ROOT_HASH,
|
||||
MAINNET_DEPOSIT_CONTRACT, U256,
|
||||
};
|
||||
use core::{
|
||||
fmt,
|
||||
fmt::{Display, Formatter},
|
||||
};
|
||||
use derive_more::From;
|
||||
use once_cell::sync::Lazy;
|
||||
use reth_trie_common::root::state_root_ref_unhashed;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::constants::MAINNET_DEPOSIT_CONTRACT;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::{
|
||||
collections::BTreeMap,
|
||||
@ -27,25 +7,46 @@ use alloc::{
|
||||
sync::Arc,
|
||||
vec::Vec,
|
||||
};
|
||||
use alloy_chains::{Chain, ChainKind, NamedChain};
|
||||
use alloy_genesis::Genesis;
|
||||
use alloy_primitives::{address, b256, Address, BlockNumber, B256, U256};
|
||||
use alloy_trie::EMPTY_ROOT_HASH;
|
||||
use core::{
|
||||
fmt,
|
||||
fmt::{Display, Formatter},
|
||||
};
|
||||
use derive_more::From;
|
||||
use once_cell::sync::Lazy;
|
||||
use reth_ethereum_forks::{ForkFilter, ForkFilterKey, ForkHash, ForkId, Hardfork, Head};
|
||||
use reth_network_peers::NodeRecord;
|
||||
use reth_primitives_traits::{
|
||||
constants::{
|
||||
EIP1559_INITIAL_BASE_FEE, EMPTY_OMMER_ROOT_HASH, EMPTY_RECEIPTS, EMPTY_TRANSACTIONS,
|
||||
EMPTY_WITHDRAWALS,
|
||||
},
|
||||
Header, SealedHeader,
|
||||
};
|
||||
use reth_trie_common::root::state_root_ref_unhashed;
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "std")]
|
||||
use std::{collections::BTreeMap, sync::Arc};
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
use crate::constants::optimism::{
|
||||
BASE_SEPOLIA_BASE_FEE_PARAMS, BASE_SEPOLIA_CANYON_BASE_FEE_PARAMS, OP_BASE_FEE_PARAMS,
|
||||
OP_CANYON_BASE_FEE_PARAMS, OP_SEPOLIA_BASE_FEE_PARAMS, OP_SEPOLIA_CANYON_BASE_FEE_PARAMS,
|
||||
};
|
||||
pub use alloy_eips::eip1559::BaseFeeParams;
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
pub(crate) use crate::{
|
||||
constants::{
|
||||
BASE_SEPOLIA_BASE_FEE_PARAMS, BASE_SEPOLIA_CANYON_BASE_FEE_PARAMS, OP_BASE_FEE_PARAMS,
|
||||
OP_CANYON_BASE_FEE_PARAMS, OP_SEPOLIA_BASE_FEE_PARAMS, OP_SEPOLIA_CANYON_BASE_FEE_PARAMS,
|
||||
},
|
||||
net::{base_nodes, base_testnet_nodes, op_nodes, op_testnet_nodes},
|
||||
};
|
||||
use crate::net::{base_nodes, base_testnet_nodes, op_nodes, op_testnet_nodes};
|
||||
use crate::net::{goerli_nodes, holesky_nodes, mainnet_nodes, sepolia_nodes};
|
||||
|
||||
/// The Ethereum mainnet spec
|
||||
pub static MAINNET: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
ChainSpec {
|
||||
chain: Chain::mainnet(),
|
||||
genesis: serde_json::from_str(include_str!("../../res/genesis/mainnet.json"))
|
||||
genesis: serde_json::from_str(include_str!("../res/genesis/mainnet.json"))
|
||||
.expect("Can't deserialize Mainnet genesis json"),
|
||||
genesis_hash: Some(b256!(
|
||||
"d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"
|
||||
@ -96,7 +97,7 @@ pub static MAINNET: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
pub static GOERLI: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
ChainSpec {
|
||||
chain: Chain::goerli(),
|
||||
genesis: serde_json::from_str(include_str!("../../res/genesis/goerli.json"))
|
||||
genesis: serde_json::from_str(include_str!("../res/genesis/goerli.json"))
|
||||
.expect("Can't deserialize Goerli genesis json"),
|
||||
genesis_hash: Some(b256!(
|
||||
"bf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a"
|
||||
@ -138,7 +139,7 @@ pub static GOERLI: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
pub static SEPOLIA: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
ChainSpec {
|
||||
chain: Chain::sepolia(),
|
||||
genesis: serde_json::from_str(include_str!("../../res/genesis/sepolia.json"))
|
||||
genesis: serde_json::from_str(include_str!("../res/genesis/sepolia.json"))
|
||||
.expect("Can't deserialize Sepolia genesis json"),
|
||||
genesis_hash: Some(b256!(
|
||||
"25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9"
|
||||
@ -184,7 +185,7 @@ pub static SEPOLIA: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
pub static HOLESKY: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
ChainSpec {
|
||||
chain: Chain::holesky(),
|
||||
genesis: serde_json::from_str(include_str!("../../res/genesis/holesky.json"))
|
||||
genesis: serde_json::from_str(include_str!("../res/genesis/holesky.json"))
|
||||
.expect("Can't deserialize Holesky genesis json"),
|
||||
genesis_hash: Some(b256!(
|
||||
"b5f7f912443c940f21fd611f12828d75b534364ed9e95ca4e307729a4661bde4"
|
||||
@ -228,7 +229,7 @@ pub static HOLESKY: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
pub static DEV: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
ChainSpec {
|
||||
chain: Chain::dev(),
|
||||
genesis: serde_json::from_str(include_str!("../../res/genesis/dev.json"))
|
||||
genesis: serde_json::from_str(include_str!("../res/genesis/dev.json"))
|
||||
.expect("Can't deserialize Dev testnet genesis json"),
|
||||
genesis_hash: Some(b256!(
|
||||
"2f980576711e3617a5e4d83dd539548ec0f7792007d505a3d2e9674833af2d7c"
|
||||
@ -274,7 +275,7 @@ pub static OP_MAINNET: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
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"))
|
||||
genesis: serde_json::from_str(include_str!("../res/genesis/optimism.json"))
|
||||
.expect("Can't deserialize Optimism Mainnet genesis json"),
|
||||
genesis_hash: Some(b256!(
|
||||
"7ca38a1916c42007829c55e69d3e9a73265554b586a499015373241b8a3fa48b"
|
||||
@ -324,7 +325,7 @@ pub static OP_MAINNET: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
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"))
|
||||
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"
|
||||
@ -374,7 +375,7 @@ pub static OP_SEPOLIA: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
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"))
|
||||
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"
|
||||
@ -424,7 +425,7 @@ pub static BASE_SEPOLIA: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
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"))
|
||||
genesis: serde_json::from_str(include_str!("../res/genesis/base.json"))
|
||||
.expect("Can't deserialize Base genesis json"),
|
||||
genesis_hash: Some(b256!(
|
||||
"f712aa9241cc24369b143cf6dce85f0902a9731e70d66818a3a5845b296c73dd"
|
||||
@ -852,12 +853,6 @@ impl ChainSpec {
|
||||
self.fork(Hardfork::Homestead).active_at_block(block_number)
|
||||
}
|
||||
|
||||
/// The Paris hardfork (merge) is activated via ttd, if we know the block is known then this
|
||||
/// returns true if the block number is greater than or equal to the Paris (merge) block.
|
||||
pub fn is_paris_active_at_block(&self, block_number: u64) -> Option<bool> {
|
||||
self.paris_block_and_final_difficulty.map(|(paris_block, _)| block_number >= paris_block)
|
||||
}
|
||||
|
||||
/// Convenience method to check if [`Hardfork::Bedrock`] is active at a given block number.
|
||||
#[cfg(feature = "optimism")]
|
||||
#[inline]
|
||||
@ -1523,7 +1518,7 @@ impl Display for DisplayFork {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use reth_primitives::MAINNET;
|
||||
/// # use reth_chainspec::MAINNET;
|
||||
/// println!("{}", MAINNET.display_hardforks());
|
||||
/// ```
|
||||
///
|
||||
@ -1737,11 +1732,15 @@ impl OptimismGenesisInfo {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use alloy_chains::Chain;
|
||||
use alloy_genesis::{ChainConfig, GenesisAccount};
|
||||
use reth_ethereum_forks::{ForkHash, ForkId, Head};
|
||||
use reth_trie_common::TrieAccount;
|
||||
|
||||
use super::*;
|
||||
use crate::{b256, hex, ChainConfig, GenesisAccount};
|
||||
use alloy_primitives::{b256, hex};
|
||||
use std::{collections::HashMap, str::FromStr};
|
||||
|
||||
fn test_fork_ids(spec: &ChainSpec, cases: &[(Head, ForkId)]) {
|
||||
for (block, expected_id) in cases {
|
||||
let computed_id = spec.fork_id(block);
|
||||
@ -16,14 +16,13 @@ workspace = true
|
||||
reth-primitives-traits.workspace = true
|
||||
reth-codecs.workspace = true
|
||||
reth-ethereum-forks.workspace = true
|
||||
reth-network-peers.workspace = true
|
||||
reth-static-file-types.workspace = true
|
||||
reth-trie-common.workspace = true
|
||||
reth-chainspec.workspace = true
|
||||
revm.workspace = true
|
||||
revm-primitives = { workspace = true, features = ["serde"] }
|
||||
|
||||
# ethereum
|
||||
alloy-chains = { workspace = true, features = ["serde", "rlp"] }
|
||||
alloy-consensus = { workspace = true, features = ["serde"] }
|
||||
alloy-primitives = { workspace = true, features = ["rand", "rlp"] }
|
||||
alloy-rlp = { workspace = true, features = ["arrayvec"] }
|
||||
@ -48,7 +47,6 @@ modular-bitfield.workspace = true
|
||||
once_cell.workspace = true
|
||||
rayon.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
tempfile = { workspace = true, optional = true }
|
||||
thiserror-no-std = { workspace = true , default-features = false }
|
||||
zstd = { version = "0.13", features = ["experimental"], optional = true }
|
||||
@ -92,10 +90,10 @@ asm-keccak = ["alloy-primitives/asm-keccak"]
|
||||
arbitrary = [
|
||||
"reth-primitives-traits/arbitrary",
|
||||
"revm-primitives/arbitrary",
|
||||
"reth-chainspec/arbitrary",
|
||||
"reth-ethereum-forks/arbitrary",
|
||||
"nybbles/arbitrary",
|
||||
"alloy-trie/arbitrary",
|
||||
"alloy-chains/arbitrary",
|
||||
"alloy-consensus/arbitrary",
|
||||
"alloy-eips/arbitrary",
|
||||
"dep:arbitrary",
|
||||
@ -112,6 +110,7 @@ c-kzg = [
|
||||
]
|
||||
zstd-codec = ["dep:zstd"]
|
||||
optimism = [
|
||||
"reth-chainspec/optimism",
|
||||
"reth-codecs/optimism",
|
||||
"reth-ethereum-forks/optimism",
|
||||
"revm/optimism",
|
||||
|
||||
@ -3,144 +3,3 @@
|
||||
// re-export
|
||||
#[doc(inline)]
|
||||
pub use alloy_eips::eip1559::calc_next_block_base_fee;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
use crate::chain::{
|
||||
BASE_SEPOLIA_BASE_FEE_PARAMS, OP_BASE_FEE_PARAMS, OP_SEPOLIA_BASE_FEE_PARAMS,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn calculate_base_fee_success() {
|
||||
let base_fee = [
|
||||
1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
|
||||
1, 2,
|
||||
];
|
||||
let gas_used = [
|
||||
10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
|
||||
10000000,
|
||||
];
|
||||
let gas_limit = [
|
||||
10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
|
||||
18000000, 18000000,
|
||||
];
|
||||
let next_base_fee = [
|
||||
1125000000, 1083333333, 1053571428, 1179939062, 1116028649, 918084097, 1063811730, 1,
|
||||
2, 3,
|
||||
];
|
||||
|
||||
for i in 0..base_fee.len() {
|
||||
assert_eq!(
|
||||
next_base_fee[i],
|
||||
calc_next_block_base_fee(
|
||||
gas_used[i] as u128,
|
||||
gas_limit[i] as u128,
|
||||
base_fee[i] as u128,
|
||||
crate::BaseFeeParams::ethereum(),
|
||||
) as u64
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
#[test]
|
||||
fn calculate_optimism_base_fee_success() {
|
||||
let base_fee = [
|
||||
1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
|
||||
1, 2,
|
||||
];
|
||||
let gas_used = [
|
||||
10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
|
||||
10000000,
|
||||
];
|
||||
let gas_limit = [
|
||||
10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
|
||||
18000000, 18000000,
|
||||
];
|
||||
let next_base_fee = [
|
||||
1100000048, 1080000000, 1065714297, 1167067046, 1128881311, 1028254188, 1098203452, 1,
|
||||
2, 3,
|
||||
];
|
||||
|
||||
for i in 0..base_fee.len() {
|
||||
assert_eq!(
|
||||
next_base_fee[i],
|
||||
calc_next_block_base_fee(
|
||||
gas_used[i] as u128,
|
||||
gas_limit[i] as u128,
|
||||
base_fee[i] as u128,
|
||||
OP_BASE_FEE_PARAMS,
|
||||
) as u64
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
#[test]
|
||||
fn calculate_optimism_sepolia_base_fee_success() {
|
||||
let base_fee = [
|
||||
1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
|
||||
1, 2,
|
||||
];
|
||||
let gas_used = [
|
||||
10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
|
||||
10000000,
|
||||
];
|
||||
let gas_limit = [
|
||||
10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
|
||||
18000000, 18000000,
|
||||
];
|
||||
let next_base_fee = [
|
||||
1100000048, 1080000000, 1065714297, 1167067046, 1128881311, 1028254188, 1098203452, 1,
|
||||
2, 3,
|
||||
];
|
||||
|
||||
for i in 0..base_fee.len() {
|
||||
assert_eq!(
|
||||
next_base_fee[i],
|
||||
calc_next_block_base_fee(
|
||||
gas_used[i] as u128,
|
||||
gas_limit[i] as u128,
|
||||
base_fee[i] as u128,
|
||||
OP_SEPOLIA_BASE_FEE_PARAMS,
|
||||
) as u64
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
#[test]
|
||||
fn calculate_base_sepolia_base_fee_success() {
|
||||
let base_fee = [
|
||||
1000000000, 1000000000, 1000000000, 1072671875, 1059263476, 1049238967, 1049238967, 0,
|
||||
1, 2,
|
||||
];
|
||||
let gas_used = [
|
||||
10000000, 10000000, 10000000, 9000000, 10001000, 0, 10000000, 10000000, 10000000,
|
||||
10000000,
|
||||
];
|
||||
let gas_limit = [
|
||||
10000000, 12000000, 14000000, 10000000, 14000000, 2000000, 18000000, 18000000,
|
||||
18000000, 18000000,
|
||||
];
|
||||
let next_base_fee = [
|
||||
1180000000, 1146666666, 1122857142, 1244299375, 1189416692, 1028254188, 1144836295, 1,
|
||||
2, 3,
|
||||
];
|
||||
|
||||
for i in 0..base_fee.len() {
|
||||
assert_eq!(
|
||||
next_base_fee[i],
|
||||
calc_next_block_base_fee(
|
||||
gas_used[i] as u128,
|
||||
gas_limit[i] as u128,
|
||||
base_fee[i] as u128,
|
||||
BASE_SEPOLIA_BASE_FEE_PARAMS,
|
||||
) as u64
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,70 +1,13 @@
|
||||
//! Ethereum protocol-related constants
|
||||
|
||||
use crate::{
|
||||
chain::DepositContract,
|
||||
revm_primitives::{address, b256},
|
||||
};
|
||||
|
||||
pub use reth_primitives_traits::constants::*;
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
use crate::chain::BaseFeeParams;
|
||||
|
||||
/// Gas units, for example [`GIGAGAS`](gas_units::GIGAGAS).
|
||||
pub mod gas_units;
|
||||
|
||||
/// [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844#parameters) constants.
|
||||
pub mod eip4844;
|
||||
|
||||
/// Deposit contract address: `0x00000000219ab540356cbb839cbe05303d7705fa`
|
||||
pub const MAINNET_DEPOSIT_CONTRACT: DepositContract = DepositContract::new(
|
||||
address!("00000000219ab540356cbb839cbe05303d7705fa"),
|
||||
11052984,
|
||||
b256!("649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5"),
|
||||
);
|
||||
|
||||
/// Get the base fee parameters for Base Sepolia.
|
||||
#[cfg(feature = "optimism")]
|
||||
pub const BASE_SEPOLIA_BASE_FEE_PARAMS: BaseFeeParams = BaseFeeParams {
|
||||
max_change_denominator: OP_SEPOLIA_EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR,
|
||||
elasticity_multiplier: BASE_SEPOLIA_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
|
||||
};
|
||||
|
||||
/// Get the base fee parameters for Base Sepolia (post Canyon).
|
||||
#[cfg(feature = "optimism")]
|
||||
pub const BASE_SEPOLIA_CANYON_BASE_FEE_PARAMS: BaseFeeParams = BaseFeeParams {
|
||||
max_change_denominator: OP_SEPOLIA_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_CANYON,
|
||||
elasticity_multiplier: BASE_SEPOLIA_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
|
||||
};
|
||||
|
||||
/// Get the base fee parameters for Optimism Sepolia.
|
||||
#[cfg(feature = "optimism")]
|
||||
pub const OP_SEPOLIA_BASE_FEE_PARAMS: BaseFeeParams = BaseFeeParams {
|
||||
max_change_denominator: OP_SEPOLIA_EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR,
|
||||
elasticity_multiplier: OP_SEPOLIA_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
|
||||
};
|
||||
|
||||
/// Get the base fee parameters for Optimism Sepolia (post Canyon).
|
||||
#[cfg(feature = "optimism")]
|
||||
pub const OP_SEPOLIA_CANYON_BASE_FEE_PARAMS: BaseFeeParams = BaseFeeParams {
|
||||
max_change_denominator: OP_SEPOLIA_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_CANYON,
|
||||
elasticity_multiplier: OP_SEPOLIA_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
|
||||
};
|
||||
|
||||
/// Get the base fee parameters for Optimism Mainnet.
|
||||
#[cfg(feature = "optimism")]
|
||||
pub const OP_BASE_FEE_PARAMS: BaseFeeParams = BaseFeeParams {
|
||||
max_change_denominator: OP_MAINNET_EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR,
|
||||
elasticity_multiplier: OP_MAINNET_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
|
||||
};
|
||||
|
||||
/// Get the base fee parameters for Optimism Mainnet (post Canyon).
|
||||
#[cfg(feature = "optimism")]
|
||||
pub const OP_CANYON_BASE_FEE_PARAMS: BaseFeeParams = BaseFeeParams {
|
||||
max_change_denominator: OP_MAINNET_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_CANYON,
|
||||
elasticity_multiplier: OP_MAINNET_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@ -27,7 +27,6 @@ mod account;
|
||||
mod alloy_compat;
|
||||
pub mod basefee;
|
||||
mod block;
|
||||
mod chain;
|
||||
#[cfg(feature = "zstd-codec")]
|
||||
mod compression;
|
||||
pub mod constants;
|
||||
@ -37,7 +36,6 @@ pub mod genesis;
|
||||
pub mod header;
|
||||
mod integer_list;
|
||||
mod log;
|
||||
mod net;
|
||||
pub mod proofs;
|
||||
mod receipt;
|
||||
mod request;
|
||||
@ -54,31 +52,31 @@ pub use block::{
|
||||
Block, BlockBody, BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag, BlockWithSenders,
|
||||
ForkBlock, RpcBlockHash, SealedBlock, SealedBlockWithSenders,
|
||||
};
|
||||
pub use chain::{
|
||||
AllGenesisFormats, BaseFeeParams, BaseFeeParamsKind, Chain, ChainInfo, ChainKind, ChainSpec,
|
||||
ChainSpecBuilder, DepositContract, DisplayHardforks, ForkBaseFeeParams, ForkCondition,
|
||||
NamedChain, DEV, GOERLI, HOLESKY, MAINNET, SEPOLIA,
|
||||
};
|
||||
#[cfg(feature = "zstd-codec")]
|
||||
pub use compression::*;
|
||||
pub use constants::{
|
||||
DEV_GENESIS_HASH, EMPTY_OMMER_ROOT_HASH, GOERLI_GENESIS_HASH, HOLESKY_GENESIS_HASH,
|
||||
KECCAK_EMPTY, MAINNET_DEPOSIT_CONTRACT, MAINNET_GENESIS_HASH, SEPOLIA_GENESIS_HASH,
|
||||
KECCAK_EMPTY, MAINNET_GENESIS_HASH, SEPOLIA_GENESIS_HASH,
|
||||
};
|
||||
pub use error::{GotExpected, GotExpectedBoxed};
|
||||
pub use genesis::{ChainConfig, Genesis, GenesisAccount};
|
||||
pub use header::{Header, HeadersDirection, SealedHeader};
|
||||
pub use integer_list::IntegerList;
|
||||
pub use log::{logs_bloom, Log};
|
||||
pub use net::{
|
||||
goerli_nodes, holesky_nodes, mainnet_nodes, parse_nodes, sepolia_nodes, NodeRecord,
|
||||
NodeRecordParseError, TrustedPeer, GOERLI_BOOTNODES, HOLESKY_BOOTNODES, MAINNET_BOOTNODES,
|
||||
SEPOLIA_BOOTNODES,
|
||||
};
|
||||
pub use receipt::{
|
||||
gas_spent_by_transactions, Receipt, ReceiptWithBloom, ReceiptWithBloomRef, Receipts,
|
||||
};
|
||||
pub use request::Requests;
|
||||
pub use reth_chainspec::{
|
||||
net::{
|
||||
goerli_nodes, holesky_nodes, mainnet_nodes, parse_nodes, sepolia_nodes, NodeRecord,
|
||||
NodeRecordParseError, TrustedPeer, GOERLI_BOOTNODES, HOLESKY_BOOTNODES, MAINNET_BOOTNODES,
|
||||
SEPOLIA_BOOTNODES,
|
||||
},
|
||||
AllGenesisFormats, BaseFeeParams, BaseFeeParamsKind, Chain, ChainInfo, ChainKind, ChainSpec,
|
||||
ChainSpecBuilder, DepositContract, DisplayHardforks, ForkBaseFeeParams, ForkCondition,
|
||||
NamedChain, DEV, GOERLI, HOLESKY, MAINNET, SEPOLIA,
|
||||
};
|
||||
pub use static_file::StaticFileSegment;
|
||||
pub use storage::StorageEntry;
|
||||
|
||||
@ -140,13 +138,13 @@ pub use c_kzg as kzg;
|
||||
/// Optimism specific re-exports
|
||||
#[cfg(feature = "optimism")]
|
||||
mod optimism {
|
||||
pub use crate::{
|
||||
chain::{BASE_MAINNET, BASE_SEPOLIA, OP_MAINNET, OP_SEPOLIA},
|
||||
pub use crate::transaction::{TxDeposit, DEPOSIT_TX_TYPE_ID};
|
||||
pub use reth_chainspec::{
|
||||
net::{
|
||||
base_nodes, base_testnet_nodes, op_nodes, op_testnet_nodes, OP_BOOTNODES,
|
||||
OP_TESTNET_BOOTNODES,
|
||||
},
|
||||
transaction::{TxDeposit, DEPOSIT_TX_TYPE_ID},
|
||||
BASE_MAINNET, BASE_SEPOLIA, OP_MAINNET, OP_SEPOLIA,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user