From 1592e51d34c5d05984e184df226dcda8fd0cd16b Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Mon, 2 Feb 2026 12:52:31 +0000 Subject: [PATCH] feat(engine): add CLI args for sparse trie pruning configuration (#21703) --- crates/engine/primitives/src/config.rs | 16 ++++-- crates/node/core/src/args/engine.rs | 67 +++++++++++++++++------ docs/vocs/docs/pages/cli/op-reth/node.mdx | 10 ++++ docs/vocs/docs/pages/cli/reth/node.mdx | 10 ++++ 4 files changed, 81 insertions(+), 22 deletions(-) diff --git a/crates/engine/primitives/src/config.rs b/crates/engine/primitives/src/config.rs index 3d69d74ae4..7529e15cda 100644 --- a/crates/engine/primitives/src/config.rs +++ b/crates/engine/primitives/src/config.rs @@ -528,8 +528,12 @@ impl TreeConfig { } /// Setter for the number of storage proof worker threads. - pub fn with_storage_worker_count(mut self, storage_worker_count: usize) -> Self { - self.storage_worker_count = storage_worker_count.max(MIN_WORKER_COUNT); + /// + /// No-op if it's [`None`]. + pub fn with_storage_worker_count_opt(mut self, storage_worker_count: Option) -> Self { + if let Some(count) = storage_worker_count { + self.storage_worker_count = count.max(MIN_WORKER_COUNT); + } self } @@ -539,8 +543,12 @@ impl TreeConfig { } /// Setter for the number of account proof worker threads. - pub fn with_account_worker_count(mut self, account_worker_count: usize) -> Self { - self.account_worker_count = account_worker_count.max(MIN_WORKER_COUNT); + /// + /// No-op if it's [`None`]. + pub fn with_account_worker_count_opt(mut self, account_worker_count: Option) -> Self { + if let Some(count) = account_worker_count { + self.account_worker_count = count.max(MIN_WORKER_COUNT); + } self } diff --git a/crates/node/core/src/args/engine.rs b/crates/node/core/src/args/engine.rs index 99e9d54ea6..f45e002cb8 100644 --- a/crates/node/core/src/args/engine.rs +++ b/crates/node/core/src/args/engine.rs @@ -1,7 +1,10 @@ //! clap [Args](clap::Args) for engine purposes use clap::{builder::Resettable, Args}; -use reth_engine_primitives::{TreeConfig, DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE}; +use reth_engine_primitives::{ + TreeConfig, DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE, DEFAULT_SPARSE_TRIE_MAX_STORAGE_TRIES, + DEFAULT_SPARSE_TRIE_PRUNE_DEPTH, +}; use std::sync::OnceLock; use crate::node_config::{ @@ -38,6 +41,8 @@ pub struct DefaultEngineValues { disable_proof_v2: bool, cache_metrics_disabled: bool, enable_sparse_trie_as_cache: bool, + sparse_trie_prune_depth: usize, + sparse_trie_max_storage_tries: usize, } impl DefaultEngineValues { @@ -179,6 +184,18 @@ impl DefaultEngineValues { self.enable_sparse_trie_as_cache = v; self } + + /// Set the sparse trie prune depth by default + pub const fn with_sparse_trie_prune_depth(mut self, v: usize) -> Self { + self.sparse_trie_prune_depth = v; + self + } + + /// Set the maximum number of storage tries to retain after sparse trie pruning by default + pub const fn with_sparse_trie_max_storage_tries(mut self, v: usize) -> Self { + self.sparse_trie_max_storage_tries = v; + self + } } impl Default for DefaultEngineValues { @@ -205,6 +222,8 @@ impl Default for DefaultEngineValues { disable_proof_v2: false, cache_metrics_disabled: false, enable_sparse_trie_as_cache: false, + sparse_trie_prune_depth: DEFAULT_SPARSE_TRIE_PRUNE_DEPTH, + sparse_trie_max_storage_tries: DEFAULT_SPARSE_TRIE_MAX_STORAGE_TRIES, } } } @@ -336,6 +355,14 @@ pub struct EngineArgs { /// Enable sparse trie as cache. #[arg(long = "engine.enable-sparse-trie-as-cache", default_value_t = DefaultEngineValues::get_global().enable_sparse_trie_as_cache, conflicts_with = "disable_proof_v2")] pub enable_sparse_trie_as_cache: bool, + + /// Sparse trie prune depth. + #[arg(long = "engine.sparse-trie-prune-depth", default_value_t = DefaultEngineValues::get_global().sparse_trie_prune_depth, requires = "enable_sparse_trie_as_cache")] + pub sparse_trie_prune_depth: usize, + + /// Maximum number of storage tries to retain after sparse trie pruning. + #[arg(long = "engine.sparse-trie-max-storage-tries", default_value_t = DefaultEngineValues::get_global().sparse_trie_max_storage_tries, requires = "enable_sparse_trie_as_cache")] + pub sparse_trie_max_storage_tries: usize, } #[allow(deprecated)] @@ -363,6 +390,8 @@ impl Default for EngineArgs { disable_proof_v2, cache_metrics_disabled, enable_sparse_trie_as_cache, + sparse_trie_prune_depth, + sparse_trie_max_storage_tries, } = DefaultEngineValues::get_global().clone(); Self { persistence_threshold, @@ -390,6 +419,8 @@ impl Default for EngineArgs { disable_proof_v2, cache_metrics_disabled, enable_sparse_trie_as_cache, + sparse_trie_prune_depth, + sparse_trie_max_storage_tries, } } } @@ -397,7 +428,7 @@ impl Default for EngineArgs { impl EngineArgs { /// Creates a [`TreeConfig`] from the engine arguments. pub fn tree_config(&self) -> TreeConfig { - let mut config = TreeConfig::default() + TreeConfig::default() .with_persistence_threshold(self.persistence_threshold) .with_memory_block_buffer_target(self.memory_block_buffer_target) .with_legacy_state_root(self.legacy_state_root_task_enabled) @@ -414,21 +445,14 @@ impl EngineArgs { .with_always_process_payload_attributes_on_canonical_head( self.always_process_payload_attributes_on_canonical_head, ) - .with_unwind_canonical_header(self.allow_unwind_canonical_header); - - if let Some(count) = self.storage_worker_count { - config = config.with_storage_worker_count(count); - } - - if let Some(count) = self.account_worker_count { - config = config.with_account_worker_count(count); - } - - config = config.with_disable_proof_v2(self.disable_proof_v2); - config = config.without_cache_metrics(self.cache_metrics_disabled); - config = config.with_enable_sparse_trie_as_cache(self.enable_sparse_trie_as_cache); - - config + .with_unwind_canonical_header(self.allow_unwind_canonical_header) + .with_storage_worker_count_opt(self.storage_worker_count) + .with_account_worker_count_opt(self.account_worker_count) + .with_disable_proof_v2(self.disable_proof_v2) + .without_cache_metrics(self.cache_metrics_disabled) + .with_enable_sparse_trie_as_cache(self.enable_sparse_trie_as_cache) + .with_sparse_trie_prune_depth(self.sparse_trie_prune_depth) + .with_sparse_trie_max_storage_tries(self.sparse_trie_max_storage_tries) } } @@ -479,7 +503,9 @@ mod tests { account_worker_count: Some(8), disable_proof_v2: false, cache_metrics_disabled: true, - enable_sparse_trie_as_cache: false, + enable_sparse_trie_as_cache: true, + sparse_trie_prune_depth: 10, + sparse_trie_max_storage_tries: 100, }; let parsed_args = CommandParser::::parse_from([ @@ -510,6 +536,11 @@ mod tests { "--engine.account-worker-count", "8", "--engine.disable-cache-metrics", + "--engine.enable-sparse-trie-as-cache", + "--engine.sparse-trie-prune-depth", + "10", + "--engine.sparse-trie-max-storage-tries", + "100", ]) .args; diff --git a/docs/vocs/docs/pages/cli/op-reth/node.mdx b/docs/vocs/docs/pages/cli/op-reth/node.mdx index 860fe345ef..6b1b3e1416 100644 --- a/docs/vocs/docs/pages/cli/op-reth/node.mdx +++ b/docs/vocs/docs/pages/cli/op-reth/node.mdx @@ -1015,6 +1015,16 @@ Engine: --engine.enable-sparse-trie-as-cache Enable sparse trie as cache + --engine.sparse-trie-prune-depth + Sparse trie prune depth + + [default: 4] + + --engine.sparse-trie-max-storage-tries + Maximum number of storage tries to retain after sparse trie pruning + + [default: 100] + ERA: --era.enable Enable import from ERA1 files diff --git a/docs/vocs/docs/pages/cli/reth/node.mdx b/docs/vocs/docs/pages/cli/reth/node.mdx index ec24a19ba2..895e09088f 100644 --- a/docs/vocs/docs/pages/cli/reth/node.mdx +++ b/docs/vocs/docs/pages/cli/reth/node.mdx @@ -1015,6 +1015,16 @@ Engine: --engine.enable-sparse-trie-as-cache Enable sparse trie as cache + --engine.sparse-trie-prune-depth + Sparse trie prune depth + + [default: 4] + + --engine.sparse-trie-max-storage-tries + Maximum number of storage tries to retain after sparse trie pruning + + [default: 100] + ERA: --era.enable Enable import from ERA1 files