diff --git a/crates/engine/primitives/src/config.rs b/crates/engine/primitives/src/config.rs index f7ed7e8f28a..a9bb41ad6a3 100644 --- a/crates/engine/primitives/src/config.rs +++ b/crates/engine/primitives/src/config.rs @@ -89,6 +89,8 @@ pub struct TreeConfig { /// Whether to always compare trie updates from the state root task to the trie updates from /// the regular state root calculation. always_compare_trie_updates: bool, + /// Whether to disable state cache. + disable_state_cache: bool, /// Whether to disable parallel prewarming. disable_prewarming: bool, /// Whether to disable the parallel sparse trie state root algorithm. @@ -143,6 +145,7 @@ impl Default for TreeConfig { max_execute_block_batch_size: DEFAULT_MAX_EXECUTE_BLOCK_BATCH_SIZE, legacy_state_root: false, always_compare_trie_updates: false, + disable_state_cache: false, disable_prewarming: false, disable_parallel_sparse_trie: false, state_provider_metrics: false, @@ -173,6 +176,7 @@ impl TreeConfig { max_execute_block_batch_size: usize, legacy_state_root: bool, always_compare_trie_updates: bool, + disable_state_cache: bool, disable_prewarming: bool, disable_parallel_sparse_trie: bool, state_provider_metrics: bool, @@ -197,6 +201,7 @@ impl TreeConfig { max_execute_block_batch_size, legacy_state_root, always_compare_trie_updates, + disable_state_cache, disable_prewarming, disable_parallel_sparse_trie, state_provider_metrics, @@ -271,7 +276,12 @@ impl TreeConfig { self.disable_parallel_sparse_trie } - /// Returns whether or not parallel prewarming should be used. + /// Returns whether or not state cache is disabled. + pub const fn disable_state_cache(&self) -> bool { + self.disable_state_cache + } + + /// Returns whether or not parallel prewarming is disabled. pub const fn disable_prewarming(&self) -> bool { self.disable_prewarming } @@ -363,6 +373,12 @@ impl TreeConfig { self } + /// Setter for whether to disable state cache. + pub const fn without_state_cache(mut self, disable_state_cache: bool) -> Self { + self.disable_state_cache = disable_state_cache; + self + } + /// Setter for whether to disable parallel prewarming. pub const fn without_prewarming(mut self, disable_prewarming: bool) -> Self { self.disable_prewarming = disable_prewarming; diff --git a/crates/engine/tree/src/tree/payload_processor/mod.rs b/crates/engine/tree/src/tree/payload_processor/mod.rs index ed951a81a54..119d71c4f7b 100644 --- a/crates/engine/tree/src/tree/payload_processor/mod.rs +++ b/crates/engine/tree/src/tree/payload_processor/mod.rs @@ -104,6 +104,8 @@ where cross_block_cache_size: u64, /// Whether transactions should not be executed on prewarming task. disable_transaction_prewarming: bool, + /// Whether state cache should be disable + disable_state_cache: bool, /// Determines how to configure the evm for execution. evm_config: Evm, /// Whether precompile cache should be disabled. @@ -147,6 +149,7 @@ where cross_block_cache_size: config.cross_block_cache_size(), disable_transaction_prewarming: config.disable_prewarming(), evm_config, + disable_state_cache: config.disable_state_cache(), precompile_cache_disabled: config.precompile_cache_disabled(), precompile_cache_map, sparse_state_trie: Arc::default(), @@ -351,9 +354,15 @@ where transactions = mpsc::channel().1; } - let saved_cache = self.cache_for(env.parent_hash); - let cache = saved_cache.cache().clone(); - let cache_metrics = saved_cache.metrics().clone(); + let (saved_cache, cache, cache_metrics) = if self.disable_state_cache { + (None, None, None) + } else { + let saved_cache = self.cache_for(env.parent_hash); + let cache = saved_cache.cache().clone(); + let cache_metrics = saved_cache.metrics().clone(); + (Some(saved_cache), Some(cache), Some(cache_metrics)) + }; + // configure prewarming let prewarm_ctx = PrewarmContext { env, @@ -565,12 +574,12 @@ impl PayloadHandle { } /// Returns a clone of the caches used by prewarming - pub(super) fn caches(&self) -> StateExecutionCache { + pub(super) fn caches(&self) -> Option { self.prewarm_handle.cache.clone() } /// Returns a clone of the cache metrics used by prewarming - pub(super) fn cache_metrics(&self) -> CachedStateMetrics { + pub(super) fn cache_metrics(&self) -> Option { self.prewarm_handle.cache_metrics.clone() } @@ -600,9 +609,9 @@ impl PayloadHandle { #[derive(Debug)] pub(crate) struct CacheTaskHandle { /// The shared cache the task operates with. - cache: StateExecutionCache, + cache: Option, /// Metrics for the caches - cache_metrics: CachedStateMetrics, + cache_metrics: Option, /// Channel to the spawned prewarm task if any to_prewarm_task: Option>, } diff --git a/crates/engine/tree/src/tree/payload_processor/prewarm.rs b/crates/engine/tree/src/tree/payload_processor/prewarm.rs index 056fdc8e0ce..17845d50dd9 100644 --- a/crates/engine/tree/src/tree/payload_processor/prewarm.rs +++ b/crates/engine/tree/src/tree/payload_processor/prewarm.rs @@ -29,7 +29,7 @@ use metrics::{Counter, Gauge, Histogram}; use reth_evm::{execute::ExecutableTxFor, ConfigureEvm, Evm, EvmFor, SpecFor}; use reth_metrics::Metrics; use reth_primitives_traits::NodePrimitives; -use reth_provider::{BlockReader, StateProviderFactory, StateReader}; +use reth_provider::{BlockReader, StateProviderBox, StateProviderFactory, StateReader}; use reth_revm::{database::StateProviderDatabase, db::BundleState, state::EvmState}; use reth_trie::MultiProofTargets; use std::{ @@ -255,31 +255,35 @@ where self; let hash = env.hash; - debug!(target: "engine::caching", parent_hash=?hash, "Updating execution cache"); - // Perform all cache operations atomically under the lock - execution_cache.update_with_guard(|cached| { - // consumes the `SavedCache` held by the prewarming task, which releases its usage guard - let (caches, cache_metrics) = saved_cache.split(); - let new_cache = SavedCache::new(hash, caches, cache_metrics); - - // Insert state into cache while holding the lock - if new_cache.cache().insert_state(&state).is_err() { - // Clear the cache on error to prevent having a polluted cache - *cached = None; - debug!(target: "engine::caching", "cleared execution cache on update error"); - return; - } + if let Some(saved_cache) = saved_cache { + debug!(target: "engine::caching", parent_hash=?hash, "Updating execution cache"); + // Perform all cache operations atomically under the lock + execution_cache.update_with_guard(|cached| { + // consumes the `SavedCache` held by the prewarming task, which releases its usage + // guard + let (caches, cache_metrics) = saved_cache.split(); + let new_cache = SavedCache::new(hash, caches, cache_metrics); + + // Insert state into cache while holding the lock + if new_cache.cache().insert_state(&state).is_err() { + // Clear the cache on error to prevent having a polluted cache + *cached = None; + debug!(target: "engine::caching", "cleared execution cache on update error"); + return; + } - new_cache.update_metrics(); + new_cache.update_metrics(); - // Replace the shared cache with the new one; the previous cache (if any) is dropped. - *cached = Some(new_cache); - }); + // Replace the shared cache with the new one; the previous cache (if any) is + // dropped. + *cached = Some(new_cache); + }); - let elapsed = start.elapsed(); - debug!(target: "engine::caching", parent_hash=?hash, elapsed=?elapsed, "Updated execution cache"); + let elapsed = start.elapsed(); + debug!(target: "engine::caching", parent_hash=?hash, elapsed=?elapsed, "Updated execution cache"); - metrics.cache_saving_duration.set(elapsed.as_secs_f64()); + metrics.cache_saving_duration.set(elapsed.as_secs_f64()); + } } /// Executes the task. @@ -356,7 +360,7 @@ where { pub(super) env: ExecutionEnv, pub(super) evm_config: Evm, - pub(super) saved_cache: SavedCache, + pub(super) saved_cache: Option, /// Provider to obtain the state pub(super) provider: StateProviderBuilder, pub(super) metrics: PrewarmMetrics, @@ -400,10 +404,13 @@ where }; // Use the caches to create a new provider with caching - let caches = saved_cache.cache().clone(); - let cache_metrics = saved_cache.metrics().clone(); - let state_provider = - CachedStateProvider::new_with_caches(state_provider, caches, cache_metrics); + let state_provider: StateProviderBox = if let Some(saved_cache) = saved_cache { + let caches = saved_cache.cache().clone(); + let cache_metrics = saved_cache.metrics().clone(); + Box::new(CachedStateProvider::new_with_caches(state_provider, caches, cache_metrics)) + } else { + state_provider + }; let state_provider = StateProviderDatabase::new(state_provider); diff --git a/crates/engine/tree/src/tree/payload_validator.rs b/crates/engine/tree/src/tree/payload_validator.rs index af368b47b2d..7f2ce7f58da 100644 --- a/crates/engine/tree/src/tree/payload_validator.rs +++ b/crates/engine/tree/src/tree/payload_validator.rs @@ -353,7 +353,7 @@ where ) .into()) }; - let state_provider = ensure_ok!(provider_builder.build()); + let mut state_provider = ensure_ok!(provider_builder.build()); drop(_enter); // fetch parent block @@ -396,11 +396,13 @@ where // Use cached state provider before executing, used in execution after prewarming threads // complete - let state_provider = CachedStateProvider::new_with_caches( - state_provider, - handle.caches(), - handle.cache_metrics(), - ); + if let Some((caches, cache_metrics)) = handle.caches().zip(handle.cache_metrics()) { + state_provider = Box::new(CachedStateProvider::new_with_caches( + state_provider, + caches, + cache_metrics, + )); + }; // Execute the block and handle any execution errors let (output, senders) = match if self.config.state_provider_metrics() { diff --git a/crates/node/core/src/args/engine.rs b/crates/node/core/src/args/engine.rs index bd34744e9e7..b917dfff7c2 100644 --- a/crates/node/core/src/args/engine.rs +++ b/crates/node/core/src/args/engine.rs @@ -35,6 +35,10 @@ pub struct EngineArgs { #[deprecated] pub caching_and_prewarming_enabled: bool, + /// Disable state cache + #[arg(long = "engine.disable-state-cache")] + pub state_cache_disabled: bool, + /// Disable parallel prewarming #[arg(long = "engine.disable-prewarming", alias = "engine.disable-caching-and-prewarming")] pub prewarming_disabled: bool, @@ -130,6 +134,7 @@ impl Default for EngineArgs { legacy_state_root_task_enabled: false, state_root_task_compare_updates: false, caching_and_prewarming_enabled: true, + state_cache_disabled: false, prewarming_disabled: false, parallel_sparse_trie_enabled: true, parallel_sparse_trie_disabled: false, @@ -157,6 +162,7 @@ impl EngineArgs { .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) + .without_state_cache(self.state_cache_disabled) .without_prewarming(self.prewarming_disabled) .with_disable_parallel_sparse_trie(self.parallel_sparse_trie_disabled) .with_state_provider_metrics(self.state_provider_metrics) diff --git a/docs/vocs/docs/pages/cli/op-reth/node.mdx b/docs/vocs/docs/pages/cli/op-reth/node.mdx index 2a6450d344c..e614d5606a3 100644 --- a/docs/vocs/docs/pages/cli/op-reth/node.mdx +++ b/docs/vocs/docs/pages/cli/op-reth/node.mdx @@ -885,6 +885,9 @@ Engine: --engine.legacy-state-root Enable legacy state root + --engine.disable-state-cache + Disable state cache + --engine.disable-prewarming Disable parallel prewarming diff --git a/docs/vocs/docs/pages/cli/reth/node.mdx b/docs/vocs/docs/pages/cli/reth/node.mdx index 6542d0c5bf8..97a2d5054b8 100644 --- a/docs/vocs/docs/pages/cli/reth/node.mdx +++ b/docs/vocs/docs/pages/cli/reth/node.mdx @@ -885,6 +885,9 @@ Engine: --engine.legacy-state-root Enable legacy state root + --engine.disable-state-cache + Disable state cache + --engine.disable-prewarming Disable parallel prewarming