1use alloy_eips::merge::EPOCH_SLOTS;
4use core::time::Duration;
5
6pub const DEFAULT_PERSISTENCE_THRESHOLD: u64 = 50;
8
9pub const DEFAULT_NUM_STATE_MASKING_BLOCKS: u64 = 30;
11
12pub const MIN_PERSISTENCE_BACKPRESSURE_THRESHOLD: u64 = 16;
15
16pub const DEFAULT_MEMORY_BLOCK_BUFFER_TARGET: u64 = 5;
18
19pub const DEFAULT_BACKFILL_RUN_THRESHOLD: u64 = EPOCH_SLOTS;
29
30pub const MAX_BACKFILL_RUN_THRESHOLD: u64 = 1024;
34
35pub const DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE: usize = 5;
37
38pub const DEFAULT_INVALID_HEADER_HIT_EVICTION_THRESHOLD: u8 = 128;
40
41pub const SMALL_BLOCK_GAS_THRESHOLD: u64 = 20_000_000;
43
44pub const DEFAULT_RESERVED_CPU_CORES: usize = 1;
48
49pub const DEFAULT_SPARSE_TRIE_PRUNE_DEPTH: usize = 4;
54
55pub const DEFAULT_STATE_ROOT_TASK_TIMEOUT: Duration = Duration::from_secs(1);
57
58const DEFAULT_BLOCK_BUFFER_LIMIT: u32 = EPOCH_SLOTS as u32 * 2;
59const DEFAULT_MAX_INVALID_HEADER_CACHE_LENGTH: u32 = 256;
60const DEFAULT_MAX_EXECUTE_BLOCK_BATCH_SIZE: usize = 4;
61const DEFAULT_CROSS_BLOCK_CACHE_SIZE: usize = default_cross_block_cache_size();
62
63const fn assert_backpressure_threshold_invariant(
64 persistence_threshold: u64,
65 persistence_backpressure_threshold: u64,
66) {
67 debug_assert!(
68 persistence_backpressure_threshold > persistence_threshold,
69 "persistence_backpressure_threshold must be greater than persistence_threshold",
70 );
71}
72
73const fn assert_state_masking_invariant(
74 persistence_threshold: u64,
75 num_state_masking_blocks: u64,
76 memory_block_buffer_target: u64,
77) {
78 let valid_window = match num_state_masking_blocks.checked_add(memory_block_buffer_target) {
79 Some(window) => window < persistence_threshold,
80 None => false,
81 };
82 debug_assert!(
83 num_state_masking_blocks == 0 || valid_window,
84 "num_state_masking_blocks + memory_block_buffer_target must be less than persistence_threshold",
85 );
86}
87
88const fn default_cross_block_cache_size() -> usize {
89 if cfg!(test) {
90 1024 * 1024 } else if cfg!(target_pointer_width = "32") {
92 usize::MAX } else {
94 4 * 1024 * 1024 * 1024 }
96}
97
98pub fn has_enough_parallelism() -> bool {
107 #[cfg(feature = "std")]
108 {
109 std::thread::available_parallelism().is_ok_and(|num| num.get() >= 5)
110 }
111 #[cfg(not(feature = "std"))]
112 false
113}
114
115#[derive(Debug, Clone)]
117pub struct TreeConfig {
118 persistence_threshold: u64,
121 num_state_masking_blocks: u64,
124 memory_block_buffer_target: u64,
129 persistence_backpressure_threshold: u64,
132 block_buffer_limit: u32,
135 backfill_run_threshold: u64,
138 max_invalid_header_cache_length: u32,
140 invalid_header_hit_eviction_threshold: u8,
145 max_execute_block_batch_size: usize,
150 always_compare_trie_updates: bool,
153 disable_state_cache: bool,
155 disable_prewarming: bool,
157 txpool_prewarming: bool,
159 state_provider_metrics: bool,
161 cross_block_cache_size: usize,
163 has_enough_parallelism: bool,
173 multiproof_chunk_size: usize,
175 reserved_cpu_cores: usize,
177 precompile_cache_disabled: bool,
179 state_root_fallback: bool,
181 always_process_payload_attributes_on_canonical_head: bool,
195 allow_unwind_canonical_header: bool,
197 disable_cache_metrics: bool,
199 sparse_trie_prune_depth: usize,
201 slow_block_threshold: Option<Duration>,
205 disable_sparse_trie_cache_pruning: bool,
207 state_root_task_timeout: Option<Duration>,
212 share_execution_cache_with_payload_builder: bool,
214 share_sparse_trie_with_payload_builder: bool,
216 suppress_persistence_during_build: bool,
221 disable_bal_parallel_execution: bool,
224 disable_bal_parallel_state_root: bool,
227 disable_bal_batch_io: bool,
231 skip_state_root: bool,
236 #[cfg(feature = "trie-debug")]
240 proof_jitter: Option<Duration>,
241}
242
243impl Default for TreeConfig {
244 fn default() -> Self {
245 assert_backpressure_threshold_invariant(
246 DEFAULT_PERSISTENCE_THRESHOLD,
247 DEFAULT_PERSISTENCE_THRESHOLD * 2,
248 );
249 assert_state_masking_invariant(
250 DEFAULT_PERSISTENCE_THRESHOLD,
251 DEFAULT_NUM_STATE_MASKING_BLOCKS,
252 DEFAULT_MEMORY_BLOCK_BUFFER_TARGET,
253 );
254 Self {
255 persistence_threshold: DEFAULT_PERSISTENCE_THRESHOLD,
256 num_state_masking_blocks: DEFAULT_NUM_STATE_MASKING_BLOCKS,
257 memory_block_buffer_target: DEFAULT_MEMORY_BLOCK_BUFFER_TARGET,
258 persistence_backpressure_threshold: DEFAULT_PERSISTENCE_THRESHOLD * 2,
259 block_buffer_limit: DEFAULT_BLOCK_BUFFER_LIMIT,
260 backfill_run_threshold: DEFAULT_BACKFILL_RUN_THRESHOLD,
261 max_invalid_header_cache_length: DEFAULT_MAX_INVALID_HEADER_CACHE_LENGTH,
262 invalid_header_hit_eviction_threshold: DEFAULT_INVALID_HEADER_HIT_EVICTION_THRESHOLD,
263 max_execute_block_batch_size: DEFAULT_MAX_EXECUTE_BLOCK_BATCH_SIZE,
264 always_compare_trie_updates: false,
265 disable_state_cache: false,
266 disable_prewarming: false,
267 txpool_prewarming: false,
268 state_provider_metrics: false,
269 cross_block_cache_size: DEFAULT_CROSS_BLOCK_CACHE_SIZE,
270 has_enough_parallelism: has_enough_parallelism(),
271 multiproof_chunk_size: DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE,
272 reserved_cpu_cores: DEFAULT_RESERVED_CPU_CORES,
273 precompile_cache_disabled: false,
274 state_root_fallback: false,
275 always_process_payload_attributes_on_canonical_head: false,
276 allow_unwind_canonical_header: false,
277 disable_cache_metrics: false,
278 sparse_trie_prune_depth: DEFAULT_SPARSE_TRIE_PRUNE_DEPTH,
279 slow_block_threshold: None,
280 disable_sparse_trie_cache_pruning: false,
281 state_root_task_timeout: Some(DEFAULT_STATE_ROOT_TASK_TIMEOUT),
282 share_execution_cache_with_payload_builder: false,
283 share_sparse_trie_with_payload_builder: false,
284 suppress_persistence_during_build: false,
285 disable_bal_parallel_execution: false,
286 disable_bal_parallel_state_root: false,
287 disable_bal_batch_io: false,
288 skip_state_root: false,
289 #[cfg(feature = "trie-debug")]
290 proof_jitter: None,
291 }
292 }
293}
294
295impl TreeConfig {
296 #[expect(clippy::too_many_arguments)]
300 pub const fn new(
301 persistence_threshold: u64,
302 num_state_masking_blocks: u64,
303 memory_block_buffer_target: u64,
304 persistence_backpressure_threshold: u64,
305 block_buffer_limit: u32,
306 backfill_run_threshold: u64,
307 max_invalid_header_cache_length: u32,
308 invalid_header_hit_eviction_threshold: u8,
309 max_execute_block_batch_size: usize,
310 always_compare_trie_updates: bool,
311 disable_state_cache: bool,
312 disable_prewarming: bool,
313 state_provider_metrics: bool,
314 cross_block_cache_size: usize,
315 has_enough_parallelism: bool,
316 multiproof_chunk_size: usize,
317 reserved_cpu_cores: usize,
318 precompile_cache_disabled: bool,
319 state_root_fallback: bool,
320 always_process_payload_attributes_on_canonical_head: bool,
321 allow_unwind_canonical_header: bool,
322 disable_cache_metrics: bool,
323 sparse_trie_prune_depth: usize,
324 slow_block_threshold: Option<Duration>,
325 state_root_task_timeout: Option<Duration>,
326 share_execution_cache_with_payload_builder: bool,
327 share_sparse_trie_with_payload_builder: bool,
328 ) -> Self {
329 let num_state_masking_blocks =
330 if persistence_threshold == 0 { 0 } else { num_state_masking_blocks };
331 assert_backpressure_threshold_invariant(
332 persistence_threshold,
333 persistence_backpressure_threshold,
334 );
335 assert_state_masking_invariant(
336 persistence_threshold,
337 num_state_masking_blocks,
338 memory_block_buffer_target,
339 );
340 Self {
341 persistence_threshold,
342 num_state_masking_blocks,
343 memory_block_buffer_target,
344 persistence_backpressure_threshold,
345 block_buffer_limit,
346 backfill_run_threshold: clamp_backfill_run_threshold(backfill_run_threshold),
347 max_invalid_header_cache_length,
348 invalid_header_hit_eviction_threshold,
349 max_execute_block_batch_size,
350 always_compare_trie_updates,
351 disable_state_cache,
352 disable_prewarming,
353 txpool_prewarming: false,
354 state_provider_metrics,
355 cross_block_cache_size,
356 has_enough_parallelism,
357 multiproof_chunk_size,
358 reserved_cpu_cores,
359 precompile_cache_disabled,
360 state_root_fallback,
361 always_process_payload_attributes_on_canonical_head,
362 allow_unwind_canonical_header,
363 disable_cache_metrics,
364 sparse_trie_prune_depth,
365 slow_block_threshold,
366 disable_sparse_trie_cache_pruning: false,
367 state_root_task_timeout,
368 share_execution_cache_with_payload_builder,
369 share_sparse_trie_with_payload_builder,
370 suppress_persistence_during_build: false,
371 disable_bal_parallel_execution: false,
372 disable_bal_parallel_state_root: false,
373 disable_bal_batch_io: false,
374 skip_state_root: false,
375 #[cfg(feature = "trie-debug")]
376 proof_jitter: None,
377 }
378 }
379
380 pub const fn persistence_threshold(&self) -> u64 {
382 self.persistence_threshold
383 }
384
385 pub const fn num_state_masking_blocks(&self) -> u64 {
387 self.num_state_masking_blocks
388 }
389
390 pub const fn memory_block_buffer_target(&self) -> u64 {
392 self.memory_block_buffer_target
393 }
394
395 pub const fn persistence_backpressure_threshold(&self) -> u64 {
397 self.persistence_backpressure_threshold
398 }
399
400 pub const fn block_buffer_limit(&self) -> u32 {
402 self.block_buffer_limit
403 }
404
405 pub const fn backfill_run_threshold(&self) -> u64 {
407 self.backfill_run_threshold
408 }
409
410 pub const fn max_invalid_header_cache_length(&self) -> u32 {
412 self.max_invalid_header_cache_length
413 }
414
415 pub const fn invalid_header_hit_eviction_threshold(&self) -> u8 {
420 self.invalid_header_hit_eviction_threshold
421 }
422
423 pub const fn max_execute_block_batch_size(&self) -> usize {
425 self.max_execute_block_batch_size
426 }
427
428 pub const fn multiproof_chunk_size(&self) -> usize {
430 self.multiproof_chunk_size
431 }
432
433 pub const fn effective_multiproof_chunk_size(&self) -> usize {
435 self.multiproof_chunk_size
436 }
437
438 pub const fn reserved_cpu_cores(&self) -> usize {
440 self.reserved_cpu_cores
441 }
442
443 pub const fn state_provider_metrics(&self) -> bool {
445 self.state_provider_metrics
446 }
447
448 pub const fn disable_state_cache(&self) -> bool {
450 self.disable_state_cache
451 }
452
453 pub const fn disable_prewarming(&self) -> bool {
455 self.disable_prewarming
456 }
457
458 pub const fn txpool_prewarming(&self) -> bool {
460 self.txpool_prewarming
461 }
462
463 pub const fn always_compare_trie_updates(&self) -> bool {
466 self.always_compare_trie_updates
467 }
468
469 pub const fn cross_block_cache_size(&self) -> usize {
471 self.cross_block_cache_size
472 }
473
474 pub const fn precompile_cache_disabled(&self) -> bool {
476 self.precompile_cache_disabled
477 }
478
479 pub const fn state_root_fallback(&self) -> bool {
481 self.state_root_fallback
482 }
483
484 pub const fn with_always_process_payload_attributes_on_canonical_head(
486 mut self,
487 always_process_payload_attributes_on_canonical_head: bool,
488 ) -> Self {
489 self.always_process_payload_attributes_on_canonical_head =
490 always_process_payload_attributes_on_canonical_head;
491 self
492 }
493
494 pub const fn always_process_payload_attributes_on_canonical_head(&self) -> bool {
497 self.always_process_payload_attributes_on_canonical_head
498 }
499
500 pub const fn unwind_canonical_header(&self) -> bool {
502 self.allow_unwind_canonical_header
503 }
504
505 pub const fn with_persistence_threshold(mut self, persistence_threshold: u64) -> Self {
507 self.persistence_threshold = persistence_threshold;
508 if persistence_threshold == 0 {
509 self.num_state_masking_blocks = 0;
510 }
511 assert_backpressure_threshold_invariant(
512 self.persistence_threshold,
513 self.persistence_backpressure_threshold,
514 );
515 assert_state_masking_invariant(
516 self.persistence_threshold,
517 self.num_state_masking_blocks,
518 self.memory_block_buffer_target,
519 );
520 self
521 }
522
523 pub const fn with_num_state_masking_blocks(mut self, num_state_masking_blocks: u64) -> Self {
526 self.num_state_masking_blocks =
527 if self.persistence_threshold == 0 { 0 } else { num_state_masking_blocks };
528 assert_state_masking_invariant(
529 self.persistence_threshold,
530 self.num_state_masking_blocks,
531 self.memory_block_buffer_target,
532 );
533 self
534 }
535
536 pub const fn with_memory_block_buffer_target(
538 mut self,
539 memory_block_buffer_target: u64,
540 ) -> Self {
541 self.memory_block_buffer_target = memory_block_buffer_target;
542 assert_state_masking_invariant(
543 self.persistence_threshold,
544 self.num_state_masking_blocks,
545 self.memory_block_buffer_target,
546 );
547 self
548 }
549
550 pub const fn with_persistence_backpressure_threshold(
552 mut self,
553 persistence_backpressure_threshold: u64,
554 ) -> Self {
555 self.persistence_backpressure_threshold = persistence_backpressure_threshold;
556 assert_backpressure_threshold_invariant(
557 self.persistence_threshold,
558 self.persistence_backpressure_threshold,
559 );
560 self
561 }
562
563 pub const fn with_block_buffer_limit(mut self, block_buffer_limit: u32) -> Self {
565 self.block_buffer_limit = block_buffer_limit;
566 self
567 }
568
569 pub const fn with_backfill_run_threshold(mut self, backfill_run_threshold: u64) -> Self {
575 self.backfill_run_threshold = clamp_backfill_run_threshold(backfill_run_threshold);
576 let buffer_limit = self.backfill_run_threshold as u32 * 2;
577 if buffer_limit > self.block_buffer_limit {
578 self.block_buffer_limit = buffer_limit;
579 }
580 self
581 }
582
583 pub const fn with_max_invalid_header_cache_length(
585 mut self,
586 max_invalid_header_cache_length: u32,
587 ) -> Self {
588 self.max_invalid_header_cache_length = max_invalid_header_cache_length;
589 self
590 }
591
592 pub const fn with_invalid_header_hit_eviction_threshold(
594 mut self,
595 invalid_header_hit_eviction_threshold: u8,
596 ) -> Self {
597 self.invalid_header_hit_eviction_threshold = invalid_header_hit_eviction_threshold;
598 self
599 }
600
601 pub const fn with_max_execute_block_batch_size(
603 mut self,
604 max_execute_block_batch_size: usize,
605 ) -> Self {
606 self.max_execute_block_batch_size = max_execute_block_batch_size;
607 self
608 }
609
610 pub const fn without_state_cache(mut self, disable_state_cache: bool) -> Self {
612 self.disable_state_cache = disable_state_cache;
613 self
614 }
615
616 pub const fn without_prewarming(mut self, disable_prewarming: bool) -> Self {
618 self.disable_prewarming = disable_prewarming;
619 self
620 }
621
622 pub const fn with_txpool_prewarming(mut self, enabled: bool) -> Self {
624 self.txpool_prewarming = enabled;
625 self
626 }
627
628 pub const fn with_always_compare_trie_updates(
631 mut self,
632 always_compare_trie_updates: bool,
633 ) -> Self {
634 self.always_compare_trie_updates = always_compare_trie_updates;
635 self
636 }
637
638 pub const fn with_cross_block_cache_size(mut self, cross_block_cache_size: usize) -> Self {
640 self.cross_block_cache_size = cross_block_cache_size;
641 self
642 }
643
644 pub const fn with_has_enough_parallelism(mut self, has_enough_parallelism: bool) -> Self {
646 self.has_enough_parallelism = has_enough_parallelism;
647 self
648 }
649
650 pub const fn has_enough_parallelism(&self) -> bool {
652 self.has_enough_parallelism
653 }
654
655 pub const fn use_state_root_task(&self) -> bool {
660 !self.skip_state_root && !self.state_root_fallback && self.has_enough_parallelism
661 }
662
663 pub const fn with_state_provider_metrics(mut self, state_provider_metrics: bool) -> Self {
665 self.state_provider_metrics = state_provider_metrics;
666 self
667 }
668
669 pub const fn with_multiproof_chunk_size(mut self, multiproof_chunk_size: usize) -> Self {
671 self.multiproof_chunk_size = multiproof_chunk_size;
672 self
673 }
674
675 pub const fn with_reserved_cpu_cores(mut self, reserved_cpu_cores: usize) -> Self {
677 self.reserved_cpu_cores = reserved_cpu_cores;
678 self
679 }
680
681 pub const fn without_precompile_cache(mut self, precompile_cache_disabled: bool) -> Self {
683 self.precompile_cache_disabled = precompile_cache_disabled;
684 self
685 }
686
687 pub const fn with_state_root_fallback(mut self, state_root_fallback: bool) -> Self {
689 self.state_root_fallback = state_root_fallback;
690 self
691 }
692
693 pub const fn with_unwind_canonical_header(mut self, unwind_canonical_header: bool) -> Self {
695 self.allow_unwind_canonical_header = unwind_canonical_header;
696 self
697 }
698
699 pub const fn disable_cache_metrics(&self) -> bool {
701 self.disable_cache_metrics
702 }
703
704 pub const fn without_cache_metrics(mut self, disable_cache_metrics: bool) -> Self {
706 self.disable_cache_metrics = disable_cache_metrics;
707 self
708 }
709
710 pub const fn sparse_trie_prune_depth(&self) -> usize {
712 self.sparse_trie_prune_depth
713 }
714
715 pub const fn with_sparse_trie_prune_depth(mut self, depth: usize) -> Self {
717 self.sparse_trie_prune_depth = depth;
718 self
719 }
720
721 pub const fn slow_block_threshold(&self) -> Option<Duration> {
727 self.slow_block_threshold
728 }
729
730 pub const fn with_slow_block_threshold(
732 mut self,
733 slow_block_threshold: Option<Duration>,
734 ) -> Self {
735 self.slow_block_threshold = slow_block_threshold;
736 self
737 }
738
739 pub const fn disable_sparse_trie_cache_pruning(&self) -> bool {
741 self.disable_sparse_trie_cache_pruning
742 }
743
744 pub const fn with_disable_sparse_trie_cache_pruning(mut self, value: bool) -> Self {
746 self.disable_sparse_trie_cache_pruning = value;
747 self
748 }
749
750 pub const fn state_root_task_timeout(&self) -> Option<Duration> {
752 self.state_root_task_timeout
753 }
754
755 pub const fn with_state_root_task_timeout(mut self, timeout: Option<Duration>) -> Self {
757 self.state_root_task_timeout = timeout;
758 self
759 }
760
761 pub const fn share_execution_cache_with_payload_builder(&self) -> bool {
763 self.share_execution_cache_with_payload_builder
764 }
765
766 pub const fn share_sparse_trie_with_payload_builder(&self) -> bool {
768 self.share_sparse_trie_with_payload_builder
769 }
770
771 pub const fn with_share_execution_cache_with_payload_builder(
773 mut self,
774 share_execution_cache_with_payload_builder: bool,
775 ) -> Self {
776 self.share_execution_cache_with_payload_builder =
777 share_execution_cache_with_payload_builder;
778 self
779 }
780
781 pub const fn with_share_sparse_trie_with_payload_builder(
783 mut self,
784 share_sparse_trie_with_payload_builder: bool,
785 ) -> Self {
786 self.share_sparse_trie_with_payload_builder = share_sparse_trie_with_payload_builder;
787 self
788 }
789
790 pub const fn suppress_persistence_during_build(&self) -> bool {
792 self.suppress_persistence_during_build
793 }
794
795 pub const fn with_suppress_persistence_during_build(mut self, value: bool) -> Self {
797 self.suppress_persistence_during_build = value;
798 self
799 }
800
801 pub const fn disable_bal_parallel_execution(&self) -> bool {
803 self.disable_bal_parallel_execution
804 }
805
806 pub const fn without_bal_parallel_execution(
808 mut self,
809 disable_bal_parallel_execution: bool,
810 ) -> Self {
811 self.disable_bal_parallel_execution = disable_bal_parallel_execution;
812 self
813 }
814
815 pub const fn disable_bal_parallel_state_root(&self) -> bool {
817 self.disable_bal_parallel_state_root
818 }
819
820 pub const fn without_bal_parallel_state_root(
822 mut self,
823 disable_bal_parallel_state_root: bool,
824 ) -> Self {
825 self.disable_bal_parallel_state_root = disable_bal_parallel_state_root;
826 self
827 }
828
829 pub const fn disable_bal_batch_io(&self) -> bool {
831 self.disable_bal_batch_io
832 }
833
834 pub const fn without_bal_batch_io(mut self, disable_bal_batch_io: bool) -> Self {
836 self.disable_bal_batch_io = disable_bal_batch_io;
837 self
838 }
839
840 pub const fn skip_state_root(&self) -> bool {
842 self.skip_state_root
843 }
844
845 pub const fn with_skip_state_root(mut self, skip_state_root: bool) -> Self {
847 self.skip_state_root = skip_state_root;
848 self
849 }
850
851 #[cfg(feature = "trie-debug")]
853 pub const fn proof_jitter(&self) -> Option<Duration> {
854 self.proof_jitter
855 }
856
857 #[cfg(feature = "trie-debug")]
859 pub const fn with_proof_jitter(mut self, proof_jitter: Option<Duration>) -> Self {
860 self.proof_jitter = proof_jitter;
861 self
862 }
863}
864
865const fn clamp_backfill_run_threshold(threshold: u64) -> u64 {
867 if threshold > MAX_BACKFILL_RUN_THRESHOLD {
868 MAX_BACKFILL_RUN_THRESHOLD
869 } else {
870 threshold
871 }
872}
873
874#[cfg(test)]
875mod tests {
876 use super::*;
877
878 #[test]
879 fn backfill_threshold_grows_block_buffer() {
880 let default = TreeConfig::default();
881 for (threshold, expected, buffer_limit) in
882 [(0, 0, 64), (500, 500, 1000), (1024, 1024, 2048), (u64::MAX, 1024, 2048)]
883 {
884 let config = default.clone().with_backfill_run_threshold(threshold);
885 assert_eq!(config.backfill_run_threshold(), expected);
886 assert_eq!(config.block_buffer_limit(), buffer_limit);
887 }
888 let config = default.with_block_buffer_limit(2000).with_backfill_run_threshold(500);
889 assert_eq!(config.block_buffer_limit(), 2000);
890 }
891
892 #[test]
893 fn txpool_prewarming_is_disabled_by_default_and_can_be_enabled() {
894 assert!(!TreeConfig::default().txpool_prewarming());
895 assert!(TreeConfig::default().with_txpool_prewarming(true).txpool_prewarming());
896 }
897
898 #[test]
899 fn state_root_task_requires_parallelism_without_overrides() {
900 assert!(TreeConfig::default().with_has_enough_parallelism(true).use_state_root_task());
901 assert!(!TreeConfig::default().with_has_enough_parallelism(false).use_state_root_task());
902 assert!(!TreeConfig::default()
903 .with_has_enough_parallelism(true)
904 .with_state_root_fallback(true)
905 .use_state_root_task());
906 assert!(!TreeConfig::default()
907 .with_has_enough_parallelism(true)
908 .with_skip_state_root(true)
909 .use_state_root_task());
910 }
911
912 #[test]
913 #[should_panic(
914 expected = "persistence_backpressure_threshold must be greater than persistence_threshold"
915 )]
916 fn rejects_backpressure_threshold_at_or_below_persistence_threshold() {
917 let _ = TreeConfig::default()
918 .with_num_state_masking_blocks(0)
919 .with_persistence_threshold(4)
920 .with_persistence_backpressure_threshold(4);
921 }
922
923 #[test]
924 fn default_persistence_settings() {
925 let config = TreeConfig::default();
926 assert_eq!(config.persistence_threshold(), 50);
927 assert_eq!(config.num_state_masking_blocks(), 30);
928 assert_eq!(config.persistence_backpressure_threshold(), 100);
929 }
930
931 #[test]
932 fn zero_persistence_threshold_disables_state_masking() {
933 let config = TreeConfig::default().with_persistence_threshold(0);
934 assert_eq!(config.num_state_masking_blocks(), 0);
935 let config = config.with_num_state_masking_blocks(u64::MAX);
936 assert_eq!(config.num_state_masking_blocks(), 0);
937 let config = config.with_memory_block_buffer_target(0);
938 assert_eq!(config.num_state_masking_blocks(), 0);
939 }
940
941 #[test]
942 #[should_panic(
943 expected = "num_state_masking_blocks + memory_block_buffer_target must be less than persistence_threshold"
944 )]
945 fn rejects_state_masking_window_at_or_above_persistence_threshold() {
946 let _ = TreeConfig::default()
947 .with_num_state_masking_blocks(0)
948 .with_persistence_threshold(4)
949 .with_memory_block_buffer_target(2)
950 .with_num_state_masking_blocks(2);
951 }
952
953 #[test]
954 #[should_panic(
955 expected = "num_state_masking_blocks + memory_block_buffer_target must be less than persistence_threshold"
956 )]
957 fn rejects_overflowing_state_masking_window() {
958 let _ = TreeConfig::default().with_num_state_masking_blocks(u64::MAX);
959 }
960}