Skip to main content

reth_engine_primitives/
config.rs

1//! Engine tree configuration.
2
3use alloy_eips::merge::EPOCH_SLOTS;
4use core::time::Duration;
5
6/// Triggers persistence when the number of canonical blocks in memory exceeds this threshold.
7pub const DEFAULT_PERSISTENCE_THRESHOLD: u64 = 2;
8
9/// Maximum canonical-minus-persisted gap before engine API processing is stalled.
10pub const DEFAULT_PERSISTENCE_BACKPRESSURE_THRESHOLD: u64 = 16;
11
12/// How close to the canonical head we persist blocks.
13pub const DEFAULT_MEMORY_BLOCK_BUFFER_TARGET: u64 = 0;
14
15/// The size of proof targets chunk to spawn in one multiproof calculation.
16pub const DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE: usize = 5;
17
18/// Gas threshold below which the small block chunk size is used.
19pub const SMALL_BLOCK_GAS_THRESHOLD: u64 = 20_000_000;
20
21/// Default number of reserved CPU cores for non-reth processes.
22///
23/// This will be deducted from the thread count of main reth global threadpool.
24pub const DEFAULT_RESERVED_CPU_CORES: usize = 1;
25
26/// Default depth for sparse trie pruning.
27///
28/// Nodes at this depth and below are converted to hash stubs to reduce memory.
29/// Depth 4 means we keep roughly 16^4 = 65536 potential branch paths at most.
30pub const DEFAULT_SPARSE_TRIE_PRUNE_DEPTH: usize = 4;
31
32/// Default LFU hot-slot capacity for sparse trie pruning.
33///
34/// Limits the number of `(address, slot)` pairs retained across prune cycles.
35pub const DEFAULT_SPARSE_TRIE_MAX_HOT_SLOTS: usize = 1500;
36
37/// Default LFU hot-account capacity for sparse trie pruning.
38///
39/// Limits the number of account addresses retained across prune cycles.
40pub const DEFAULT_SPARSE_TRIE_MAX_HOT_ACCOUNTS: usize = 1000;
41
42/// Default timeout for the state root task before spawning a sequential fallback.
43pub const DEFAULT_STATE_ROOT_TASK_TIMEOUT: Duration = Duration::from_secs(1);
44
45const DEFAULT_BLOCK_BUFFER_LIMIT: u32 = EPOCH_SLOTS as u32 * 2;
46const DEFAULT_MAX_INVALID_HEADER_CACHE_LENGTH: u32 = 256;
47const DEFAULT_MAX_EXECUTE_BLOCK_BATCH_SIZE: usize = 4;
48const DEFAULT_CROSS_BLOCK_CACHE_SIZE: usize = default_cross_block_cache_size();
49
50const fn assert_backpressure_threshold_invariant(
51    persistence_threshold: u64,
52    persistence_backpressure_threshold: u64,
53) {
54    debug_assert!(
55        persistence_backpressure_threshold > persistence_threshold,
56        "persistence_backpressure_threshold must be greater than persistence_threshold",
57    );
58}
59
60const fn default_cross_block_cache_size() -> usize {
61    if cfg!(test) {
62        1024 * 1024 // 1 MB in tests
63    } else if cfg!(target_pointer_width = "32") {
64        usize::MAX // max possible on wasm32 / 32-bit
65    } else {
66        4 * 1024 * 1024 * 1024 // 4 GB on 64-bit
67    }
68}
69
70/// Determines if the host has enough parallelism to run the payload processor.
71///
72/// It requires at least 5 parallel threads:
73/// - Engine in main thread that spawns the state root task.
74/// - Multiproof task in payload processor
75/// - Sparse Trie task in payload processor
76/// - Multiproof computation spawned in payload processor
77/// - Storage root computation spawned in trie parallel proof
78pub fn has_enough_parallelism() -> bool {
79    #[cfg(feature = "std")]
80    {
81        std::thread::available_parallelism().is_ok_and(|num| num.get() >= 5)
82    }
83    #[cfg(not(feature = "std"))]
84    false
85}
86
87/// The configuration of the engine tree.
88#[derive(Debug, Clone)]
89pub struct TreeConfig {
90    /// Maximum number of blocks to be kept only in memory without triggering
91    /// persistence.
92    persistence_threshold: u64,
93    /// How close to the canonical head we persist blocks. Represents the ideal
94    /// number of most recent blocks to keep in memory for quick access and reorgs.
95    ///
96    /// Note: this should be less than or equal to `persistence_threshold`.
97    memory_block_buffer_target: u64,
98    /// Maximum canonical-minus-persisted gap before engine API processing is stalled.
99    persistence_backpressure_threshold: u64,
100    /// Number of pending blocks that cannot be executed due to missing parent and
101    /// are kept in cache.
102    block_buffer_limit: u32,
103    /// Number of invalid headers to keep in cache.
104    max_invalid_header_cache_length: u32,
105    /// Maximum number of blocks to execute sequentially in a batch.
106    ///
107    /// This is used as a cutoff to prevent long-running sequential block execution when we receive
108    /// a batch of downloaded blocks.
109    max_execute_block_batch_size: usize,
110    /// Whether to use the legacy state root calculation method instead of the
111    /// new state root task.
112    legacy_state_root: bool,
113    /// Whether to always compare trie updates from the state root task to the trie updates from
114    /// the regular state root calculation.
115    always_compare_trie_updates: bool,
116    /// Whether to disable state cache.
117    disable_state_cache: bool,
118    /// Whether to disable parallel prewarming.
119    disable_prewarming: bool,
120    /// Whether to enable state provider metrics.
121    state_provider_metrics: bool,
122    /// Cross-block cache size in bytes.
123    cross_block_cache_size: usize,
124    /// Whether the host has enough parallelism to run state root task.
125    has_enough_parallelism: bool,
126    /// Multiproof task chunk size for proof targets.
127    multiproof_chunk_size: usize,
128    /// Number of reserved CPU cores for non-reth processes
129    reserved_cpu_cores: usize,
130    /// Whether to disable the precompile cache
131    precompile_cache_disabled: bool,
132    /// Whether to use state root fallback for testing
133    state_root_fallback: bool,
134    /// Whether to always process payload attributes and begin a payload build process
135    /// even if `forkchoiceState.headBlockHash` is already the canonical head or an ancestor.
136    ///
137    /// The Engine API specification generally states that client software "MUST NOT begin a
138    /// payload build process if `forkchoiceState.headBlockHash` references a `VALID`
139    /// ancestor of the head of canonical chain".
140    /// See: <https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md#engine_forkchoiceupdatedv1> (Rule 2)
141    ///
142    /// This flag allows overriding that behavior.
143    /// This is useful for specific chain configurations (e.g., OP Stack where proposers
144    /// can reorg their own chain), various custom chains, or for development/testing purposes
145    /// where immediate payload regeneration is desired despite the head not changing or moving to
146    /// an ancestor.
147    always_process_payload_attributes_on_canonical_head: bool,
148    /// Whether to unwind canonical header to ancestor during forkchoice updates.
149    allow_unwind_canonical_header: bool,
150    /// Whether to disable cache metrics recording (can be expensive with large cached state).
151    disable_cache_metrics: bool,
152    /// Depth for sparse trie pruning after state root computation.
153    sparse_trie_prune_depth: usize,
154    /// LFU hot-slot capacity: max `(address, slot)` pairs retained across prune cycles.
155    sparse_trie_max_hot_slots: usize,
156    /// LFU hot-account capacity: max account addresses retained across prune cycles.
157    sparse_trie_max_hot_accounts: usize,
158    /// When set, blocks whose total processing time (execution + state reads + state root +
159    /// DB commit) exceeds this duration trigger a structured `warn!` log with detailed timing,
160    /// state-operation counts, and cache hit-rate metrics. `Duration::ZERO` logs every block.
161    slow_block_threshold: Option<Duration>,
162    /// Whether to fully disable sparse trie cache pruning between blocks.
163    disable_sparse_trie_cache_pruning: bool,
164    /// Timeout for the state root task before spawning a sequential fallback computation.
165    /// If `Some`, after waiting this duration for the state root task, a sequential state root
166    /// computation is spawned in parallel and whichever finishes first is used.
167    /// If `None`, the timeout fallback is disabled.
168    state_root_task_timeout: Option<Duration>,
169    /// Whether to share execution cache with the payload builder.
170    share_execution_cache_with_payload_builder: bool,
171    /// Whether to share sparse trie with the payload builder.
172    share_sparse_trie_with_payload_builder: bool,
173    /// Maximum random jitter applied before each proof computation (trie-debug only).
174    /// When set, each proof worker sleeps for a random duration up to this value
175    /// before starting a proof calculation.
176    #[cfg(feature = "trie-debug")]
177    proof_jitter: Option<Duration>,
178}
179
180impl Default for TreeConfig {
181    fn default() -> Self {
182        assert_backpressure_threshold_invariant(
183            DEFAULT_PERSISTENCE_THRESHOLD,
184            DEFAULT_PERSISTENCE_BACKPRESSURE_THRESHOLD,
185        );
186        Self {
187            persistence_threshold: DEFAULT_PERSISTENCE_THRESHOLD,
188            memory_block_buffer_target: DEFAULT_MEMORY_BLOCK_BUFFER_TARGET,
189            persistence_backpressure_threshold: DEFAULT_PERSISTENCE_BACKPRESSURE_THRESHOLD,
190            block_buffer_limit: DEFAULT_BLOCK_BUFFER_LIMIT,
191            max_invalid_header_cache_length: DEFAULT_MAX_INVALID_HEADER_CACHE_LENGTH,
192            max_execute_block_batch_size: DEFAULT_MAX_EXECUTE_BLOCK_BATCH_SIZE,
193            legacy_state_root: false,
194            always_compare_trie_updates: false,
195            disable_state_cache: false,
196            disable_prewarming: false,
197            state_provider_metrics: false,
198            cross_block_cache_size: DEFAULT_CROSS_BLOCK_CACHE_SIZE,
199            has_enough_parallelism: has_enough_parallelism(),
200            multiproof_chunk_size: DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE,
201            reserved_cpu_cores: DEFAULT_RESERVED_CPU_CORES,
202            precompile_cache_disabled: false,
203            state_root_fallback: false,
204            always_process_payload_attributes_on_canonical_head: false,
205            allow_unwind_canonical_header: false,
206            disable_cache_metrics: false,
207            sparse_trie_prune_depth: DEFAULT_SPARSE_TRIE_PRUNE_DEPTH,
208            sparse_trie_max_hot_slots: DEFAULT_SPARSE_TRIE_MAX_HOT_SLOTS,
209            sparse_trie_max_hot_accounts: DEFAULT_SPARSE_TRIE_MAX_HOT_ACCOUNTS,
210            slow_block_threshold: None,
211            disable_sparse_trie_cache_pruning: false,
212            state_root_task_timeout: Some(DEFAULT_STATE_ROOT_TASK_TIMEOUT),
213            share_execution_cache_with_payload_builder: false,
214            share_sparse_trie_with_payload_builder: false,
215            #[cfg(feature = "trie-debug")]
216            proof_jitter: None,
217        }
218    }
219}
220
221impl TreeConfig {
222    /// Create engine tree configuration.
223    #[expect(clippy::too_many_arguments)]
224    pub const fn new(
225        persistence_threshold: u64,
226        memory_block_buffer_target: u64,
227        persistence_backpressure_threshold: u64,
228        block_buffer_limit: u32,
229        max_invalid_header_cache_length: u32,
230        max_execute_block_batch_size: usize,
231        legacy_state_root: bool,
232        always_compare_trie_updates: bool,
233        disable_state_cache: bool,
234        disable_prewarming: bool,
235        state_provider_metrics: bool,
236        cross_block_cache_size: usize,
237        has_enough_parallelism: bool,
238        multiproof_chunk_size: usize,
239        reserved_cpu_cores: usize,
240        precompile_cache_disabled: bool,
241        state_root_fallback: bool,
242        always_process_payload_attributes_on_canonical_head: bool,
243        allow_unwind_canonical_header: bool,
244        disable_cache_metrics: bool,
245        sparse_trie_prune_depth: usize,
246        sparse_trie_max_hot_slots: usize,
247        sparse_trie_max_hot_accounts: usize,
248        slow_block_threshold: Option<Duration>,
249        state_root_task_timeout: Option<Duration>,
250        share_execution_cache_with_payload_builder: bool,
251        share_sparse_trie_with_payload_builder: bool,
252    ) -> Self {
253        assert_backpressure_threshold_invariant(
254            persistence_threshold,
255            persistence_backpressure_threshold,
256        );
257        Self {
258            persistence_threshold,
259            memory_block_buffer_target,
260            persistence_backpressure_threshold,
261            block_buffer_limit,
262            max_invalid_header_cache_length,
263            max_execute_block_batch_size,
264            legacy_state_root,
265            always_compare_trie_updates,
266            disable_state_cache,
267            disable_prewarming,
268            state_provider_metrics,
269            cross_block_cache_size,
270            has_enough_parallelism,
271            multiproof_chunk_size,
272            reserved_cpu_cores,
273            precompile_cache_disabled,
274            state_root_fallback,
275            always_process_payload_attributes_on_canonical_head,
276            allow_unwind_canonical_header,
277            disable_cache_metrics,
278            sparse_trie_prune_depth,
279            sparse_trie_max_hot_slots,
280            sparse_trie_max_hot_accounts,
281            slow_block_threshold,
282            disable_sparse_trie_cache_pruning: false,
283            state_root_task_timeout,
284            share_execution_cache_with_payload_builder,
285            share_sparse_trie_with_payload_builder,
286            #[cfg(feature = "trie-debug")]
287            proof_jitter: None,
288        }
289    }
290
291    /// Return the persistence threshold.
292    pub const fn persistence_threshold(&self) -> u64 {
293        self.persistence_threshold
294    }
295
296    /// Return the memory block buffer target.
297    pub const fn memory_block_buffer_target(&self) -> u64 {
298        self.memory_block_buffer_target
299    }
300
301    /// Return the persistence backpressure threshold.
302    pub const fn persistence_backpressure_threshold(&self) -> u64 {
303        self.persistence_backpressure_threshold
304    }
305
306    /// Return the block buffer limit.
307    pub const fn block_buffer_limit(&self) -> u32 {
308        self.block_buffer_limit
309    }
310
311    /// Return the maximum invalid cache header length.
312    pub const fn max_invalid_header_cache_length(&self) -> u32 {
313        self.max_invalid_header_cache_length
314    }
315
316    /// Return the maximum execute block batch size.
317    pub const fn max_execute_block_batch_size(&self) -> usize {
318        self.max_execute_block_batch_size
319    }
320
321    /// Return the multiproof task chunk size.
322    pub const fn multiproof_chunk_size(&self) -> usize {
323        self.multiproof_chunk_size
324    }
325
326    /// Return the effective multiproof task chunk size.
327    pub const fn effective_multiproof_chunk_size(&self) -> usize {
328        self.multiproof_chunk_size
329    }
330
331    /// Return the number of reserved CPU cores for non-reth processes
332    pub const fn reserved_cpu_cores(&self) -> usize {
333        self.reserved_cpu_cores
334    }
335
336    /// Returns whether to use the legacy state root calculation method instead
337    /// of the new state root task
338    pub const fn legacy_state_root(&self) -> bool {
339        self.legacy_state_root
340    }
341
342    /// Returns whether or not state provider metrics are enabled.
343    pub const fn state_provider_metrics(&self) -> bool {
344        self.state_provider_metrics
345    }
346
347    /// Returns whether or not state cache is disabled.
348    pub const fn disable_state_cache(&self) -> bool {
349        self.disable_state_cache
350    }
351
352    /// Returns whether or not parallel prewarming is disabled.
353    pub const fn disable_prewarming(&self) -> bool {
354        self.disable_prewarming
355    }
356
357    /// Returns whether to always compare trie updates from the state root task to the trie updates
358    /// from the regular state root calculation.
359    pub const fn always_compare_trie_updates(&self) -> bool {
360        self.always_compare_trie_updates
361    }
362
363    /// Returns the cross-block cache size.
364    pub const fn cross_block_cache_size(&self) -> usize {
365        self.cross_block_cache_size
366    }
367
368    /// Returns whether precompile cache is disabled.
369    pub const fn precompile_cache_disabled(&self) -> bool {
370        self.precompile_cache_disabled
371    }
372
373    /// Returns whether to use state root fallback.
374    pub const fn state_root_fallback(&self) -> bool {
375        self.state_root_fallback
376    }
377
378    /// Sets whether to always process payload attributes when the FCU head is already canonical.
379    pub const fn with_always_process_payload_attributes_on_canonical_head(
380        mut self,
381        always_process_payload_attributes_on_canonical_head: bool,
382    ) -> Self {
383        self.always_process_payload_attributes_on_canonical_head =
384            always_process_payload_attributes_on_canonical_head;
385        self
386    }
387
388    /// Returns true if payload attributes should always be processed even when the FCU head is
389    /// canonical.
390    pub const fn always_process_payload_attributes_on_canonical_head(&self) -> bool {
391        self.always_process_payload_attributes_on_canonical_head
392    }
393
394    /// Returns true if canonical header should be unwound to ancestor during forkchoice updates.
395    pub const fn unwind_canonical_header(&self) -> bool {
396        self.allow_unwind_canonical_header
397    }
398
399    /// Setter for persistence threshold.
400    pub const fn with_persistence_threshold(mut self, persistence_threshold: u64) -> Self {
401        self.persistence_threshold = persistence_threshold;
402        assert_backpressure_threshold_invariant(
403            self.persistence_threshold,
404            self.persistence_backpressure_threshold,
405        );
406        self
407    }
408
409    /// Setter for memory block buffer target.
410    pub const fn with_memory_block_buffer_target(
411        mut self,
412        memory_block_buffer_target: u64,
413    ) -> Self {
414        self.memory_block_buffer_target = memory_block_buffer_target;
415        self
416    }
417
418    /// Setter for persistence backpressure threshold.
419    pub const fn with_persistence_backpressure_threshold(
420        mut self,
421        persistence_backpressure_threshold: u64,
422    ) -> Self {
423        self.persistence_backpressure_threshold = persistence_backpressure_threshold;
424        assert_backpressure_threshold_invariant(
425            self.persistence_threshold,
426            self.persistence_backpressure_threshold,
427        );
428        self
429    }
430
431    /// Setter for block buffer limit.
432    pub const fn with_block_buffer_limit(mut self, block_buffer_limit: u32) -> Self {
433        self.block_buffer_limit = block_buffer_limit;
434        self
435    }
436
437    /// Setter for maximum invalid header cache length.
438    pub const fn with_max_invalid_header_cache_length(
439        mut self,
440        max_invalid_header_cache_length: u32,
441    ) -> Self {
442        self.max_invalid_header_cache_length = max_invalid_header_cache_length;
443        self
444    }
445
446    /// Setter for maximum execute block batch size.
447    pub const fn with_max_execute_block_batch_size(
448        mut self,
449        max_execute_block_batch_size: usize,
450    ) -> Self {
451        self.max_execute_block_batch_size = max_execute_block_batch_size;
452        self
453    }
454
455    /// Setter for whether to use the legacy state root calculation method.
456    pub const fn with_legacy_state_root(mut self, legacy_state_root: bool) -> Self {
457        self.legacy_state_root = legacy_state_root;
458        self
459    }
460
461    /// Setter for whether to disable state cache.
462    pub const fn without_state_cache(mut self, disable_state_cache: bool) -> Self {
463        self.disable_state_cache = disable_state_cache;
464        self
465    }
466
467    /// Setter for whether to disable parallel prewarming.
468    pub const fn without_prewarming(mut self, disable_prewarming: bool) -> Self {
469        self.disable_prewarming = disable_prewarming;
470        self
471    }
472
473    /// Setter for whether to always compare trie updates from the state root task to the trie
474    /// updates from the regular state root calculation.
475    pub const fn with_always_compare_trie_updates(
476        mut self,
477        always_compare_trie_updates: bool,
478    ) -> Self {
479        self.always_compare_trie_updates = always_compare_trie_updates;
480        self
481    }
482
483    /// Setter for cross block cache size.
484    pub const fn with_cross_block_cache_size(mut self, cross_block_cache_size: usize) -> Self {
485        self.cross_block_cache_size = cross_block_cache_size;
486        self
487    }
488
489    /// Setter for has enough parallelism.
490    pub const fn with_has_enough_parallelism(mut self, has_enough_parallelism: bool) -> Self {
491        self.has_enough_parallelism = has_enough_parallelism;
492        self
493    }
494
495    /// Setter for state provider metrics.
496    pub const fn with_state_provider_metrics(mut self, state_provider_metrics: bool) -> Self {
497        self.state_provider_metrics = state_provider_metrics;
498        self
499    }
500
501    /// Setter for multiproof task chunk size for proof targets.
502    pub const fn with_multiproof_chunk_size(mut self, multiproof_chunk_size: usize) -> Self {
503        self.multiproof_chunk_size = multiproof_chunk_size;
504        self
505    }
506
507    /// Setter for the number of reserved CPU cores for any non-reth processes
508    pub const fn with_reserved_cpu_cores(mut self, reserved_cpu_cores: usize) -> Self {
509        self.reserved_cpu_cores = reserved_cpu_cores;
510        self
511    }
512
513    /// Setter for whether to disable the precompile cache.
514    pub const fn without_precompile_cache(mut self, precompile_cache_disabled: bool) -> Self {
515        self.precompile_cache_disabled = precompile_cache_disabled;
516        self
517    }
518
519    /// Setter for whether to use state root fallback, useful for testing.
520    pub const fn with_state_root_fallback(mut self, state_root_fallback: bool) -> Self {
521        self.state_root_fallback = state_root_fallback;
522        self
523    }
524
525    /// Setter for whether to unwind canonical header to ancestor during forkchoice updates.
526    pub const fn with_unwind_canonical_header(mut self, unwind_canonical_header: bool) -> Self {
527        self.allow_unwind_canonical_header = unwind_canonical_header;
528        self
529    }
530
531    /// Whether or not to use state root task
532    pub const fn use_state_root_task(&self) -> bool {
533        self.has_enough_parallelism && !self.legacy_state_root
534    }
535
536    /// Returns whether cache metrics recording is disabled.
537    pub const fn disable_cache_metrics(&self) -> bool {
538        self.disable_cache_metrics
539    }
540
541    /// Setter for whether to disable cache metrics recording.
542    pub const fn without_cache_metrics(mut self, disable_cache_metrics: bool) -> Self {
543        self.disable_cache_metrics = disable_cache_metrics;
544        self
545    }
546
547    /// Returns the sparse trie prune depth.
548    pub const fn sparse_trie_prune_depth(&self) -> usize {
549        self.sparse_trie_prune_depth
550    }
551
552    /// Setter for sparse trie prune depth.
553    pub const fn with_sparse_trie_prune_depth(mut self, depth: usize) -> Self {
554        self.sparse_trie_prune_depth = depth;
555        self
556    }
557
558    /// Returns the LFU hot-slot capacity for sparse trie pruning.
559    pub const fn sparse_trie_max_hot_slots(&self) -> usize {
560        self.sparse_trie_max_hot_slots
561    }
562
563    /// Setter for LFU hot-slot capacity.
564    pub const fn with_sparse_trie_max_hot_slots(mut self, max_hot_slots: usize) -> Self {
565        self.sparse_trie_max_hot_slots = max_hot_slots;
566        self
567    }
568
569    /// Returns the LFU hot-account capacity for sparse trie pruning.
570    pub const fn sparse_trie_max_hot_accounts(&self) -> usize {
571        self.sparse_trie_max_hot_accounts
572    }
573
574    /// Setter for LFU hot-account capacity.
575    pub const fn with_sparse_trie_max_hot_accounts(mut self, max_hot_accounts: usize) -> Self {
576        self.sparse_trie_max_hot_accounts = max_hot_accounts;
577        self
578    }
579
580    /// Returns the slow block threshold, if configured.
581    ///
582    /// When `Some`, blocks whose total processing time exceeds this duration emit a structured
583    /// warning with timing, state-operation, and cache-hit-rate details. `Duration::ZERO` logs
584    /// every block.
585    pub const fn slow_block_threshold(&self) -> Option<Duration> {
586        self.slow_block_threshold
587    }
588
589    /// Setter for slow block threshold.
590    pub const fn with_slow_block_threshold(
591        mut self,
592        slow_block_threshold: Option<Duration>,
593    ) -> Self {
594        self.slow_block_threshold = slow_block_threshold;
595        self
596    }
597
598    /// Returns whether sparse trie cache pruning is disabled.
599    pub const fn disable_sparse_trie_cache_pruning(&self) -> bool {
600        self.disable_sparse_trie_cache_pruning
601    }
602
603    /// Setter for whether to disable sparse trie cache pruning.
604    pub const fn with_disable_sparse_trie_cache_pruning(mut self, value: bool) -> Self {
605        self.disable_sparse_trie_cache_pruning = value;
606        self
607    }
608
609    /// Returns the state root task timeout.
610    pub const fn state_root_task_timeout(&self) -> Option<Duration> {
611        self.state_root_task_timeout
612    }
613
614    /// Setter for state root task timeout.
615    pub const fn with_state_root_task_timeout(mut self, timeout: Option<Duration>) -> Self {
616        self.state_root_task_timeout = timeout;
617        self
618    }
619
620    /// Returns whether to share execution cache with the payload builder.
621    pub const fn share_execution_cache_with_payload_builder(&self) -> bool {
622        self.share_execution_cache_with_payload_builder
623    }
624
625    /// Returns whether to share sparse trie with the payload builder.
626    pub const fn share_sparse_trie_with_payload_builder(&self) -> bool {
627        self.share_sparse_trie_with_payload_builder
628    }
629
630    /// Setter for whether to share execution cache with the payload builder.
631    pub const fn with_share_execution_cache_with_payload_builder(
632        mut self,
633        share_execution_cache_with_payload_builder: bool,
634    ) -> Self {
635        self.share_execution_cache_with_payload_builder =
636            share_execution_cache_with_payload_builder;
637        self
638    }
639
640    /// Setter for whether to share sparse trie with the payload builder.
641    pub const fn with_share_sparse_trie_with_payload_builder(
642        mut self,
643        share_sparse_trie_with_payload_builder: bool,
644    ) -> Self {
645        self.share_sparse_trie_with_payload_builder = share_sparse_trie_with_payload_builder;
646        self
647    }
648
649    /// Returns the proof jitter duration, if configured (trie-debug only).
650    #[cfg(feature = "trie-debug")]
651    pub const fn proof_jitter(&self) -> Option<Duration> {
652        self.proof_jitter
653    }
654
655    /// Setter for proof jitter (trie-debug only).
656    #[cfg(feature = "trie-debug")]
657    pub const fn with_proof_jitter(mut self, proof_jitter: Option<Duration>) -> Self {
658        self.proof_jitter = proof_jitter;
659        self
660    }
661}
662
663#[cfg(test)]
664mod tests {
665    use super::TreeConfig;
666
667    #[test]
668    #[should_panic(
669        expected = "persistence_backpressure_threshold must be greater than persistence_threshold"
670    )]
671    fn rejects_backpressure_threshold_at_or_below_persistence_threshold() {
672        let _ = TreeConfig::default()
673            .with_persistence_threshold(4)
674            .with_persistence_backpressure_threshold(4);
675    }
676}