From ce2dc9203beb6b280e6771808b2a09b4aa9cd2a9 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com> Date: Thu, 13 Nov 2025 17:48:53 +0000 Subject: [PATCH] feat(cli): `reth db static-file-header` (#19719) --- crates/cli/commands/src/common.rs | 18 ++- crates/cli/commands/src/db/mod.rs | 4 + .../cli/commands/src/db/static_file_header.rs | 74 +++++++++ crates/storage/errors/src/provider.rs | 6 +- .../src/providers/static_file/manager.rs | 17 +- docs/vocs/docs/pages/cli/SUMMARY.mdx | 3 + docs/vocs/docs/pages/cli/reth/db.mdx | 23 +-- .../pages/cli/reth/db/static-file-header.mdx | 144 +++++++++++++++++ .../cli/reth/db/static-file-header/block.mdx | 151 ++++++++++++++++++ .../cli/reth/db/static-file-header/path.mdx | 143 +++++++++++++++++ 10 files changed, 566 insertions(+), 17 deletions(-) create mode 100644 crates/cli/commands/src/db/static_file_header.rs create mode 100644 docs/vocs/docs/pages/cli/reth/db/static-file-header.mdx create mode 100644 docs/vocs/docs/pages/cli/reth/db/static-file-header/block.mdx create mode 100644 docs/vocs/docs/pages/cli/reth/db/static-file-header/path.mdx diff --git a/crates/cli/commands/src/common.rs b/crates/cli/commands/src/common.rs index 81a5cad6d1..2fb1f71086 100644 --- a/crates/cli/commands/src/common.rs +++ b/crates/cli/commands/src/common.rs @@ -101,13 +101,13 @@ impl EnvironmentArgs { Arc::new(init_db(db_path, self.db.database_args())?), StaticFileProvider::read_write(sf_path)?, ), - AccessRights::RO => ( + AccessRights::RO | AccessRights::RoInconsistent => ( Arc::new(open_db_read_only(&db_path, self.db.database_args())?), StaticFileProvider::read_only(sf_path, false)?, ), }; - let provider_factory = self.create_provider_factory(&config, db, sfp)?; + let provider_factory = self.create_provider_factory(&config, db, sfp, access)?; if access.is_read_write() { debug!(target: "reth::cli", chain=%self.chain.chain(), genesis=?self.chain.genesis_hash(), "Initializing genesis"); init_genesis_with_settings(&provider_factory, self.static_files.to_settings())?; @@ -126,6 +126,7 @@ impl EnvironmentArgs { config: &Config, db: Arc, static_file_provider: StaticFileProvider, + access: AccessRights, ) -> eyre::Result>>> where C: ChainSpecParser, @@ -139,8 +140,9 @@ impl EnvironmentArgs { .with_prune_modes(prune_modes.clone()); // Check for consistency between database and static files. - if let Some(unwind_target) = - factory.static_file_provider().check_consistency(&factory.provider()?)? + if !access.is_read_only_inconsistent() && + let Some(unwind_target) = + factory.static_file_provider().check_consistency(&factory.provider()?)? { if factory.db_ref().is_read_only()? { warn!(target: "reth::cli", ?unwind_target, "Inconsistent storage. Restart node to heal."); @@ -201,6 +203,8 @@ pub enum AccessRights { RW, /// Read-only access RO, + /// Read-only access with possibly inconsistent data + RoInconsistent, } impl AccessRights { @@ -208,6 +212,12 @@ impl AccessRights { pub const fn is_read_write(&self) -> bool { matches!(self, Self::RW) } + + /// Returns `true` if it requires read-only access to the environment with possibly inconsistent + /// data. + pub const fn is_read_only_inconsistent(&self) -> bool { + matches!(self, Self::RoInconsistent) + } } /// Helper alias to satisfy `FullNodeTypes` bound on [`Node`] trait generic. diff --git a/crates/cli/commands/src/db/mod.rs b/crates/cli/commands/src/db/mod.rs index 1ea66b2f55..ecac88fc28 100644 --- a/crates/cli/commands/src/db/mod.rs +++ b/crates/cli/commands/src/db/mod.rs @@ -14,6 +14,7 @@ mod diff; mod get; mod list; mod repair_trie; +mod static_file_header; mod stats; /// DB List TUI mod tui; @@ -51,6 +52,8 @@ pub enum Subcommands { Clear(clear::Command), /// Verifies trie consistency and outputs any inconsistencies RepairTrie(repair_trie::Command), + /// Reads and displays the static file segment header + StaticFileHeader(static_file_header::Command), /// Lists current and local database versions Version, /// Returns the full database path @@ -144,6 +147,7 @@ impl> Command let Environment { provider_factory, .. } = self.env.init::(access_rights)?; command.execute(provider_factory)?; } + Subcommands::StaticFileHeader(command) => command.execute::(self.env)?, Subcommands::Version => { let local_db_version = match get_db_version(&db_path) { Ok(version) => Some(version), diff --git a/crates/cli/commands/src/db/static_file_header.rs b/crates/cli/commands/src/db/static_file_header.rs new file mode 100644 index 0000000000..dea7bb40cc --- /dev/null +++ b/crates/cli/commands/src/db/static_file_header.rs @@ -0,0 +1,74 @@ +use clap::{Parser, Subcommand}; +use reth_cli::chainspec::ChainSpecParser; +use reth_provider::StaticFileProviderFactory; +use reth_static_file_types::StaticFileSegment; +use std::path::PathBuf; +use tracing::warn; + +use crate::common::{AccessRights, CliNodeTypes, EnvironmentArgs}; + +/// The arguments for the `reth db static-file-header` command +#[derive(Parser, Debug)] +pub struct Command { + #[command(subcommand)] + source: Source, +} + +/// Source for locating the static file +#[derive(Subcommand, Debug)] +enum Source { + /// Query by segment and block number + Block { + /// Static file segment + #[arg(value_enum)] + segment: StaticFileSegment, + /// Block number to query + block: u64, + }, + /// Query by path to static file + Path { + /// Path to the static file + path: PathBuf, + }, +} + +impl Command { + /// Execute `db static-file-header` command + pub fn execute>( + self, + env: EnvironmentArgs, + ) -> eyre::Result<()> { + // Try to initialize the environment as read-only. If it fails, try to initialize it as + // read-only without consistency checks. + let provider_factory = match env.init::(AccessRights::RO) { + Ok(env) => env, + Err(err) => { + warn!(?err, "Failed to initialize environment"); + env.init::(AccessRights::RoInconsistent)? + } + } + .provider_factory; + let static_file_provider = provider_factory.static_file_provider(); + + // Get the provider based on the source + let provider = match self.source { + Source::Path { path } => { + static_file_provider.get_segment_provider_for_path(&path)?.ok_or_else(|| { + eyre::eyre!("Could not find static file segment for path: {}", path.display()) + })? + } + Source::Block { segment, block } => { + static_file_provider.get_segment_provider(segment, block)? + } + }; + + let header = provider.user_header(); + + println!("Segment: {}", header.segment()); + println!("Expected Block Range: {}", header.expected_block_range()); + println!("Block Range: {:?}", header.block_range()); + println!("Transaction Range: {:?}", header.tx_range()); + + Ok(()) + } +} diff --git a/crates/storage/errors/src/provider.rs b/crates/storage/errors/src/provider.rs index ed5230c18f..4aadd6a8b1 100644 --- a/crates/storage/errors/src/provider.rs +++ b/crates/storage/errors/src/provider.rs @@ -103,7 +103,11 @@ pub enum ProviderError { /// Static File is not found at specified path. #[cfg(feature = "std")] #[error("not able to find {_0} static file at {_1:?}")] - MissingStaticFilePath(StaticFileSegment, std::path::PathBuf), + MissingStaticFileSegmentPath(StaticFileSegment, std::path::PathBuf), + /// Static File is not found at specified path. + #[cfg(feature = "std")] + #[error("not able to find static file at {_0:?}")] + MissingStaticFilePath(std::path::PathBuf), /// Static File is not found for requested block. #[error("not able to find {_0} static file for block number {_1}")] MissingStaticFileBlock(StaticFileSegment, BlockNumber), diff --git a/crates/storage/provider/src/providers/static_file/manager.rs b/crates/storage/provider/src/providers/static_file/manager.rs index ab86b455bf..0d0bf95a5b 100644 --- a/crates/storage/provider/src/providers/static_file/manager.rs +++ b/crates/storage/provider/src/providers/static_file/manager.rs @@ -539,7 +539,7 @@ impl StaticFileProvider { &path .file_name() .ok_or_else(|| { - ProviderError::MissingStaticFilePath(segment, path.to_path_buf()) + ProviderError::MissingStaticFileSegmentPath(segment, path.to_path_buf()) })? .to_string_lossy(), ) @@ -560,6 +560,21 @@ impl StaticFileProvider { Ok(None) } + /// Gets the [`StaticFileJarProvider`] of the requested path. + pub fn get_segment_provider_for_path( + &self, + path: &Path, + ) -> ProviderResult>> { + StaticFileSegment::parse_filename( + &path + .file_name() + .ok_or_else(|| ProviderError::MissingStaticFilePath(path.to_path_buf()))? + .to_string_lossy(), + ) + .map(|(segment, block_range)| self.get_or_create_jar_provider(segment, &block_range)) + .transpose() + } + /// Given a segment and block range it removes the cached provider from the map. /// /// CAUTION: cached provider should be dropped before calling this or IT WILL deadlock. diff --git a/docs/vocs/docs/pages/cli/SUMMARY.mdx b/docs/vocs/docs/pages/cli/SUMMARY.mdx index 7f7012f4c1..7194007af9 100644 --- a/docs/vocs/docs/pages/cli/SUMMARY.mdx +++ b/docs/vocs/docs/pages/cli/SUMMARY.mdx @@ -19,6 +19,9 @@ - [`reth db clear mdbx`](/cli/reth/db/clear/mdbx) - [`reth db clear static-file`](/cli/reth/db/clear/static-file) - [`reth db repair-trie`](/cli/reth/db/repair-trie) + - [`reth db static-file-header`](/cli/reth/db/static-file-header) + - [`reth db static-file-header block`](/cli/reth/db/static-file-header/block) + - [`reth db static-file-header path`](/cli/reth/db/static-file-header/path) - [`reth db version`](/cli/reth/db/version) - [`reth db path`](/cli/reth/db/path) - [`reth download`](/cli/reth/download) diff --git a/docs/vocs/docs/pages/cli/reth/db.mdx b/docs/vocs/docs/pages/cli/reth/db.mdx index b9cfb992a6..ca71de11f5 100644 --- a/docs/vocs/docs/pages/cli/reth/db.mdx +++ b/docs/vocs/docs/pages/cli/reth/db.mdx @@ -9,17 +9,18 @@ $ reth db --help Usage: reth db [OPTIONS] Commands: - stats Lists all the tables, their entry count and their size - list Lists the contents of a table - checksum Calculates the content checksum of a table - diff Create a diff between two database tables or two entire databases - get Gets the content of a table for the given key - drop Deletes all database entries - clear Deletes all table entries - repair-trie Verifies trie consistency and outputs any inconsistencies - version Lists current and local database versions - path Returns the full database path - help Print this message or the help of the given subcommand(s) + stats Lists all the tables, their entry count and their size + list Lists the contents of a table + checksum Calculates the content checksum of a table + diff Create a diff between two database tables or two entire databases + get Gets the content of a table for the given key + drop Deletes all database entries + clear Deletes all table entries + repair-trie Verifies trie consistency and outputs any inconsistencies + static-file-header Reads and displays the static file segment header + version Lists current and local database versions + path Returns the full database path + help Print this message or the help of the given subcommand(s) Options: -h, --help diff --git a/docs/vocs/docs/pages/cli/reth/db/static-file-header.mdx b/docs/vocs/docs/pages/cli/reth/db/static-file-header.mdx new file mode 100644 index 0000000000..5d4764a2e6 --- /dev/null +++ b/docs/vocs/docs/pages/cli/reth/db/static-file-header.mdx @@ -0,0 +1,144 @@ +# reth db static-file-header + +Reads and displays the static file segment header + +```bash +$ reth db static-file-header --help +``` +```txt +Usage: reth db static-file-header [OPTIONS] + +Commands: + block Query by segment and block number + path Query by path to static file + help Print this message or the help of the given subcommand(s) + +Options: + -h, --help + Print help (see a summary with '-h') + +Datadir: + --chain + The chain this node is running. + Possible values are either a built-in chain or the path to a chain specification file. + + Built-in chains: + mainnet, sepolia, holesky, hoodi, dev + + [default: mainnet] + +Logging: + --log.stdout.format + The format to use for logs written to stdout + + Possible values: + - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging + - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications + - terminal: Represents terminal-friendly formatting for logs + + [default: terminal] + + --log.stdout.filter + The filter to use for logs written to stdout + + [default: ] + + --log.file.format + The format to use for logs written to the log file + + Possible values: + - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging + - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications + - terminal: Represents terminal-friendly formatting for logs + + [default: terminal] + + --log.file.filter + The filter to use for logs written to the log file + + [default: debug] + + --log.file.directory + The path to put log files in + + [default: /logs] + + --log.file.name + The prefix name of the log files + + [default: reth.log] + + --log.file.max-size + The maximum size (in MB) of one log file + + [default: 200] + + --log.file.max-files + The maximum amount of log files that will be stored. If set to 0, background file logging is disabled + + [default: 5] + + --log.journald + Write logs to journald + + --log.journald.filter + The filter to use for logs written to journald + + [default: error] + + --color + Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting + + Possible values: + - always: Colors on + - auto: Auto-detect + - never: Colors off + + [default: always] + +Display: + -v, --verbosity... + Set the minimum log level. + + -v Errors + -vv Warnings + -vvv Info + -vvvv Debug + -vvvvv Traces (warning: very verbose!) + + -q, --quiet + Silence all log output + +Tracing: + --tracing-otlp[=] + Enable `Opentelemetry` tracing export to an OTLP endpoint. + + If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` + + Example: --tracing-otlp=http://collector:4318/v1/traces + + [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] + + --tracing-otlp-protocol + OTLP transport protocol to use for exporting traces. + + - `http`: expects endpoint path to end with `/v1/traces` - `grpc`: expects endpoint without a path + + Defaults to HTTP if not specified. + + Possible values: + - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path + - grpc: gRPC transport, port 4317 + + [env: OTEL_EXPORTER_OTLP_PROTOCOL=] + [default: http] + + --tracing-otlp.filter + Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. + + Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off + + Defaults to TRACE if not specified. + + [default: debug] +``` \ No newline at end of file diff --git a/docs/vocs/docs/pages/cli/reth/db/static-file-header/block.mdx b/docs/vocs/docs/pages/cli/reth/db/static-file-header/block.mdx new file mode 100644 index 0000000000..4d7fb55544 --- /dev/null +++ b/docs/vocs/docs/pages/cli/reth/db/static-file-header/block.mdx @@ -0,0 +1,151 @@ +# reth db static-file-header block + +Query by segment and block number + +```bash +$ reth db static-file-header block --help +``` +```txt +Usage: reth db static-file-header block [OPTIONS] + +Arguments: + + Static file segment + + Possible values: + - headers: Static File segment responsible for the `CanonicalHeaders`, `Headers`, `HeaderTerminalDifficulties` tables + - transactions: Static File segment responsible for the `Transactions` table + - receipts: Static File segment responsible for the `Receipts` table + + + Block number to query + +Options: + -h, --help + Print help (see a summary with '-h') + +Datadir: + --chain + The chain this node is running. + Possible values are either a built-in chain or the path to a chain specification file. + + Built-in chains: + mainnet, sepolia, holesky, hoodi, dev + + [default: mainnet] + +Logging: + --log.stdout.format + The format to use for logs written to stdout + + Possible values: + - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging + - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications + - terminal: Represents terminal-friendly formatting for logs + + [default: terminal] + + --log.stdout.filter + The filter to use for logs written to stdout + + [default: ] + + --log.file.format + The format to use for logs written to the log file + + Possible values: + - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging + - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications + - terminal: Represents terminal-friendly formatting for logs + + [default: terminal] + + --log.file.filter + The filter to use for logs written to the log file + + [default: debug] + + --log.file.directory + The path to put log files in + + [default: /logs] + + --log.file.name + The prefix name of the log files + + [default: reth.log] + + --log.file.max-size + The maximum size (in MB) of one log file + + [default: 200] + + --log.file.max-files + The maximum amount of log files that will be stored. If set to 0, background file logging is disabled + + [default: 5] + + --log.journald + Write logs to journald + + --log.journald.filter + The filter to use for logs written to journald + + [default: error] + + --color + Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting + + Possible values: + - always: Colors on + - auto: Auto-detect + - never: Colors off + + [default: always] + +Display: + -v, --verbosity... + Set the minimum log level. + + -v Errors + -vv Warnings + -vvv Info + -vvvv Debug + -vvvvv Traces (warning: very verbose!) + + -q, --quiet + Silence all log output + +Tracing: + --tracing-otlp[=] + Enable `Opentelemetry` tracing export to an OTLP endpoint. + + If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` + + Example: --tracing-otlp=http://collector:4318/v1/traces + + [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] + + --tracing-otlp-protocol + OTLP transport protocol to use for exporting traces. + + - `http`: expects endpoint path to end with `/v1/traces` - `grpc`: expects endpoint without a path + + Defaults to HTTP if not specified. + + Possible values: + - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path + - grpc: gRPC transport, port 4317 + + [env: OTEL_EXPORTER_OTLP_PROTOCOL=] + [default: http] + + --tracing-otlp.filter + Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. + + Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off + + Defaults to TRACE if not specified. + + [default: debug] +``` \ No newline at end of file diff --git a/docs/vocs/docs/pages/cli/reth/db/static-file-header/path.mdx b/docs/vocs/docs/pages/cli/reth/db/static-file-header/path.mdx new file mode 100644 index 0000000000..2c8dc766cb --- /dev/null +++ b/docs/vocs/docs/pages/cli/reth/db/static-file-header/path.mdx @@ -0,0 +1,143 @@ +# reth db static-file-header path + +Query by path to static file + +```bash +$ reth db static-file-header path --help +``` +```txt +Usage: reth db static-file-header path [OPTIONS] + +Arguments: + + Path to the static file + +Options: + -h, --help + Print help (see a summary with '-h') + +Datadir: + --chain + The chain this node is running. + Possible values are either a built-in chain or the path to a chain specification file. + + Built-in chains: + mainnet, sepolia, holesky, hoodi, dev + + [default: mainnet] + +Logging: + --log.stdout.format + The format to use for logs written to stdout + + Possible values: + - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging + - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications + - terminal: Represents terminal-friendly formatting for logs + + [default: terminal] + + --log.stdout.filter + The filter to use for logs written to stdout + + [default: ] + + --log.file.format + The format to use for logs written to the log file + + Possible values: + - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging + - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications + - terminal: Represents terminal-friendly formatting for logs + + [default: terminal] + + --log.file.filter + The filter to use for logs written to the log file + + [default: debug] + + --log.file.directory + The path to put log files in + + [default: /logs] + + --log.file.name + The prefix name of the log files + + [default: reth.log] + + --log.file.max-size + The maximum size (in MB) of one log file + + [default: 200] + + --log.file.max-files + The maximum amount of log files that will be stored. If set to 0, background file logging is disabled + + [default: 5] + + --log.journald + Write logs to journald + + --log.journald.filter + The filter to use for logs written to journald + + [default: error] + + --color + Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting + + Possible values: + - always: Colors on + - auto: Auto-detect + - never: Colors off + + [default: always] + +Display: + -v, --verbosity... + Set the minimum log level. + + -v Errors + -vv Warnings + -vvv Info + -vvvv Debug + -vvvvv Traces (warning: very verbose!) + + -q, --quiet + Silence all log output + +Tracing: + --tracing-otlp[=] + Enable `Opentelemetry` tracing export to an OTLP endpoint. + + If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317` + + Example: --tracing-otlp=http://collector:4318/v1/traces + + [env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=] + + --tracing-otlp-protocol + OTLP transport protocol to use for exporting traces. + + - `http`: expects endpoint path to end with `/v1/traces` - `grpc`: expects endpoint without a path + + Defaults to HTTP if not specified. + + Possible values: + - http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path + - grpc: gRPC transport, port 4317 + + [env: OTEL_EXPORTER_OTLP_PROTOCOL=] + [default: http] + + --tracing-otlp.filter + Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable. + + Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off + + Defaults to TRACE if not specified. + + [default: debug] +``` \ No newline at end of file