1use clap::{builder::Resettable, Args};
4use reth_engine_primitives::{
5 TreeConfig, DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE, DEFAULT_SPARSE_TRIE_MAX_STORAGE_TRIES,
6 DEFAULT_SPARSE_TRIE_PRUNE_DEPTH,
7};
8use std::{sync::OnceLock, time::Duration};
9
10use crate::node_config::{
11 DEFAULT_CROSS_BLOCK_CACHE_SIZE_MB, DEFAULT_MEMORY_BLOCK_BUFFER_TARGET,
12 DEFAULT_PERSISTENCE_THRESHOLD, DEFAULT_RESERVED_CPU_CORES,
13};
14
15static ENGINE_DEFAULTS: OnceLock<DefaultEngineValues> = OnceLock::new();
17
18#[derive(Debug, Clone)]
22pub struct DefaultEngineValues {
23 persistence_threshold: u64,
24 memory_block_buffer_target: u64,
25 legacy_state_root_task_enabled: bool,
26 state_cache_disabled: bool,
27 prewarming_disabled: bool,
28 state_provider_metrics: bool,
29 cross_block_cache_size: usize,
30 state_root_task_compare_updates: bool,
31 accept_execution_requests_hash: bool,
32 multiproof_chunking_enabled: bool,
33 multiproof_chunk_size: usize,
34 reserved_cpu_cores: usize,
35 precompile_cache_disabled: bool,
36 state_root_fallback: bool,
37 always_process_payload_attributes_on_canonical_head: bool,
38 allow_unwind_canonical_header: bool,
39 storage_worker_count: Option<usize>,
40 account_worker_count: Option<usize>,
41 disable_proof_v2: bool,
42 cache_metrics_disabled: bool,
43 disable_trie_cache: bool,
44 sparse_trie_prune_depth: usize,
45 sparse_trie_max_storage_tries: usize,
46 disable_sparse_trie_cache_pruning: bool,
47 state_root_task_timeout: Option<String>,
48}
49
50impl DefaultEngineValues {
51 pub fn try_init(self) -> Result<(), Self> {
53 ENGINE_DEFAULTS.set(self)
54 }
55
56 pub fn get_global() -> &'static Self {
58 ENGINE_DEFAULTS.get_or_init(Self::default)
59 }
60
61 pub const fn with_persistence_threshold(mut self, v: u64) -> Self {
63 self.persistence_threshold = v;
64 self
65 }
66
67 pub const fn with_memory_block_buffer_target(mut self, v: u64) -> Self {
69 self.memory_block_buffer_target = v;
70 self
71 }
72
73 pub const fn with_legacy_state_root_task_enabled(mut self, v: bool) -> Self {
75 self.legacy_state_root_task_enabled = v;
76 self
77 }
78
79 pub const fn with_state_cache_disabled(mut self, v: bool) -> Self {
81 self.state_cache_disabled = v;
82 self
83 }
84
85 pub const fn with_prewarming_disabled(mut self, v: bool) -> Self {
87 self.prewarming_disabled = v;
88 self
89 }
90
91 pub const fn with_state_provider_metrics(mut self, v: bool) -> Self {
93 self.state_provider_metrics = v;
94 self
95 }
96
97 pub const fn with_cross_block_cache_size(mut self, v: usize) -> Self {
99 self.cross_block_cache_size = v;
100 self
101 }
102
103 pub const fn with_state_root_task_compare_updates(mut self, v: bool) -> Self {
105 self.state_root_task_compare_updates = v;
106 self
107 }
108
109 pub const fn with_accept_execution_requests_hash(mut self, v: bool) -> Self {
111 self.accept_execution_requests_hash = v;
112 self
113 }
114
115 pub const fn with_multiproof_chunking_enabled(mut self, v: bool) -> Self {
117 self.multiproof_chunking_enabled = v;
118 self
119 }
120
121 pub const fn with_multiproof_chunk_size(mut self, v: usize) -> Self {
123 self.multiproof_chunk_size = v;
124 self
125 }
126
127 pub const fn with_reserved_cpu_cores(mut self, v: usize) -> Self {
129 self.reserved_cpu_cores = v;
130 self
131 }
132
133 pub const fn with_precompile_cache_disabled(mut self, v: bool) -> Self {
135 self.precompile_cache_disabled = v;
136 self
137 }
138
139 pub const fn with_state_root_fallback(mut self, v: bool) -> Self {
141 self.state_root_fallback = v;
142 self
143 }
144
145 pub const fn with_always_process_payload_attributes_on_canonical_head(
147 mut self,
148 v: bool,
149 ) -> Self {
150 self.always_process_payload_attributes_on_canonical_head = v;
151 self
152 }
153
154 pub const fn with_allow_unwind_canonical_header(mut self, v: bool) -> Self {
156 self.allow_unwind_canonical_header = v;
157 self
158 }
159
160 pub const fn with_storage_worker_count(mut self, v: Option<usize>) -> Self {
162 self.storage_worker_count = v;
163 self
164 }
165
166 pub const fn with_account_worker_count(mut self, v: Option<usize>) -> Self {
168 self.account_worker_count = v;
169 self
170 }
171
172 pub const fn with_disable_proof_v2(mut self, v: bool) -> Self {
174 self.disable_proof_v2 = v;
175 self
176 }
177
178 pub const fn with_cache_metrics_disabled(mut self, v: bool) -> Self {
180 self.cache_metrics_disabled = v;
181 self
182 }
183
184 pub const fn with_disable_trie_cache(mut self, v: bool) -> Self {
186 self.disable_trie_cache = v;
187 self
188 }
189
190 pub const fn with_sparse_trie_prune_depth(mut self, v: usize) -> Self {
192 self.sparse_trie_prune_depth = v;
193 self
194 }
195
196 pub const fn with_sparse_trie_max_storage_tries(mut self, v: usize) -> Self {
198 self.sparse_trie_max_storage_tries = v;
199 self
200 }
201
202 pub const fn with_disable_sparse_trie_cache_pruning(mut self, v: bool) -> Self {
204 self.disable_sparse_trie_cache_pruning = v;
205 self
206 }
207
208 pub fn with_state_root_task_timeout(mut self, v: Option<String>) -> Self {
210 self.state_root_task_timeout = v;
211 self
212 }
213}
214
215impl Default for DefaultEngineValues {
216 fn default() -> Self {
217 Self {
218 persistence_threshold: DEFAULT_PERSISTENCE_THRESHOLD,
219 memory_block_buffer_target: DEFAULT_MEMORY_BLOCK_BUFFER_TARGET,
220 legacy_state_root_task_enabled: false,
221 state_cache_disabled: false,
222 prewarming_disabled: false,
223 state_provider_metrics: false,
224 cross_block_cache_size: DEFAULT_CROSS_BLOCK_CACHE_SIZE_MB,
225 state_root_task_compare_updates: false,
226 accept_execution_requests_hash: false,
227 multiproof_chunking_enabled: true,
228 multiproof_chunk_size: DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE,
229 reserved_cpu_cores: DEFAULT_RESERVED_CPU_CORES,
230 precompile_cache_disabled: false,
231 state_root_fallback: false,
232 always_process_payload_attributes_on_canonical_head: false,
233 allow_unwind_canonical_header: false,
234 storage_worker_count: None,
235 account_worker_count: None,
236 disable_proof_v2: false,
237 cache_metrics_disabled: false,
238 disable_trie_cache: false,
239 sparse_trie_prune_depth: DEFAULT_SPARSE_TRIE_PRUNE_DEPTH,
240 sparse_trie_max_storage_tries: DEFAULT_SPARSE_TRIE_MAX_STORAGE_TRIES,
241 disable_sparse_trie_cache_pruning: false,
242 state_root_task_timeout: Some("1s".to_string()),
243 }
244 }
245}
246
247#[derive(Debug, Clone, Args, PartialEq, Eq)]
249#[command(next_help_heading = "Engine")]
250pub struct EngineArgs {
251 #[arg(long = "engine.persistence-threshold", default_value_t = DefaultEngineValues::get_global().persistence_threshold)]
258 pub persistence_threshold: u64,
259
260 #[arg(long = "engine.memory-block-buffer-target", default_value_t = DefaultEngineValues::get_global().memory_block_buffer_target)]
262 pub memory_block_buffer_target: u64,
263
264 #[arg(long = "engine.legacy-state-root", default_value_t = DefaultEngineValues::get_global().legacy_state_root_task_enabled)]
266 pub legacy_state_root_task_enabled: bool,
267
268 #[arg(long = "engine.caching-and-prewarming", default_value = "true", hide = true)]
271 #[deprecated]
272 pub caching_and_prewarming_enabled: bool,
273
274 #[arg(long = "engine.disable-state-cache", default_value_t = DefaultEngineValues::get_global().state_cache_disabled)]
276 pub state_cache_disabled: bool,
277
278 #[arg(long = "engine.disable-prewarming", alias = "engine.disable-caching-and-prewarming", default_value_t = DefaultEngineValues::get_global().prewarming_disabled)]
280 pub prewarming_disabled: bool,
281
282 #[deprecated]
284 #[arg(long = "engine.parallel-sparse-trie", default_value = "true", hide = true)]
285 pub parallel_sparse_trie_enabled: bool,
286
287 #[deprecated]
289 #[arg(long = "engine.disable-parallel-sparse-trie", default_value = "false", hide = true)]
290 pub parallel_sparse_trie_disabled: bool,
291
292 #[arg(long = "engine.state-provider-metrics", default_value_t = DefaultEngineValues::get_global().state_provider_metrics)]
296 pub state_provider_metrics: bool,
297
298 #[arg(long = "engine.cross-block-cache-size", default_value_t = DefaultEngineValues::get_global().cross_block_cache_size)]
300 pub cross_block_cache_size: usize,
301
302 #[arg(long = "engine.state-root-task-compare-updates", default_value_t = DefaultEngineValues::get_global().state_root_task_compare_updates)]
305 pub state_root_task_compare_updates: bool,
306
307 #[arg(long = "engine.accept-execution-requests-hash", default_value_t = DefaultEngineValues::get_global().accept_execution_requests_hash)]
309 pub accept_execution_requests_hash: bool,
310
311 #[arg(long = "engine.multiproof-chunking", default_value_t = DefaultEngineValues::get_global().multiproof_chunking_enabled)]
313 pub multiproof_chunking_enabled: bool,
314
315 #[arg(long = "engine.multiproof-chunk-size", default_value_t = DefaultEngineValues::get_global().multiproof_chunk_size)]
317 pub multiproof_chunk_size: usize,
318
319 #[arg(long = "engine.reserved-cpu-cores", default_value_t = DefaultEngineValues::get_global().reserved_cpu_cores)]
321 pub reserved_cpu_cores: usize,
322
323 #[arg(long = "engine.precompile-cache", default_value = "true", hide = true)]
326 #[deprecated]
327 pub precompile_cache_enabled: bool,
328
329 #[arg(long = "engine.disable-precompile-cache", default_value_t = DefaultEngineValues::get_global().precompile_cache_disabled)]
331 pub precompile_cache_disabled: bool,
332
333 #[arg(long = "engine.state-root-fallback", default_value_t = DefaultEngineValues::get_global().state_root_fallback)]
335 pub state_root_fallback: bool,
336
337 #[arg(
343 long = "engine.always-process-payload-attributes-on-canonical-head",
344 default_value_t = DefaultEngineValues::get_global().always_process_payload_attributes_on_canonical_head
345 )]
346 pub always_process_payload_attributes_on_canonical_head: bool,
347
348 #[arg(long = "engine.allow-unwind-canonical-header", default_value_t = DefaultEngineValues::get_global().allow_unwind_canonical_header)]
351 pub allow_unwind_canonical_header: bool,
352
353 #[arg(long = "engine.storage-worker-count", default_value = Resettable::from(DefaultEngineValues::get_global().storage_worker_count.map(|v| v.to_string().into())))]
356 pub storage_worker_count: Option<usize>,
357
358 #[arg(long = "engine.account-worker-count", default_value = Resettable::from(DefaultEngineValues::get_global().account_worker_count.map(|v| v.to_string().into())))]
361 pub account_worker_count: Option<usize>,
362
363 #[arg(long = "engine.disable-proof-v2", default_value_t = DefaultEngineValues::get_global().disable_proof_v2)]
365 pub disable_proof_v2: bool,
366
367 #[arg(long = "engine.disable-cache-metrics", default_value_t = DefaultEngineValues::get_global().cache_metrics_disabled)]
369 pub cache_metrics_disabled: bool,
370
371 #[arg(long = "engine.disable-trie-cache", default_value_t = DefaultEngineValues::get_global().disable_trie_cache, conflicts_with = "disable_proof_v2")]
373 pub disable_trie_cache: bool,
374
375 #[arg(long = "engine.sparse-trie-prune-depth", default_value_t = DefaultEngineValues::get_global().sparse_trie_prune_depth)]
377 pub sparse_trie_prune_depth: usize,
378
379 #[arg(long = "engine.sparse-trie-max-storage-tries", default_value_t = DefaultEngineValues::get_global().sparse_trie_max_storage_tries)]
381 pub sparse_trie_max_storage_tries: usize,
382
383 #[arg(long = "engine.disable-sparse-trie-cache-pruning", default_value_t = DefaultEngineValues::get_global().disable_sparse_trie_cache_pruning)]
387 pub disable_sparse_trie_cache_pruning: bool,
388
389 #[arg(
398 long = "engine.state-root-task-timeout",
399 value_parser = humantime::parse_duration,
400 default_value = DefaultEngineValues::get_global().state_root_task_timeout.as_deref().unwrap_or("1s"),
401 )]
402 pub state_root_task_timeout: Option<Duration>,
403}
404
405#[allow(deprecated)]
406impl Default for EngineArgs {
407 fn default() -> Self {
408 let DefaultEngineValues {
409 persistence_threshold,
410 memory_block_buffer_target,
411 legacy_state_root_task_enabled,
412 state_cache_disabled,
413 prewarming_disabled,
414 state_provider_metrics,
415 cross_block_cache_size,
416 state_root_task_compare_updates,
417 accept_execution_requests_hash,
418 multiproof_chunking_enabled,
419 multiproof_chunk_size,
420 reserved_cpu_cores,
421 precompile_cache_disabled,
422 state_root_fallback,
423 always_process_payload_attributes_on_canonical_head,
424 allow_unwind_canonical_header,
425 storage_worker_count,
426 account_worker_count,
427 disable_proof_v2,
428 cache_metrics_disabled,
429 disable_trie_cache,
430 sparse_trie_prune_depth,
431 sparse_trie_max_storage_tries,
432 disable_sparse_trie_cache_pruning,
433 state_root_task_timeout,
434 } = DefaultEngineValues::get_global().clone();
435 Self {
436 persistence_threshold,
437 memory_block_buffer_target,
438 legacy_state_root_task_enabled,
439 state_root_task_compare_updates,
440 caching_and_prewarming_enabled: true,
441 state_cache_disabled,
442 prewarming_disabled,
443 parallel_sparse_trie_enabled: true,
444 parallel_sparse_trie_disabled: false,
445 state_provider_metrics,
446 cross_block_cache_size,
447 accept_execution_requests_hash,
448 multiproof_chunking_enabled,
449 multiproof_chunk_size,
450 reserved_cpu_cores,
451 precompile_cache_enabled: true,
452 precompile_cache_disabled,
453 state_root_fallback,
454 always_process_payload_attributes_on_canonical_head,
455 allow_unwind_canonical_header,
456 storage_worker_count,
457 account_worker_count,
458 disable_proof_v2,
459 cache_metrics_disabled,
460 disable_trie_cache,
461 sparse_trie_prune_depth,
462 sparse_trie_max_storage_tries,
463 disable_sparse_trie_cache_pruning,
464 state_root_task_timeout: state_root_task_timeout
465 .as_deref()
466 .map(|s| humantime::parse_duration(s).expect("valid default duration")),
467 }
468 }
469}
470
471impl EngineArgs {
472 pub fn tree_config(&self) -> TreeConfig {
474 TreeConfig::default()
475 .with_persistence_threshold(self.persistence_threshold)
476 .with_memory_block_buffer_target(self.memory_block_buffer_target)
477 .with_legacy_state_root(self.legacy_state_root_task_enabled)
478 .without_state_cache(self.state_cache_disabled)
479 .without_prewarming(self.prewarming_disabled)
480 .with_state_provider_metrics(self.state_provider_metrics)
481 .with_always_compare_trie_updates(self.state_root_task_compare_updates)
482 .with_cross_block_cache_size(self.cross_block_cache_size * 1024 * 1024)
483 .with_multiproof_chunking_enabled(self.multiproof_chunking_enabled)
484 .with_multiproof_chunk_size(self.multiproof_chunk_size)
485 .with_reserved_cpu_cores(self.reserved_cpu_cores)
486 .without_precompile_cache(self.precompile_cache_disabled)
487 .with_state_root_fallback(self.state_root_fallback)
488 .with_always_process_payload_attributes_on_canonical_head(
489 self.always_process_payload_attributes_on_canonical_head,
490 )
491 .with_unwind_canonical_header(self.allow_unwind_canonical_header)
492 .with_storage_worker_count_opt(self.storage_worker_count)
493 .with_account_worker_count_opt(self.account_worker_count)
494 .with_disable_proof_v2(self.disable_proof_v2)
495 .without_cache_metrics(self.cache_metrics_disabled)
496 .with_disable_trie_cache(self.disable_trie_cache)
497 .with_sparse_trie_prune_depth(self.sparse_trie_prune_depth)
498 .with_sparse_trie_max_storage_tries(self.sparse_trie_max_storage_tries)
499 .with_disable_sparse_trie_cache_pruning(self.disable_sparse_trie_cache_pruning)
500 .with_state_root_task_timeout(self.state_root_task_timeout.filter(|d| !d.is_zero()))
501 }
502}
503
504#[cfg(test)]
505mod tests {
506 use super::*;
507 use clap::Parser;
508
509 #[derive(Parser)]
511 struct CommandParser<T: Args> {
512 #[command(flatten)]
513 args: T,
514 }
515
516 #[test]
517 fn test_parse_engine_args() {
518 let default_args = EngineArgs::default();
519 let args = CommandParser::<EngineArgs>::parse_from(["reth"]).args;
520 assert_eq!(args, default_args);
521 }
522
523 #[test]
524 #[allow(deprecated)]
525 fn engine_args() {
526 let args = EngineArgs {
527 persistence_threshold: 100,
528 memory_block_buffer_target: 50,
529 legacy_state_root_task_enabled: true,
530 caching_and_prewarming_enabled: true,
531 state_cache_disabled: true,
532 prewarming_disabled: true,
533 parallel_sparse_trie_enabled: true,
534 parallel_sparse_trie_disabled: false,
535 state_provider_metrics: true,
536 cross_block_cache_size: 256,
537 state_root_task_compare_updates: true,
538 accept_execution_requests_hash: true,
539 multiproof_chunking_enabled: true,
540 multiproof_chunk_size: 512,
541 reserved_cpu_cores: 4,
542 precompile_cache_enabled: true,
543 precompile_cache_disabled: true,
544 state_root_fallback: true,
545 always_process_payload_attributes_on_canonical_head: true,
546 allow_unwind_canonical_header: true,
547 storage_worker_count: Some(16),
548 account_worker_count: Some(8),
549 disable_proof_v2: false,
550 cache_metrics_disabled: true,
551 disable_trie_cache: true,
552 sparse_trie_prune_depth: 10,
553 sparse_trie_max_storage_tries: 100,
554 disable_sparse_trie_cache_pruning: true,
555 state_root_task_timeout: Some(Duration::from_secs(2)),
556 };
557
558 let parsed_args = CommandParser::<EngineArgs>::parse_from([
559 "reth",
560 "--engine.persistence-threshold",
561 "100",
562 "--engine.memory-block-buffer-target",
563 "50",
564 "--engine.legacy-state-root",
565 "--engine.disable-state-cache",
566 "--engine.disable-prewarming",
567 "--engine.state-provider-metrics",
568 "--engine.cross-block-cache-size",
569 "256",
570 "--engine.state-root-task-compare-updates",
571 "--engine.accept-execution-requests-hash",
572 "--engine.multiproof-chunking",
573 "--engine.multiproof-chunk-size",
574 "512",
575 "--engine.reserved-cpu-cores",
576 "4",
577 "--engine.disable-precompile-cache",
578 "--engine.state-root-fallback",
579 "--engine.always-process-payload-attributes-on-canonical-head",
580 "--engine.allow-unwind-canonical-header",
581 "--engine.storage-worker-count",
582 "16",
583 "--engine.account-worker-count",
584 "8",
585 "--engine.disable-cache-metrics",
586 "--engine.disable-trie-cache",
587 "--engine.sparse-trie-prune-depth",
588 "10",
589 "--engine.sparse-trie-max-storage-tries",
590 "100",
591 "--engine.disable-sparse-trie-cache-pruning",
592 "--engine.state-root-task-timeout",
593 "2s",
594 ])
595 .args;
596
597 assert_eq!(parsed_args, args);
598 }
599}