reth_cli_commands/init_state/
mod.rs1use crate::common::{AccessRights, CliHeader, CliNodeTypes, Environment, EnvironmentArgs};
4use alloy_consensus::BlockHeader as AlloyBlockHeader;
5use alloy_primitives::{B256, U256};
6use clap::Parser;
7use reth_chainspec::{EthChainSpec, EthereumHardforks};
8use reth_cli::chainspec::ChainSpecParser;
9use reth_db_common::init::init_from_state_dump;
10use reth_node_api::NodePrimitives;
11use reth_primitives_traits::{BlockHeader, SealedHeader};
12use reth_provider::{
13 BlockNumReader, DBProvider, DatabaseProviderFactory, StaticFileProviderFactory,
14 StaticFileWriter,
15};
16use std::{io::BufReader, path::PathBuf, str::FromStr, sync::Arc};
17use tracing::info;
18
19pub mod without_evm;
20
21#[derive(Debug, Parser)]
23pub struct InitStateCommand<C: ChainSpecParser> {
24 #[command(flatten)]
25 pub env: EnvironmentArgs<C>,
26
27 #[arg(value_name = "STATE_DUMP_FILE", verbatim_doc_comment)]
45 pub state: PathBuf,
46
47 #[arg(long, default_value = "false")]
55 pub without_evm: bool,
56
57 #[arg(long, value_name = "HEADER_FILE", verbatim_doc_comment)]
59 pub header: Option<PathBuf>,
60
61 #[arg(long, value_name = "TOTAL_DIFFICULTY", verbatim_doc_comment)]
63 pub total_difficulty: Option<String>,
64
65 #[arg(long, value_name = "HEADER_HASH", verbatim_doc_comment)]
67 pub header_hash: Option<String>,
68}
69
70impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> InitStateCommand<C> {
71 pub async fn execute<N>(self) -> eyre::Result<()>
73 where
74 N: CliNodeTypes<
75 ChainSpec = C::ChainSpec,
76 Primitives: NodePrimitives<BlockHeader: BlockHeader + CliHeader>,
77 >,
78 {
79 info!(target: "reth::cli", "Reth init-state starting");
80
81 let Environment { config, provider_factory, .. } = self.env.init::<N>(AccessRights::RW)?;
82
83 let static_file_provider = provider_factory.static_file_provider();
84 let provider_rw = provider_factory.database_provider_rw()?;
85
86 if self.without_evm {
87 let header = self.header.ok_or_else(|| eyre::eyre!("Header file must be provided"))?;
89 let header = without_evm::read_header_from_file::<
90 <N::Primitives as NodePrimitives>::BlockHeader,
91 >(header)?;
92
93 let header_hash =
94 self.header_hash.ok_or_else(|| eyre::eyre!("Header hash must be provided"))?;
95 let header_hash = B256::from_str(&header_hash)?;
96
97 let total_difficulty = self
98 .total_difficulty
99 .ok_or_else(|| eyre::eyre!("Total difficulty must be provided"))?;
100 let total_difficulty = U256::from_str(&total_difficulty)?;
101
102 let last_block_number = provider_rw.last_block_number()?;
103
104 if last_block_number == 0 {
105 without_evm::setup_without_evm(
106 &provider_rw,
107 SealedHeader::new(header, header_hash),
108 total_difficulty,
109 |number| {
110 let mut header =
111 <<N::Primitives as NodePrimitives>::BlockHeader>::default();
112 header.set_number(number);
113 header
114 },
115 )?;
116
117 static_file_provider.commit()?;
123 } else if last_block_number > 0 && last_block_number < header.number() {
124 return Err(eyre::eyre!(
125 "Data directory should be empty when calling init-state with --without-evm-history."
126 ));
127 }
128 }
129
130 info!(target: "reth::cli", "Initiating state dump");
131
132 let reader = BufReader::new(reth_fs_util::open(self.state)?);
133
134 let hash = init_from_state_dump(reader, &provider_rw, config.stages.etl)?;
135
136 provider_rw.commit()?;
137
138 info!(target: "reth::cli", hash = ?hash, "Genesis block written");
139 Ok(())
140 }
141}
142
143impl<C: ChainSpecParser> InitStateCommand<C> {
144 pub fn chain_spec(&self) -> Option<&Arc<C::ChainSpec>> {
146 Some(&self.env.chain)
147 }
148}