reth_optimism_cli/commands/
init_state.rs

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