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 SMALL_BLOCK_GAS_THRESHOLD: u64 = 20_000_000;
20
21pub const DEFAULT_RESERVED_CPU_CORES: usize = 1;
25
26pub const DEFAULT_SPARSE_TRIE_PRUNE_DEPTH: usize = 4;
31
32pub const DEFAULT_SPARSE_TRIE_MAX_HOT_SLOTS: usize = 1500;
36
37pub const DEFAULT_SPARSE_TRIE_MAX_HOT_ACCOUNTS: usize = 1000;
41
42pub 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 } else if cfg!(target_pointer_width = "32") {
64 usize::MAX } else {
66 4 * 1024 * 1024 * 1024 }
68}
69
70pub 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#[derive(Debug, Clone)]
89pub struct TreeConfig {
90 persistence_threshold: u64,
93 memory_block_buffer_target: u64,
98 persistence_backpressure_threshold: u64,
100 block_buffer_limit: u32,
103 max_invalid_header_cache_length: u32,
105 max_execute_block_batch_size: usize,
110 legacy_state_root: bool,
113 always_compare_trie_updates: bool,
116 disable_state_cache: bool,
118 disable_prewarming: bool,
120 state_provider_metrics: bool,
122 cross_block_cache_size: usize,
124 has_enough_parallelism: bool,
126 multiproof_chunk_size: usize,
128 reserved_cpu_cores: usize,
130 precompile_cache_disabled: bool,
132 state_root_fallback: bool,
134 always_process_payload_attributes_on_canonical_head: bool,
148 allow_unwind_canonical_header: bool,
150 disable_cache_metrics: bool,
152 sparse_trie_prune_depth: usize,
154 sparse_trie_max_hot_slots: usize,
156 sparse_trie_max_hot_accounts: usize,
158 slow_block_threshold: Option<Duration>,
162 disable_sparse_trie_cache_pruning: bool,
164 state_root_task_timeout: Option<Duration>,
169 share_execution_cache_with_payload_builder: bool,
171 share_sparse_trie_with_payload_builder: bool,
173 #[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 #[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 pub const fn persistence_threshold(&self) -> u64 {
293 self.persistence_threshold
294 }
295
296 pub const fn memory_block_buffer_target(&self) -> u64 {
298 self.memory_block_buffer_target
299 }
300
301 pub const fn persistence_backpressure_threshold(&self) -> u64 {
303 self.persistence_backpressure_threshold
304 }
305
306 pub const fn block_buffer_limit(&self) -> u32 {
308 self.block_buffer_limit
309 }
310
311 pub const fn max_invalid_header_cache_length(&self) -> u32 {
313 self.max_invalid_header_cache_length
314 }
315
316 pub const fn max_execute_block_batch_size(&self) -> usize {
318 self.max_execute_block_batch_size
319 }
320
321 pub const fn multiproof_chunk_size(&self) -> usize {
323 self.multiproof_chunk_size
324 }
325
326 pub const fn effective_multiproof_chunk_size(&self) -> usize {
328 self.multiproof_chunk_size
329 }
330
331 pub const fn reserved_cpu_cores(&self) -> usize {
333 self.reserved_cpu_cores
334 }
335
336 pub const fn legacy_state_root(&self) -> bool {
339 self.legacy_state_root
340 }
341
342 pub const fn state_provider_metrics(&self) -> bool {
344 self.state_provider_metrics
345 }
346
347 pub const fn disable_state_cache(&self) -> bool {
349 self.disable_state_cache
350 }
351
352 pub const fn disable_prewarming(&self) -> bool {
354 self.disable_prewarming
355 }
356
357 pub const fn always_compare_trie_updates(&self) -> bool {
360 self.always_compare_trie_updates
361 }
362
363 pub const fn cross_block_cache_size(&self) -> usize {
365 self.cross_block_cache_size
366 }
367
368 pub const fn precompile_cache_disabled(&self) -> bool {
370 self.precompile_cache_disabled
371 }
372
373 pub const fn state_root_fallback(&self) -> bool {
375 self.state_root_fallback
376 }
377
378 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 pub const fn always_process_payload_attributes_on_canonical_head(&self) -> bool {
391 self.always_process_payload_attributes_on_canonical_head
392 }
393
394 pub const fn unwind_canonical_header(&self) -> bool {
396 self.allow_unwind_canonical_header
397 }
398
399 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 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 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 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 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 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 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 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 pub const fn without_prewarming(mut self, disable_prewarming: bool) -> Self {
469 self.disable_prewarming = disable_prewarming;
470 self
471 }
472
473 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 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 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 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 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 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 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 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 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 pub const fn use_state_root_task(&self) -> bool {
533 self.has_enough_parallelism && !self.legacy_state_root
534 }
535
536 pub const fn disable_cache_metrics(&self) -> bool {
538 self.disable_cache_metrics
539 }
540
541 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 pub const fn sparse_trie_prune_depth(&self) -> usize {
549 self.sparse_trie_prune_depth
550 }
551
552 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 pub const fn sparse_trie_max_hot_slots(&self) -> usize {
560 self.sparse_trie_max_hot_slots
561 }
562
563 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 pub const fn sparse_trie_max_hot_accounts(&self) -> usize {
571 self.sparse_trie_max_hot_accounts
572 }
573
574 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 pub const fn slow_block_threshold(&self) -> Option<Duration> {
586 self.slow_block_threshold
587 }
588
589 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 pub const fn disable_sparse_trie_cache_pruning(&self) -> bool {
600 self.disable_sparse_trie_cache_pruning
601 }
602
603 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 pub const fn state_root_task_timeout(&self) -> Option<Duration> {
611 self.state_root_task_timeout
612 }
613
614 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 pub const fn share_execution_cache_with_payload_builder(&self) -> bool {
622 self.share_execution_cache_with_payload_builder
623 }
624
625 pub const fn share_sparse_trie_with_payload_builder(&self) -> bool {
627 self.share_sparse_trie_with_payload_builder
628 }
629
630 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 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 #[cfg(feature = "trie-debug")]
651 pub const fn proof_jitter(&self) -> Option<Duration> {
652 self.proof_jitter
653 }
654
655 #[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}