perf: improve genesis handling (#10878)

This commit is contained in:
DaniPopes
2024-09-13 19:48:44 +02:00
committed by GitHub
parent 75c6295d29
commit b23bb7e8bc
24 changed files with 121 additions and 120 deletions

View File

@ -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 {

View File

@ -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::*;

View File

@ -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,

View File

@ -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 })

View File

@ -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)?;
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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));

View File

@ -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 =

View File

@ -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()),

View File

@ -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()),

View File

@ -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()))?;

View File

@ -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

View File

@ -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))),

View File

@ -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))),

View File

@ -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()
});

View File

@ -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))),

View File

@ -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))),

View File

@ -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

View File

@ -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();

View File

@ -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,

View File

@ -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.

View File

@ -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(),

View File

@ -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)),