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_chunk_size: usize,
33 reserved_cpu_cores: usize,
34 precompile_cache_disabled: bool,
35 state_root_fallback: bool,
36 always_process_payload_attributes_on_canonical_head: bool,
37 allow_unwind_canonical_header: bool,
38 storage_worker_count: Option<usize>,
39 account_worker_count: Option<usize>,
40 prewarming_threads: Option<usize>,
41 cache_metrics_disabled: bool,
42 sparse_trie_prune_depth: usize,
43 sparse_trie_max_storage_tries: usize,
44 disable_sparse_trie_cache_pruning: bool,
45 state_root_task_timeout: Option<String>,
46}
47
48impl DefaultEngineValues {
49 pub fn try_init(self) -> Result<(), Self> {
51 ENGINE_DEFAULTS.set(self)
52 }
53
54 pub fn get_global() -> &'static Self {
56 ENGINE_DEFAULTS.get_or_init(Self::default)
57 }
58
59 pub const fn with_persistence_threshold(mut self, v: u64) -> Self {
61 self.persistence_threshold = v;
62 self
63 }
64
65 pub const fn with_memory_block_buffer_target(mut self, v: u64) -> Self {
67 self.memory_block_buffer_target = v;
68 self
69 }
70
71 pub const fn with_legacy_state_root_task_enabled(mut self, v: bool) -> Self {
73 self.legacy_state_root_task_enabled = v;
74 self
75 }
76
77 pub const fn with_state_cache_disabled(mut self, v: bool) -> Self {
79 self.state_cache_disabled = v;
80 self
81 }
82
83 pub const fn with_prewarming_disabled(mut self, v: bool) -> Self {
85 self.prewarming_disabled = v;
86 self
87 }
88
89 pub const fn with_state_provider_metrics(mut self, v: bool) -> Self {
91 self.state_provider_metrics = v;
92 self
93 }
94
95 pub const fn with_cross_block_cache_size(mut self, v: usize) -> Self {
97 self.cross_block_cache_size = v;
98 self
99 }
100
101 pub const fn with_state_root_task_compare_updates(mut self, v: bool) -> Self {
103 self.state_root_task_compare_updates = v;
104 self
105 }
106
107 pub const fn with_accept_execution_requests_hash(mut self, v: bool) -> Self {
109 self.accept_execution_requests_hash = v;
110 self
111 }
112
113 pub const fn with_multiproof_chunk_size(mut self, v: usize) -> Self {
115 self.multiproof_chunk_size = v;
116 self
117 }
118
119 pub const fn with_reserved_cpu_cores(mut self, v: usize) -> Self {
121 self.reserved_cpu_cores = v;
122 self
123 }
124
125 pub const fn with_precompile_cache_disabled(mut self, v: bool) -> Self {
127 self.precompile_cache_disabled = v;
128 self
129 }
130
131 pub const fn with_state_root_fallback(mut self, v: bool) -> Self {
133 self.state_root_fallback = v;
134 self
135 }
136
137 pub const fn with_always_process_payload_attributes_on_canonical_head(
139 mut self,
140 v: bool,
141 ) -> Self {
142 self.always_process_payload_attributes_on_canonical_head = v;
143 self
144 }
145
146 pub const fn with_allow_unwind_canonical_header(mut self, v: bool) -> Self {
148 self.allow_unwind_canonical_header = v;
149 self
150 }
151
152 pub const fn with_storage_worker_count(mut self, v: Option<usize>) -> Self {
154 self.storage_worker_count = v;
155 self
156 }
157
158 pub const fn with_account_worker_count(mut self, v: Option<usize>) -> Self {
160 self.account_worker_count = v;
161 self
162 }
163
164 pub const fn with_prewarming_threads(mut self, v: Option<usize>) -> Self {
166 self.prewarming_threads = v;
167 self
168 }
169
170 pub const fn with_cache_metrics_disabled(mut self, v: bool) -> Self {
172 self.cache_metrics_disabled = v;
173 self
174 }
175
176 pub const fn with_sparse_trie_prune_depth(mut self, v: usize) -> Self {
178 self.sparse_trie_prune_depth = v;
179 self
180 }
181
182 pub const fn with_sparse_trie_max_storage_tries(mut self, v: usize) -> Self {
184 self.sparse_trie_max_storage_tries = v;
185 self
186 }
187
188 pub const fn with_disable_sparse_trie_cache_pruning(mut self, v: bool) -> Self {
190 self.disable_sparse_trie_cache_pruning = v;
191 self
192 }
193
194 pub fn with_state_root_task_timeout(mut self, v: Option<String>) -> Self {
196 self.state_root_task_timeout = v;
197 self
198 }
199}
200
201impl Default for DefaultEngineValues {
202 fn default() -> Self {
203 Self {
204 persistence_threshold: DEFAULT_PERSISTENCE_THRESHOLD,
205 memory_block_buffer_target: DEFAULT_MEMORY_BLOCK_BUFFER_TARGET,
206 legacy_state_root_task_enabled: false,
207 state_cache_disabled: false,
208 prewarming_disabled: false,
209 state_provider_metrics: false,
210 cross_block_cache_size: DEFAULT_CROSS_BLOCK_CACHE_SIZE_MB,
211 state_root_task_compare_updates: false,
212 accept_execution_requests_hash: false,
213 multiproof_chunk_size: DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE,
214 reserved_cpu_cores: DEFAULT_RESERVED_CPU_CORES,
215 precompile_cache_disabled: false,
216 state_root_fallback: false,
217 always_process_payload_attributes_on_canonical_head: false,
218 allow_unwind_canonical_header: false,
219 storage_worker_count: None,
220 account_worker_count: None,
221 prewarming_threads: None,
222 cache_metrics_disabled: false,
223 sparse_trie_prune_depth: DEFAULT_SPARSE_TRIE_PRUNE_DEPTH,
224 sparse_trie_max_storage_tries: DEFAULT_SPARSE_TRIE_MAX_STORAGE_TRIES,
225 disable_sparse_trie_cache_pruning: false,
226 state_root_task_timeout: Some("1s".to_string()),
227 }
228 }
229}
230
231#[derive(Debug, Clone, Args, PartialEq, Eq)]
233#[command(next_help_heading = "Engine")]
234pub struct EngineArgs {
235 #[arg(long = "engine.persistence-threshold", default_value_t = DefaultEngineValues::get_global().persistence_threshold)]
242 pub persistence_threshold: u64,
243
244 #[arg(long = "engine.memory-block-buffer-target", default_value_t = DefaultEngineValues::get_global().memory_block_buffer_target)]
246 pub memory_block_buffer_target: u64,
247
248 #[arg(long = "engine.legacy-state-root", default_value_t = DefaultEngineValues::get_global().legacy_state_root_task_enabled)]
250 pub legacy_state_root_task_enabled: bool,
251
252 #[arg(long = "engine.caching-and-prewarming", default_value = "true", hide = true)]
255 #[deprecated]
256 pub caching_and_prewarming_enabled: bool,
257
258 #[arg(long = "engine.disable-state-cache", default_value_t = DefaultEngineValues::get_global().state_cache_disabled)]
260 pub state_cache_disabled: bool,
261
262 #[arg(long = "engine.disable-prewarming", alias = "engine.disable-caching-and-prewarming", default_value_t = DefaultEngineValues::get_global().prewarming_disabled)]
264 pub prewarming_disabled: bool,
265
266 #[deprecated]
268 #[arg(long = "engine.parallel-sparse-trie", default_value = "true", hide = true)]
269 pub parallel_sparse_trie_enabled: bool,
270
271 #[deprecated]
273 #[arg(long = "engine.disable-parallel-sparse-trie", default_value = "false", hide = true)]
274 pub parallel_sparse_trie_disabled: bool,
275
276 #[arg(long = "engine.state-provider-metrics", default_value_t = DefaultEngineValues::get_global().state_provider_metrics)]
280 pub state_provider_metrics: bool,
281
282 #[arg(long = "engine.cross-block-cache-size", default_value_t = DefaultEngineValues::get_global().cross_block_cache_size)]
284 pub cross_block_cache_size: usize,
285
286 #[arg(long = "engine.state-root-task-compare-updates", default_value_t = DefaultEngineValues::get_global().state_root_task_compare_updates)]
289 pub state_root_task_compare_updates: bool,
290
291 #[arg(long = "engine.accept-execution-requests-hash", default_value_t = DefaultEngineValues::get_global().accept_execution_requests_hash)]
293 pub accept_execution_requests_hash: bool,
294
295 #[arg(long = "engine.multiproof-chunk-size", default_value_t = DefaultEngineValues::get_global().multiproof_chunk_size)]
297 pub multiproof_chunk_size: usize,
298
299 #[arg(long = "engine.reserved-cpu-cores", default_value_t = DefaultEngineValues::get_global().reserved_cpu_cores)]
301 pub reserved_cpu_cores: usize,
302
303 #[arg(long = "engine.precompile-cache", default_value = "true", hide = true)]
306 #[deprecated]
307 pub precompile_cache_enabled: bool,
308
309 #[arg(long = "engine.disable-precompile-cache", default_value_t = DefaultEngineValues::get_global().precompile_cache_disabled)]
311 pub precompile_cache_disabled: bool,
312
313 #[arg(long = "engine.state-root-fallback", default_value_t = DefaultEngineValues::get_global().state_root_fallback)]
315 pub state_root_fallback: bool,
316
317 #[arg(
323 long = "engine.always-process-payload-attributes-on-canonical-head",
324 default_value_t = DefaultEngineValues::get_global().always_process_payload_attributes_on_canonical_head
325 )]
326 pub always_process_payload_attributes_on_canonical_head: bool,
327
328 #[arg(long = "engine.allow-unwind-canonical-header", default_value_t = DefaultEngineValues::get_global().allow_unwind_canonical_header)]
331 pub allow_unwind_canonical_header: bool,
332
333 #[arg(long = "engine.storage-worker-count", default_value = Resettable::from(DefaultEngineValues::get_global().storage_worker_count.map(|v| v.to_string().into())))]
336 pub storage_worker_count: Option<usize>,
337
338 #[arg(long = "engine.account-worker-count", default_value = Resettable::from(DefaultEngineValues::get_global().account_worker_count.map(|v| v.to_string().into())))]
341 pub account_worker_count: Option<usize>,
342
343 #[arg(long = "engine.prewarming-threads", default_value = Resettable::from(DefaultEngineValues::get_global().prewarming_threads.map(|v| v.to_string().into())))]
346 pub prewarming_threads: Option<usize>,
347
348 #[arg(long = "engine.disable-cache-metrics", default_value_t = DefaultEngineValues::get_global().cache_metrics_disabled)]
350 pub cache_metrics_disabled: bool,
351
352 #[arg(long = "engine.sparse-trie-prune-depth", default_value_t = DefaultEngineValues::get_global().sparse_trie_prune_depth)]
354 pub sparse_trie_prune_depth: usize,
355
356 #[arg(long = "engine.sparse-trie-max-storage-tries", default_value_t = DefaultEngineValues::get_global().sparse_trie_max_storage_tries)]
358 pub sparse_trie_max_storage_tries: usize,
359
360 #[arg(long = "engine.disable-sparse-trie-cache-pruning", default_value_t = DefaultEngineValues::get_global().disable_sparse_trie_cache_pruning)]
364 pub disable_sparse_trie_cache_pruning: bool,
365
366 #[arg(
375 long = "engine.state-root-task-timeout",
376 value_parser = humantime::parse_duration,
377 default_value = DefaultEngineValues::get_global().state_root_task_timeout.as_deref().unwrap_or("1s"),
378 )]
379 pub state_root_task_timeout: Option<Duration>,
380}
381
382#[allow(deprecated)]
383impl Default for EngineArgs {
384 fn default() -> Self {
385 let DefaultEngineValues {
386 persistence_threshold,
387 memory_block_buffer_target,
388 legacy_state_root_task_enabled,
389 state_cache_disabled,
390 prewarming_disabled,
391 state_provider_metrics,
392 cross_block_cache_size,
393 state_root_task_compare_updates,
394 accept_execution_requests_hash,
395 multiproof_chunk_size,
396 reserved_cpu_cores,
397 precompile_cache_disabled,
398 state_root_fallback,
399 always_process_payload_attributes_on_canonical_head,
400 allow_unwind_canonical_header,
401 storage_worker_count,
402 account_worker_count,
403 prewarming_threads,
404 cache_metrics_disabled,
405 sparse_trie_prune_depth,
406 sparse_trie_max_storage_tries,
407 disable_sparse_trie_cache_pruning,
408 state_root_task_timeout,
409 } = DefaultEngineValues::get_global().clone();
410 Self {
411 persistence_threshold,
412 memory_block_buffer_target,
413 legacy_state_root_task_enabled,
414 state_root_task_compare_updates,
415 caching_and_prewarming_enabled: true,
416 state_cache_disabled,
417 prewarming_disabled,
418 parallel_sparse_trie_enabled: true,
419 parallel_sparse_trie_disabled: false,
420 state_provider_metrics,
421 cross_block_cache_size,
422 accept_execution_requests_hash,
423 multiproof_chunk_size,
424 reserved_cpu_cores,
425 precompile_cache_enabled: true,
426 precompile_cache_disabled,
427 state_root_fallback,
428 always_process_payload_attributes_on_canonical_head,
429 allow_unwind_canonical_header,
430 storage_worker_count,
431 account_worker_count,
432 prewarming_threads,
433 cache_metrics_disabled,
434 sparse_trie_prune_depth,
435 sparse_trie_max_storage_tries,
436 disable_sparse_trie_cache_pruning,
437 state_root_task_timeout: state_root_task_timeout
438 .as_deref()
439 .map(|s| humantime::parse_duration(s).expect("valid default duration")),
440 }
441 }
442}
443
444impl EngineArgs {
445 pub fn tree_config(&self) -> TreeConfig {
447 TreeConfig::default()
448 .with_persistence_threshold(self.persistence_threshold)
449 .with_memory_block_buffer_target(self.memory_block_buffer_target)
450 .with_legacy_state_root(self.legacy_state_root_task_enabled)
451 .without_state_cache(self.state_cache_disabled)
452 .without_prewarming(self.prewarming_disabled)
453 .with_state_provider_metrics(self.state_provider_metrics)
454 .with_always_compare_trie_updates(self.state_root_task_compare_updates)
455 .with_cross_block_cache_size(self.cross_block_cache_size * 1024 * 1024)
456 .with_multiproof_chunk_size(self.multiproof_chunk_size)
457 .with_reserved_cpu_cores(self.reserved_cpu_cores)
458 .without_precompile_cache(self.precompile_cache_disabled)
459 .with_state_root_fallback(self.state_root_fallback)
460 .with_always_process_payload_attributes_on_canonical_head(
461 self.always_process_payload_attributes_on_canonical_head,
462 )
463 .with_unwind_canonical_header(self.allow_unwind_canonical_header)
464 .without_cache_metrics(self.cache_metrics_disabled)
465 .with_sparse_trie_prune_depth(self.sparse_trie_prune_depth)
466 .with_sparse_trie_max_storage_tries(self.sparse_trie_max_storage_tries)
467 .with_disable_sparse_trie_cache_pruning(self.disable_sparse_trie_cache_pruning)
468 .with_state_root_task_timeout(self.state_root_task_timeout.filter(|d| !d.is_zero()))
469 }
470}
471
472#[cfg(test)]
473mod tests {
474 use super::*;
475 use clap::Parser;
476
477 #[derive(Parser)]
479 struct CommandParser<T: Args> {
480 #[command(flatten)]
481 args: T,
482 }
483
484 #[test]
485 fn test_parse_engine_args() {
486 let default_args = EngineArgs::default();
487 let args = CommandParser::<EngineArgs>::parse_from(["reth"]).args;
488 assert_eq!(args, default_args);
489 }
490
491 #[test]
492 #[allow(deprecated)]
493 fn engine_args() {
494 let args = EngineArgs {
495 persistence_threshold: 100,
496 memory_block_buffer_target: 50,
497 legacy_state_root_task_enabled: true,
498 caching_and_prewarming_enabled: true,
499 state_cache_disabled: true,
500 prewarming_disabled: true,
501 parallel_sparse_trie_enabled: true,
502 parallel_sparse_trie_disabled: false,
503 state_provider_metrics: true,
504 cross_block_cache_size: 256,
505 state_root_task_compare_updates: true,
506 accept_execution_requests_hash: true,
507 multiproof_chunk_size: 512,
508 reserved_cpu_cores: 4,
509 precompile_cache_enabled: true,
510 precompile_cache_disabled: true,
511 state_root_fallback: true,
512 always_process_payload_attributes_on_canonical_head: true,
513 allow_unwind_canonical_header: true,
514 storage_worker_count: Some(16),
515 account_worker_count: Some(8),
516 prewarming_threads: Some(4),
517 cache_metrics_disabled: true,
518 sparse_trie_prune_depth: 10,
519 sparse_trie_max_storage_tries: 100,
520 disable_sparse_trie_cache_pruning: true,
521 state_root_task_timeout: Some(Duration::from_secs(2)),
522 };
523
524 let parsed_args = CommandParser::<EngineArgs>::parse_from([
525 "reth",
526 "--engine.persistence-threshold",
527 "100",
528 "--engine.memory-block-buffer-target",
529 "50",
530 "--engine.legacy-state-root",
531 "--engine.disable-state-cache",
532 "--engine.disable-prewarming",
533 "--engine.state-provider-metrics",
534 "--engine.cross-block-cache-size",
535 "256",
536 "--engine.state-root-task-compare-updates",
537 "--engine.accept-execution-requests-hash",
538 "--engine.multiproof-chunk-size",
539 "512",
540 "--engine.reserved-cpu-cores",
541 "4",
542 "--engine.disable-precompile-cache",
543 "--engine.state-root-fallback",
544 "--engine.always-process-payload-attributes-on-canonical-head",
545 "--engine.allow-unwind-canonical-header",
546 "--engine.storage-worker-count",
547 "16",
548 "--engine.account-worker-count",
549 "8",
550 "--engine.prewarming-threads",
551 "4",
552 "--engine.disable-cache-metrics",
553 "--engine.sparse-trie-prune-depth",
554 "10",
555 "--engine.sparse-trie-max-storage-tries",
556 "100",
557 "--engine.disable-sparse-trie-cache-pruning",
558 "--engine.state-root-task-timeout",
559 "2s",
560 ])
561 .args;
562
563 assert_eq!(parsed_args, args);
564 }
565}