reth_cli_commands/init_state/
mod.rsuse crate::common::{AccessRights, CliNodeTypes, Environment, EnvironmentArgs};
use alloy_primitives::{B256, U256};
use clap::Parser;
use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_cli::chainspec::ChainSpecParser;
use reth_db_common::init::init_from_state_dump;
use reth_node_api::NodePrimitives;
use reth_primitives::SealedHeader;
use reth_provider::{
BlockNumReader, DatabaseProviderFactory, StaticFileProviderFactory, StaticFileWriter,
};
use std::{io::BufReader, path::PathBuf, str::FromStr};
use tracing::info;
pub mod without_evm;
#[derive(Debug, Parser)]
pub struct InitStateCommand<C: ChainSpecParser> {
#[command(flatten)]
pub env: EnvironmentArgs<C>,
#[arg(value_name = "STATE_DUMP_FILE", verbatim_doc_comment)]
pub state: PathBuf,
#[arg(long, default_value = "false")]
pub without_evm: bool,
#[arg(long, value_name = "HEADER_FILE", verbatim_doc_comment)]
pub header: Option<PathBuf>,
#[arg(long, value_name = "TOTAL_DIFFICULTY", verbatim_doc_comment)]
pub total_difficulty: Option<String>,
#[arg(long, value_name = "HEADER_HASH", verbatim_doc_comment)]
pub header_hash: Option<String>,
}
impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> InitStateCommand<C> {
pub async fn execute<N>(self) -> eyre::Result<()>
where
N: CliNodeTypes<
ChainSpec = C::ChainSpec,
Primitives: NodePrimitives<BlockHeader = alloy_consensus::Header>,
>,
{
info!(target: "reth::cli", "Reth init-state starting");
let Environment { config, provider_factory, .. } = self.env.init::<N>(AccessRights::RW)?;
let static_file_provider = provider_factory.static_file_provider();
let provider_rw = provider_factory.database_provider_rw()?;
if self.without_evm {
let header = self.header.ok_or_else(|| eyre::eyre!("Header file must be provided"))?;
let header = without_evm::read_header_from_file(header)?;
let header_hash =
self.header_hash.ok_or_else(|| eyre::eyre!("Header hash must be provided"))?;
let header_hash = B256::from_str(&header_hash)?;
let total_difficulty = self
.total_difficulty
.ok_or_else(|| eyre::eyre!("Total difficulty must be provided"))?;
let total_difficulty = U256::from_str(&total_difficulty)?;
let last_block_number = provider_rw.last_block_number()?;
if last_block_number == 0 {
without_evm::setup_without_evm(
&provider_rw,
SealedHeader::new(header, header_hash),
total_difficulty,
)?;
static_file_provider.commit()?;
} else if last_block_number > 0 && last_block_number < header.number {
return Err(eyre::eyre!(
"Data directory should be empty when calling init-state with --without-evm-history."
));
}
}
info!(target: "reth::cli", "Initiating state dump");
let reader = BufReader::new(reth_fs_util::open(self.state)?);
let hash = init_from_state_dump(reader, &provider_rw, config.stages.etl)?;
provider_rw.commit()?;
info!(target: "reth::cli", hash = ?hash, "Genesis block written");
Ok(())
}
}