diff --git a/crates/cli/util/src/parsers.rs b/crates/cli/util/src/parsers.rs index ddb120452e7..dae9f9bc6ef 100644 --- a/crates/cli/util/src/parsers.rs +++ b/crates/cli/util/src/parsers.rs @@ -31,6 +31,16 @@ pub fn parse_duration_from_secs_or_ms( } } +/// Helper to format a [Duration] to the format that can be parsed by +/// [`parse_duration_from_secs_or_ms`]. +pub fn format_duration_as_secs_or_ms(duration: Duration) -> String { + if duration.as_millis().is_multiple_of(1000) { + format!("{}", duration.as_secs()) + } else { + format!("{}ms", duration.as_millis()) + } +} + /// Parse [`BlockHashOrNumber`] pub fn hash_or_num_value_parser(value: &str) -> eyre::Result { match B256::from_str(value) { diff --git a/crates/node/core/src/args/mod.rs b/crates/node/core/src/args/mod.rs index fa21e438fa3..8112d733fc7 100644 --- a/crates/node/core/src/args/mod.rs +++ b/crates/node/core/src/args/mod.rs @@ -34,7 +34,7 @@ pub use metric::MetricArgs; /// `PayloadBuilderArgs` struct for configuring the payload builder mod payload_builder; -pub use payload_builder::PayloadBuilderArgs; +pub use payload_builder::{DefaultPayloadBuilderValues, PayloadBuilderArgs}; /// Stage related arguments mod stage; diff --git a/crates/node/core/src/args/payload_builder.rs b/crates/node/core/src/args/payload_builder.rs index 181648cc7ab..d9ce66499f0 100644 --- a/crates/node/core/src/args/payload_builder.rs +++ b/crates/node/core/src/args/payload_builder.rs @@ -1,19 +1,90 @@ use crate::{cli::config::PayloadBuilderConfig, version::default_extra_data}; use alloy_consensus::constants::MAXIMUM_EXTRA_DATA_SIZE; -use alloy_eips::merge::SLOT_DURATION; use clap::{ builder::{RangedU64ValueParser, TypedValueParser}, Arg, Args, Command, }; -use reth_cli_util::{parse_duration_from_secs, parse_duration_from_secs_or_ms}; -use std::{borrow::Cow, ffi::OsStr, time::Duration}; +use reth_cli_util::{ + parse_duration_from_secs, parse_duration_from_secs_or_ms, + parsers::format_duration_as_secs_or_ms, +}; +use std::{borrow::Cow, ffi::OsStr, sync::OnceLock, time::Duration}; + +/// Global static payload builder defaults +static PAYLOAD_BUILDER_DEFAULTS: OnceLock = OnceLock::new(); + +/// Default values for payload builder that can be customized +/// +/// Global defaults can be set via [`DefaultPayloadBuilderValues::try_init`]. +#[derive(Debug, Clone)] +pub struct DefaultPayloadBuilderValues { + /// Default extra data for blocks + extra_data: String, + /// Default interval between payload builds in seconds + interval: String, + /// Default deadline for payload builds in seconds + deadline: String, + /// Default maximum number of concurrent payload building tasks + max_payload_tasks: usize, +} + +impl DefaultPayloadBuilderValues { + /// Initialize the global payload builder defaults with this configuration + pub fn try_init(self) -> Result<(), Self> { + PAYLOAD_BUILDER_DEFAULTS.set(self) + } + + /// Get a reference to the global payload builder defaults + pub fn get_global() -> &'static Self { + PAYLOAD_BUILDER_DEFAULTS.get_or_init(Self::default) + } + + /// Set the default extra data + pub fn with_extra_data(mut self, v: impl Into) -> Self { + self.extra_data = v.into(); + self + } + + /// Set the default interval in seconds + pub fn with_interval(mut self, v: Duration) -> Self { + self.interval = format_duration_as_secs_or_ms(v); + self + } + + /// Set the default deadline in seconds + pub fn with_deadline(mut self, v: u64) -> Self { + self.deadline = format!("{}", v); + self + } + + /// Set the default maximum payload tasks + pub const fn with_max_payload_tasks(mut self, v: usize) -> Self { + self.max_payload_tasks = v; + self + } +} + +impl Default for DefaultPayloadBuilderValues { + fn default() -> Self { + Self { + extra_data: default_extra_data(), + interval: "1".to_string(), + deadline: "12".to_string(), + max_payload_tasks: 3, + } + } +} /// Parameters for configuring the Payload Builder #[derive(Debug, Clone, Args, PartialEq, Eq)] #[command(next_help_heading = "Builder")] pub struct PayloadBuilderArgs { /// Block extra data set by the payload builder. - #[arg(long = "builder.extradata", value_parser = ExtraDataValueParser::default(), default_value_t = default_extra_data())] + #[arg( + long = "builder.extradata", + value_parser = ExtraDataValueParser::default(), + default_value_t = DefaultPayloadBuilderValues::get_global().extra_data.clone() + )] pub extra_data: String, /// Target gas limit for built blocks. @@ -25,15 +96,29 @@ pub struct PayloadBuilderArgs { /// Interval is specified in seconds or in milliseconds if the value ends with `ms`: /// * `50ms` -> 50 milliseconds /// * `1` -> 1 second - #[arg(long = "builder.interval", value_parser = parse_duration_from_secs_or_ms, default_value = "1", value_name = "DURATION")] + #[arg( + long = "builder.interval", + value_parser = parse_duration_from_secs_or_ms, + default_value = DefaultPayloadBuilderValues::get_global().interval.as_str(), + value_name = "DURATION" + )] pub interval: Duration, /// The deadline for when the payload builder job should resolve. - #[arg(long = "builder.deadline", value_parser = parse_duration_from_secs, default_value = "12", value_name = "SECONDS")] + #[arg( + long = "builder.deadline", + value_parser = parse_duration_from_secs, + default_value = DefaultPayloadBuilderValues::get_global().deadline.as_str(), + value_name = "SECONDS" + )] pub deadline: Duration, /// Maximum number of tasks to spawn for building a payload. - #[arg(long = "builder.max-tasks", default_value = "3", value_parser = RangedU64ValueParser::::new().range(1..))] + #[arg( + long = "builder.max-tasks", + value_parser = RangedU64ValueParser::::new().range(1..), + default_value_t = DefaultPayloadBuilderValues::get_global().max_payload_tasks + )] pub max_payload_tasks: usize, /// Maximum number of blobs to include per block. @@ -43,12 +128,13 @@ pub struct PayloadBuilderArgs { impl Default for PayloadBuilderArgs { fn default() -> Self { + let defaults = DefaultPayloadBuilderValues::get_global(); Self { - extra_data: default_extra_data(), - interval: Duration::from_secs(1), + extra_data: defaults.extra_data.clone(), + interval: parse_duration_from_secs_or_ms(defaults.interval.as_str()).unwrap(), gas_limit: None, - deadline: SLOT_DURATION, - max_payload_tasks: 3, + deadline: Duration::from_secs(defaults.deadline.parse().unwrap()), + max_payload_tasks: defaults.max_payload_tasks, max_blobs_per_block: None, } }