diff --git a/crates/engine/primitives/src/config.rs b/crates/engine/primitives/src/config.rs index 2a57fda6f9..b34f368c7f 100644 --- a/crates/engine/primitives/src/config.rs +++ b/crates/engine/primitives/src/config.rs @@ -179,6 +179,8 @@ pub struct TreeConfig { sparse_trie_prune_depth: usize, /// Maximum number of storage tries to retain after pruning. sparse_trie_max_storage_tries: usize, + /// Whether to fully disable sparse trie cache pruning between blocks. + disable_sparse_trie_cache_pruning: bool, /// Timeout for the state root task before spawning a sequential fallback computation. /// If `Some`, after waiting this duration for the state root task, a sequential state root /// computation is spawned in parallel and whichever finishes first is used. @@ -216,6 +218,7 @@ impl Default for TreeConfig { disable_trie_cache: false, sparse_trie_prune_depth: DEFAULT_SPARSE_TRIE_PRUNE_DEPTH, sparse_trie_max_storage_tries: DEFAULT_SPARSE_TRIE_MAX_STORAGE_TRIES, + disable_sparse_trie_cache_pruning: false, state_root_task_timeout: Some(DEFAULT_STATE_ROOT_TASK_TIMEOUT), } } @@ -281,6 +284,7 @@ impl TreeConfig { disable_trie_cache: false, sparse_trie_prune_depth, sparse_trie_max_storage_tries, + disable_sparse_trie_cache_pruning: false, state_root_task_timeout, } } @@ -631,6 +635,17 @@ impl TreeConfig { self } + /// Returns whether sparse trie cache pruning is disabled. + pub const fn disable_sparse_trie_cache_pruning(&self) -> bool { + self.disable_sparse_trie_cache_pruning + } + + /// Setter for whether to disable sparse trie cache pruning. + pub const fn with_disable_sparse_trie_cache_pruning(mut self, value: bool) -> Self { + self.disable_sparse_trie_cache_pruning = value; + self + } + /// Returns the state root task timeout. pub const fn state_root_task_timeout(&self) -> Option { self.state_root_task_timeout diff --git a/crates/engine/tree/src/tree/payload_processor/mod.rs b/crates/engine/tree/src/tree/payload_processor/mod.rs index bb34a75dfa..b1ea7c7006 100644 --- a/crates/engine/tree/src/tree/payload_processor/mod.rs +++ b/crates/engine/tree/src/tree/payload_processor/mod.rs @@ -135,6 +135,8 @@ where sparse_trie_prune_depth: usize, /// Maximum storage tries to retain after pruning. sparse_trie_max_storage_tries: usize, + /// Whether sparse trie cache pruning is fully disabled. + disable_sparse_trie_cache_pruning: bool, /// Whether to disable cache metrics recording. disable_cache_metrics: bool, } @@ -170,6 +172,7 @@ where prewarm_max_concurrency: config.prewarm_max_concurrency(), sparse_trie_prune_depth: config.sparse_trie_prune_depth(), sparse_trie_max_storage_tries: config.sparse_trie_max_storage_tries(), + disable_sparse_trie_cache_pruning: config.disable_sparse_trie_cache_pruning(), disable_cache_metrics: config.disable_cache_metrics(), } } @@ -546,6 +549,7 @@ where let disable_trie_cache = config.disable_trie_cache(); let prune_depth = self.sparse_trie_prune_depth; let max_storage_tries = self.sparse_trie_max_storage_tries; + let disable_cache_pruning = self.disable_sparse_trie_cache_pruning; let chunk_size = config.multiproof_chunking_enabled().then_some(config.multiproof_chunk_size()); let executor = self.executor.clone(); @@ -642,6 +646,7 @@ where max_storage_tries, SPARSE_TRIE_MAX_NODES_SHRINK_CAPACITY, SPARSE_TRIE_MAX_VALUES_SHRINK_CAPACITY, + disable_cache_pruning, ); trie_metrics .into_trie_for_reuse_duration_histogram diff --git a/crates/engine/tree/src/tree/payload_processor/sparse_trie.rs b/crates/engine/tree/src/tree/payload_processor/sparse_trie.rs index ef62e42cee..1f67db4e2e 100644 --- a/crates/engine/tree/src/tree/payload_processor/sparse_trie.rs +++ b/crates/engine/tree/src/tree/payload_processor/sparse_trie.rs @@ -72,6 +72,7 @@ where max_storage_tries: usize, max_nodes_capacity: usize, max_values_capacity: usize, + disable_pruning: bool, ) -> (SparseStateTrie, DeferredDrops) { match self { Self::Cleared(task) => task.into_cleared_trie(max_nodes_capacity, max_values_capacity), @@ -80,6 +81,7 @@ where max_storage_tries, max_nodes_capacity, max_values_capacity, + disable_pruning, ), } } @@ -356,16 +358,23 @@ where /// Prunes and shrinks the trie for reuse in the next payload built on top of this one. /// /// Should be called after the state root result has been sent. + /// + /// When `disable_pruning` is true, the trie is preserved without any node pruning, + /// storage trie eviction, or capacity shrinking, keeping the full cache intact for + /// benchmarking purposes. pub(super) fn into_trie_for_reuse( self, prune_depth: usize, max_storage_tries: usize, max_nodes_capacity: usize, max_values_capacity: usize, + disable_pruning: bool, ) -> (SparseStateTrie, DeferredDrops) { let Self { mut trie, .. } = self; - trie.prune(prune_depth, max_storage_tries); - trie.shrink_to(max_nodes_capacity, max_values_capacity); + if !disable_pruning { + trie.prune(prune_depth, max_storage_tries); + trie.shrink_to(max_nodes_capacity, max_values_capacity); + } let deferred = trie.take_deferred_drops(); (trie, deferred) } diff --git a/crates/node/core/src/args/engine.rs b/crates/node/core/src/args/engine.rs index bd7db697ff..cc747c5bef 100644 --- a/crates/node/core/src/args/engine.rs +++ b/crates/node/core/src/args/engine.rs @@ -43,6 +43,7 @@ pub struct DefaultEngineValues { disable_trie_cache: bool, sparse_trie_prune_depth: usize, sparse_trie_max_storage_tries: usize, + disable_sparse_trie_cache_pruning: bool, state_root_task_timeout: Option, } @@ -198,6 +199,12 @@ impl DefaultEngineValues { self } + /// Set whether to disable sparse trie cache pruning by default + pub const fn with_disable_sparse_trie_cache_pruning(mut self, v: bool) -> Self { + self.disable_sparse_trie_cache_pruning = v; + self + } + /// Set the default state root task timeout pub fn with_state_root_task_timeout(mut self, v: Option) -> Self { self.state_root_task_timeout = v; @@ -231,6 +238,7 @@ impl Default for DefaultEngineValues { disable_trie_cache: false, sparse_trie_prune_depth: DEFAULT_SPARSE_TRIE_PRUNE_DEPTH, sparse_trie_max_storage_tries: DEFAULT_SPARSE_TRIE_MAX_STORAGE_TRIES, + disable_sparse_trie_cache_pruning: false, state_root_task_timeout: Some("1s".to_string()), } } @@ -372,6 +380,12 @@ pub struct EngineArgs { #[arg(long = "engine.sparse-trie-max-storage-tries", default_value_t = DefaultEngineValues::get_global().sparse_trie_max_storage_tries)] pub sparse_trie_max_storage_tries: usize, + /// Fully disable sparse trie cache pruning. When set, the cached sparse trie is preserved + /// without any node pruning or storage trie eviction between blocks. Useful for benchmarking + /// the effects of retaining the full trie cache. + #[arg(long = "engine.disable-sparse-trie-cache-pruning", default_value_t = DefaultEngineValues::get_global().disable_sparse_trie_cache_pruning)] + pub disable_sparse_trie_cache_pruning: bool, + /// Configure the timeout for the state root task before spawning a sequential fallback. /// If the state root task takes longer than this, a sequential computation starts in /// parallel and whichever finishes first is used. @@ -415,6 +429,7 @@ impl Default for EngineArgs { disable_trie_cache, sparse_trie_prune_depth, sparse_trie_max_storage_tries, + disable_sparse_trie_cache_pruning, state_root_task_timeout, } = DefaultEngineValues::get_global().clone(); Self { @@ -445,6 +460,7 @@ impl Default for EngineArgs { disable_trie_cache, sparse_trie_prune_depth, sparse_trie_max_storage_tries, + disable_sparse_trie_cache_pruning, state_root_task_timeout: state_root_task_timeout .as_deref() .map(|s| humantime::parse_duration(s).expect("valid default duration")), @@ -480,6 +496,7 @@ impl EngineArgs { .with_disable_trie_cache(self.disable_trie_cache) .with_sparse_trie_prune_depth(self.sparse_trie_prune_depth) .with_sparse_trie_max_storage_tries(self.sparse_trie_max_storage_tries) + .with_disable_sparse_trie_cache_pruning(self.disable_sparse_trie_cache_pruning) .with_state_root_task_timeout(self.state_root_task_timeout.filter(|d| !d.is_zero())) } } @@ -534,6 +551,7 @@ mod tests { disable_trie_cache: true, sparse_trie_prune_depth: 10, sparse_trie_max_storage_tries: 100, + disable_sparse_trie_cache_pruning: true, state_root_task_timeout: Some(Duration::from_secs(2)), }; @@ -570,6 +588,7 @@ mod tests { "10", "--engine.sparse-trie-max-storage-tries", "100", + "--engine.disable-sparse-trie-cache-pruning", "--engine.state-root-task-timeout", "2s", ]) diff --git a/docs/vocs/docs/pages/cli/reth/node.mdx b/docs/vocs/docs/pages/cli/reth/node.mdx index b9d55a1693..a296eb6162 100644 --- a/docs/vocs/docs/pages/cli/reth/node.mdx +++ b/docs/vocs/docs/pages/cli/reth/node.mdx @@ -1027,6 +1027,9 @@ Engine: [default: 100] + --engine.disable-sparse-trie-cache-pruning + Fully disable sparse trie cache pruning. When set, the cached sparse trie is preserved without any node pruning or storage trie eviction between blocks. Useful for benchmarking the effects of retaining the full trie cache + --engine.state-root-task-timeout Configure the timeout for the state root task before spawning a sequential fallback. If the state root task takes longer than this, a sequential computation starts in parallel and whichever finishes first is used.