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 #[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 legacy_state_root: false,
219 always_compare_trie_updates: false,
220 disable_state_cache: false,
221 disable_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 sparse_trie_max_hot_slots: DEFAULT_SPARSE_TRIE_MAX_HOT_SLOTS,
234 sparse_trie_max_hot_accounts: DEFAULT_SPARSE_TRIE_MAX_HOT_ACCOUNTS,
235 slow_block_threshold: None,
236 disable_sparse_trie_cache_pruning: false,
237 state_root_task_timeout: Some(DEFAULT_STATE_ROOT_TASK_TIMEOUT),
238 share_execution_cache_with_payload_builder: false,
239 share_sparse_trie_with_payload_builder: false,
240 suppress_persistence_during_build: false,
241 disable_bal_parallel_execution: false,
242 disable_bal_parallel_state_root: false,
243 disable_bal_batch_io: false,
244 #[cfg(feature = "trie-debug")]
245 proof_jitter: None,
246 }
247 }
248}
249
250impl TreeConfig {
251 #[expect(clippy::too_many_arguments)]
253 pub const fn new(
254 persistence_threshold: u64,
255 memory_block_buffer_target: u64,
256 persistence_backpressure_threshold: u64,
257 block_buffer_limit: u32,
258 max_invalid_header_cache_length: u32,
259 invalid_header_hit_eviction_threshold: u8,
260 max_execute_block_batch_size: usize,
261 legacy_state_root: bool,
262 always_compare_trie_updates: bool,
263 disable_state_cache: bool,
264 disable_prewarming: bool,
265 state_provider_metrics: bool,
266 cross_block_cache_size: usize,
267 has_enough_parallelism: bool,
268 multiproof_chunk_size: usize,
269 reserved_cpu_cores: usize,
270 precompile_cache_disabled: bool,
271 state_root_fallback: bool,
272 always_process_payload_attributes_on_canonical_head: bool,
273 allow_unwind_canonical_header: bool,
274 disable_cache_metrics: bool,
275 sparse_trie_prune_depth: usize,
276 sparse_trie_max_hot_slots: usize,
277 sparse_trie_max_hot_accounts: usize,
278 slow_block_threshold: Option<Duration>,
279 state_root_task_timeout: Option<Duration>,
280 share_execution_cache_with_payload_builder: bool,
281 share_sparse_trie_with_payload_builder: bool,
282 ) -> Self {
283 assert_backpressure_threshold_invariant(
284 persistence_threshold,
285 persistence_backpressure_threshold,
286 );
287 Self {
288 persistence_threshold,
289 memory_block_buffer_target,
290 persistence_backpressure_threshold,
291 block_buffer_limit,
292 max_invalid_header_cache_length,
293 invalid_header_hit_eviction_threshold,
294 max_execute_block_batch_size,
295 legacy_state_root,
296 always_compare_trie_updates,
297 disable_state_cache,
298 disable_prewarming,
299 state_provider_metrics,
300 cross_block_cache_size,
301 has_enough_parallelism,
302 multiproof_chunk_size,
303 reserved_cpu_cores,
304 precompile_cache_disabled,
305 state_root_fallback,
306 always_process_payload_attributes_on_canonical_head,
307 allow_unwind_canonical_header,
308 disable_cache_metrics,
309 sparse_trie_prune_depth,
310 sparse_trie_max_hot_slots,
311 sparse_trie_max_hot_accounts,
312 slow_block_threshold,
313 disable_sparse_trie_cache_pruning: false,
314 state_root_task_timeout,
315 share_execution_cache_with_payload_builder,
316 share_sparse_trie_with_payload_builder,
317 suppress_persistence_during_build: false,
318 disable_bal_parallel_execution: false,
319 disable_bal_parallel_state_root: false,
320 disable_bal_batch_io: false,
321 #[cfg(feature = "trie-debug")]
322 proof_jitter: None,
323 }
324 }
325
326 pub const fn persistence_threshold(&self) -> u64 {
328 self.persistence_threshold
329 }
330
331 pub const fn memory_block_buffer_target(&self) -> u64 {
333 self.memory_block_buffer_target
334 }
335
336 pub const fn persistence_backpressure_threshold(&self) -> u64 {
338 self.persistence_backpressure_threshold
339 }
340
341 pub const fn block_buffer_limit(&self) -> u32 {
343 self.block_buffer_limit
344 }
345
346 pub const fn max_invalid_header_cache_length(&self) -> u32 {
348 self.max_invalid_header_cache_length
349 }
350
351 pub const fn invalid_header_hit_eviction_threshold(&self) -> u8 {
356 self.invalid_header_hit_eviction_threshold
357 }
358
359 pub const fn max_execute_block_batch_size(&self) -> usize {
361 self.max_execute_block_batch_size
362 }
363
364 pub const fn multiproof_chunk_size(&self) -> usize {
366 self.multiproof_chunk_size
367 }
368
369 pub const fn effective_multiproof_chunk_size(&self) -> usize {
371 self.multiproof_chunk_size
372 }
373
374 pub const fn reserved_cpu_cores(&self) -> usize {
376 self.reserved_cpu_cores
377 }
378
379 pub const fn legacy_state_root(&self) -> bool {
382 self.legacy_state_root
383 }
384
385 pub const fn state_provider_metrics(&self) -> bool {
387 self.state_provider_metrics
388 }
389
390 pub const fn disable_state_cache(&self) -> bool {
392 self.disable_state_cache
393 }
394
395 pub const fn disable_prewarming(&self) -> bool {
397 self.disable_prewarming
398 }
399
400 pub const fn always_compare_trie_updates(&self) -> bool {
403 self.always_compare_trie_updates
404 }
405
406 pub const fn cross_block_cache_size(&self) -> usize {
408 self.cross_block_cache_size
409 }
410
411 pub const fn precompile_cache_disabled(&self) -> bool {
413 self.precompile_cache_disabled
414 }
415
416 pub const fn state_root_fallback(&self) -> bool {
418 self.state_root_fallback
419 }
420
421 pub const fn with_always_process_payload_attributes_on_canonical_head(
423 mut self,
424 always_process_payload_attributes_on_canonical_head: bool,
425 ) -> Self {
426 self.always_process_payload_attributes_on_canonical_head =
427 always_process_payload_attributes_on_canonical_head;
428 self
429 }
430
431 pub const fn always_process_payload_attributes_on_canonical_head(&self) -> bool {
434 self.always_process_payload_attributes_on_canonical_head
435 }
436
437 pub const fn unwind_canonical_header(&self) -> bool {
439 self.allow_unwind_canonical_header
440 }
441
442 pub const fn with_persistence_threshold(mut self, persistence_threshold: u64) -> Self {
444 self.persistence_threshold = persistence_threshold;
445 assert_backpressure_threshold_invariant(
446 self.persistence_threshold,
447 self.persistence_backpressure_threshold,
448 );
449 self
450 }
451
452 pub const fn with_memory_block_buffer_target(
454 mut self,
455 memory_block_buffer_target: u64,
456 ) -> Self {
457 self.memory_block_buffer_target = memory_block_buffer_target;
458 self
459 }
460
461 pub const fn with_persistence_backpressure_threshold(
463 mut self,
464 persistence_backpressure_threshold: u64,
465 ) -> Self {
466 self.persistence_backpressure_threshold = persistence_backpressure_threshold;
467 assert_backpressure_threshold_invariant(
468 self.persistence_threshold,
469 self.persistence_backpressure_threshold,
470 );
471 self
472 }
473
474 pub const fn with_block_buffer_limit(mut self, block_buffer_limit: u32) -> Self {
476 self.block_buffer_limit = block_buffer_limit;
477 self
478 }
479
480 pub const fn with_max_invalid_header_cache_length(
482 mut self,
483 max_invalid_header_cache_length: u32,
484 ) -> Self {
485 self.max_invalid_header_cache_length = max_invalid_header_cache_length;
486 self
487 }
488
489 pub const fn with_invalid_header_hit_eviction_threshold(
491 mut self,
492 invalid_header_hit_eviction_threshold: u8,
493 ) -> Self {
494 self.invalid_header_hit_eviction_threshold = invalid_header_hit_eviction_threshold;
495 self
496 }
497
498 pub const fn with_max_execute_block_batch_size(
500 mut self,
501 max_execute_block_batch_size: usize,
502 ) -> Self {
503 self.max_execute_block_batch_size = max_execute_block_batch_size;
504 self
505 }
506
507 pub const fn with_legacy_state_root(mut self, legacy_state_root: bool) -> Self {
509 self.legacy_state_root = legacy_state_root;
510 self
511 }
512
513 pub const fn without_state_cache(mut self, disable_state_cache: bool) -> Self {
515 self.disable_state_cache = disable_state_cache;
516 self
517 }
518
519 pub const fn without_prewarming(mut self, disable_prewarming: bool) -> Self {
521 self.disable_prewarming = disable_prewarming;
522 self
523 }
524
525 pub const fn with_always_compare_trie_updates(
528 mut self,
529 always_compare_trie_updates: bool,
530 ) -> Self {
531 self.always_compare_trie_updates = always_compare_trie_updates;
532 self
533 }
534
535 pub const fn with_cross_block_cache_size(mut self, cross_block_cache_size: usize) -> Self {
537 self.cross_block_cache_size = cross_block_cache_size;
538 self
539 }
540
541 pub const fn with_has_enough_parallelism(mut self, has_enough_parallelism: bool) -> Self {
543 self.has_enough_parallelism = has_enough_parallelism;
544 self
545 }
546
547 pub const fn with_state_provider_metrics(mut self, state_provider_metrics: bool) -> Self {
549 self.state_provider_metrics = state_provider_metrics;
550 self
551 }
552
553 pub const fn with_multiproof_chunk_size(mut self, multiproof_chunk_size: usize) -> Self {
555 self.multiproof_chunk_size = multiproof_chunk_size;
556 self
557 }
558
559 pub const fn with_reserved_cpu_cores(mut self, reserved_cpu_cores: usize) -> Self {
561 self.reserved_cpu_cores = reserved_cpu_cores;
562 self
563 }
564
565 pub const fn without_precompile_cache(mut self, precompile_cache_disabled: bool) -> Self {
567 self.precompile_cache_disabled = precompile_cache_disabled;
568 self
569 }
570
571 pub const fn with_state_root_fallback(mut self, state_root_fallback: bool) -> Self {
573 self.state_root_fallback = state_root_fallback;
574 self
575 }
576
577 pub const fn with_unwind_canonical_header(mut self, unwind_canonical_header: bool) -> Self {
579 self.allow_unwind_canonical_header = unwind_canonical_header;
580 self
581 }
582
583 pub const fn use_state_root_task(&self) -> bool {
585 self.has_enough_parallelism && !self.legacy_state_root
586 }
587
588 pub const fn disable_cache_metrics(&self) -> bool {
590 self.disable_cache_metrics
591 }
592
593 pub const fn without_cache_metrics(mut self, disable_cache_metrics: bool) -> Self {
595 self.disable_cache_metrics = disable_cache_metrics;
596 self
597 }
598
599 pub const fn sparse_trie_prune_depth(&self) -> usize {
601 self.sparse_trie_prune_depth
602 }
603
604 pub const fn with_sparse_trie_prune_depth(mut self, depth: usize) -> Self {
606 self.sparse_trie_prune_depth = depth;
607 self
608 }
609
610 pub const fn sparse_trie_max_hot_slots(&self) -> usize {
612 self.sparse_trie_max_hot_slots
613 }
614
615 pub const fn with_sparse_trie_max_hot_slots(mut self, max_hot_slots: usize) -> Self {
617 self.sparse_trie_max_hot_slots = max_hot_slots;
618 self
619 }
620
621 pub const fn sparse_trie_max_hot_accounts(&self) -> usize {
623 self.sparse_trie_max_hot_accounts
624 }
625
626 pub const fn with_sparse_trie_max_hot_accounts(mut self, max_hot_accounts: usize) -> Self {
628 self.sparse_trie_max_hot_accounts = max_hot_accounts;
629 self
630 }
631
632 pub const fn slow_block_threshold(&self) -> Option<Duration> {
638 self.slow_block_threshold
639 }
640
641 pub const fn with_slow_block_threshold(
643 mut self,
644 slow_block_threshold: Option<Duration>,
645 ) -> Self {
646 self.slow_block_threshold = slow_block_threshold;
647 self
648 }
649
650 pub const fn disable_sparse_trie_cache_pruning(&self) -> bool {
652 self.disable_sparse_trie_cache_pruning
653 }
654
655 pub const fn with_disable_sparse_trie_cache_pruning(mut self, value: bool) -> Self {
657 self.disable_sparse_trie_cache_pruning = value;
658 self
659 }
660
661 pub const fn state_root_task_timeout(&self) -> Option<Duration> {
663 self.state_root_task_timeout
664 }
665
666 pub const fn with_state_root_task_timeout(mut self, timeout: Option<Duration>) -> Self {
668 self.state_root_task_timeout = timeout;
669 self
670 }
671
672 pub const fn share_execution_cache_with_payload_builder(&self) -> bool {
674 self.share_execution_cache_with_payload_builder
675 }
676
677 pub const fn share_sparse_trie_with_payload_builder(&self) -> bool {
679 self.share_sparse_trie_with_payload_builder
680 }
681
682 pub const fn with_share_execution_cache_with_payload_builder(
684 mut self,
685 share_execution_cache_with_payload_builder: bool,
686 ) -> Self {
687 self.share_execution_cache_with_payload_builder =
688 share_execution_cache_with_payload_builder;
689 self
690 }
691
692 pub const fn with_share_sparse_trie_with_payload_builder(
694 mut self,
695 share_sparse_trie_with_payload_builder: bool,
696 ) -> Self {
697 self.share_sparse_trie_with_payload_builder = share_sparse_trie_with_payload_builder;
698 self
699 }
700
701 pub const fn suppress_persistence_during_build(&self) -> bool {
703 self.suppress_persistence_during_build
704 }
705
706 pub const fn with_suppress_persistence_during_build(mut self, value: bool) -> Self {
708 self.suppress_persistence_during_build = value;
709 self
710 }
711
712 pub const fn disable_bal_parallel_execution(&self) -> bool {
714 self.disable_bal_parallel_execution
715 }
716
717 pub const fn without_bal_parallel_execution(
719 mut self,
720 disable_bal_parallel_execution: bool,
721 ) -> Self {
722 self.disable_bal_parallel_execution = disable_bal_parallel_execution;
723 self
724 }
725
726 pub const fn disable_bal_parallel_state_root(&self) -> bool {
728 self.disable_bal_parallel_state_root
729 }
730
731 pub const fn without_bal_parallel_state_root(
733 mut self,
734 disable_bal_parallel_state_root: bool,
735 ) -> Self {
736 self.disable_bal_parallel_state_root = disable_bal_parallel_state_root;
737 self
738 }
739
740 pub const fn disable_bal_batch_io(&self) -> bool {
742 self.disable_bal_batch_io
743 }
744
745 pub const fn without_bal_batch_io(mut self, disable_bal_batch_io: bool) -> Self {
747 self.disable_bal_batch_io = disable_bal_batch_io;
748 self
749 }
750
751 #[cfg(feature = "trie-debug")]
753 pub const fn proof_jitter(&self) -> Option<Duration> {
754 self.proof_jitter
755 }
756
757 #[cfg(feature = "trie-debug")]
759 pub const fn with_proof_jitter(mut self, proof_jitter: Option<Duration>) -> Self {
760 self.proof_jitter = proof_jitter;
761 self
762 }
763}
764
765#[cfg(test)]
766mod tests {
767 use super::TreeConfig;
768
769 #[test]
770 #[should_panic(
771 expected = "persistence_backpressure_threshold must be greater than persistence_threshold"
772 )]
773 fn rejects_backpressure_threshold_at_or_below_persistence_threshold() {
774 let _ = TreeConfig::default()
775 .with_persistence_threshold(4)
776 .with_persistence_backpressure_threshold(4);
777 }
778}