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: u64,
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}
40
41impl DefaultEngineValues {
42 pub fn try_init(self) -> Result<(), Self> {
44 ENGINE_DEFAULTS.set(self)
45 }
46
47 pub fn get_global() -> &'static Self {
49 ENGINE_DEFAULTS.get_or_init(Self::default)
50 }
51
52 pub const fn with_persistence_threshold(mut self, v: u64) -> Self {
54 self.persistence_threshold = v;
55 self
56 }
57
58 pub const fn with_memory_block_buffer_target(mut self, v: u64) -> Self {
60 self.memory_block_buffer_target = v;
61 self
62 }
63
64 pub const fn with_legacy_state_root_task_enabled(mut self, v: bool) -> Self {
66 self.legacy_state_root_task_enabled = v;
67 self
68 }
69
70 pub const fn with_state_cache_disabled(mut self, v: bool) -> Self {
72 self.state_cache_disabled = v;
73 self
74 }
75
76 pub const fn with_prewarming_disabled(mut self, v: bool) -> Self {
78 self.prewarming_disabled = v;
79 self
80 }
81
82 pub const fn with_parallel_sparse_trie_disabled(mut self, v: bool) -> Self {
84 self.parallel_sparse_trie_disabled = v;
85 self
86 }
87
88 pub const fn with_state_provider_metrics(mut self, v: bool) -> Self {
90 self.state_provider_metrics = v;
91 self
92 }
93
94 pub const fn with_cross_block_cache_size(mut self, v: u64) -> Self {
96 self.cross_block_cache_size = v;
97 self
98 }
99
100 pub const fn with_state_root_task_compare_updates(mut self, v: bool) -> Self {
102 self.state_root_task_compare_updates = v;
103 self
104 }
105
106 pub const fn with_accept_execution_requests_hash(mut self, v: bool) -> Self {
108 self.accept_execution_requests_hash = v;
109 self
110 }
111
112 pub const fn with_multiproof_chunking_enabled(mut self, v: bool) -> Self {
114 self.multiproof_chunking_enabled = v;
115 self
116 }
117
118 pub const fn with_multiproof_chunk_size(mut self, v: usize) -> Self {
120 self.multiproof_chunk_size = v;
121 self
122 }
123
124 pub const fn with_reserved_cpu_cores(mut self, v: usize) -> Self {
126 self.reserved_cpu_cores = v;
127 self
128 }
129
130 pub const fn with_precompile_cache_disabled(mut self, v: bool) -> Self {
132 self.precompile_cache_disabled = v;
133 self
134 }
135
136 pub const fn with_state_root_fallback(mut self, v: bool) -> Self {
138 self.state_root_fallback = v;
139 self
140 }
141
142 pub const fn with_always_process_payload_attributes_on_canonical_head(
144 mut self,
145 v: bool,
146 ) -> Self {
147 self.always_process_payload_attributes_on_canonical_head = v;
148 self
149 }
150
151 pub const fn with_allow_unwind_canonical_header(mut self, v: bool) -> Self {
153 self.allow_unwind_canonical_header = v;
154 self
155 }
156
157 pub const fn with_storage_worker_count(mut self, v: Option<usize>) -> Self {
159 self.storage_worker_count = v;
160 self
161 }
162
163 pub const fn with_account_worker_count(mut self, v: Option<usize>) -> Self {
165 self.account_worker_count = v;
166 self
167 }
168}
169
170impl Default for DefaultEngineValues {
171 fn default() -> Self {
172 Self {
173 persistence_threshold: DEFAULT_PERSISTENCE_THRESHOLD,
174 memory_block_buffer_target: DEFAULT_MEMORY_BLOCK_BUFFER_TARGET,
175 legacy_state_root_task_enabled: false,
176 state_cache_disabled: false,
177 prewarming_disabled: false,
178 parallel_sparse_trie_disabled: false,
179 state_provider_metrics: false,
180 cross_block_cache_size: DEFAULT_CROSS_BLOCK_CACHE_SIZE_MB,
181 state_root_task_compare_updates: false,
182 accept_execution_requests_hash: false,
183 multiproof_chunking_enabled: true,
184 multiproof_chunk_size: DEFAULT_MULTIPROOF_TASK_CHUNK_SIZE,
185 reserved_cpu_cores: DEFAULT_RESERVED_CPU_CORES,
186 precompile_cache_disabled: false,
187 state_root_fallback: false,
188 always_process_payload_attributes_on_canonical_head: false,
189 allow_unwind_canonical_header: false,
190 storage_worker_count: None,
191 account_worker_count: None,
192 }
193 }
194}
195
196#[derive(Debug, Clone, Args, PartialEq, Eq)]
198#[command(next_help_heading = "Engine")]
199pub struct EngineArgs {
200 #[arg(long = "engine.persistence-threshold", default_value_t = DefaultEngineValues::get_global().persistence_threshold)]
207 pub persistence_threshold: u64,
208
209 #[arg(long = "engine.memory-block-buffer-target", default_value_t = DefaultEngineValues::get_global().memory_block_buffer_target)]
211 pub memory_block_buffer_target: u64,
212
213 #[arg(long = "engine.legacy-state-root", default_value_t = DefaultEngineValues::get_global().legacy_state_root_task_enabled)]
215 pub legacy_state_root_task_enabled: bool,
216
217 #[arg(long = "engine.caching-and-prewarming", default_value = "true", hide = true)]
220 #[deprecated]
221 pub caching_and_prewarming_enabled: bool,
222
223 #[arg(long = "engine.disable-state-cache", default_value_t = DefaultEngineValues::get_global().state_cache_disabled)]
225 pub state_cache_disabled: bool,
226
227 #[arg(long = "engine.disable-prewarming", alias = "engine.disable-caching-and-prewarming", default_value_t = DefaultEngineValues::get_global().prewarming_disabled)]
229 pub prewarming_disabled: bool,
230
231 #[deprecated]
234 #[arg(long = "engine.parallel-sparse-trie", default_value = "true", hide = true)]
235 pub parallel_sparse_trie_enabled: bool,
236
237 #[arg(long = "engine.disable-parallel-sparse-trie", default_value_t = DefaultEngineValues::get_global().parallel_sparse_trie_disabled)]
239 pub parallel_sparse_trie_disabled: bool,
240
241 #[arg(long = "engine.state-provider-metrics", default_value_t = DefaultEngineValues::get_global().state_provider_metrics)]
245 pub state_provider_metrics: bool,
246
247 #[arg(long = "engine.cross-block-cache-size", default_value_t = DefaultEngineValues::get_global().cross_block_cache_size)]
249 pub cross_block_cache_size: u64,
250
251 #[arg(long = "engine.state-root-task-compare-updates", default_value_t = DefaultEngineValues::get_global().state_root_task_compare_updates)]
254 pub state_root_task_compare_updates: bool,
255
256 #[arg(long = "engine.accept-execution-requests-hash", default_value_t = DefaultEngineValues::get_global().accept_execution_requests_hash)]
258 pub accept_execution_requests_hash: bool,
259
260 #[arg(long = "engine.multiproof-chunking", default_value_t = DefaultEngineValues::get_global().multiproof_chunking_enabled)]
262 pub multiproof_chunking_enabled: bool,
263
264 #[arg(long = "engine.multiproof-chunk-size", default_value_t = DefaultEngineValues::get_global().multiproof_chunk_size)]
266 pub multiproof_chunk_size: usize,
267
268 #[arg(long = "engine.reserved-cpu-cores", default_value_t = DefaultEngineValues::get_global().reserved_cpu_cores)]
270 pub reserved_cpu_cores: usize,
271
272 #[arg(long = "engine.precompile-cache", default_value = "true", hide = true)]
275 #[deprecated]
276 pub precompile_cache_enabled: bool,
277
278 #[arg(long = "engine.disable-precompile-cache", default_value_t = DefaultEngineValues::get_global().precompile_cache_disabled)]
280 pub precompile_cache_disabled: bool,
281
282 #[arg(long = "engine.state-root-fallback", default_value_t = DefaultEngineValues::get_global().state_root_fallback)]
284 pub state_root_fallback: bool,
285
286 #[arg(
292 long = "engine.always-process-payload-attributes-on-canonical-head",
293 default_value_t = DefaultEngineValues::get_global().always_process_payload_attributes_on_canonical_head
294 )]
295 pub always_process_payload_attributes_on_canonical_head: bool,
296
297 #[arg(long = "engine.allow-unwind-canonical-header", default_value_t = DefaultEngineValues::get_global().allow_unwind_canonical_header)]
300 pub allow_unwind_canonical_header: bool,
301
302 #[arg(long = "engine.storage-worker-count", default_value = Resettable::from(DefaultEngineValues::get_global().storage_worker_count.map(|v| v.to_string().into())))]
305 pub storage_worker_count: Option<usize>,
306
307 #[arg(long = "engine.account-worker-count", default_value = Resettable::from(DefaultEngineValues::get_global().account_worker_count.map(|v| v.to_string().into())))]
310 pub account_worker_count: Option<usize>,
311}
312
313#[allow(deprecated)]
314impl Default for EngineArgs {
315 fn default() -> Self {
316 let DefaultEngineValues {
317 persistence_threshold,
318 memory_block_buffer_target,
319 legacy_state_root_task_enabled,
320 state_cache_disabled,
321 prewarming_disabled,
322 parallel_sparse_trie_disabled,
323 state_provider_metrics,
324 cross_block_cache_size,
325 state_root_task_compare_updates,
326 accept_execution_requests_hash,
327 multiproof_chunking_enabled,
328 multiproof_chunk_size,
329 reserved_cpu_cores,
330 precompile_cache_disabled,
331 state_root_fallback,
332 always_process_payload_attributes_on_canonical_head,
333 allow_unwind_canonical_header,
334 storage_worker_count,
335 account_worker_count,
336 } = DefaultEngineValues::get_global().clone();
337 Self {
338 persistence_threshold,
339 memory_block_buffer_target,
340 legacy_state_root_task_enabled,
341 state_root_task_compare_updates,
342 caching_and_prewarming_enabled: true,
343 state_cache_disabled,
344 prewarming_disabled,
345 parallel_sparse_trie_enabled: true,
346 parallel_sparse_trie_disabled,
347 state_provider_metrics,
348 cross_block_cache_size,
349 accept_execution_requests_hash,
350 multiproof_chunking_enabled,
351 multiproof_chunk_size,
352 reserved_cpu_cores,
353 precompile_cache_enabled: true,
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 }
361 }
362}
363
364impl EngineArgs {
365 pub fn tree_config(&self) -> TreeConfig {
367 let mut config = TreeConfig::default()
368 .with_persistence_threshold(self.persistence_threshold)
369 .with_memory_block_buffer_target(self.memory_block_buffer_target)
370 .with_legacy_state_root(self.legacy_state_root_task_enabled)
371 .without_state_cache(self.state_cache_disabled)
372 .without_prewarming(self.prewarming_disabled)
373 .with_disable_parallel_sparse_trie(self.parallel_sparse_trie_disabled)
374 .with_state_provider_metrics(self.state_provider_metrics)
375 .with_always_compare_trie_updates(self.state_root_task_compare_updates)
376 .with_cross_block_cache_size(self.cross_block_cache_size * 1024 * 1024)
377 .with_multiproof_chunking_enabled(self.multiproof_chunking_enabled)
378 .with_multiproof_chunk_size(self.multiproof_chunk_size)
379 .with_reserved_cpu_cores(self.reserved_cpu_cores)
380 .without_precompile_cache(self.precompile_cache_disabled)
381 .with_state_root_fallback(self.state_root_fallback)
382 .with_always_process_payload_attributes_on_canonical_head(
383 self.always_process_payload_attributes_on_canonical_head,
384 )
385 .with_unwind_canonical_header(self.allow_unwind_canonical_header);
386
387 if let Some(count) = self.storage_worker_count {
388 config = config.with_storage_worker_count(count);
389 }
390
391 if let Some(count) = self.account_worker_count {
392 config = config.with_account_worker_count(count);
393 }
394
395 config
396 }
397}
398
399#[cfg(test)]
400mod tests {
401 use super::*;
402 use clap::Parser;
403
404 #[derive(Parser)]
406 struct CommandParser<T: Args> {
407 #[command(flatten)]
408 args: T,
409 }
410
411 #[test]
412 fn test_parse_engine_args() {
413 let default_args = EngineArgs::default();
414 let args = CommandParser::<EngineArgs>::parse_from(["reth"]).args;
415 assert_eq!(args, default_args);
416 }
417
418 #[test]
419 #[allow(deprecated)]
420 fn engine_args() {
421 let args = EngineArgs {
422 persistence_threshold: 100,
423 memory_block_buffer_target: 50,
424 legacy_state_root_task_enabled: true,
425 caching_and_prewarming_enabled: true,
426 state_cache_disabled: true,
427 prewarming_disabled: true,
428 parallel_sparse_trie_enabled: true,
429 parallel_sparse_trie_disabled: true,
430 state_provider_metrics: true,
431 cross_block_cache_size: 256,
432 state_root_task_compare_updates: true,
433 accept_execution_requests_hash: true,
434 multiproof_chunking_enabled: true,
435 multiproof_chunk_size: 512,
436 reserved_cpu_cores: 4,
437 precompile_cache_enabled: true,
438 precompile_cache_disabled: true,
439 state_root_fallback: true,
440 always_process_payload_attributes_on_canonical_head: true,
441 allow_unwind_canonical_header: true,
442 storage_worker_count: Some(16),
443 account_worker_count: Some(8),
444 };
445
446 let parsed_args = CommandParser::<EngineArgs>::parse_from([
447 "reth",
448 "--engine.persistence-threshold",
449 "100",
450 "--engine.memory-block-buffer-target",
451 "50",
452 "--engine.legacy-state-root",
453 "--engine.disable-state-cache",
454 "--engine.disable-prewarming",
455 "--engine.disable-parallel-sparse-trie",
456 "--engine.state-provider-metrics",
457 "--engine.cross-block-cache-size",
458 "256",
459 "--engine.state-root-task-compare-updates",
460 "--engine.accept-execution-requests-hash",
461 "--engine.multiproof-chunking",
462 "--engine.multiproof-chunk-size",
463 "512",
464 "--engine.reserved-cpu-cores",
465 "4",
466 "--engine.disable-precompile-cache",
467 "--engine.state-root-fallback",
468 "--engine.always-process-payload-attributes-on-canonical-head",
469 "--engine.allow-unwind-canonical-header",
470 "--engine.storage-worker-count",
471 "16",
472 "--engine.account-worker-count",
473 "8",
474 ])
475 .args;
476
477 assert_eq!(parsed_args, args);
478 }
479}