reth_cli_commands/
export_era.rs

1//! Command exporting block data to convert them to ERA1 files.
2
3use crate::common::{AccessRights, CliNodeTypes, Environment, EnvironmentArgs};
4use clap::{Args, Parser};
5use reth_chainspec::{EthChainSpec, EthereumHardforks};
6use reth_cli::chainspec::ChainSpecParser;
7use reth_era::execution_types::MAX_BLOCKS_PER_ERA1;
8use reth_era_utils as era1;
9use reth_provider::DatabaseProviderFactory;
10use std::{path::PathBuf, sync::Arc};
11use tracing::info;
12
13// Default folder name for era1 export files
14const ERA1_EXPORT_FOLDER_NAME: &str = "era1-export";
15
16#[derive(Debug, Parser)]
17pub struct ExportEraCommand<C: ChainSpecParser> {
18    #[command(flatten)]
19    env: EnvironmentArgs<C>,
20
21    #[clap(flatten)]
22    export: ExportArgs,
23}
24
25#[derive(Debug, Args)]
26pub struct ExportArgs {
27    /// Optional first block number to export from the db.
28    /// It is by default 0.
29    #[arg(long, value_name = "first-block-number", verbatim_doc_comment)]
30    first_block_number: Option<u64>,
31    /// Optional last block number to export from the db.
32    /// It is by default 8191.
33    #[arg(long, value_name = "last-block-number", verbatim_doc_comment)]
34    last_block_number: Option<u64>,
35    /// The maximum number of blocks per file, it can help you to decrease the size of the files.
36    /// Must be less than or equal to 8192.
37    #[arg(long, value_name = "max-blocks-per-file", verbatim_doc_comment)]
38    max_blocks_per_file: Option<u64>,
39    /// The directory path where to export era1 files.
40    /// The block data are read from the database.
41    #[arg(long, value_name = "EXPORT_ERA1_PATH", verbatim_doc_comment)]
42    path: Option<PathBuf>,
43}
44
45impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> ExportEraCommand<C> {
46    /// Execute `export-era` command
47    pub async fn execute<N>(self) -> eyre::Result<()>
48    where
49        N: CliNodeTypes<ChainSpec = C::ChainSpec>,
50    {
51        let Environment { provider_factory, .. } = self.env.init::<N>(AccessRights::RO)?;
52
53        // Either specified path or default to `<data-dir>/<chain>/era1-export/`
54        let data_dir = match &self.export.path {
55            Some(path) => path.clone(),
56            None => self
57                .env
58                .datadir
59                .resolve_datadir(self.env.chain.chain())
60                .data_dir()
61                .join(ERA1_EXPORT_FOLDER_NAME),
62        };
63
64        let export_config = era1::ExportConfig {
65            network: self.env.chain.chain().to_string(),
66            first_block_number: self.export.first_block_number.unwrap_or(0),
67            last_block_number: self
68                .export
69                .last_block_number
70                .unwrap_or(MAX_BLOCKS_PER_ERA1 as u64 - 1),
71            max_blocks_per_file: self
72                .export
73                .max_blocks_per_file
74                .unwrap_or(MAX_BLOCKS_PER_ERA1 as u64),
75            dir: data_dir,
76        };
77
78        export_config.validate()?;
79
80        info!(
81            target: "reth::cli",
82            "Starting ERA1 block export: blocks {}-{} to {}",
83            export_config.first_block_number,
84            export_config.last_block_number,
85            export_config.dir.display()
86        );
87
88        // Only read access is needed for the database provider
89        let provider = provider_factory.database_provider_ro()?;
90
91        let exported_files = era1::export(&provider, &export_config)?;
92
93        info!(
94            target: "reth::cli",
95            "Successfully exported {} ERA1 files to {}",
96            exported_files.len(),
97            export_config.dir.display()
98        );
99
100        Ok(())
101    }
102}
103
104impl<C: ChainSpecParser> ExportEraCommand<C> {
105    /// Returns the underlying chain being used to run this command
106    pub fn chain_spec(&self) -> Option<&Arc<C::ChainSpec>> {
107        Some(&self.env.chain)
108    }
109}