1use clap::{builder::Resettable, Args};
4use reth_engine_primitives::{TreeConfig, DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE};
5use std::sync::OnceLock;
6
7use crate::node_config::{
8 DEFAULT_CROSS_BLOCK_CACHE_SIZE_MB, DEFAULT_MEMORY_BLOCK_BUFFER_TARGET,
9 DEFAULT_PERSISTENCE_THRESHOLD, DEFAULT_RESERVED_CPU_CORES,
10};
11
12static ENGINE_DEFAULTS: OnceLock<DefaultEngineValues> = OnceLock::new();
14
15#[derive(Debug, Clone)]
19pub struct DefaultEngineValues {
20 persistence_threshold: u64,
21 memory_block_buffer_target: u64,
22 legacy_state_root_task_enabled: bool,
23 state_cache_disabled: bool,
24 prewarming_disabled: bool,
25 parallel_sparse_trie_disabled: bool,
26 state_provider_metrics: bool,
27 cross_block_cache_size: usize,
28 state_root_task_compare_updates: bool,
29 accept_execution_requests_hash: bool,
30 multiproof_chunking_enabled: bool,
31 multiproof_chunk_size: usize,
32 reserved_cpu_cores: usize,
33 precompile_cache_disabled: bool,
34 state_root_fallback: bool,
35 always_process_payload_attributes_on_canonical_head: bool,
36 allow_unwind_canonical_header: bool,
37 storage_worker_count: Option<usize>,
38 account_worker_count: Option<usize>,
39 enable_proof_v2: bool,
40 cache_metrics_disabled: bool,
41}
42
43impl DefaultEngineValues {
44 pub fn try_init(self) -> Result<(), Self> {
46 ENGINE_DEFAULTS.set(self)
47 }
48
49 pub fn get_global() -> &'static Self {
51 ENGINE_DEFAULTS.get_or_init(Self::default)
52 }
53
54 pub const fn with_persistence_threshold(mut self, v: u64) -> Self {
56 self.persistence_threshold = v;
57 self
58 }
59
60 pub const fn with_memory_block_buffer_target(mut self, v: u64) -> Self {
62 self.memory_block_buffer_target = v;
63 self
64 }
65
66 pub const fn with_legacy_state_root_task_enabled(mut self, v: bool) -> Self {
68 self.legacy_state_root_task_enabled = v;
69 self
70 }
71
72 pub const fn with_state_cache_disabled(mut self, v: bool) -> Self {
74 self.state_cache_disabled = v;
75 self
76 }
77
78 pub const fn with_prewarming_disabled(mut self, v: bool) -> Self {
80 self.prewarming_disabled = v;
81 self
82 }
83
84 pub const fn with_parallel_sparse_trie_disabled(mut self, v: bool) -> Self {
86 self.parallel_sparse_trie_disabled = v;
87 self
88 }
89
90 pub const fn with_state_provider_metrics(mut self, v: bool) -> Self {
92 self.state_provider_metrics = v;
93 self
94 }
95
96 pub const fn with_cross_block_cache_size(mut self, v: usize) -> Self {
98 self.cross_block_cache_size = v;
99 self
100 }
101
102 pub const fn with_state_root_task_compare_updates(mut self, v: bool) -> Self {
104 self.state_root_task_compare_updates = v;
105 self
106 }
107
108 pub const fn with_accept_execution_requests_hash(mut self, v: bool) -> Self {
110 self.accept_execution_requests_hash = v;
111 self
112 }
113
114 pub const fn with_multiproof_chunking_enabled(mut self, v: bool) -> Self {
116 self.multiproof_chunking_enabled = v;
117 self
118 }
119
120 pub const fn with_multiproof_chunk_size(mut self, v: usize) -> Self {
122 self.multiproof_chunk_size = v;
123 self
124 }
125
126 pub const fn with_reserved_cpu_cores(mut self, v: usize) -> Self {
128 self.reserved_cpu_cores = v;
129 self
130 }
131
132 pub const fn with_precompile_cache_disabled(mut self, v: bool) -> Self {
134 self.precompile_cache_disabled = v;
135 self
136 }
137
138 pub const fn with_state_root_fallback(mut self, v: bool) -> Self {
140 self.state_root_fallback = v;
141 self
142 }
143
144 pub const fn with_always_process_payload_attributes_on_canonical_head(
146 mut self,
147 v: bool,
148 ) -> Self {
149 self.always_process_payload_attributes_on_canonical_head = v;
150 self
151 }
152
153 pub const fn with_allow_unwind_canonical_header(mut self, v: bool) -> Self {
155 self.allow_unwind_canonical_header = v;
156 self
157 }
158
159 pub const fn with_storage_worker_count(mut self, v: Option<usize>) -> Self {
161 self.storage_worker_count = v;
162 self
163 }
164
165 pub const fn with_account_worker_count(mut self, v: Option<usize>) -> Self {
167 self.account_worker_count = v;
168 self
169 }
170
171 pub const fn with_enable_proof_v2(mut self, v: bool) -> Self {
173 self.enable_proof_v2 = v;
174 self
175 }
176
177 pub const fn with_cache_metrics_disabled(mut self, v: bool) -> Self {
179 self.cache_metrics_disabled = v;
180 self
181 }
182}
183
184impl Default for DefaultEngineValues {
185 fn default() -> Self {
186 Self {
187 persistence_threshold: DEFAULT_PERSISTENCE_THRESHOLD,
188 memory_block_buffer_target: DEFAULT_MEMORY_BLOCK_BUFFER_TARGET,
189 legacy_state_root_task_enabled: false,
190 state_cache_disabled: false,
191 prewarming_disabled: false,
192 parallel_sparse_trie_disabled: false,
193 state_provider_metrics: false,
194 cross_block_cache_size: DEFAULT_CROSS_BLOCK_CACHE_SIZE_MB,
195 state_root_task_compare_updates: false,
196 accept_execution_requests_hash: false,
197 multiproof_chunking_enabled: true,
198 multiproof_chunk_size: DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE,
199 reserved_cpu_cores: DEFAULT_RESERVED_CPU_CORES,
200 precompile_cache_disabled: false,
201 state_root_fallback: false,
202 always_process_payload_attributes_on_canonical_head: false,
203 allow_unwind_canonical_header: false,
204 storage_worker_count: None,
205 account_worker_count: None,
206 enable_proof_v2: false,
207 cache_metrics_disabled: false,
208 }
209 }
210}
211
212#[derive(Debug, Clone, Args, PartialEq, Eq)]
214#[command(next_help_heading = "Engine")]
215pub struct EngineArgs {
216 #[arg(long = "engine.persistence-threshold", default_value_t = DefaultEngineValues::get_global().persistence_threshold)]
223 pub persistence_threshold: u64,
224
225 #[arg(long = "engine.memory-block-buffer-target", default_value_t = DefaultEngineValues::get_global().memory_block_buffer_target)]
227 pub memory_block_buffer_target: u64,
228
229 #[arg(long = "engine.legacy-state-root", default_value_t = DefaultEngineValues::get_global().legacy_state_root_task_enabled)]
231 pub legacy_state_root_task_enabled: bool,
232
233 #[arg(long = "engine.caching-and-prewarming", default_value = "true", hide = true)]
236 #[deprecated]
237 pub caching_and_prewarming_enabled: bool,
238
239 #[arg(long = "engine.disable-state-cache", default_value_t = DefaultEngineValues::get_global().state_cache_disabled)]
241 pub state_cache_disabled: bool,
242
243 #[arg(long = "engine.disable-prewarming", alias = "engine.disable-caching-and-prewarming", default_value_t = DefaultEngineValues::get_global().prewarming_disabled)]
245 pub prewarming_disabled: bool,
246
247 #[deprecated]
250 #[arg(long = "engine.parallel-sparse-trie", default_value = "true", hide = true)]
251 pub parallel_sparse_trie_enabled: bool,
252
253 #[arg(long = "engine.disable-parallel-sparse-trie", default_value_t = DefaultEngineValues::get_global().parallel_sparse_trie_disabled)]
255 pub parallel_sparse_trie_disabled: bool,
256
257 #[arg(long = "engine.state-provider-metrics", default_value_t = DefaultEngineValues::get_global().state_provider_metrics)]
261 pub state_provider_metrics: bool,
262
263 #[arg(long = "engine.cross-block-cache-size", default_value_t = DefaultEngineValues::get_global().cross_block_cache_size)]
265 pub cross_block_cache_size: usize,
266
267 #[arg(long = "engine.state-root-task-compare-updates", default_value_t = DefaultEngineValues::get_global().state_root_task_compare_updates)]
270 pub state_root_task_compare_updates: bool,
271
272 #[arg(long = "engine.accept-execution-requests-hash", default_value_t = DefaultEngineValues::get_global().accept_execution_requests_hash)]
274 pub accept_execution_requests_hash: bool,
275
276 #[arg(long = "engine.multiproof-chunking", default_value_t = DefaultEngineValues::get_global().multiproof_chunking_enabled)]
278 pub multiproof_chunking_enabled: bool,
279
280 #[arg(long = "engine.multiproof-chunk-size", default_value_t = DefaultEngineValues::get_global().multiproof_chunk_size)]
282 pub multiproof_chunk_size: usize,
283
284 #[arg(long = "engine.reserved-cpu-cores", default_value_t = DefaultEngineValues::get_global().reserved_cpu_cores)]
286 pub reserved_cpu_cores: usize,
287
288 #[arg(long = "engine.precompile-cache", default_value = "true", hide = true)]
291 #[deprecated]
292 pub precompile_cache_enabled: bool,
293
294 #[arg(long = "engine.disable-precompile-cache", default_value_t = DefaultEngineValues::get_global().precompile_cache_disabled)]
296 pub precompile_cache_disabled: bool,
297
298 #[arg(long = "engine.state-root-fallback", default_value_t = DefaultEngineValues::get_global().state_root_fallback)]
300 pub state_root_fallback: bool,
301
302 #[arg(
308 long = "engine.always-process-payload-attributes-on-canonical-head",
309 default_value_t = DefaultEngineValues::get_global().always_process_payload_attributes_on_canonical_head
310 )]
311 pub always_process_payload_attributes_on_canonical_head: bool,
312
313 #[arg(long = "engine.allow-unwind-canonical-header", default_value_t = DefaultEngineValues::get_global().allow_unwind_canonical_header)]
316 pub allow_unwind_canonical_header: bool,
317
318 #[arg(long = "engine.storage-worker-count", default_value = Resettable::from(DefaultEngineValues::get_global().storage_worker_count.map(|v| v.to_string().into())))]
321 pub storage_worker_count: Option<usize>,
322
323 #[arg(long = "engine.account-worker-count", default_value = Resettable::from(DefaultEngineValues::get_global().account_worker_count.map(|v| v.to_string().into())))]
326 pub account_worker_count: Option<usize>,
327
328 #[arg(long = "engine.enable-proof-v2", default_value_t = DefaultEngineValues::get_global().enable_proof_v2)]
330 pub enable_proof_v2: bool,
331
332 #[arg(long = "engine.disable-cache-metrics", default_value_t = DefaultEngineValues::get_global().cache_metrics_disabled)]
334 pub cache_metrics_disabled: bool,
335}
336
337#[allow(deprecated)]
338impl Default for EngineArgs {
339 fn default() -> Self {
340 let DefaultEngineValues {
341 persistence_threshold,
342 memory_block_buffer_target,
343 legacy_state_root_task_enabled,
344 state_cache_disabled,
345 prewarming_disabled,
346 parallel_sparse_trie_disabled,
347 state_provider_metrics,
348 cross_block_cache_size,
349 state_root_task_compare_updates,
350 accept_execution_requests_hash,
351 multiproof_chunking_enabled,
352 multiproof_chunk_size,
353 reserved_cpu_cores,
354 precompile_cache_disabled,
355 state_root_fallback,
356 always_process_payload_attributes_on_canonical_head,
357 allow_unwind_canonical_header,
358 storage_worker_count,
359 account_worker_count,
360 enable_proof_v2,
361 cache_metrics_disabled,
362 } = DefaultEngineValues::get_global().clone();
363 Self {
364 persistence_threshold,
365 memory_block_buffer_target,
366 legacy_state_root_task_enabled,
367 state_root_task_compare_updates,
368 caching_and_prewarming_enabled: true,
369 state_cache_disabled,
370 prewarming_disabled,
371 parallel_sparse_trie_enabled: true,
372 parallel_sparse_trie_disabled,
373 state_provider_metrics,
374 cross_block_cache_size,
375 accept_execution_requests_hash,
376 multiproof_chunking_enabled,
377 multiproof_chunk_size,
378 reserved_cpu_cores,
379 precompile_cache_enabled: true,
380 precompile_cache_disabled,
381 state_root_fallback,
382 always_process_payload_attributes_on_canonical_head,
383 allow_unwind_canonical_header,
384 storage_worker_count,
385 account_worker_count,
386 enable_proof_v2,
387 cache_metrics_disabled,
388 }
389 }
390}
391
392impl EngineArgs {
393 pub fn tree_config(&self) -> TreeConfig {
395 let mut config = TreeConfig::default()
396 .with_persistence_threshold(self.persistence_threshold)
397 .with_memory_block_buffer_target(self.memory_block_buffer_target)
398 .with_legacy_state_root(self.legacy_state_root_task_enabled)
399 .without_state_cache(self.state_cache_disabled)
400 .without_prewarming(self.prewarming_disabled)
401 .with_disable_parallel_sparse_trie(self.parallel_sparse_trie_disabled)
402 .with_state_provider_metrics(self.state_provider_metrics)
403 .with_always_compare_trie_updates(self.state_root_task_compare_updates)
404 .with_cross_block_cache_size(self.cross_block_cache_size * 1024 * 1024)
405 .with_multiproof_chunking_enabled(self.multiproof_chunking_enabled)
406 .with_multiproof_chunk_size(self.multiproof_chunk_size)
407 .with_reserved_cpu_cores(self.reserved_cpu_cores)
408 .without_precompile_cache(self.precompile_cache_disabled)
409 .with_state_root_fallback(self.state_root_fallback)
410 .with_always_process_payload_attributes_on_canonical_head(
411 self.always_process_payload_attributes_on_canonical_head,
412 )
413 .with_unwind_canonical_header(self.allow_unwind_canonical_header);
414
415 if let Some(count) = self.storage_worker_count {
416 config = config.with_storage_worker_count(count);
417 }
418
419 if let Some(count) = self.account_worker_count {
420 config = config.with_account_worker_count(count);
421 }
422
423 config = config.with_enable_proof_v2(self.enable_proof_v2);
424 config = config.without_cache_metrics(self.cache_metrics_disabled);
425
426 config
427 }
428}
429
430#[cfg(test)]
431mod tests {
432 use super::*;
433 use clap::Parser;
434
435 #[derive(Parser)]
437 struct CommandParser<T: Args> {
438 #[command(flatten)]
439 args: T,
440 }
441
442 #[test]
443 fn test_parse_engine_args() {
444 let default_args = EngineArgs::default();
445 let args = CommandParser::<EngineArgs>::parse_from(["reth"]).args;
446 assert_eq!(args, default_args);
447 }
448
449 #[test]
450 #[allow(deprecated)]
451 fn engine_args() {
452 let args = EngineArgs {
453 persistence_threshold: 100,
454 memory_block_buffer_target: 50,
455 legacy_state_root_task_enabled: true,
456 caching_and_prewarming_enabled: true,
457 state_cache_disabled: true,
458 prewarming_disabled: true,
459 parallel_sparse_trie_enabled: true,
460 parallel_sparse_trie_disabled: true,
461 state_provider_metrics: true,
462 cross_block_cache_size: 256,
463 state_root_task_compare_updates: true,
464 accept_execution_requests_hash: true,
465 multiproof_chunking_enabled: true,
466 multiproof_chunk_size: 512,
467 reserved_cpu_cores: 4,
468 precompile_cache_enabled: true,
469 precompile_cache_disabled: true,
470 state_root_fallback: true,
471 always_process_payload_attributes_on_canonical_head: true,
472 allow_unwind_canonical_header: true,
473 storage_worker_count: Some(16),
474 account_worker_count: Some(8),
475 enable_proof_v2: false,
476 cache_metrics_disabled: true,
477 };
478
479 let parsed_args = CommandParser::<EngineArgs>::parse_from([
480 "reth",
481 "--engine.persistence-threshold",
482 "100",
483 "--engine.memory-block-buffer-target",
484 "50",
485 "--engine.legacy-state-root",
486 "--engine.disable-state-cache",
487 "--engine.disable-prewarming",
488 "--engine.disable-parallel-sparse-trie",
489 "--engine.state-provider-metrics",
490 "--engine.cross-block-cache-size",
491 "256",
492 "--engine.state-root-task-compare-updates",
493 "--engine.accept-execution-requests-hash",
494 "--engine.multiproof-chunking",
495 "--engine.multiproof-chunk-size",
496 "512",
497 "--engine.reserved-cpu-cores",
498 "4",
499 "--engine.disable-precompile-cache",
500 "--engine.state-root-fallback",
501 "--engine.always-process-payload-attributes-on-canonical-head",
502 "--engine.allow-unwind-canonical-header",
503 "--engine.storage-worker-count",
504 "16",
505 "--engine.account-worker-count",
506 "8",
507 "--engine.disable-cache-metrics",
508 ])
509 .args;
510
511 assert_eq!(parsed_args, args);
512 }
513}