1use alloy_eips::merge::EPOCH_SLOTS;
4use core::time::Duration;
5
6pub const DEFAULT_PERSISTENCE_THRESHOLD: u64 = 7;
8
9pub const DEFAULT_PERSISTENCE_BACKPRESSURE_THRESHOLD: u64 = 16;
12
13pub const DEFAULT_MEMORY_BLOCK_BUFFER_TARGET: u64 = 5;
15
16pub const DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE: usize = 5;
18
19pub const DEFAULT_INVALID_HEADER_HIT_EVICTION_THRESHOLD: u8 = 128;
21
22pub const SMALL_BLOCK_GAS_THRESHOLD: u64 = 20_000_000;
24
25pub const DEFAULT_RESERVED_CPU_CORES: usize = 1;
29
30pub const DEFAULT_SPARSE_TRIE_PRUNE_DEPTH: usize = 4;
35
36pub const DEFAULT_STATE_ROOT_TASK_TIMEOUT: Duration = Duration::from_secs(1);
38
39const DEFAULT_BLOCK_BUFFER_LIMIT: u32 = EPOCH_SLOTS as u32 * 2;
40const DEFAULT_MAX_INVALID_HEADER_CACHE_LENGTH: u32 = 256;
41const DEFAULT_MAX_EXECUTE_BLOCK_BATCH_SIZE: usize = 4;
42const DEFAULT_CROSS_BLOCK_CACHE_SIZE: usize = default_cross_block_cache_size();
43
44const fn assert_backpressure_threshold_invariant(
45 persistence_threshold: u64,
46 persistence_backpressure_threshold: u64,
47) {
48 debug_assert!(
49 persistence_backpressure_threshold > persistence_threshold,
50 "persistence_backpressure_threshold must be greater than persistence_threshold",
51 );
52}
53
54const fn default_cross_block_cache_size() -> usize {
55 if cfg!(test) {
56 1024 * 1024 } else if cfg!(target_pointer_width = "32") {
58 usize::MAX } else {
60 4 * 1024 * 1024 * 1024 }
62}
63
64pub fn has_enough_parallelism() -> bool {
73 #[cfg(feature = "std")]
74 {
75 std::thread::available_parallelism().is_ok_and(|num| num.get() >= 5)
76 }
77 #[cfg(not(feature = "std"))]
78 false
79}
80
81#[derive(Debug, Clone)]
83pub struct TreeConfig {
84 persistence_threshold: u64,
87 memory_block_buffer_target: u64,
92 persistence_backpressure_threshold: u64,
95 block_buffer_limit: u32,
98 max_invalid_header_cache_length: u32,
100 invalid_header_hit_eviction_threshold: u8,
105 max_execute_block_batch_size: usize,
110 always_compare_trie_updates: bool,
113 disable_state_cache: bool,
115 disable_prewarming: bool,
117 txpool_prewarming: bool,
119 state_provider_metrics: bool,
121 cross_block_cache_size: usize,
123 has_enough_parallelism: bool,
133 multiproof_chunk_size: usize,
135 reserved_cpu_cores: usize,
137 precompile_cache_disabled: bool,
139 state_root_fallback: bool,
141 always_process_payload_attributes_on_canonical_head: bool,
155 allow_unwind_canonical_header: bool,
157 disable_cache_metrics: bool,
159 sparse_trie_prune_depth: usize,
161 slow_block_threshold: Option<Duration>,
165 disable_sparse_trie_cache_pruning: bool,
167 state_root_task_timeout: Option<Duration>,
172 share_execution_cache_with_payload_builder: bool,
174 share_sparse_trie_with_payload_builder: bool,
176 suppress_persistence_during_build: bool,
182 disable_bal_parallel_execution: bool,
185 disable_bal_parallel_state_root: bool,
188 disable_bal_batch_io: bool,
192 skip_state_root: bool,
197 #[cfg(feature = "trie-debug")]
201 proof_jitter: Option<Duration>,
202}
203
204impl Default for TreeConfig {
205 fn default() -> Self {
206 assert_backpressure_threshold_invariant(
207 DEFAULT_PERSISTENCE_THRESHOLD,
208 DEFAULT_PERSISTENCE_BACKPRESSURE_THRESHOLD,
209 );
210 Self {
211 persistence_threshold: DEFAULT_PERSISTENCE_THRESHOLD,
212 memory_block_buffer_target: DEFAULT_MEMORY_BLOCK_BUFFER_TARGET,
213 persistence_backpressure_threshold: DEFAULT_PERSISTENCE_BACKPRESSURE_THRESHOLD,
214 block_buffer_limit: DEFAULT_BLOCK_BUFFER_LIMIT,
215 max_invalid_header_cache_length: DEFAULT_MAX_INVALID_HEADER_CACHE_LENGTH,
216 invalid_header_hit_eviction_threshold: DEFAULT_INVALID_HEADER_HIT_EVICTION_THRESHOLD,
217 max_execute_block_batch_size: DEFAULT_MAX_EXECUTE_BLOCK_BATCH_SIZE,
218 always_compare_trie_updates: false,
219 disable_state_cache: false,
220 disable_prewarming: false,
221 txpool_prewarming: false,
222 state_provider_metrics: false,
223 cross_block_cache_size: DEFAULT_CROSS_BLOCK_CACHE_SIZE,
224 has_enough_parallelism: has_enough_parallelism(),
225 multiproof_chunk_size: DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE,
226 reserved_cpu_cores: DEFAULT_RESERVED_CPU_CORES,
227 precompile_cache_disabled: false,
228 state_root_fallback: false,
229 always_process_payload_attributes_on_canonical_head: false,
230 allow_unwind_canonical_header: false,
231 disable_cache_metrics: false,
232 sparse_trie_prune_depth: DEFAULT_SPARSE_TRIE_PRUNE_DEPTH,
233 slow_block_threshold: None,
234 disable_sparse_trie_cache_pruning: false,
235 state_root_task_timeout: Some(DEFAULT_STATE_ROOT_TASK_TIMEOUT),
236 share_execution_cache_with_payload_builder: false,
237 share_sparse_trie_with_payload_builder: false,
238 suppress_persistence_during_build: false,
239 disable_bal_parallel_execution: false,
240 disable_bal_parallel_state_root: false,
241 disable_bal_batch_io: false,
242 skip_state_root: false,
243 #[cfg(feature = "trie-debug")]
244 proof_jitter: None,
245 }
246 }
247}
248
249impl TreeConfig {
250 #[expect(clippy::too_many_arguments)]
252 pub const fn new(
253 persistence_threshold: u64,
254 memory_block_buffer_target: u64,
255 persistence_backpressure_threshold: u64,
256 block_buffer_limit: u32,
257 max_invalid_header_cache_length: u32,
258 invalid_header_hit_eviction_threshold: u8,
259 max_execute_block_batch_size: usize,
260 always_compare_trie_updates: bool,
261 disable_state_cache: bool,
262 disable_prewarming: bool,
263 state_provider_metrics: bool,
264 cross_block_cache_size: usize,
265 has_enough_parallelism: bool,
266 multiproof_chunk_size: usize,
267 reserved_cpu_cores: usize,
268 precompile_cache_disabled: bool,
269 state_root_fallback: bool,
270 always_process_payload_attributes_on_canonical_head: bool,
271 allow_unwind_canonical_header: bool,
272 disable_cache_metrics: bool,
273 sparse_trie_prune_depth: usize,
274 slow_block_threshold: Option<Duration>,
275 state_root_task_timeout: Option<Duration>,
276 share_execution_cache_with_payload_builder: bool,
277 share_sparse_trie_with_payload_builder: bool,
278 ) -> Self {
279 assert_backpressure_threshold_invariant(
280 persistence_threshold,
281 persistence_backpressure_threshold,
282 );
283 Self {
284 persistence_threshold,
285 memory_block_buffer_target,
286 persistence_backpressure_threshold,
287 block_buffer_limit,
288 max_invalid_header_cache_length,
289 invalid_header_hit_eviction_threshold,
290 max_execute_block_batch_size,
291 always_compare_trie_updates,
292 disable_state_cache,
293 disable_prewarming,
294 txpool_prewarming: false,
295 state_provider_metrics,
296 cross_block_cache_size,
297 has_enough_parallelism,
298 multiproof_chunk_size,
299 reserved_cpu_cores,
300 precompile_cache_disabled,
301 state_root_fallback,
302 always_process_payload_attributes_on_canonical_head,
303 allow_unwind_canonical_header,
304 disable_cache_metrics,
305 sparse_trie_prune_depth,
306 slow_block_threshold,
307 disable_sparse_trie_cache_pruning: false,
308 state_root_task_timeout,
309 share_execution_cache_with_payload_builder,
310 share_sparse_trie_with_payload_builder,
311 suppress_persistence_during_build: false,
312 disable_bal_parallel_execution: false,
313 disable_bal_parallel_state_root: false,
314 disable_bal_batch_io: false,
315 skip_state_root: false,
316 #[cfg(feature = "trie-debug")]
317 proof_jitter: None,
318 }
319 }
320
321 pub const fn persistence_threshold(&self) -> u64 {
323 self.persistence_threshold
324 }
325
326 pub const fn memory_block_buffer_target(&self) -> u64 {
328 self.memory_block_buffer_target
329 }
330
331 pub const fn persistence_backpressure_threshold(&self) -> u64 {
333 self.persistence_backpressure_threshold
334 }
335
336 pub const fn block_buffer_limit(&self) -> u32 {
338 self.block_buffer_limit
339 }
340
341 pub const fn max_invalid_header_cache_length(&self) -> u32 {
343 self.max_invalid_header_cache_length
344 }
345
346 pub const fn invalid_header_hit_eviction_threshold(&self) -> u8 {
351 self.invalid_header_hit_eviction_threshold
352 }
353
354 pub const fn max_execute_block_batch_size(&self) -> usize {
356 self.max_execute_block_batch_size
357 }
358
359 pub const fn multiproof_chunk_size(&self) -> usize {
361 self.multiproof_chunk_size
362 }
363
364 pub const fn effective_multiproof_chunk_size(&self) -> usize {
366 self.multiproof_chunk_size
367 }
368
369 pub const fn reserved_cpu_cores(&self) -> usize {
371 self.reserved_cpu_cores
372 }
373
374 pub const fn state_provider_metrics(&self) -> bool {
376 self.state_provider_metrics
377 }
378
379 pub const fn disable_state_cache(&self) -> bool {
381 self.disable_state_cache
382 }
383
384 pub const fn disable_prewarming(&self) -> bool {
386 self.disable_prewarming
387 }
388
389 pub const fn txpool_prewarming(&self) -> bool {
391 self.txpool_prewarming
392 }
393
394 pub const fn always_compare_trie_updates(&self) -> bool {
397 self.always_compare_trie_updates
398 }
399
400 pub const fn cross_block_cache_size(&self) -> usize {
402 self.cross_block_cache_size
403 }
404
405 pub const fn precompile_cache_disabled(&self) -> bool {
407 self.precompile_cache_disabled
408 }
409
410 pub const fn state_root_fallback(&self) -> bool {
412 self.state_root_fallback
413 }
414
415 pub const fn with_always_process_payload_attributes_on_canonical_head(
417 mut self,
418 always_process_payload_attributes_on_canonical_head: bool,
419 ) -> Self {
420 self.always_process_payload_attributes_on_canonical_head =
421 always_process_payload_attributes_on_canonical_head;
422 self
423 }
424
425 pub const fn always_process_payload_attributes_on_canonical_head(&self) -> bool {
428 self.always_process_payload_attributes_on_canonical_head
429 }
430
431 pub const fn unwind_canonical_header(&self) -> bool {
433 self.allow_unwind_canonical_header
434 }
435
436 pub const fn with_persistence_threshold(mut self, persistence_threshold: u64) -> Self {
438 self.persistence_threshold = persistence_threshold;
439 assert_backpressure_threshold_invariant(
440 self.persistence_threshold,
441 self.persistence_backpressure_threshold,
442 );
443 self
444 }
445
446 pub const fn with_memory_block_buffer_target(
448 mut self,
449 memory_block_buffer_target: u64,
450 ) -> Self {
451 self.memory_block_buffer_target = memory_block_buffer_target;
452 self
453 }
454
455 pub const fn with_persistence_backpressure_threshold(
457 mut self,
458 persistence_backpressure_threshold: u64,
459 ) -> Self {
460 self.persistence_backpressure_threshold = persistence_backpressure_threshold;
461 assert_backpressure_threshold_invariant(
462 self.persistence_threshold,
463 self.persistence_backpressure_threshold,
464 );
465 self
466 }
467
468 pub const fn with_block_buffer_limit(mut self, block_buffer_limit: u32) -> Self {
470 self.block_buffer_limit = block_buffer_limit;
471 self
472 }
473
474 pub const fn with_max_invalid_header_cache_length(
476 mut self,
477 max_invalid_header_cache_length: u32,
478 ) -> Self {
479 self.max_invalid_header_cache_length = max_invalid_header_cache_length;
480 self
481 }
482
483 pub const fn with_invalid_header_hit_eviction_threshold(
485 mut self,
486 invalid_header_hit_eviction_threshold: u8,
487 ) -> Self {
488 self.invalid_header_hit_eviction_threshold = invalid_header_hit_eviction_threshold;
489 self
490 }
491
492 pub const fn with_max_execute_block_batch_size(
494 mut self,
495 max_execute_block_batch_size: usize,
496 ) -> Self {
497 self.max_execute_block_batch_size = max_execute_block_batch_size;
498 self
499 }
500
501 pub const fn without_state_cache(mut self, disable_state_cache: bool) -> Self {
503 self.disable_state_cache = disable_state_cache;
504 self
505 }
506
507 pub const fn without_prewarming(mut self, disable_prewarming: bool) -> Self {
509 self.disable_prewarming = disable_prewarming;
510 self
511 }
512
513 pub const fn with_txpool_prewarming(mut self, enabled: bool) -> Self {
515 self.txpool_prewarming = enabled;
516 self
517 }
518
519 pub const fn with_always_compare_trie_updates(
522 mut self,
523 always_compare_trie_updates: bool,
524 ) -> Self {
525 self.always_compare_trie_updates = always_compare_trie_updates;
526 self
527 }
528
529 pub const fn with_cross_block_cache_size(mut self, cross_block_cache_size: usize) -> Self {
531 self.cross_block_cache_size = cross_block_cache_size;
532 self
533 }
534
535 pub const fn with_has_enough_parallelism(mut self, has_enough_parallelism: bool) -> Self {
537 self.has_enough_parallelism = has_enough_parallelism;
538 self
539 }
540
541 pub const fn has_enough_parallelism(&self) -> bool {
543 self.has_enough_parallelism
544 }
545
546 pub const fn use_state_root_task(&self) -> bool {
551 !self.skip_state_root && !self.state_root_fallback && self.has_enough_parallelism
552 }
553
554 pub const fn with_state_provider_metrics(mut self, state_provider_metrics: bool) -> Self {
556 self.state_provider_metrics = state_provider_metrics;
557 self
558 }
559
560 pub const fn with_multiproof_chunk_size(mut self, multiproof_chunk_size: usize) -> Self {
562 self.multiproof_chunk_size = multiproof_chunk_size;
563 self
564 }
565
566 pub const fn with_reserved_cpu_cores(mut self, reserved_cpu_cores: usize) -> Self {
568 self.reserved_cpu_cores = reserved_cpu_cores;
569 self
570 }
571
572 pub const fn without_precompile_cache(mut self, precompile_cache_disabled: bool) -> Self {
574 self.precompile_cache_disabled = precompile_cache_disabled;
575 self
576 }
577
578 pub const fn with_state_root_fallback(mut self, state_root_fallback: bool) -> Self {
580 self.state_root_fallback = state_root_fallback;
581 self
582 }
583
584 pub const fn with_unwind_canonical_header(mut self, unwind_canonical_header: bool) -> Self {
586 self.allow_unwind_canonical_header = unwind_canonical_header;
587 self
588 }
589
590 pub const fn disable_cache_metrics(&self) -> bool {
592 self.disable_cache_metrics
593 }
594
595 pub const fn without_cache_metrics(mut self, disable_cache_metrics: bool) -> Self {
597 self.disable_cache_metrics = disable_cache_metrics;
598 self
599 }
600
601 pub const fn sparse_trie_prune_depth(&self) -> usize {
603 self.sparse_trie_prune_depth
604 }
605
606 pub const fn with_sparse_trie_prune_depth(mut self, depth: usize) -> Self {
608 self.sparse_trie_prune_depth = depth;
609 self
610 }
611
612 pub const fn slow_block_threshold(&self) -> Option<Duration> {
618 self.slow_block_threshold
619 }
620
621 pub const fn with_slow_block_threshold(
623 mut self,
624 slow_block_threshold: Option<Duration>,
625 ) -> Self {
626 self.slow_block_threshold = slow_block_threshold;
627 self
628 }
629
630 pub const fn disable_sparse_trie_cache_pruning(&self) -> bool {
632 self.disable_sparse_trie_cache_pruning
633 }
634
635 pub const fn with_disable_sparse_trie_cache_pruning(mut self, value: bool) -> Self {
637 self.disable_sparse_trie_cache_pruning = value;
638 self
639 }
640
641 pub const fn state_root_task_timeout(&self) -> Option<Duration> {
643 self.state_root_task_timeout
644 }
645
646 pub const fn with_state_root_task_timeout(mut self, timeout: Option<Duration>) -> Self {
648 self.state_root_task_timeout = timeout;
649 self
650 }
651
652 pub const fn share_execution_cache_with_payload_builder(&self) -> bool {
654 self.share_execution_cache_with_payload_builder
655 }
656
657 pub const fn share_sparse_trie_with_payload_builder(&self) -> bool {
659 self.share_sparse_trie_with_payload_builder
660 }
661
662 pub const fn with_share_execution_cache_with_payload_builder(
664 mut self,
665 share_execution_cache_with_payload_builder: bool,
666 ) -> Self {
667 self.share_execution_cache_with_payload_builder =
668 share_execution_cache_with_payload_builder;
669 self
670 }
671
672 pub const fn with_share_sparse_trie_with_payload_builder(
674 mut self,
675 share_sparse_trie_with_payload_builder: bool,
676 ) -> Self {
677 self.share_sparse_trie_with_payload_builder = share_sparse_trie_with_payload_builder;
678 self
679 }
680
681 pub const fn suppress_persistence_during_build(&self) -> bool {
683 self.suppress_persistence_during_build
684 }
685
686 pub const fn with_suppress_persistence_during_build(mut self, value: bool) -> Self {
688 self.suppress_persistence_during_build = value;
689 self
690 }
691
692 pub const fn disable_bal_parallel_execution(&self) -> bool {
694 self.disable_bal_parallel_execution
695 }
696
697 pub const fn without_bal_parallel_execution(
699 mut self,
700 disable_bal_parallel_execution: bool,
701 ) -> Self {
702 self.disable_bal_parallel_execution = disable_bal_parallel_execution;
703 self
704 }
705
706 pub const fn disable_bal_parallel_state_root(&self) -> bool {
708 self.disable_bal_parallel_state_root
709 }
710
711 pub const fn without_bal_parallel_state_root(
713 mut self,
714 disable_bal_parallel_state_root: bool,
715 ) -> Self {
716 self.disable_bal_parallel_state_root = disable_bal_parallel_state_root;
717 self
718 }
719
720 pub const fn disable_bal_batch_io(&self) -> bool {
722 self.disable_bal_batch_io
723 }
724
725 pub const fn without_bal_batch_io(mut self, disable_bal_batch_io: bool) -> Self {
727 self.disable_bal_batch_io = disable_bal_batch_io;
728 self
729 }
730
731 pub const fn skip_state_root(&self) -> bool {
733 self.skip_state_root
734 }
735
736 pub const fn with_skip_state_root(mut self, skip_state_root: bool) -> Self {
738 self.skip_state_root = skip_state_root;
739 self
740 }
741
742 #[cfg(feature = "trie-debug")]
744 pub const fn proof_jitter(&self) -> Option<Duration> {
745 self.proof_jitter
746 }
747
748 #[cfg(feature = "trie-debug")]
750 pub const fn with_proof_jitter(mut self, proof_jitter: Option<Duration>) -> Self {
751 self.proof_jitter = proof_jitter;
752 self
753 }
754}
755
756#[cfg(test)]
757mod tests {
758 use super::TreeConfig;
759
760 #[test]
761 fn txpool_prewarming_is_disabled_by_default_and_can_be_enabled() {
762 assert!(!TreeConfig::default().txpool_prewarming());
763 assert!(TreeConfig::default().with_txpool_prewarming(true).txpool_prewarming());
764 }
765
766 #[test]
767 fn state_root_task_requires_parallelism_without_overrides() {
768 assert!(TreeConfig::default().with_has_enough_parallelism(true).use_state_root_task());
769 assert!(!TreeConfig::default().with_has_enough_parallelism(false).use_state_root_task());
770 assert!(!TreeConfig::default()
771 .with_has_enough_parallelism(true)
772 .with_state_root_fallback(true)
773 .use_state_root_task());
774 assert!(!TreeConfig::default()
775 .with_has_enough_parallelism(true)
776 .with_skip_state_root(true)
777 .use_state_root_task());
778 }
779
780 #[test]
781 #[should_panic(
782 expected = "persistence_backpressure_threshold must be greater than persistence_threshold"
783 )]
784 fn rejects_backpressure_threshold_at_or_below_persistence_threshold() {
785 let _ = TreeConfig::default()
786 .with_persistence_threshold(4)
787 .with_persistence_backpressure_threshold(4);
788 }
789}