mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
perf: improve genesis handling (#10878)
This commit is contained in:
@ -1,7 +1,6 @@
|
||||
use core::fmt::Debug;
|
||||
|
||||
use crate::ChainSpec;
|
||||
use alloy_chains::Chain;
|
||||
use core::fmt::Debug;
|
||||
|
||||
/// Trait representing type configuring a chain spec.
|
||||
pub trait EthChainSpec: Send + Sync + Unpin + Debug + 'static {
|
||||
|
||||
@ -33,6 +33,13 @@ pub use spec::{
|
||||
DepositContract, ForkBaseFeeParams, DEV, HOLESKY, MAINNET, SEPOLIA,
|
||||
};
|
||||
|
||||
/// Simple utility to create a `OnceCell` with a value set.
|
||||
pub fn once_cell_set<T>(value: T) -> once_cell::sync::OnceCell<T> {
|
||||
let once = once_cell::sync::OnceCell::new();
|
||||
let _ = once.set(value);
|
||||
once
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@ -1,12 +1,11 @@
|
||||
use crate::{constants::MAINNET_DEPOSIT_CONTRACT, once_cell_set, EthChainSpec};
|
||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||
pub use alloy_eips::eip1559::BaseFeeParams;
|
||||
|
||||
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 derive_more::From;
|
||||
use once_cell::sync::Lazy;
|
||||
use once_cell::sync::{Lazy, OnceCell};
|
||||
#[cfg(feature = "optimism")]
|
||||
use reth_ethereum_forks::OptimismHardfork;
|
||||
use reth_ethereum_forks::{
|
||||
@ -26,7 +25,7 @@ use reth_primitives_traits::{
|
||||
};
|
||||
use reth_trie_common::root::state_root_ref_unhashed;
|
||||
|
||||
use crate::{constants::MAINNET_DEPOSIT_CONTRACT, EthChainSpec};
|
||||
pub use alloy_eips::eip1559::BaseFeeParams;
|
||||
|
||||
/// The Ethereum mainnet spec
|
||||
pub static MAINNET: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
@ -34,7 +33,8 @@ pub static MAINNET: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
chain: Chain::mainnet(),
|
||||
genesis: serde_json::from_str(include_str!("../res/genesis/mainnet.json"))
|
||||
.expect("Can't deserialize Mainnet genesis json"),
|
||||
genesis_hash: Some(MAINNET_GENESIS_HASH),
|
||||
genesis_hash: once_cell_set(MAINNET_GENESIS_HASH),
|
||||
genesis_header: Default::default(),
|
||||
// <https://etherscan.io/block/15537394>
|
||||
paris_block_and_final_difficulty: Some((
|
||||
15537394,
|
||||
@ -61,7 +61,8 @@ pub static SEPOLIA: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
chain: Chain::sepolia(),
|
||||
genesis: serde_json::from_str(include_str!("../res/genesis/sepolia.json"))
|
||||
.expect("Can't deserialize Sepolia genesis json"),
|
||||
genesis_hash: Some(SEPOLIA_GENESIS_HASH),
|
||||
genesis_hash: once_cell_set(SEPOLIA_GENESIS_HASH),
|
||||
genesis_header: Default::default(),
|
||||
// <https://sepolia.etherscan.io/block/1450409>
|
||||
paris_block_and_final_difficulty: Some((1450409, U256::from(17_000_018_015_853_232u128))),
|
||||
hardforks: EthereumHardfork::sepolia().into(),
|
||||
@ -85,7 +86,8 @@ pub static HOLESKY: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
chain: Chain::holesky(),
|
||||
genesis: serde_json::from_str(include_str!("../res/genesis/holesky.json"))
|
||||
.expect("Can't deserialize Holesky genesis json"),
|
||||
genesis_hash: Some(HOLESKY_GENESIS_HASH),
|
||||
genesis_hash: once_cell_set(HOLESKY_GENESIS_HASH),
|
||||
genesis_header: Default::default(),
|
||||
paris_block_and_final_difficulty: Some((0, U256::from(1))),
|
||||
hardforks: EthereumHardfork::holesky().into(),
|
||||
deposit_contract: Some(DepositContract::new(
|
||||
@ -110,7 +112,7 @@ pub static DEV: Lazy<Arc<ChainSpec>> = Lazy::new(|| {
|
||||
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),
|
||||
genesis_hash: once_cell_set(DEV_GENESIS_HASH),
|
||||
paris_block_and_final_difficulty: Some((0, U256::from(0))),
|
||||
hardforks: DEV_HARDFORKS.clone(),
|
||||
base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()),
|
||||
@ -174,14 +176,20 @@ pub struct ChainSpec {
|
||||
/// The chain ID
|
||||
pub chain: Chain,
|
||||
|
||||
/// The genesis block.
|
||||
pub genesis: Genesis,
|
||||
|
||||
/// The hash of the genesis block.
|
||||
///
|
||||
/// This acts as a small cache for known chains. If the chain is known, then the genesis hash
|
||||
/// is also known ahead of time, and this will be `Some`.
|
||||
pub genesis_hash: Option<B256>,
|
||||
/// This is either stored at construction time if it is known using [`once_cell_set`], or
|
||||
/// computed once on the first access.
|
||||
pub genesis_hash: OnceCell<B256>,
|
||||
|
||||
/// The genesis block
|
||||
pub genesis: Genesis,
|
||||
/// The header corresponding to the genesis block.
|
||||
///
|
||||
/// This is either stored at construction time if it is known using [`once_cell_set`], or
|
||||
/// computed once on the first access.
|
||||
pub genesis_header: OnceCell<Header>,
|
||||
|
||||
/// The block at which [`EthereumHardfork::Paris`] was activated and the final difficulty at
|
||||
/// this block.
|
||||
@ -209,6 +217,7 @@ impl Default for ChainSpec {
|
||||
chain: Default::default(),
|
||||
genesis_hash: Default::default(),
|
||||
genesis: Default::default(),
|
||||
genesis_header: Default::default(),
|
||||
paris_block_and_final_difficulty: Default::default(),
|
||||
hardforks: Default::default(),
|
||||
deposit_contract: Default::default(),
|
||||
@ -271,7 +280,11 @@ impl ChainSpec {
|
||||
}
|
||||
|
||||
/// Get the header for the genesis block.
|
||||
pub fn genesis_header(&self) -> Header {
|
||||
pub fn genesis_header(&self) -> &Header {
|
||||
self.genesis_header.get_or_init(|| self.make_genesis_header())
|
||||
}
|
||||
|
||||
fn make_genesis_header(&self) -> Header {
|
||||
// If London is activated at genesis, we set the initial base fee as per EIP-1559.
|
||||
let base_fee_per_gas = self.initial_base_fee();
|
||||
|
||||
@ -323,7 +336,7 @@ impl ChainSpec {
|
||||
|
||||
/// Get the sealed header for the genesis block.
|
||||
pub fn sealed_genesis_header(&self) -> SealedHeader {
|
||||
SealedHeader::new(self.genesis_header(), self.genesis_hash())
|
||||
SealedHeader::new(self.genesis_header().clone(), self.genesis_hash())
|
||||
}
|
||||
|
||||
/// Get the initial base fee of the genesis block.
|
||||
@ -376,7 +389,7 @@ impl ChainSpec {
|
||||
|
||||
/// Get the hash of the genesis block.
|
||||
pub fn genesis_hash(&self) -> B256 {
|
||||
self.genesis_hash.unwrap_or_else(|| self.genesis_header().hash_slow())
|
||||
*self.genesis_hash.get_or_init(|| self.genesis_header().hash_slow())
|
||||
}
|
||||
|
||||
/// Get the timestamp of the genesis block.
|
||||
@ -694,7 +707,7 @@ impl From<Genesis> for ChainSpec {
|
||||
Self {
|
||||
chain: genesis.config.chain_id.into(),
|
||||
genesis,
|
||||
genesis_hash: None,
|
||||
genesis_hash: OnceCell::new(),
|
||||
hardforks: ChainHardforks::new(ordered_hardforks),
|
||||
paris_block_and_final_difficulty,
|
||||
deposit_contract,
|
||||
@ -939,7 +952,7 @@ impl ChainSpecBuilder {
|
||||
ChainSpec {
|
||||
chain: self.chain.expect("The chain is required"),
|
||||
genesis: self.genesis.expect("The genesis is required"),
|
||||
genesis_hash: None,
|
||||
genesis_hash: OnceCell::new(),
|
||||
hardforks: self.hardforks,
|
||||
paris_block_and_final_difficulty,
|
||||
deposit_contract: None,
|
||||
@ -1921,7 +1934,7 @@ Post-merge hard forks (timestamp based):
|
||||
assert_eq!(&alloy_rlp::encode(TrieAccount::from(account.clone())), expected_rlp);
|
||||
}
|
||||
|
||||
assert_eq!(chainspec.genesis_hash, None);
|
||||
assert_eq!(chainspec.genesis_hash.get(), None);
|
||||
let expected_state_root: B256 =
|
||||
hex!("078dc6061b1d8eaa8493384b59c9c65ceb917201221d08b80c4de6770b6ec7e7").into();
|
||||
assert_eq!(chainspec.genesis_header().state_root, expected_state_root);
|
||||
@ -1996,7 +2009,7 @@ Post-merge hard forks (timestamp based):
|
||||
|
||||
let genesis = serde_json::from_str::<Genesis>(hive_json).unwrap();
|
||||
let chainspec: ChainSpec = genesis.into();
|
||||
assert_eq!(chainspec.genesis_hash, None);
|
||||
assert_eq!(chainspec.genesis_hash.get(), None);
|
||||
assert_eq!(chainspec.chain, Chain::from_named(NamedChain::Optimism));
|
||||
let expected_state_root: B256 =
|
||||
hex!("9a6049ac535e3dc7436c189eaa81c73f35abd7f282ab67c32944ff0301d63360").into();
|
||||
@ -2228,7 +2241,7 @@ Post-merge hard forks (timestamp based):
|
||||
.genesis(genesis)
|
||||
.cancun_activated()
|
||||
.build();
|
||||
let mut header = default_chainspec.genesis_header();
|
||||
let mut header = default_chainspec.genesis_header().clone();
|
||||
|
||||
// set the state root to the same as in the hive test the hash was pulled from
|
||||
header.state_root =
|
||||
@ -2311,7 +2324,7 @@ Post-merge hard forks (timestamp based):
|
||||
let spec = ChainSpec {
|
||||
chain: Chain::mainnet(),
|
||||
genesis: Genesis::default(),
|
||||
genesis_hash: None,
|
||||
genesis_hash: OnceCell::new(),
|
||||
hardforks: ChainHardforks::new(vec![(
|
||||
EthereumHardfork::Frontier.boxed(),
|
||||
ForkCondition::Never,
|
||||
@ -2329,7 +2342,7 @@ Post-merge hard forks (timestamp based):
|
||||
let spec = ChainSpec {
|
||||
chain: Chain::mainnet(),
|
||||
genesis: Genesis::default(),
|
||||
genesis_hash: None,
|
||||
genesis_hash: OnceCell::new(),
|
||||
hardforks: ChainHardforks::new(vec![(
|
||||
EthereumHardfork::Shanghai.boxed(),
|
||||
ForkCondition::Never,
|
||||
|
||||
@ -94,7 +94,7 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> EnvironmentArgs<C> {
|
||||
let provider_factory = self.create_provider_factory(&config, db, sfp)?;
|
||||
if access.is_read_write() {
|
||||
debug!(target: "reth::cli", chain=%self.chain.chain, genesis=?self.chain.genesis_hash(), "Initializing genesis");
|
||||
init_genesis(provider_factory.clone())?;
|
||||
init_genesis(&provider_factory)?;
|
||||
}
|
||||
|
||||
Ok(Environment { config, provider_factory, data_dir })
|
||||
|
||||
@ -73,7 +73,7 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
|
||||
StageId::Headers.to_string(),
|
||||
Default::default(),
|
||||
)?;
|
||||
insert_genesis_header(&provider_rw, &static_file_provider, self.env.chain)?;
|
||||
insert_genesis_header(&provider_rw, &static_file_provider, &self.env.chain)?;
|
||||
}
|
||||
StageEnum::Bodies => {
|
||||
tx.clear::<tables::BlockBodyIndices>()?;
|
||||
@ -86,7 +86,7 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
|
||||
StageId::Bodies.to_string(),
|
||||
Default::default(),
|
||||
)?;
|
||||
insert_genesis_header(&provider_rw, &static_file_provider, self.env.chain)?;
|
||||
insert_genesis_header(&provider_rw, &static_file_provider, &self.env.chain)?;
|
||||
}
|
||||
StageEnum::Senders => {
|
||||
tx.clear::<tables::TransactionSenders>()?;
|
||||
@ -173,7 +173,7 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
|
||||
StageId::TransactionLookup.to_string(),
|
||||
Default::default(),
|
||||
)?;
|
||||
insert_genesis_header(&provider_rw, &static_file_provider, self.env.chain)?;
|
||||
insert_genesis_header(&provider_rw, &static_file_provider, &self.env.chain)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -392,7 +392,7 @@ where
|
||||
BlockchainTree::new(externals, BlockchainTreeConfig::new(1, 2, 3, 2))
|
||||
.expect("failed to create tree"),
|
||||
));
|
||||
let genesis_block = self.base_config.chain_spec.genesis_header().seal_slow();
|
||||
let genesis_block = self.base_config.chain_spec.genesis_header().clone().seal_slow();
|
||||
|
||||
let blockchain_provider =
|
||||
BlockchainProvider::with_blocks(provider_factory.clone(), tree, genesis_block, None);
|
||||
|
||||
@ -2691,7 +2691,7 @@ mod tests {
|
||||
|
||||
let (from_tree_tx, from_tree_rx) = unbounded_channel();
|
||||
|
||||
let header = chain_spec.genesis_header().seal_slow();
|
||||
let header = chain_spec.genesis_header().clone().seal_slow();
|
||||
let engine_api_tree_state = EngineApiTreeState::new(10, 10, header.num_hash());
|
||||
let canonical_in_memory_state = CanonicalInMemoryState::with_head(header, None);
|
||||
|
||||
|
||||
@ -417,7 +417,7 @@ mod tests {
|
||||
|
||||
// use cfg_and_block_env
|
||||
let cfg_and_block_env =
|
||||
payload_builder_attributes.cfg_and_block_env(&chainspec, &chainspec.genesis_header());
|
||||
payload_builder_attributes.cfg_and_block_env(&chainspec, chainspec.genesis_header());
|
||||
|
||||
// ensure the base fee is non zero
|
||||
assert_eq!(cfg_and_block_env.1.basefee, U256::from(EIP1559_INITIAL_BASE_FEE));
|
||||
|
||||
@ -814,7 +814,7 @@ mod tests {
|
||||
.build(),
|
||||
);
|
||||
|
||||
let mut header = chain_spec.genesis_header();
|
||||
let mut header = chain_spec.genesis_header().clone();
|
||||
let provider = executor_provider(chain_spec);
|
||||
let mut executor = provider.batch_executor(StateProviderDatabase::new(&db));
|
||||
|
||||
@ -1036,7 +1036,7 @@ mod tests {
|
||||
.build(),
|
||||
);
|
||||
|
||||
let header = chain_spec.genesis_header();
|
||||
let header = chain_spec.genesis_header().clone();
|
||||
let provider = executor_provider(chain_spec);
|
||||
let mut executor = provider.batch_executor(StateProviderDatabase::new(&db));
|
||||
|
||||
@ -1207,7 +1207,7 @@ mod tests {
|
||||
.build(),
|
||||
);
|
||||
|
||||
let mut header = chain_spec.genesis_header();
|
||||
let mut header = chain_spec.genesis_header().clone();
|
||||
header.requests_root = Some(EMPTY_ROOT_HASH);
|
||||
let header_hash = header.hash_slow();
|
||||
|
||||
@ -1365,7 +1365,7 @@ mod tests {
|
||||
let input: Bytes = [&validator_public_key[..], &withdrawal_amount[..]].concat().into();
|
||||
assert_eq!(input.len(), 56);
|
||||
|
||||
let mut header = chain_spec.genesis_header();
|
||||
let mut header = chain_spec.genesis_header().clone();
|
||||
header.gas_limit = 1_500_000;
|
||||
header.gas_used = 134_807;
|
||||
header.receipts_root =
|
||||
@ -1454,7 +1454,7 @@ mod tests {
|
||||
assert_eq!(input.len(), 56);
|
||||
|
||||
// Create a genesis block header with a specified gas limit and gas used
|
||||
let mut header = chain_spec.genesis_header();
|
||||
let mut header = chain_spec.genesis_header().clone();
|
||||
header.gas_limit = 1_500_000;
|
||||
header.gas_used = 134_807;
|
||||
header.receipts_root =
|
||||
|
||||
@ -252,7 +252,7 @@ mod tests {
|
||||
|
||||
let executor = EthExecutorProvider::ethereum(chain_spec.clone());
|
||||
let provider_factory = create_test_provider_factory_with_chain_spec(chain_spec.clone());
|
||||
init_genesis(provider_factory.clone())?;
|
||||
init_genesis(&provider_factory)?;
|
||||
let blockchain_db = BlockchainProvider::new(
|
||||
provider_factory.clone(),
|
||||
Arc::new(NoopBlockchainTree::default()),
|
||||
@ -291,7 +291,7 @@ mod tests {
|
||||
|
||||
let executor = EthExecutorProvider::ethereum(chain_spec.clone());
|
||||
let provider_factory = create_test_provider_factory_with_chain_spec(chain_spec.clone());
|
||||
init_genesis(provider_factory.clone())?;
|
||||
init_genesis(&provider_factory)?;
|
||||
let blockchain_db = BlockchainProvider::new(
|
||||
provider_factory.clone(),
|
||||
Arc::new(NoopBlockchainTree::default()),
|
||||
|
||||
@ -202,7 +202,7 @@ mod tests {
|
||||
|
||||
let executor = EthExecutorProvider::ethereum(chain_spec.clone());
|
||||
let provider_factory = create_test_provider_factory_with_chain_spec(chain_spec.clone());
|
||||
init_genesis(provider_factory.clone())?;
|
||||
init_genesis(&provider_factory)?;
|
||||
let blockchain_db = BlockchainProvider::new(
|
||||
provider_factory.clone(),
|
||||
Arc::new(NoopBlockchainTree::default()),
|
||||
@ -243,7 +243,7 @@ mod tests {
|
||||
|
||||
let executor = EthExecutorProvider::ethereum(chain_spec.clone());
|
||||
let provider_factory = create_test_provider_factory_with_chain_spec(chain_spec.clone());
|
||||
init_genesis(provider_factory.clone())?;
|
||||
init_genesis(&provider_factory)?;
|
||||
let blockchain_db = BlockchainProvider::new(
|
||||
provider_factory.clone(),
|
||||
Arc::new(NoopBlockchainTree::default()),
|
||||
|
||||
@ -250,7 +250,7 @@ pub async fn test_exex_context_with_chain_spec(
|
||||
StaticFileProvider::read_write(static_dir.into_path()).expect("static file provider"),
|
||||
);
|
||||
|
||||
let genesis_hash = init_genesis(provider_factory.clone())?;
|
||||
let genesis_hash = init_genesis(&provider_factory)?;
|
||||
let provider =
|
||||
BlockchainProvider::new(provider_factory.clone(), Arc::new(NoopBlockchainTree::default()))?;
|
||||
|
||||
|
||||
@ -522,13 +522,13 @@ where
|
||||
|
||||
/// Convenience function to [`Self::init_genesis`]
|
||||
pub fn with_genesis(self) -> Result<Self, InitDatabaseError> {
|
||||
init_genesis(self.provider_factory().clone())?;
|
||||
init_genesis(self.provider_factory())?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Write the genesis block and state if it has not already been written
|
||||
pub fn init_genesis(&self) -> Result<B256, InitDatabaseError> {
|
||||
init_genesis(self.provider_factory().clone())
|
||||
init_genesis(self.provider_factory())
|
||||
}
|
||||
|
||||
/// Creates a new `WithMeteredProvider` container and attaches it to the
|
||||
|
||||
@ -5,7 +5,7 @@ use alloc::sync::Arc;
|
||||
use alloy_chains::Chain;
|
||||
use alloy_primitives::{b256, U256};
|
||||
use once_cell::sync::Lazy;
|
||||
use reth_chainspec::{BaseFeeParams, BaseFeeParamsKind, ChainSpec};
|
||||
use reth_chainspec::{once_cell_set, BaseFeeParams, BaseFeeParamsKind, ChainSpec};
|
||||
use reth_ethereum_forks::{EthereumHardfork, OptimismHardfork};
|
||||
|
||||
use crate::OpChainSpec;
|
||||
@ -17,7 +17,7 @@ pub static BASE_MAINNET: Lazy<Arc<OpChainSpec>> = Lazy::new(|| {
|
||||
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!(
|
||||
genesis_hash: once_cell_set(b256!(
|
||||
"f712aa9241cc24369b143cf6dce85f0902a9731e70d66818a3a5845b296c73dd"
|
||||
)),
|
||||
paris_block_and_final_difficulty: Some((0, U256::from(0))),
|
||||
|
||||
@ -5,7 +5,7 @@ use alloc::sync::Arc;
|
||||
use alloy_chains::Chain;
|
||||
use alloy_primitives::{b256, U256};
|
||||
use once_cell::sync::Lazy;
|
||||
use reth_chainspec::{BaseFeeParams, BaseFeeParamsKind, ChainSpec};
|
||||
use reth_chainspec::{once_cell_set, BaseFeeParams, BaseFeeParamsKind, ChainSpec};
|
||||
use reth_ethereum_forks::{EthereumHardfork, OptimismHardfork};
|
||||
|
||||
use crate::OpChainSpec;
|
||||
@ -17,7 +17,7 @@ pub static BASE_SEPOLIA: Lazy<Arc<OpChainSpec>> = Lazy::new(|| {
|
||||
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!(
|
||||
genesis_hash: once_cell_set(b256!(
|
||||
"0dcc9e089e30b90ddfc55be9a37dd15bc551aeee999d2e2b51414c54eaf934e4"
|
||||
)),
|
||||
paris_block_and_final_difficulty: Some((0, U256::from(0))),
|
||||
|
||||
@ -5,7 +5,7 @@ use alloc::sync::Arc;
|
||||
use alloy_chains::Chain;
|
||||
use alloy_primitives::U256;
|
||||
use once_cell::sync::Lazy;
|
||||
use reth_chainspec::{BaseFeeParams, BaseFeeParamsKind, ChainSpec};
|
||||
use reth_chainspec::{once_cell_set, BaseFeeParams, BaseFeeParamsKind, ChainSpec};
|
||||
use reth_ethereum_forks::DEV_HARDFORKS;
|
||||
use reth_primitives_traits::constants::DEV_GENESIS_HASH;
|
||||
|
||||
@ -16,20 +16,18 @@ use crate::OpChainSpec;
|
||||
/// Includes 20 prefunded accounts with `10_000` ETH each derived from mnemonic "test test test test
|
||||
/// test test test test test test test junk".
|
||||
pub static OP_DEV: 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()
|
||||
},
|
||||
}
|
||||
OpChainSpec {
|
||||
inner: ChainSpec {
|
||||
chain: Chain::dev(),
|
||||
genesis: serde_json::from_str(include_str!("../res/genesis/dev.json"))
|
||||
.expect("Can't deserialize Dev testnet genesis json"),
|
||||
genesis_hash: once_cell_set(DEV_GENESIS_HASH),
|
||||
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,7 +5,7 @@ use alloc::sync::Arc;
|
||||
use alloy_chains::Chain;
|
||||
use alloy_primitives::{b256, U256};
|
||||
use once_cell::sync::Lazy;
|
||||
use reth_chainspec::{BaseFeeParams, BaseFeeParamsKind, ChainSpec};
|
||||
use reth_chainspec::{once_cell_set, BaseFeeParams, BaseFeeParamsKind, ChainSpec};
|
||||
use reth_ethereum_forks::{EthereumHardfork, OptimismHardfork};
|
||||
use reth_primitives_traits::constants::ETHEREUM_BLOCK_GAS_LIMIT;
|
||||
|
||||
@ -20,7 +20,7 @@ pub static OP_MAINNET: Lazy<Arc<OpChainSpec>> = Lazy::new(|| {
|
||||
// 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!(
|
||||
genesis_hash: once_cell_set(b256!(
|
||||
"7ca38a1916c42007829c55e69d3e9a73265554b586a499015373241b8a3fa48b"
|
||||
)),
|
||||
paris_block_and_final_difficulty: Some((0, U256::from(0))),
|
||||
|
||||
@ -5,7 +5,7 @@ use alloc::sync::Arc;
|
||||
use alloy_chains::{Chain, NamedChain};
|
||||
use alloy_primitives::{b256, U256};
|
||||
use once_cell::sync::Lazy;
|
||||
use reth_chainspec::{BaseFeeParams, BaseFeeParamsKind, ChainSpec};
|
||||
use reth_chainspec::{once_cell_set, BaseFeeParams, BaseFeeParamsKind, ChainSpec};
|
||||
use reth_ethereum_forks::{EthereumHardfork, OptimismHardfork};
|
||||
use reth_primitives_traits::constants::ETHEREUM_BLOCK_GAS_LIMIT;
|
||||
|
||||
@ -18,7 +18,7 @@ pub static OP_SEPOLIA: Lazy<Arc<OpChainSpec>> = Lazy::new(|| {
|
||||
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!(
|
||||
genesis_hash: once_cell_set(b256!(
|
||||
"102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d"
|
||||
)),
|
||||
paris_block_and_final_difficulty: Some((0, U256::from(0))),
|
||||
|
||||
@ -285,7 +285,7 @@ mod test {
|
||||
ChunkedFileReader::from_file(f, DEFAULT_BYTE_LEN_CHUNK_CHAIN_FILE).await.unwrap();
|
||||
|
||||
let db = TestStageDB::default();
|
||||
init_genesis(db.factory.clone()).unwrap();
|
||||
init_genesis(&db.factory).unwrap();
|
||||
|
||||
// todo: where does import command init receipts ? probably somewhere in pipeline
|
||||
|
||||
|
||||
@ -23,11 +23,7 @@ use reth_stages_types::{StageCheckpoint, StageId};
|
||||
use reth_trie::{IntermediateStateRootState, StateRoot as StateRootComputer, StateRootProgress};
|
||||
use reth_trie_db::DatabaseStateRoot;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
io::BufRead,
|
||||
sync::Arc,
|
||||
};
|
||||
use std::{collections::HashMap, io::BufRead};
|
||||
use tracing::{debug, error, info, trace};
|
||||
|
||||
/// Default soft limit for number of bytes to read from state dump file, before inserting into
|
||||
@ -75,7 +71,7 @@ impl From<DatabaseError> for InitDatabaseError {
|
||||
|
||||
/// Write the genesis block if it has not already been written
|
||||
pub fn init_genesis<N: NodeTypesWithDB<ChainSpec = ChainSpec>>(
|
||||
factory: ProviderFactory<N>,
|
||||
factory: &ProviderFactory<N>,
|
||||
) -> Result<B256, InitDatabaseError> {
|
||||
let chain = factory.chain_spec();
|
||||
|
||||
@ -110,7 +106,7 @@ pub fn init_genesis<N: NodeTypesWithDB<ChainSpec = ChainSpec>>(
|
||||
|
||||
// Insert header
|
||||
let static_file_provider = factory.static_file_provider();
|
||||
insert_genesis_header(&provider_rw, &static_file_provider, chain.clone())?;
|
||||
insert_genesis_header(&provider_rw, &static_file_provider, &chain)?;
|
||||
|
||||
insert_genesis_state(&provider_rw, alloc.len(), alloc.iter())?;
|
||||
|
||||
@ -235,13 +231,7 @@ pub fn insert_genesis_hashes<'a, 'b, DB: Database>(
|
||||
let alloc_storage = alloc.filter_map(|(addr, account)| {
|
||||
// only return Some if there is storage
|
||||
account.storage.as_ref().map(|storage| {
|
||||
(
|
||||
*addr,
|
||||
storage
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|(key, value)| StorageEntry { key, value: value.into() }),
|
||||
)
|
||||
(*addr, storage.iter().map(|(&key, &value)| StorageEntry { key, value: value.into() }))
|
||||
})
|
||||
});
|
||||
provider.insert_storage_for_hashing(alloc_storage)?;
|
||||
@ -265,16 +255,14 @@ pub fn insert_history<'a, 'b, DB: Database>(
|
||||
alloc: impl Iterator<Item = (&'a Address, &'b GenesisAccount)> + Clone,
|
||||
block: u64,
|
||||
) -> ProviderResult<()> {
|
||||
let account_transitions =
|
||||
alloc.clone().map(|(addr, _)| (*addr, vec![block])).collect::<BTreeMap<_, _>>();
|
||||
let account_transitions = alloc.clone().map(|(addr, _)| (*addr, [block]));
|
||||
provider.insert_account_history_index(account_transitions)?;
|
||||
|
||||
trace!(target: "reth::cli", "Inserted account history");
|
||||
|
||||
let storage_transitions = alloc
|
||||
.filter_map(|(addr, account)| account.storage.as_ref().map(|storage| (addr, storage)))
|
||||
.flat_map(|(addr, storage)| storage.iter().map(|(key, _)| ((*addr, *key), vec![block])))
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
.flat_map(|(addr, storage)| storage.iter().map(|(key, _)| ((*addr, *key), [block])));
|
||||
provider.insert_storage_history_index(storage_transitions)?;
|
||||
|
||||
trace!(target: "reth::cli", "Inserted storage history");
|
||||
@ -286,15 +274,15 @@ pub fn insert_history<'a, 'b, DB: Database>(
|
||||
pub fn insert_genesis_header<DB: Database>(
|
||||
provider: &DatabaseProviderRW<DB>,
|
||||
static_file_provider: &StaticFileProvider,
|
||||
chain: Arc<ChainSpec>,
|
||||
chain: &ChainSpec,
|
||||
) -> ProviderResult<()> {
|
||||
let (header, block_hash) = chain.sealed_genesis_header().split();
|
||||
let (header, block_hash) = (chain.genesis_header(), chain.genesis_hash());
|
||||
|
||||
match static_file_provider.block_hash(0) {
|
||||
Ok(None) | Err(ProviderError::MissingStaticFileBlock(StaticFileSegment::Headers, 0)) => {
|
||||
let (difficulty, hash) = (header.difficulty, block_hash);
|
||||
let mut writer = static_file_provider.latest_writer(StaticFileSegment::Headers)?;
|
||||
writer.append_header(&header, difficulty, &hash)?;
|
||||
writer.append_header(header, difficulty, &hash)?;
|
||||
}
|
||||
Ok(Some(_)) => {}
|
||||
Err(e) => return Err(e),
|
||||
@ -563,6 +551,7 @@ mod tests {
|
||||
use reth_provider::test_utils::{
|
||||
create_test_provider_factory_with_chain_spec, MockNodeTypesWithDB,
|
||||
};
|
||||
use std::{collections::BTreeMap, sync::Arc};
|
||||
|
||||
fn collect_table_entries<DB, T>(
|
||||
tx: &<DB as Database>::TX,
|
||||
@ -577,7 +566,7 @@ mod tests {
|
||||
#[test]
|
||||
fn success_init_genesis_mainnet() {
|
||||
let genesis_hash =
|
||||
init_genesis(create_test_provider_factory_with_chain_spec(MAINNET.clone())).unwrap();
|
||||
init_genesis(&create_test_provider_factory_with_chain_spec(MAINNET.clone())).unwrap();
|
||||
|
||||
// actual, expected
|
||||
assert_eq!(genesis_hash, MAINNET_GENESIS_HASH);
|
||||
@ -586,7 +575,7 @@ mod tests {
|
||||
#[test]
|
||||
fn success_init_genesis_sepolia() {
|
||||
let genesis_hash =
|
||||
init_genesis(create_test_provider_factory_with_chain_spec(SEPOLIA.clone())).unwrap();
|
||||
init_genesis(&create_test_provider_factory_with_chain_spec(SEPOLIA.clone())).unwrap();
|
||||
|
||||
// actual, expected
|
||||
assert_eq!(genesis_hash, SEPOLIA_GENESIS_HASH);
|
||||
@ -595,7 +584,7 @@ mod tests {
|
||||
#[test]
|
||||
fn success_init_genesis_holesky() {
|
||||
let genesis_hash =
|
||||
init_genesis(create_test_provider_factory_with_chain_spec(HOLESKY.clone())).unwrap();
|
||||
init_genesis(&create_test_provider_factory_with_chain_spec(HOLESKY.clone())).unwrap();
|
||||
|
||||
// actual, expected
|
||||
assert_eq!(genesis_hash, HOLESKY_GENESIS_HASH);
|
||||
@ -605,10 +594,10 @@ mod tests {
|
||||
fn fail_init_inconsistent_db() {
|
||||
let factory = create_test_provider_factory_with_chain_spec(SEPOLIA.clone());
|
||||
let static_file_provider = factory.static_file_provider();
|
||||
init_genesis(factory.clone()).unwrap();
|
||||
init_genesis(&factory).unwrap();
|
||||
|
||||
// Try to init db with a different genesis block
|
||||
let genesis_hash = init_genesis(ProviderFactory::<MockNodeTypesWithDB>::new(
|
||||
let genesis_hash = init_genesis(&ProviderFactory::<MockNodeTypesWithDB>::new(
|
||||
factory.into_db(),
|
||||
MAINNET.clone(),
|
||||
static_file_provider,
|
||||
@ -647,14 +636,14 @@ mod tests {
|
||||
..Default::default()
|
||||
},
|
||||
hardforks: Default::default(),
|
||||
genesis_hash: None,
|
||||
genesis_hash: Default::default(),
|
||||
paris_block_and_final_difficulty: None,
|
||||
deposit_contract: None,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let factory = create_test_provider_factory_with_chain_spec(chain_spec);
|
||||
init_genesis(factory.clone()).unwrap();
|
||||
init_genesis(&factory).unwrap();
|
||||
|
||||
let provider = factory.provider().unwrap();
|
||||
|
||||
|
||||
@ -1658,7 +1658,7 @@ impl<TX: DbTxMut + DbTx> DatabaseProvider<TX> {
|
||||
/// This function is used by history indexing stages.
|
||||
fn append_history_index<P, T>(
|
||||
&self,
|
||||
index_updates: BTreeMap<P, Vec<u64>>,
|
||||
index_updates: impl IntoIterator<Item = (P, impl IntoIterator<Item = u64>)>,
|
||||
mut sharded_key_factory: impl FnMut(P, BlockNumber) -> T::Key,
|
||||
) -> ProviderResult<()>
|
||||
where
|
||||
@ -1666,21 +1666,17 @@ impl<TX: DbTxMut + DbTx> DatabaseProvider<TX> {
|
||||
T: Table<Value = BlockNumberList>,
|
||||
{
|
||||
for (partial_key, indices) in index_updates {
|
||||
let last_shard = self.take_shard::<T>(sharded_key_factory(partial_key, u64::MAX))?;
|
||||
// chunk indices and insert them in shards of N size.
|
||||
let indices = last_shard.iter().chain(indices.iter());
|
||||
let chunks = indices
|
||||
.chunks(sharded_key::NUM_OF_INDICES_IN_SHARD)
|
||||
.into_iter()
|
||||
.map(|chunks| chunks.copied().collect())
|
||||
.collect::<Vec<Vec<_>>>();
|
||||
|
||||
let mut chunks = chunks.into_iter().peekable();
|
||||
let mut last_shard =
|
||||
self.take_shard::<T>(sharded_key_factory(partial_key, u64::MAX))?;
|
||||
last_shard.extend(indices);
|
||||
// Chunk indices and insert them in shards of N size.
|
||||
let indices = last_shard;
|
||||
let mut chunks = indices.chunks(sharded_key::NUM_OF_INDICES_IN_SHARD).peekable();
|
||||
while let Some(list) = chunks.next() {
|
||||
let highest_block_number = if chunks.peek().is_some() {
|
||||
*list.last().expect("`chunks` does not return empty list")
|
||||
} else {
|
||||
// Insert last list with u64::MAX
|
||||
// Insert last list with `u64::MAX`.
|
||||
u64::MAX
|
||||
};
|
||||
self.tx.put::<T>(
|
||||
@ -3139,7 +3135,7 @@ impl<TX: DbTxMut + DbTx> HistoryWriter for DatabaseProvider<TX> {
|
||||
|
||||
fn insert_account_history_index(
|
||||
&self,
|
||||
account_transitions: BTreeMap<Address, Vec<u64>>,
|
||||
account_transitions: impl IntoIterator<Item = (Address, impl IntoIterator<Item = u64>)>,
|
||||
) -> ProviderResult<()> {
|
||||
self.append_history_index::<_, tables::AccountsHistory>(
|
||||
account_transitions,
|
||||
@ -3189,7 +3185,7 @@ impl<TX: DbTxMut + DbTx> HistoryWriter for DatabaseProvider<TX> {
|
||||
|
||||
fn insert_storage_history_index(
|
||||
&self,
|
||||
storage_transitions: BTreeMap<(Address, B256), Vec<u64>>,
|
||||
storage_transitions: impl IntoIterator<Item = ((Address, B256), impl IntoIterator<Item = u64>)>,
|
||||
) -> ProviderResult<()> {
|
||||
self.append_history_index::<_, tables::StoragesHistory>(
|
||||
storage_transitions,
|
||||
|
||||
@ -2,10 +2,7 @@ use auto_impl::auto_impl;
|
||||
use reth_db_api::models::BlockNumberAddress;
|
||||
use reth_primitives::{Address, BlockNumber, B256};
|
||||
use reth_storage_errors::provider::ProviderResult;
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
ops::{Range, RangeInclusive},
|
||||
};
|
||||
use std::ops::{Range, RangeInclusive};
|
||||
|
||||
/// History Writer
|
||||
#[auto_impl(&, Arc, Box)]
|
||||
@ -21,7 +18,7 @@ pub trait HistoryWriter: Send + Sync {
|
||||
/// Insert account change index to database. Used inside AccountHistoryIndex stage
|
||||
fn insert_account_history_index(
|
||||
&self,
|
||||
account_transitions: BTreeMap<Address, Vec<u64>>,
|
||||
index_updates: impl IntoIterator<Item = (Address, impl IntoIterator<Item = u64>)>,
|
||||
) -> ProviderResult<()>;
|
||||
|
||||
/// Unwind and clear storage history indices.
|
||||
@ -35,7 +32,7 @@ pub trait HistoryWriter: Send + Sync {
|
||||
/// Insert storage change index to database. Used inside StorageHistoryIndex stage
|
||||
fn insert_storage_history_index(
|
||||
&self,
|
||||
storage_transitions: BTreeMap<(Address, B256), Vec<u64>>,
|
||||
storage_transitions: impl IntoIterator<Item = ((Address, B256), impl IntoIterator<Item = u64>)>,
|
||||
) -> ProviderResult<()>;
|
||||
|
||||
/// Read account/storage changesets and update account/storage history indices.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use reth_chainspec::{
|
||||
BaseFeeParams, Chain, ChainHardforks, ChainSpec, EthereumHardfork, ForkCondition,
|
||||
once_cell_set, BaseFeeParams, Chain, ChainHardforks, ChainSpec, EthereumHardfork, ForkCondition,
|
||||
};
|
||||
use reth_network_peers::NodeRecord;
|
||||
use reth_primitives::{b256, B256};
|
||||
@ -14,7 +14,8 @@ pub(crate) fn bsc_chain_spec() -> Arc<ChainSpec> {
|
||||
ChainSpec {
|
||||
chain: Chain::from_id(56),
|
||||
genesis: serde_json::from_str(include_str!("./genesis.json")).expect("deserialize genesis"),
|
||||
genesis_hash: Some(GENESIS),
|
||||
genesis_hash: once_cell_set(GENESIS),
|
||||
genesis_header: Default::default(),
|
||||
paris_block_and_final_difficulty: None,
|
||||
hardforks: ChainHardforks::new(vec![(
|
||||
EthereumHardfork::Shanghai.boxed(),
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use reth_chainspec::{
|
||||
BaseFeeParams, Chain, ChainHardforks, ChainSpec, EthereumHardfork, ForkCondition,
|
||||
once_cell_set, BaseFeeParams, Chain, ChainHardforks, ChainSpec, EthereumHardfork, ForkCondition,
|
||||
};
|
||||
use reth_discv4::NodeRecord;
|
||||
use reth_primitives::{b256, Head, B256};
|
||||
@ -15,7 +15,8 @@ pub(crate) fn polygon_chain_spec() -> Arc<ChainSpec> {
|
||||
chain: Chain::from_id(137),
|
||||
// <https://github.com/maticnetwork/bor/blob/d521b8e266b97efe9c8fdce8167e9dd77b04637d/builder/files/genesis-mainnet-v1.json>
|
||||
genesis: serde_json::from_str(include_str!("./genesis.json")).expect("deserialize genesis"),
|
||||
genesis_hash: Some(GENESIS),
|
||||
genesis_hash: once_cell_set(GENESIS),
|
||||
genesis_header: Default::default(),
|
||||
paris_block_and_final_difficulty: None,
|
||||
hardforks: ChainHardforks::new(vec![
|
||||
(EthereumHardfork::Petersburg.boxed(), ForkCondition::Block(0)),
|
||||
|
||||
Reference in New Issue
Block a user