Skip to main content

reth_cli_commands/
export_era.rs

1//! Command that exports block history from the database into ERA 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::era1::types::execution::MAX_BLOCKS_PER_ERA1;
8use reth_era_utils as era;
9use reth_provider::DatabaseProviderFactory;
10use std::{path::PathBuf, sync::Arc};
11use tracing::info;
12
13#[derive(Debug, Parser)]
14pub struct ExportEraCommand<C: ChainSpecParser> {
15    #[command(flatten)]
16    env: EnvironmentArgs<C>,
17
18    #[clap(flatten)]
19    export: ExportArgs,
20}
21
22#[derive(Debug, Args)]
23pub struct ExportArgs {
24    /// The ERA file format to export: `era1` writes `.era1` files, `ere` writes `.ere` files.
25    #[arg(long, value_enum, default_value_t = ExportFileType::Era1, verbatim_doc_comment)]
26    file_type: ExportFileType,
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 where the exported ERA files are written.
40    /// Defaults to `<data-dir>/<chain>/<format>-export/`, where `<format>` is `era1` or `ere`.
41    #[arg(long, value_name = "EXPORT_PATH", verbatim_doc_comment)]
42    path: Option<PathBuf>,
43}
44
45/// Execution-layer ERA formats that can be produced from the database.
46///
47/// Consensus-layer `.era` files cannot be exported, so they are not representable here.
48#[derive(Debug, Clone, Copy, clap::ValueEnum)]
49enum ExportFileType {
50    /// Execution blocks written in the `.era1` format.
51    Era1,
52    /// Execution blocks written in the `.ere` format.
53    Ere,
54}
55
56impl ExportFileType {
57    /// The format name (`era1` / `ere`), used for log lines and the default directory name.
58    const fn format(&self) -> &'static str {
59        match self {
60            Self::Era1 => "era1",
61            Self::Ere => "ere",
62        }
63    }
64}
65
66impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> ExportEraCommand<C> {
67    /// Execute `export-era` command
68    pub async fn execute<N>(self, runtime: reth_tasks::Runtime) -> eyre::Result<()>
69    where
70        N: CliNodeTypes<ChainSpec = C::ChainSpec>,
71    {
72        let Environment { provider_factory, .. } = self.env.init::<N>(AccessRights::RO, runtime)?;
73
74        let file_type = self.export.file_type;
75        let format = file_type.format();
76
77        // Either the specified path or default to `<data-dir>/<chain>/<format>-export/`.
78        let data_dir = match &self.export.path {
79            Some(path) => path.clone(),
80            None => self
81                .env
82                .datadir
83                .resolve_datadir(self.env.chain.chain())
84                .data_dir()
85                .join(format!("{format}-export")),
86        };
87
88        let export_config = era::ExportConfig {
89            network: self.env.chain.chain().to_string(),
90            first_block_number: self.export.first_block_number.unwrap_or(0),
91            last_block_number: self
92                .export
93                .last_block_number
94                .unwrap_or(MAX_BLOCKS_PER_ERA1 as u64 - 1),
95            max_blocks_per_file: self
96                .export
97                .max_blocks_per_file
98                .unwrap_or(MAX_BLOCKS_PER_ERA1 as u64),
99            dir: data_dir,
100        };
101
102        export_config.validate()?;
103
104        info!(
105            target: "reth::cli",
106            "Starting {format} block export: blocks {}-{} to {}",
107            export_config.first_block_number,
108            export_config.last_block_number,
109            export_config.dir.display()
110        );
111
112        // Only read access is needed for the database provider.
113        let provider = provider_factory.database_provider_ro()?;
114
115        let exported_files = match file_type {
116            ExportFileType::Era1 => era::export::<era::Era1, _>(&provider, &export_config)?,
117            ExportFileType::Ere => era::export::<era::Ere, _>(&provider, &export_config)?,
118        };
119
120        info!(
121            target: "reth::cli",
122            "Successfully exported {} {format} files to {}",
123            exported_files.len(),
124            export_config.dir.display()
125        );
126
127        Ok(())
128    }
129}
130
131impl<C: ChainSpecParser> ExportEraCommand<C> {
132    /// Returns the underlying chain being used to run this command
133    pub fn chain_spec(&self) -> Option<&Arc<C::ChainSpec>> {
134        Some(&self.env.chain)
135    }
136}