From 1124f4bb40b9422d5904a54721a2866f66a19ad9 Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Tue, 31 Dec 2024 17:54:54 +0100 Subject: [PATCH] Fix --- crates/rbuilder/src/live_builder/config.rs | 205 +++++++++++------- .../testdata/config_with_relay_empty_url.toml | 41 ++++ .../testdata/config_with_relay_override.toml | 41 ++++ crates/rbuilder/src/primitives/mev_boost.rs | 39 +++- 4 files changed, 249 insertions(+), 77 deletions(-) create mode 100644 crates/rbuilder/src/live_builder/testdata/config_with_relay_empty_url.toml create mode 100644 crates/rbuilder/src/live_builder/testdata/config_with_relay_override.toml diff --git a/crates/rbuilder/src/live_builder/config.rs b/crates/rbuilder/src/live_builder/config.rs index b65fca91..9bf79fc1 100644 --- a/crates/rbuilder/src/live_builder/config.rs +++ b/crates/rbuilder/src/live_builder/config.rs @@ -46,6 +46,7 @@ use ethereum_consensus::{ state_transition::Context as ContextEth, }; use eyre::Context; +use lazy_static::lazy_static; use reth::revm::cached::CachedReads; use reth_chainspec::{Chain, ChainSpec, NamedChain}; use reth_db::{Database, DatabaseEnv}; @@ -65,7 +66,7 @@ use std::{ sync::Arc, time::Duration, }; -use tracing::info; +use tracing::{info, warn}; use url::Url; /// We initialize the wallet with the last full day. This should be enough for any bidder. @@ -140,69 +141,7 @@ pub struct L1Config { impl Default for L1Config { fn default() -> Self { Self { - relays: vec![ - RelayConfig { - name: "flashbots".to_string(), - url: "http://k8s-default-boostrel-9f278153f5-947835446.us-east-2.elb.amazonaws.com".to_string(), - use_ssz_for_submit: true, - use_gzip_for_submit: false, - priority: 0, - optimistic: false, - interval_between_submissions_ms: Some(250), - authorization_header: None, - builder_id_header: None, - api_token_header: None, - }, - RelayConfig { - name: "ultrasound-us".to_string(), - url: "https://relay-builders-us.ultrasound.money".to_string(), - use_ssz_for_submit: true, - use_gzip_for_submit: true, - priority: 0, - optimistic: true, - interval_between_submissions_ms: None, - authorization_header: None, - builder_id_header: None, - api_token_header: None, - }, - RelayConfig { - name: "ultrasound-eu".to_string(), - url: "https://relay-builders-eu.ultrasound.money".to_string(), - use_ssz_for_submit: true, - use_gzip_for_submit: true, - priority: 0, - optimistic: true, - interval_between_submissions_ms: None, - authorization_header: None, - builder_id_header: None, - api_token_header: None, - }, - RelayConfig { - name: "agnostic".to_string(), - url: "https://0xa7ab7a996c8584251c8f925da3170bdfd6ebc75d50f5ddc4050a6fdc77f2a3b5fce2cc750d0865e05d7228af97d69561@agnostic-relay.net".to_string(), - use_ssz_for_submit: true, - use_gzip_for_submit: true, - priority: 0, - optimistic: true, - interval_between_submissions_ms: None, - authorization_header: None, - builder_id_header: None, - api_token_header: None, - }, - // Local relay configuration for the playground - RelayConfig { - name: "playground".to_string(), - url: "http://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@localhost:5555".to_string(), - priority: 0, - use_ssz_for_submit: false, - use_gzip_for_submit: false, - optimistic: false, - interval_between_submissions_ms: None, - authorization_header: None, - builder_id_header: None, - api_token_header: None, - } - ], + relays: vec![], enabled_relays: vec![], dry_run: false, dry_run_validation_url: vec![], @@ -234,18 +173,45 @@ impl L1Config { } pub fn create_relays(&self) -> eyre::Result> { + let mut relays = DEFAULT_RELAYS.to_vec(); + + for relay in self.relays.clone() { + if let Some(default) = relays.iter_mut().find(|d| d.name == relay.name) { + // If found in defaults, update it with an or operation + *default = default.clone() | relay.clone(); + } else { + // If not found in defaults, add as new relay + relays.push(relay.clone()); + } + + // Emit warning if this relay is defined but not enabled + if !self.enabled_relays.contains(&relay.name) { + warn!( + "Relay '{}' is defined but not enabled in enabled_relays", + relay.name + ); + } + } + let mut results = Vec::new(); for relay_name in &self.enabled_relays { - match self.relays.iter().find(|r| r.name == *relay_name) { - Some(relay) => { - match MevBoostRelay::from_config(relay) { - Ok(relay) => { - info!("Created relay: {:?} (priority: {})", relay_name, relay.priority); - results.push(relay) - }, - Err(e) => return Err(eyre::eyre!("Failed to create relay {}: {:?}", relay_name, e)), + match relays.iter().find(|r| r.name == *relay_name) { + Some(relay) => match MevBoostRelay::from_config(relay) { + Ok(relay) => { + info!( + "Created relay: {:?} (priority: {})", + relay_name, relay.priority + ); + results.push(relay) } - } + Err(e) => { + return Err(eyre::eyre!( + "Failed to create relay {}: {:?}", + relay_name, + e + )) + } + }, None => return Err(eyre::eyre!("Relay {} not found in relays list", relay_name)), } } @@ -672,6 +638,72 @@ fn get_signing_domain( Ok(B256::from(&compute_builder_domain(&cl_context)?)) } +lazy_static! { + static ref DEFAULT_RELAYS: Vec = vec![ + RelayConfig { + name: "flashbots".to_string(), + url: Some("http://k8s-default-boostrel-9f278153f5-947835446.us-east-2.elb.amazonaws.com".to_string()), + use_ssz_for_submit: true, + use_gzip_for_submit: false, + priority: 0, + optimistic: false, + interval_between_submissions_ms: Some(250), + authorization_header: None, + builder_id_header: None, + api_token_header: None, + }, + RelayConfig { + name: "ultrasound-us".to_string(), + url: Some("https://relay-builders-us.ultrasound.money".to_string()), + use_ssz_for_submit: true, + use_gzip_for_submit: true, + priority: 0, + optimistic: true, + interval_between_submissions_ms: None, + authorization_header: None, + builder_id_header: None, + api_token_header: None, + }, + RelayConfig { + name: "ultrasound-eu".to_string(), + url: Some("https://relay-builders-eu.ultrasound.money".to_string()), + use_ssz_for_submit: true, + use_gzip_for_submit: true, + priority: 0, + optimistic: true, + interval_between_submissions_ms: None, + authorization_header: None, + builder_id_header: None, + api_token_header: None, + }, + RelayConfig { + name: "agnostic".to_string(), + url:Some("https://0xa7ab7a996c8584251c8f925da3170bdfd6ebc75d50f5ddc4050a6fdc77f2a3b5fce2cc750d0865e05d7228af97d69561@agnostic-relay.net".to_string()), + use_ssz_for_submit: true, + use_gzip_for_submit: true, + priority: 0, + optimistic: true, + interval_between_submissions_ms: None, + authorization_header: None, + builder_id_header: None, + api_token_header: None, + }, + // Local relay configuration for the playground + RelayConfig { + name: "playground".to_string(), + url:Some("http://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@localhost:5555".to_string()), + priority: 0, + use_ssz_for_submit: false, + use_gzip_for_submit: false, + optimistic: false, + interval_between_submissions_ms: None, + authorization_header: None, + builder_id_header: None, + api_token_header: None, + } + ]; +} + #[cfg(test)] mod test { use super::*; @@ -729,6 +761,33 @@ mod test { .contains(&"http://localhost:3500".to_string())); } + #[test] + fn test_parse_enabled_relays() { + let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + p.push("./src/live_builder/testdata/config_with_relay_override.toml"); + + let config: Config = load_config_toml_and_env(p.clone()).expect("Config load"); + + let relays = config.l1_config.create_relays().unwrap(); + assert_eq!(relays.len(), 1); + assert_eq!(relays[0].id, "playground"); + assert_eq!(relays[0].priority, 10); + } + + #[test] + fn test_parse_empty_relay_url() { + let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + p.push("./src/live_builder/testdata/config_with_relay_empty_url.toml"); + + let config: Config = load_config_toml_and_env(p).expect("Config load"); + assert!(config + .l1_config + .create_relays() + .unwrap_err() + .to_string() + .contains("url is required")); + } + #[test] fn test_parse_backtest_example_config() { let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); diff --git a/crates/rbuilder/src/live_builder/testdata/config_with_relay_empty_url.toml b/crates/rbuilder/src/live_builder/testdata/config_with_relay_empty_url.toml new file mode 100644 index 00000000..dc7f7ffa --- /dev/null +++ b/crates/rbuilder/src/live_builder/testdata/config_with_relay_empty_url.toml @@ -0,0 +1,41 @@ +log_json = true +log_level = "info,rbuilder=debug" +redacted_telemetry_server_port = 6061 +redacted_telemetry_server_ip = "0.0.0.0" +full_telemetry_server_port = 6060 +full_telemetry_server_ip = "0.0.0.0" + +chain = "mainnet" +reth_datadir = "/mnt/data/reth" + +coinbase_secret_key = "env:COINBASE_SECRET_KEY" +relay_secret_key = "env:RELAY_SECRET_KEY" +optimistic_relay_secret_key = "env:OPTIMISTIC_RELAY_SECRET_KEY" + +# cl_node_url can be a single value, array of values, or passed by an environment variables with values separated with a comma +# cl_node_url = "http://localhost:3500" +cl_node_url = ["env:CL_NODE_URL"] +jsonrpc_server_port = 8645 +jsonrpc_server_ip = "0.0.0.0" +el_node_ipc_path = "/tmp/reth.ipc" +extra_data = "⚡🤖" + +blocklist_file_path = "./blocklist.json" + +dry_run = true +dry_run_validation_url = "http://localhost:8545" + +ignore_cancellable_orders = true + +max_concurrent_seals = 4 + +# genesis_fork_version = "0x00112233" + +sbundle_mergeable_signers = [] +live_builders = ["mp-ordering", "mgp-ordering", "merging"] + +enabled_relays = ["custom"] + +[[relays]] +name = "custom" +priority = 10 diff --git a/crates/rbuilder/src/live_builder/testdata/config_with_relay_override.toml b/crates/rbuilder/src/live_builder/testdata/config_with_relay_override.toml new file mode 100644 index 00000000..5b9afae7 --- /dev/null +++ b/crates/rbuilder/src/live_builder/testdata/config_with_relay_override.toml @@ -0,0 +1,41 @@ +log_json = true +log_level = "info,rbuilder=debug" +redacted_telemetry_server_port = 6061 +redacted_telemetry_server_ip = "0.0.0.0" +full_telemetry_server_port = 6060 +full_telemetry_server_ip = "0.0.0.0" + +chain = "mainnet" +reth_datadir = "/mnt/data/reth" + +coinbase_secret_key = "env:COINBASE_SECRET_KEY" +relay_secret_key = "env:RELAY_SECRET_KEY" +optimistic_relay_secret_key = "env:OPTIMISTIC_RELAY_SECRET_KEY" + +# cl_node_url can be a single value, array of values, or passed by an environment variables with values separated with a comma +# cl_node_url = "http://localhost:3500" +cl_node_url = ["env:CL_NODE_URL"] +jsonrpc_server_port = 8645 +jsonrpc_server_ip = "0.0.0.0" +el_node_ipc_path = "/tmp/reth.ipc" +extra_data = "⚡🤖" + +blocklist_file_path = "./blocklist.json" + +dry_run = true +dry_run_validation_url = "http://localhost:8545" + +ignore_cancellable_orders = true + +max_concurrent_seals = 4 + +# genesis_fork_version = "0x00112233" + +sbundle_mergeable_signers = [] +live_builders = ["mp-ordering", "mgp-ordering", "merging"] + +enabled_relays = ["playground"] + +[[relays]] +name = "playground" +priority = 10 diff --git a/crates/rbuilder/src/primitives/mev_boost.rs b/crates/rbuilder/src/primitives/mev_boost.rs index 0881ef1a..1457d8da 100644 --- a/crates/rbuilder/src/primitives/mev_boost.rs +++ b/crates/rbuilder/src/primitives/mev_boost.rs @@ -1,6 +1,7 @@ use crate::mev_boost::{RelayClient, SubmitBlockErr, SubmitBlockRequest}; use governor::{DefaultDirectRateLimiter, Quota, RateLimiter}; use serde::{Deserialize, Deserializer}; +use std::ops::BitOr; use std::{env, sync::Arc, time::Duration}; use url::Url; @@ -11,7 +12,8 @@ pub type MevBoostRelayID = String; #[serde(deny_unknown_fields)] pub struct RelayConfig { pub name: String, - pub url: String, + pub url: Option, + #[serde(default)] pub priority: usize, // true->ssz false->json #[serde(default)] @@ -33,7 +35,7 @@ pub struct RelayConfig { impl RelayConfig { pub fn with_url(self, url: &str) -> Self { Self { - url: url.to_string(), + url: Some(url.to_string()), ..self } } @@ -46,6 +48,30 @@ impl RelayConfig { } } +impl BitOr for RelayConfig { + type Output = Self; + + fn bitor(self, other: Self) -> Self { + if self.name != other.name { + return self; + } + Self { + name: self.name, + url: other.url.or(self.url), + priority: self.priority | other.priority, + use_ssz_for_submit: self.use_ssz_for_submit | other.use_ssz_for_submit, + use_gzip_for_submit: self.use_gzip_for_submit | other.use_gzip_for_submit, + optimistic: self.optimistic | other.optimistic, + authorization_header: other.authorization_header.or(self.authorization_header), + builder_id_header: other.builder_id_header.or(self.builder_id_header), + api_token_header: other.api_token_header.or(self.api_token_header), + interval_between_submissions_ms: other + .interval_between_submissions_ms + .or(self.interval_between_submissions_ms), + } + } +} + /// Wrapper over RelayClient that allows to submit blocks and /// hides the particular configuration (eg: ssz, gip, optimistic). /// Sometimes the client is used externally. @@ -66,8 +92,13 @@ pub struct MevBoostRelay { impl MevBoostRelay { pub fn from_config(config: &RelayConfig) -> eyre::Result { + let url = config + .url + .as_ref() + .ok_or_else(|| eyre::eyre!("url is required"))?; + let client = { - let url: Url = config.url.parse()?; + let url: Url = url.parse()?; RelayClient::from_url( url, config.authorization_header.clone(), @@ -135,7 +166,7 @@ mod test { let config: RelayConfig = toml::from_str(example).unwrap(); assert_eq!(config.name, "relay1"); - assert_eq!(config.url, "url"); + assert_eq!(config.url.expect("url expected"), "url"); assert_eq!(config.priority, 0); assert_eq!(config.authorization_header.unwrap(), "AAA"); assert_eq!(config.builder_id_header.unwrap(), "BBB");