reth_optimism_cli/commands/
init_state.rs

1//! Command that initializes the node from a genesis file.
2
3use clap::Parser;
4use reth_cli::chainspec::ChainSpecParser;
5use reth_cli_commands::common::{AccessRights, CliNodeTypes, Environment};
6use reth_db_common::init::init_from_state_dump;
7use reth_optimism_chainspec::OpChainSpec;
8use reth_optimism_primitives::{
9    bedrock::{BEDROCK_HEADER, BEDROCK_HEADER_HASH, BEDROCK_HEADER_TTD},
10    OpPrimitives,
11};
12use reth_primitives::SealedHeader;
13use reth_provider::{
14    BlockNumReader, ChainSpecProvider, DatabaseProviderFactory, StaticFileProviderFactory,
15    StaticFileWriter,
16};
17use std::io::BufReader;
18use tracing::info;
19
20/// Initializes the database with the genesis block.
21#[derive(Debug, Parser)]
22pub struct InitStateCommandOp<C: ChainSpecParser> {
23    #[command(flatten)]
24    init_state: reth_cli_commands::init_state::InitStateCommand<C>,
25
26    /// **Optimism Mainnet Only**
27    ///
28    /// Specifies whether to initialize the state without relying on OVM historical data.
29    ///
30    /// When enabled, and before inserting the state, it creates a dummy chain up to the last OVM
31    /// block (#105235062) (14GB / 90 seconds). It then, appends the Bedrock block.
32    ///
33    /// - **Note**: **Do not** import receipts and blocks beforehand, or this will fail or be
34    ///   ignored.
35    #[arg(long, default_value = "false")]
36    without_ovm: bool,
37}
38
39impl<C: ChainSpecParser<ChainSpec = OpChainSpec>> InitStateCommandOp<C> {
40    /// Execute the `init` command
41    pub async fn execute<N: CliNodeTypes<ChainSpec = C::ChainSpec, Primitives = OpPrimitives>>(
42        self,
43    ) -> eyre::Result<()> {
44        info!(target: "reth::cli", "Reth init-state starting");
45
46        let Environment { config, provider_factory, .. } =
47            self.init_state.env.init::<N>(AccessRights::RW)?;
48
49        let static_file_provider = provider_factory.static_file_provider();
50        let provider_rw = provider_factory.database_provider_rw()?;
51
52        // OP-Mainnet may want to bootstrap a chain without OVM historical data
53        if provider_factory.chain_spec().is_optimism_mainnet() && self.without_ovm {
54            let last_block_number = provider_rw.last_block_number()?;
55
56            if last_block_number == 0 {
57                reth_cli_commands::init_state::without_evm::setup_without_evm(
58                    &provider_rw,
59                    SealedHeader::new(BEDROCK_HEADER, BEDROCK_HEADER_HASH),
60                    BEDROCK_HEADER_TTD,
61                )?;
62
63                // SAFETY: it's safe to commit static files, since in the event of a crash, they
64                // will be unwound according to database checkpoints.
65                //
66                // Necessary to commit, so the BEDROCK_HEADER is accessible to provider_rw and
67                // init_state_dump
68                static_file_provider.commit()?;
69            } else if last_block_number > 0 && last_block_number < BEDROCK_HEADER.number {
70                return Err(eyre::eyre!(
71                    "Data directory should be empty when calling init-state with --without-ovm."
72                ))
73            }
74        }
75
76        info!(target: "reth::cli", "Initiating state dump");
77
78        let reader = BufReader::new(reth_fs_util::open(self.init_state.state)?);
79        let hash = init_from_state_dump(reader, &provider_rw, config.stages.etl)?;
80
81        provider_rw.commit()?;
82
83        info!(target: "reth::cli", hash = ?hash, "Genesis block written");
84        Ok(())
85    }
86}