1use alloy_eips::merge::EPOCH_SLOTS;
4use core::time::Duration;
5
6pub const DEFAULT_PERSISTENCE_THRESHOLD: u64 = 2;
8
9pub const DEFAULT_PERSISTENCE_BACKPRESSURE_THRESHOLD: u64 = 16;
11
12pub const DEFAULT_MEMORY_BLOCK_BUFFER_TARGET: u64 = 0;
14
15pub const DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE: usize = 5;
17
18pub const DEFAULT_INVALID_HEADER_HIT_EVICTION_THRESHOLD: u8 = 128;
20
21pub const SMALL_BLOCK_GAS_THRESHOLD: u64 = 20_000_000;
23
24pub const DEFAULT_RESERVED_CPU_CORES: usize = 1;
28
29pub const DEFAULT_SPARSE_TRIE_PRUNE_DEPTH: usize = 4;
34
35pub const DEFAULT_SPARSE_TRIE_MAX_HOT_SLOTS: usize = 1500;
39
40pub const DEFAULT_SPARSE_TRIE_MAX_HOT_ACCOUNTS: usize = 1000;
44
45pub const DEFAULT_STATE_ROOT_TASK_TIMEOUT: Duration = Duration::from_secs(1);
47
48const DEFAULT_BLOCK_BUFFER_LIMIT: u32 = EPOCH_SLOTS as u32 * 2;
49const DEFAULT_MAX_INVALID_HEADER_CACHE_LENGTH: u32 = 256;
50const DEFAULT_MAX_EXECUTE_BLOCK_BATCH_SIZE: usize = 4;
51const DEFAULT_CROSS_BLOCK_CACHE_SIZE: usize = default_cross_block_cache_size();
52
53const fn assert_backpressure_threshold_invariant(
54 persistence_threshold: u64,
55 persistence_backpressure_threshold: u64,
56) {
57 debug_assert!(
58 persistence_backpressure_threshold > persistence_threshold,
59 "persistence_backpressure_threshold must be greater than persistence_threshold",
60 );
61}
62
63const fn default_cross_block_cache_size() -> usize {
64 if cfg!(test) {
65 1024 * 1024 } else if cfg!(target_pointer_width = "32") {
67 usize::MAX } else {
69 4 * 1024 * 1024 * 1024 }
71}
72
73pub fn has_enough_parallelism() -> bool {
82 #[cfg(feature = "std")]
83 {
84 std::thread::available_parallelism().is_ok_and(|num| num.get() >= 5)
85 }
86 #[cfg(not(feature = "std"))]
87 false
88}
89
90#[derive(Debug, Clone)]
92pub struct TreeConfig {
93 persistence_threshold: u64,
96 memory_block_buffer_target: u64,
101 persistence_backpressure_threshold: u64,
103 block_buffer_limit: u32,
106 max_invalid_header_cache_length: u32,
108 invalid_header_hit_eviction_threshold: u8,
113 max_execute_block_batch_size: usize,
118 legacy_state_root: bool,
121 always_compare_trie_updates: bool,
124 disable_state_cache: bool,
126 disable_prewarming: bool,
128 state_provider_metrics: bool,
130 cross_block_cache_size: usize,
132 has_enough_parallelism: bool,
134 multiproof_chunk_size: usize,
136 reserved_cpu_cores: usize,
138 precompile_cache_disabled: bool,
140 state_root_fallback: bool,
142 always_process_payload_attributes_on_canonical_head: bool,
156 allow_unwind_canonical_header: bool,
158 disable_cache_metrics: bool,
160 sparse_trie_prune_depth: usize,
162 sparse_trie_max_hot_slots: usize,
164 sparse_trie_max_hot_accounts: usize,
166 slow_block_threshold: Option<Duration>,
170 disable_sparse_trie_cache_pruning: bool,
172 state_root_task_timeout: Option<Duration>,
177 share_execution_cache_with_payload_builder: bool,
179 share_sparse_trie_with_payload_builder: bool,
181 suppress_persistence_during_build: bool,
187 disable_bal_parallel_execution: bool,
190 disable_bal_parallel_state_root: bool,
193 disable_bal_batch_io: bool,
197 skip_state_root: bool,
202 #[cfg(feature = "trie-debug")]
206 proof_jitter: Option<Duration>,
207}
208
209impl Default for TreeConfig {
210 fn default() -> Self {
211 assert_backpressure_threshold_invariant(
212 DEFAULT_PERSISTENCE_THRESHOLD,
213 DEFAULT_PERSISTENCE_BACKPRESSURE_THRESHOLD,
214 );
215 Self {
216 persistence_threshold: DEFAULT_PERSISTENCE_THRESHOLD,
217 memory_block_buffer_target: DEFAULT_MEMORY_BLOCK_BUFFER_TARGET,
218 persistence_backpressure_threshold: DEFAULT_PERSISTENCE_BACKPRESSURE_THRESHOLD,
219 block_buffer_limit: DEFAULT_BLOCK_BUFFER_LIMIT,
220 max_invalid_header_cache_length: DEFAULT_MAX_INVALID_HEADER_CACHE_LENGTH,
221 invalid_header_hit_eviction_threshold: DEFAULT_INVALID_HEADER_HIT_EVICTION_THRESHOLD,
222 max_execute_block_batch_size: DEFAULT_MAX_EXECUTE_BLOCK_BATCH_SIZE,
223 legacy_state_root: false,
224 always_compare_trie_updates: false,
225 disable_state_cache: false,
226 disable_prewarming: false,
227 state_provider_metrics: false,
228 cross_block_cache_size: DEFAULT_CROSS_BLOCK_CACHE_SIZE,
229 has_enough_parallelism: has_enough_parallelism(),
230 multiproof_chunk_size: DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE,
231 reserved_cpu_cores: DEFAULT_RESERVED_CPU_CORES,
232 precompile_cache_disabled: false,
233 state_root_fallback: false,
234 always_process_payload_attributes_on_canonical_head: false,
235 allow_unwind_canonical_header: false,
236 disable_cache_metrics: false,
237 sparse_trie_prune_depth: DEFAULT_SPARSE_TRIE_PRUNE_DEPTH,
238 sparse_trie_max_hot_slots: DEFAULT_SPARSE_TRIE_MAX_HOT_SLOTS,
239 sparse_trie_max_hot_accounts: DEFAULT_SPARSE_TRIE_MAX_HOT_ACCOUNTS,
240 slow_block_threshold: None,
241 disable_sparse_trie_cache_pruning: false,
242 state_root_task_timeout: Some(DEFAULT_STATE_ROOT_TASK_TIMEOUT),
243 share_execution_cache_with_payload_builder: false,
244 share_sparse_trie_with_payload_builder: false,
245 suppress_persistence_during_build: false,
246 disable_bal_parallel_execution: false,
247 disable_bal_parallel_state_root: false,
248 disable_bal_batch_io: false,
249 skip_state_root: false,
250 #[cfg(feature = "trie-debug")]
251 proof_jitter: None,
252 }
253 }
254}
255
256impl TreeConfig {
257 #[expect(clippy::too_many_arguments)]
259 pub const fn new(
260 persistence_threshold: u64,
261 memory_block_buffer_target: u64,
262 persistence_backpressure_threshold: u64,
263 block_buffer_limit: u32,
264 max_invalid_header_cache_length: u32,
265 invalid_header_hit_eviction_threshold: u8,
266 max_execute_block_batch_size: usize,
267 legacy_state_root: bool,
268 always_compare_trie_updates: bool,
269 disable_state_cache: bool,
270 disable_prewarming: bool,
271 state_provider_metrics: bool,
272 cross_block_cache_size: usize,
273 has_enough_parallelism: bool,
274 multiproof_chunk_size: usize,
275 reserved_cpu_cores: usize,
276 precompile_cache_disabled: bool,
277 state_root_fallback: bool,
278 always_process_payload_attributes_on_canonical_head: bool,
279 allow_unwind_canonical_header: bool,
280 disable_cache_metrics: bool,
281 sparse_trie_prune_depth: usize,
282 sparse_trie_max_hot_slots: usize,
283 sparse_trie_max_hot_accounts: usize,
284 slow_block_threshold: Option<Duration>,
285 state_root_task_timeout: Option<Duration>,
286 share_execution_cache_with_payload_builder: bool,
287 share_sparse_trie_with_payload_builder: bool,
288 ) -> Self {
289 assert_backpressure_threshold_invariant(
290 persistence_threshold,
291 persistence_backpressure_threshold,
292 );
293 Self {
294 persistence_threshold,
295 memory_block_buffer_target,
296 persistence_backpressure_threshold,
297 block_buffer_limit,
298 max_invalid_header_cache_length,
299 invalid_header_hit_eviction_threshold,
300 max_execute_block_batch_size,
301 legacy_state_root,
302 always_compare_trie_updates,
303 disable_state_cache,
304 disable_prewarming,
305 state_provider_metrics,
306 cross_block_cache_size,
307 has_enough_parallelism,
308 multiproof_chunk_size,
309 reserved_cpu_cores,
310 precompile_cache_disabled,
311 state_root_fallback,
312 always_process_payload_attributes_on_canonical_head,
313 allow_unwind_canonical_header,
314 disable_cache_metrics,
315 sparse_trie_prune_depth,
316 sparse_trie_max_hot_slots,
317 sparse_trie_max_hot_accounts,
318 slow_block_threshold,
319 disable_sparse_trie_cache_pruning: false,
320 state_root_task_timeout,
321 share_execution_cache_with_payload_builder,
322 share_sparse_trie_with_payload_builder,
323 suppress_persistence_during_build: false,
324 disable_bal_parallel_execution: false,
325 disable_bal_parallel_state_root: false,
326 disable_bal_batch_io: false,
327 skip_state_root: false,
328 #[cfg(feature = "trie-debug")]
329 proof_jitter: None,
330 }
331 }
332
333 pub const fn persistence_threshold(&self) -> u64 {
335 self.persistence_threshold
336 }
337
338 pub const fn memory_block_buffer_target(&self) -> u64 {
340 self.memory_block_buffer_target
341 }
342
343 pub const fn persistence_backpressure_threshold(&self) -> u64 {
345 self.persistence_backpressure_threshold
346 }
347
348 pub const fn block_buffer_limit(&self) -> u32 {
350 self.block_buffer_limit
351 }
352
353 pub const fn max_invalid_header_cache_length(&self) -> u32 {
355 self.max_invalid_header_cache_length
356 }
357
358 pub const fn invalid_header_hit_eviction_threshold(&self) -> u8 {
363 self.invalid_header_hit_eviction_threshold
364 }
365
366 pub const fn max_execute_block_batch_size(&self) -> usize {
368 self.max_execute_block_batch_size
369 }
370
371 pub const fn multiproof_chunk_size(&self) -> usize {
373 self.multiproof_chunk_size
374 }
375
376 pub const fn effective_multiproof_chunk_size(&self) -> usize {
378 self.multiproof_chunk_size
379 }
380
381 pub const fn reserved_cpu_cores(&self) -> usize {
383 self.reserved_cpu_cores
384 }
385
386 pub const fn legacy_state_root(&self) -> bool {
389 self.legacy_state_root
390 }
391
392 pub const fn state_provider_metrics(&self) -> bool {
394 self.state_provider_metrics
395 }
396
397 pub const fn disable_state_cache(&self) -> bool {
399 self.disable_state_cache
400 }
401
402 pub const fn disable_prewarming(&self) -> bool {
404 self.disable_prewarming
405 }
406
407 pub const fn always_compare_trie_updates(&self) -> bool {
410 self.always_compare_trie_updates
411 }
412
413 pub const fn cross_block_cache_size(&self) -> usize {
415 self.cross_block_cache_size
416 }
417
418 pub const fn precompile_cache_disabled(&self) -> bool {
420 self.precompile_cache_disabled
421 }
422
423 pub const fn state_root_fallback(&self) -> bool {
425 self.state_root_fallback
426 }
427
428 pub const fn with_always_process_payload_attributes_on_canonical_head(
430 mut self,
431 always_process_payload_attributes_on_canonical_head: bool,
432 ) -> Self {
433 self.always_process_payload_attributes_on_canonical_head =
434 always_process_payload_attributes_on_canonical_head;
435 self
436 }
437
438 pub const fn always_process_payload_attributes_on_canonical_head(&self) -> bool {
441 self.always_process_payload_attributes_on_canonical_head
442 }
443
444 pub const fn unwind_canonical_header(&self) -> bool {
446 self.allow_unwind_canonical_header
447 }
448
449 pub const fn with_persistence_threshold(mut self, persistence_threshold: u64) -> Self {
451 self.persistence_threshold = persistence_threshold;
452 assert_backpressure_threshold_invariant(
453 self.persistence_threshold,
454 self.persistence_backpressure_threshold,
455 );
456 self
457 }
458
459 pub const fn with_memory_block_buffer_target(
461 mut self,
462 memory_block_buffer_target: u64,
463 ) -> Self {
464 self.memory_block_buffer_target = memory_block_buffer_target;
465 self
466 }
467
468 pub const fn with_persistence_backpressure_threshold(
470 mut self,
471 persistence_backpressure_threshold: u64,
472 ) -> Self {
473 self.persistence_backpressure_threshold = persistence_backpressure_threshold;
474 assert_backpressure_threshold_invariant(
475 self.persistence_threshold,
476 self.persistence_backpressure_threshold,
477 );
478 self
479 }
480
481 pub const fn with_block_buffer_limit(mut self, block_buffer_limit: u32) -> Self {
483 self.block_buffer_limit = block_buffer_limit;
484 self
485 }
486
487 pub const fn with_max_invalid_header_cache_length(
489 mut self,
490 max_invalid_header_cache_length: u32,
491 ) -> Self {
492 self.max_invalid_header_cache_length = max_invalid_header_cache_length;
493 self
494 }
495
496 pub const fn with_invalid_header_hit_eviction_threshold(
498 mut self,
499 invalid_header_hit_eviction_threshold: u8,
500 ) -> Self {
501 self.invalid_header_hit_eviction_threshold = invalid_header_hit_eviction_threshold;
502 self
503 }
504
505 pub const fn with_max_execute_block_batch_size(
507 mut self,
508 max_execute_block_batch_size: usize,
509 ) -> Self {
510 self.max_execute_block_batch_size = max_execute_block_batch_size;
511 self
512 }
513
514 pub const fn with_legacy_state_root(mut self, legacy_state_root: bool) -> Self {
516 self.legacy_state_root = legacy_state_root;
517 self
518 }
519
520 pub const fn without_state_cache(mut self, disable_state_cache: bool) -> Self {
522 self.disable_state_cache = disable_state_cache;
523 self
524 }
525
526 pub const fn without_prewarming(mut self, disable_prewarming: bool) -> Self {
528 self.disable_prewarming = disable_prewarming;
529 self
530 }
531
532 pub const fn with_always_compare_trie_updates(
535 mut self,
536 always_compare_trie_updates: bool,
537 ) -> Self {
538 self.always_compare_trie_updates = always_compare_trie_updates;
539 self
540 }
541
542 pub const fn with_cross_block_cache_size(mut self, cross_block_cache_size: usize) -> Self {
544 self.cross_block_cache_size = cross_block_cache_size;
545 self
546 }
547
548 pub const fn with_has_enough_parallelism(mut self, has_enough_parallelism: bool) -> Self {
550 self.has_enough_parallelism = has_enough_parallelism;
551 self
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 use_state_root_task(&self) -> bool {
592 self.has_enough_parallelism && !self.legacy_state_root
593 }
594
595 pub const fn disable_cache_metrics(&self) -> bool {
597 self.disable_cache_metrics
598 }
599
600 pub const fn without_cache_metrics(mut self, disable_cache_metrics: bool) -> Self {
602 self.disable_cache_metrics = disable_cache_metrics;
603 self
604 }
605
606 pub const fn sparse_trie_prune_depth(&self) -> usize {
608 self.sparse_trie_prune_depth
609 }
610
611 pub const fn with_sparse_trie_prune_depth(mut self, depth: usize) -> Self {
613 self.sparse_trie_prune_depth = depth;
614 self
615 }
616
617 pub const fn sparse_trie_max_hot_slots(&self) -> usize {
619 self.sparse_trie_max_hot_slots
620 }
621
622 pub const fn with_sparse_trie_max_hot_slots(mut self, max_hot_slots: usize) -> Self {
624 self.sparse_trie_max_hot_slots = max_hot_slots;
625 self
626 }
627
628 pub const fn sparse_trie_max_hot_accounts(&self) -> usize {
630 self.sparse_trie_max_hot_accounts
631 }
632
633 pub const fn with_sparse_trie_max_hot_accounts(mut self, max_hot_accounts: usize) -> Self {
635 self.sparse_trie_max_hot_accounts = max_hot_accounts;
636 self
637 }
638
639 pub const fn slow_block_threshold(&self) -> Option<Duration> {
645 self.slow_block_threshold
646 }
647
648 pub const fn with_slow_block_threshold(
650 mut self,
651 slow_block_threshold: Option<Duration>,
652 ) -> Self {
653 self.slow_block_threshold = slow_block_threshold;
654 self
655 }
656
657 pub const fn disable_sparse_trie_cache_pruning(&self) -> bool {
659 self.disable_sparse_trie_cache_pruning
660 }
661
662 pub const fn with_disable_sparse_trie_cache_pruning(mut self, value: bool) -> Self {
664 self.disable_sparse_trie_cache_pruning = value;
665 self
666 }
667
668 pub const fn state_root_task_timeout(&self) -> Option<Duration> {
670 self.state_root_task_timeout
671 }
672
673 pub const fn with_state_root_task_timeout(mut self, timeout: Option<Duration>) -> Self {
675 self.state_root_task_timeout = timeout;
676 self
677 }
678
679 pub const fn share_execution_cache_with_payload_builder(&self) -> bool {
681 self.share_execution_cache_with_payload_builder
682 }
683
684 pub const fn share_sparse_trie_with_payload_builder(&self) -> bool {
686 self.share_sparse_trie_with_payload_builder
687 }
688
689 pub const fn with_share_execution_cache_with_payload_builder(
691 mut self,
692 share_execution_cache_with_payload_builder: bool,
693 ) -> Self {
694 self.share_execution_cache_with_payload_builder =
695 share_execution_cache_with_payload_builder;
696 self
697 }
698
699 pub const fn with_share_sparse_trie_with_payload_builder(
701 mut self,
702 share_sparse_trie_with_payload_builder: bool,
703 ) -> Self {
704 self.share_sparse_trie_with_payload_builder = share_sparse_trie_with_payload_builder;
705 self
706 }
707
708 pub const fn suppress_persistence_during_build(&self) -> bool {
710 self.suppress_persistence_during_build
711 }
712
713 pub const fn with_suppress_persistence_during_build(mut self, value: bool) -> Self {
715 self.suppress_persistence_during_build = value;
716 self
717 }
718
719 pub const fn disable_bal_parallel_execution(&self) -> bool {
721 self.disable_bal_parallel_execution
722 }
723
724 pub const fn without_bal_parallel_execution(
726 mut self,
727 disable_bal_parallel_execution: bool,
728 ) -> Self {
729 self.disable_bal_parallel_execution = disable_bal_parallel_execution;
730 self
731 }
732
733 pub const fn disable_bal_parallel_state_root(&self) -> bool {
735 self.disable_bal_parallel_state_root
736 }
737
738 pub const fn without_bal_parallel_state_root(
740 mut self,
741 disable_bal_parallel_state_root: bool,
742 ) -> Self {
743 self.disable_bal_parallel_state_root = disable_bal_parallel_state_root;
744 self
745 }
746
747 pub const fn disable_bal_batch_io(&self) -> bool {
749 self.disable_bal_batch_io
750 }
751
752 pub const fn without_bal_batch_io(mut self, disable_bal_batch_io: bool) -> Self {
754 self.disable_bal_batch_io = disable_bal_batch_io;
755 self
756 }
757
758 pub const fn skip_state_root(&self) -> bool {
760 self.skip_state_root
761 }
762
763 pub const fn with_skip_state_root(mut self, skip_state_root: bool) -> Self {
765 self.skip_state_root = skip_state_root;
766 self
767 }
768
769 #[cfg(feature = "trie-debug")]
771 pub const fn proof_jitter(&self) -> Option<Duration> {
772 self.proof_jitter
773 }
774
775 #[cfg(feature = "trie-debug")]
777 pub const fn with_proof_jitter(mut self, proof_jitter: Option<Duration>) -> Self {
778 self.proof_jitter = proof_jitter;
779 self
780 }
781}
782
783#[cfg(test)]
784mod tests {
785 use super::TreeConfig;
786
787 #[test]
788 #[should_panic(
789 expected = "persistence_backpressure_threshold must be greater than persistence_threshold"
790 )]
791 fn rejects_backpressure_threshold_at_or_below_persistence_threshold() {
792 let _ = TreeConfig::default()
793 .with_persistence_threshold(4)
794 .with_persistence_backpressure_threshold(4);
795 }
796}