Skip to content

Commit

Permalink
feat: add CLI flag support to builder config
Browse files Browse the repository at this point in the history
Signed-off-by: 7suyash7 <[email protected]>
  • Loading branch information
7suyash7 committed Dec 22, 2024
1 parent f131f2f commit 58f386b
Show file tree
Hide file tree
Showing 3 changed files with 288 additions and 6 deletions.
95 changes: 94 additions & 1 deletion crates/rbuilder/src/live_builder/base_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ use std::{
use tokio::sync::mpsc;
use tracing::{error, warn};

use super::SlotSource;
use super::{
cli::{BaseCliArgs, L1CliArgs},
config::L1Config,
SlotSource,
};

/// Prefix for env variables in config
const ENV_PREFIX: &str = "env:";
Expand Down Expand Up @@ -469,6 +473,95 @@ impl Default for BaseConfig {
}
}

pub trait MergeFromCli<T> {
fn merge(&mut self, cli: &T);
}

impl MergeFromCli<BaseCliArgs> for BaseConfig {
fn merge(&mut self, cli: &BaseCliArgs) {
if let Some(log_json) = cli.log_json {
self.log_json = log_json;
}
if let Some(log_level) = &cli.log_level {
self.log_level = EnvOrValue(log_level.clone(), std::marker::PhantomData);
}
if let Some(port) = cli.full_telemetry_server_port {
self.full_telemetry_server_port = port;
}
if let Some(ip) = &cli.full_telemetry_server_ip {
self.full_telemetry_server_ip = Some(ip.clone());
}
if let Some(port) = cli.redacted_telemetry_server_port {
self.redacted_telemetry_server_port = port;
}
if let Some(ip) = &cli.redacted_telemetry_server_ip {
self.redacted_telemetry_server_ip = Some(ip.clone());
}
if let Some(log_color) = cli.log_color {
self.log_color = log_color;
}
if let Some(enable_dynamic) = cli.log_enable_dynamic {
self.log_enable_dynamic = enable_dynamic;
}
if let Some(path) = &cli.error_storage_path {
self.error_storage_path = Some(path.clone());
}
if let Some(db) = &cli.flashbots_db {
self.flashbots_db = Some(EnvOrValue(db.clone(), std::marker::PhantomData));
}
if let Some(port) = cli.jsonrpc_server_port {
self.jsonrpc_server_port = port;
}
if let Some(ip) = &cli.jsonrpc_server_ip {
self.jsonrpc_server_ip = Some(ip.clone());
}
if let Some(ignore) = cli.ignore_cancellable_orders {
self.ignore_cancellable_orders = ignore;
}
if let Some(ignore) = cli.ignore_blobs {
self.ignore_blobs = ignore;
}
if let Some(chain) = &cli.chain {
self.chain = chain.clone();
}
if let Some(dir) = &cli.reth_datadir {
self.reth_datadir = Some(dir.clone());
}
}
}

impl MergeFromCli<L1CliArgs> for L1Config {
fn merge(&mut self, cli: &L1CliArgs) {
if let Some(dry_run) = cli.dry_run {
self.dry_run = dry_run;
}
if let Some(urls) = &cli.dry_run_validation_url {
self.dry_run_validation_url = urls.clone();
}
if let Some(enabled) = cli.optimistic_enabled {
self.optimistic_enabled = enabled;
}
if let Some(val) = &cli.optimistic_max_bid_value_eth {
self.optimistic_max_bid_value_eth = val.clone();
}
if let Some(validate) = cli.optimistic_prevalidate_optimistic_blocks {
self.optimistic_prevalidate_optimistic_blocks = validate;
}
if let Some(seals) = cli.max_concurrent_seals {
self.max_concurrent_seals = seals;
}
if let Some(urls) = &cli.cl_node_url {
self.cl_node_url = urls
.iter()
.map(|u| EnvOrValue(u.clone(), std::marker::PhantomData))
.collect();
}
if let Some(version) = &cli.genesis_fork_version {
self.genesis_fork_version = Some(version.clone());
}
}
}

/// Open reth db and DB should be opened once per process but it can be cloned and moved to different threads.
pub fn create_provider_factory(
reth_datadir: Option<&Path>,
Expand Down
102 changes: 98 additions & 4 deletions crates/rbuilder/src/live_builder/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ use crate::{
utils::build_info::Version,
};

use super::{base_config::BaseConfig, LiveBuilder};
use super::{
base_config::{BaseConfig, MergeFromCli},
LiveBuilder,
};

#[derive(Parser, Debug)]
enum Cli {
Expand All @@ -40,6 +43,93 @@ enum Cli {
struct RunCmd {
#[clap(env = "RBUILDER_CONFIG", help = "Config file path")]
config: PathBuf,

#[command(flatten)]
base: BaseCliArgs,

#[command(flatten)]
l1: L1CliArgs,
}

#[derive(Parser, Debug, Default)]
pub struct BaseCliArgs {
#[arg(long, help = "Enable JSON logging format")]
pub log_json: Option<bool>,

#[arg(long, help = "Log level configuration string")]
pub log_level: Option<String>,

#[arg(long, help = "Port for full telemetry server")]
pub full_telemetry_server_port: Option<u16>,

#[arg(long, help = "IP address for full telemetry server")]
pub full_telemetry_server_ip: Option<String>,

#[arg(long, help = "Port for redacted telemetry server")]
pub redacted_telemetry_server_port: Option<u16>,

#[arg(long, help = "IP address for redacted telemetry server")]
pub redacted_telemetry_server_ip: Option<String>,

#[arg(long, help = "Enable colored log output")]
pub log_color: Option<bool>,

#[arg(long, help = "Enable dynamic logging to file")]
pub log_enable_dynamic: Option<bool>,

#[arg(long, help = "Path to store error logs")]
pub error_storage_path: Option<PathBuf>,

#[arg(long, help = "Coinbase signer secret key")]
pub coinbase_secret_key: Option<String>,

#[arg(long, help = "Flashbots database URL")]
pub flashbots_db: Option<String>,

#[arg(long, help = "JSON-RPC server port")]
pub jsonrpc_server_port: Option<u16>,

#[arg(long, help = "JSON-RPC server IP address")]
pub jsonrpc_server_ip: Option<String>,

#[arg(long, help = "Ignore cancellable orders")]
pub ignore_cancellable_orders: Option<bool>,

#[arg(long, help = "Ignore blob transactions")]
pub ignore_blobs: Option<bool>,

#[arg(long, help = "Chain identifier (mainnet/goerli/etc)")]
pub chain: Option<String>,

#[arg(long, help = "Path to reth data directory")]
pub reth_datadir: Option<PathBuf>,
}

#[derive(Parser, Debug, Default)]
pub struct L1CliArgs {
#[arg(long, help = "Enable dry run mode")]
pub dry_run: Option<bool>,

#[arg(long, help = "URLs for dry run validation")]
pub dry_run_validation_url: Option<Vec<String>>,

#[arg(long, help = "Enable optimistic submission mode")]
pub optimistic_enabled: Option<bool>,

#[arg(long, help = "Maximum bid value (ETH) for optimistic mode")]
pub optimistic_max_bid_value_eth: Option<String>,

#[arg(long, help = "Pre-validate optimistic blocks")]
pub optimistic_prevalidate_optimistic_blocks: Option<bool>,

#[arg(long, help = "Maximum concurrent block sealing operations")]
pub max_concurrent_seals: Option<u64>,

#[arg(long, help = "Consensus layer node URLs")]
pub cl_node_url: Option<Vec<String>>,

#[arg(long, help = "Genesis fork version override")]
pub genesis_fork_version: Option<String>,
}

/// Basic stuff needed to call cli::run
Expand Down Expand Up @@ -84,13 +174,15 @@ pub trait LiveBuilderConfig: Debug + DeserializeOwned + Sync {
/// on_run func that will be called on command Cli::Run just before running
pub async fn run<ConfigType>(print_version_info: fn(), on_run: Option<fn()>) -> eyre::Result<()>
where
ConfigType: LiveBuilderConfig,
ConfigType: LiveBuilderConfig + MergeFromCli<BaseCliArgs> + MergeFromCli<L1CliArgs>,
{
let cli = Cli::parse();
let cli = match cli {
Cli::Run(cli) => cli,
Cli::Config(cli) => {
let config: ConfigType = load_config_toml_and_env(cli.config)?;
let mut config: ConfigType = load_config_toml_and_env(cli.config)?;
config.merge(&cli.base);
config.merge(&cli.l1);
println!("{:#?}", config);
return Ok(());
}
Expand All @@ -108,7 +200,9 @@ where
}
};

let config: ConfigType = load_config_toml_and_env(cli.config)?;
let mut config: ConfigType = load_config_toml_and_env(cli.config)?;
config.merge(&cli.base);
config.merge(&cli.l1);
config.base_config().setup_tracing_subscriber()?;

let cancel = CancellationToken::new();
Expand Down
97 changes: 96 additions & 1 deletion crates/rbuilder/src/live_builder/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//!
//!
use super::{
base_config::BaseConfig,
base_config::{BaseConfig, MergeFromCli},
block_output::{
bid_observer::{BidObserver, NullBidObserver},
bid_value_source::null_bid_value_source::NullBidValueSource,
Expand All @@ -13,6 +13,7 @@ use super::{
block_sealing_bidder_factory::BlockSealingBidderFactory,
relay_submit::{RelaySubmitSinkFactory, SubmissionConfig},
},
cli::{BaseCliArgs, L1CliArgs},
};
use crate::{
beacon_api_client::Client,
Expand Down Expand Up @@ -464,6 +465,18 @@ impl Default for Config {
}
}

impl MergeFromCli<BaseCliArgs> for Config {
fn merge(&mut self, cli: &BaseCliArgs) {
self.base_config.merge(cli);
}
}

impl MergeFromCli<L1CliArgs> for Config {
fn merge(&mut self, cli: &L1CliArgs) {
self.l1_config.merge(cli);
}
}

/// Open reth db and DB should be opened once per process but it can be cloned and moved to different threads.
pub fn create_provider_factory(
reth_datadir: Option<&Path>,
Expand Down Expand Up @@ -715,4 +728,86 @@ mod test {
fixed_bytes!("00000001aaf2630a2874a74199f4b5d11a7d6377f363a236271bff4bf8eb4ab3")
);
}

#[test]
fn test_cli_overrides_config() {
let config_str = r#"
log_json = false
chain = "mainnet"
dry_run = false
"#;
let mut config: Config = toml::from_str(config_str).unwrap();

let cli_args = BaseCliArgs {
log_json: Some(true),
chain: Some("goerli".to_string()),
..Default::default()
};

let l1_args = L1CliArgs {
dry_run: Some(true),
..Default::default()
};

config.merge(&cli_args);
config.merge(&l1_args);

assert_eq!(config.base_config.log_json, true);
assert_eq!(config.base_config.chain, "goerli");
assert_eq!(config.l1_config.dry_run, true);
}

#[test]
fn test_multiple_cli_overrides() {
let config_str = r#"
log_json = false
full_telemetry_server_port = 6060
redacted_telemetry_server_port = 6070
dry_run_validation_url = ["http://localhost:8545"]
"#;
let mut config: Config = toml::from_str(config_str).unwrap();

let cli_args = BaseCliArgs {
log_json: Some(true),
full_telemetry_server_port: Some(7000),
redacted_telemetry_server_port: Some(7001),
..Default::default()
};

let l1_args = L1CliArgs {
dry_run_validation_url: Some(vec!["http://localhost:9545".to_string()]),
..Default::default()
};

config.merge(&cli_args);
config.merge(&l1_args);

assert_eq!(config.base_config.log_json, true);
assert_eq!(config.base_config.full_telemetry_server_port, 7000);
assert_eq!(config.base_config.redacted_telemetry_server_port, 7001);
assert_eq!(
config.l1_config.dry_run_validation_url,
vec!["http://localhost:9545"]
);
}

#[test]
fn test_unset_cli_values_preserve_config() {
let config_str = r#"
chain = "mainnet"
max_concurrent_seals = 4
optimistic_enabled = true
"#;
let mut config: Config = toml::from_str(config_str).unwrap();

let cli_args = BaseCliArgs::default();
let l1_args = L1CliArgs::default();

config.merge(&cli_args);
config.merge(&l1_args);

assert_eq!(config.base_config.chain, "mainnet");
assert_eq!(config.l1_config.max_concurrent_seals, 4);
assert_eq!(config.l1_config.optimistic_enabled, true);
}
}

0 comments on commit 58f386b

Please sign in to comment.