reth_cli_commands/init_state/
mod.rs1use crate::common::{AccessRights, CliNodeTypes, Environment, EnvironmentArgs};
4use alloy_primitives::{B256, U256};
5use clap::Parser;
6use reth_chainspec::{EthChainSpec, EthereumHardforks};
7use reth_cli::chainspec::ChainSpecParser;
8use reth_db_common::init::init_from_state_dump;
9use reth_primitives::SealedHeader;
10use reth_provider::{
11 BlockNumReader, DatabaseProviderFactory, StaticFileProviderFactory, StaticFileWriter,
12};
13
14use std::{io::BufReader, path::PathBuf, str::FromStr};
15use tracing::info;
16
17pub mod without_evm;
18
19#[derive(Debug, Parser)]
21pub struct InitStateCommand<C: ChainSpecParser> {
22 #[command(flatten)]
23 pub env: EnvironmentArgs<C>,
24
25 #[arg(value_name = "STATE_DUMP_FILE", verbatim_doc_comment)]
43 pub state: PathBuf,
44
45 #[arg(long, default_value = "false")]
53 pub without_evm: bool,
54
55 #[arg(long, value_name = "HEADER_FILE", verbatim_doc_comment)]
57 pub header: Option<PathBuf>,
58
59 #[arg(long, value_name = "TOTAL_DIFFICULTY", verbatim_doc_comment)]
61 pub total_difficulty: Option<String>,
62
63 #[arg(long, value_name = "HEADER_HASH", verbatim_doc_comment)]
65 pub header_hash: Option<String>,
66}
67
68impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> InitStateCommand<C> {
69 pub async fn execute<N: CliNodeTypes<ChainSpec = C::ChainSpec>>(self) -> eyre::Result<()> {
71 info!(target: "reth::cli", "Reth init-state starting");
72
73 let Environment { config, provider_factory, .. } = self.env.init::<N>(AccessRights::RW)?;
74
75 let static_file_provider = provider_factory.static_file_provider();
76 let provider_rw = provider_factory.database_provider_rw()?;
77
78 if self.without_evm {
79 let header = self.header.ok_or_else(|| eyre::eyre!("Header file must be provided"))?;
81 let header = without_evm::read_header_from_file(header)?;
82
83 let header_hash =
84 self.header_hash.ok_or_else(|| eyre::eyre!("Header hash must be provided"))?;
85 let header_hash = B256::from_str(&header_hash)?;
86
87 let total_difficulty = self
88 .total_difficulty
89 .ok_or_else(|| eyre::eyre!("Total difficulty must be provided"))?;
90 let total_difficulty = U256::from_str(&total_difficulty)?;
91
92 let last_block_number = provider_rw.last_block_number()?;
93
94 if last_block_number == 0 {
95 without_evm::setup_without_evm(
96 &provider_rw,
97 SealedHeader::new(header, header_hash),
100 total_difficulty,
101 )?;
102
103 static_file_provider.commit()?;
109 } else if last_block_number > 0 && last_block_number < header.number {
110 return Err(eyre::eyre!(
111 "Data directory should be empty when calling init-state with --without-evm-history."
112 ));
113 }
114 }
115
116 info!(target: "reth::cli", "Initiating state dump");
117
118 let reader = BufReader::new(reth_fs_util::open(self.state)?);
119
120 let hash = init_from_state_dump(reader, &provider_rw, config.stages.etl)?;
121
122 provider_rw.commit()?;
123
124 info!(target: "reth::cli", hash = ?hash, "Genesis block written");
125 Ok(())
126 }
127}