From 4bd17e81acca82a5f75b52d474d5454be5ee2c65 Mon Sep 17 00:00:00 2001 From: Daniel Xifra Date: Wed, 30 Apr 2025 16:09:07 -0300 Subject: [PATCH 1/3] fast split between fast and independent --- .../live_builder/block_output/relay_submit.rs | 44 +++++++++++++------ crates/rbuilder/src/live_builder/config.rs | 15 +++++-- crates/rbuilder/src/primitives/mev_boost.rs | 16 ++++++- crates/rbuilder/src/telemetry/metrics/mod.rs | 14 ++++-- docs/CONFIG.md | 4 +- 5 files changed, 71 insertions(+), 22 deletions(-) diff --git a/crates/rbuilder/src/live_builder/block_output/relay_submit.rs b/crates/rbuilder/src/live_builder/block_output/relay_submit.rs index 996e50bcc..36144afa0 100644 --- a/crates/rbuilder/src/live_builder/block_output/relay_submit.rs +++ b/crates/rbuilder/src/live_builder/block_output/relay_submit.rs @@ -105,7 +105,7 @@ pub struct SubmissionConfig { pub optimistic_config: Option, pub bid_observer: Box, /// Bids above this value will only go to fast relays. - pub fast_bid_threshold: U256, + pub independent_bid_threshold: U256, } /// Configuration for optimistic block submission to relays. @@ -244,8 +244,11 @@ async fn run_submit_to_relays_job( parent: &submission_span, "Submitting bid", ); - let send_to_slow_relays = can_send_to_slow_relay(&block, config.fast_bid_threshold); - inc_initiated_submissions(optimistic_config.is_some(), send_to_slow_relays); + let relay_filter = get_relay_filter_and_update_metrics( + &block, + optimistic_config.is_some(), + config.independent_bid_threshold, + ); let (normal_signed_submission, optimistic_signed_submission) = { let normal_signed_submission = match sign_block_for_relay( @@ -302,7 +305,7 @@ async fn run_submit_to_relays_job( submit_block_to_relays( &normal_relays, &normal_signed_submission, - send_to_slow_relays, + &relay_filter, false, &submission_span, &cancel, @@ -312,7 +315,7 @@ async fn run_submit_to_relays_job( submit_block_to_relays( &optimistic_relays, optimistic_signed_submission, - send_to_slow_relays, + &relay_filter, true, &submission_span, &cancel, @@ -322,7 +325,7 @@ async fn run_submit_to_relays_job( submit_block_to_relays( &optimistic_relays, &normal_signed_submission, - send_to_slow_relays, + &relay_filter, false, &submission_span, &cancel, @@ -345,13 +348,13 @@ async fn run_submit_to_relays_job( fn submit_block_to_relays( relays: &Vec, submission: &SubmitBlockRequestWithMetadata, - send_to_slow_relays: bool, + relay_filter: &impl Fn(&MevBoostRelayBidSubmitter) -> bool, optimistic: bool, submission_span: &Span, cancel: &CancellationToken, ) { for relay in relays { - if relay.is_fast() || send_to_slow_relays { + if relay_filter(relay) { let span = info_span!(parent: submission_span, "relay_submit", relay = &relay.id(), optimistic); let relay = relay.clone(); let cancel = cancel.clone(); @@ -366,9 +369,16 @@ fn submit_block_to_relays( } } -/// can send only cheap blocks with no bundle replacement data. -fn can_send_to_slow_relay(block: &Block, fast_bid_threshold: U256) -> bool { - let has_replacement_uuid = block +/// Creates a Fn to decide if the block should go to a relay. +fn get_relay_filter_and_update_metrics( + block: &Block, + optimistic: bool, + independent_bid_threshold: U256, +) -> impl Fn(&MevBoostRelayBidSubmitter) -> bool { + // only_independent = expensive blocks. + let only_independent = block.trace.bid_value > independent_bid_threshold; + // only_fast = blocks with replaceable orders. + let only_fast = block .trace .included_orders .iter() @@ -378,8 +388,16 @@ fn can_send_to_slow_relay(block: &Block, fast_bid_threshold: U256) -> bool { Order::Tx(_) => false, Order::ShareBundle(_) => false, }); - let is_expensive_block = block.trace.bid_value > fast_bid_threshold; - !has_replacement_uuid && !is_expensive_block + inc_initiated_submissions(optimistic, !only_fast, !only_independent); + move |relay: &MevBoostRelayBidSubmitter| { + if only_independent && !relay.is_independent() { + return false; + } + if only_fast && !relay.is_fast() { + return false; + } + true + } } pub async fn run_submit_to_relays_job_and_metrics( diff --git a/crates/rbuilder/src/live_builder/config.rs b/crates/rbuilder/src/live_builder/config.rs index 60f62a824..871b80266 100644 --- a/crates/rbuilder/src/live_builder/config.rs +++ b/crates/rbuilder/src/live_builder/config.rs @@ -114,6 +114,7 @@ pub struct Config { } const DEFAULT_SLOT_DELTA_TO_START_BIDDING_MS: i64 = -8000; +const DEFAULT_INDEPENDENT_BID_THRESHOLD_ETH: &str = "0"; #[serde_as] #[derive(Debug, Clone, Deserialize, PartialEq, Eq)] @@ -140,8 +141,8 @@ pub struct L1Config { /// Genesis fork version for the chain. If not provided it will be fetched from the beacon client. pub genesis_fork_version: Option, - /// Bids above this value will only go to fast relays. - pub fast_bid_threshold_eth: String, + /// Bids above this value will only go to independent relays. + pub independent_bid_threshold_eth: String, } impl Default for L1Config { @@ -155,7 +156,7 @@ impl Default for L1Config { optimistic_max_bid_value_eth: "0.0".to_string(), cl_node_url: vec![EnvOrValue::from("http://127.0.0.1:3500")], genesis_fork_version: None, - fast_bid_threshold_eth: "0".to_owned(), + independent_bid_threshold_eth: DEFAULT_INDEPENDENT_BID_THRESHOLD_ETH.to_owned(), } } } @@ -197,6 +198,7 @@ impl L1Config { submit_config, relay_config.mode == RelayMode::Test, relay_config.is_fast(), + relay_config.is_independent(), )); } else { eyre::bail!( @@ -314,7 +316,7 @@ impl L1Config { signer, optimistic_config, bid_observer, - fast_bid_threshold: parse_ether(&self.fast_bid_threshold_eth)?, + independent_bid_threshold: parse_ether(&self.independent_bid_threshold_eth)?, }) } @@ -719,6 +721,7 @@ lazy_static! { builder_id_header: None, api_token_header: None, is_fast: None, + is_independent: None, }, ); map.insert( @@ -738,6 +741,7 @@ lazy_static! { builder_id_header: None, api_token_header: None, is_fast: None, + is_independent: None, }, ); map.insert( @@ -757,6 +761,7 @@ lazy_static! { builder_id_header: None, api_token_header: None, is_fast: None, + is_independent: None, }, ); map.insert( @@ -775,6 +780,7 @@ lazy_static! { builder_id_header: None, api_token_header: None, is_fast: None, + is_independent: None, }, ); map.insert( @@ -794,6 +800,7 @@ lazy_static! { builder_id_header: None, api_token_header: None, is_fast: None, + is_independent: None, }, ); map diff --git a/crates/rbuilder/src/primitives/mev_boost.rs b/crates/rbuilder/src/primitives/mev_boost.rs index f9372174b..433b80efa 100644 --- a/crates/rbuilder/src/primitives/mev_boost.rs +++ b/crates/rbuilder/src/primitives/mev_boost.rs @@ -61,11 +61,14 @@ pub struct RelayConfig { pub submit_config: Option, /// Deprecated field that is not used pub priority: Option, - /// critical blocks go only to fast relays. None -> true + /// Critical blocks (containing bundles with replacement ids) go only to fast relays. None -> true pub is_fast: Option, + /// Big blocks (bid > [L1Config::independent_bid_threshold_eth]) go only to independent relay. None -> true + pub is_independent: Option, } const IS_FAST_DEFAULT: bool = true; +const IS_INDEPENDENT_DEFAULT: bool = true; #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Default)] #[serde(deny_unknown_fields)] pub struct RelaySubmitConfig { @@ -98,6 +101,10 @@ impl RelayConfig { pub fn is_fast(&self) -> bool { self.is_fast.unwrap_or(IS_FAST_DEFAULT) } + + pub fn is_independent(&self) -> bool { + self.is_independent.unwrap_or(IS_INDEPENDENT_DEFAULT) + } } /// Wrapper in RelayClient to submit blocks. @@ -120,6 +127,7 @@ pub struct MevBoostRelayBidSubmitter { /// Parameter for the relay cancellations: bool, is_fast: bool, + is_independent: bool, } impl MevBoostRelayBidSubmitter { @@ -129,6 +137,7 @@ impl MevBoostRelayBidSubmitter { config: &RelaySubmitConfig, test_relay: bool, is_fast: bool, + is_independent: bool, ) -> Self { let submission_rate_limiter = config.interval_between_submissions_ms.map(|d| { Arc::new(RateLimiter::direct( @@ -145,6 +154,7 @@ impl MevBoostRelayBidSubmitter { test_relay, cancellations: true, is_fast, + is_independent, } } @@ -152,6 +162,10 @@ impl MevBoostRelayBidSubmitter { self.is_fast } + pub fn is_independent(&self) -> bool { + self.is_independent + } + pub fn test_relay(&self) -> bool { self.test_relay } diff --git a/crates/rbuilder/src/telemetry/metrics/mod.rs b/crates/rbuilder/src/telemetry/metrics/mod.rs index 802310d90..80c29b0b2 100644 --- a/crates/rbuilder/src/telemetry/metrics/mod.rs +++ b/crates/rbuilder/src/telemetry/metrics/mod.rs @@ -134,7 +134,7 @@ register_metrics! { "initiated_submissions", "Number of initiated submissions to the relays" ), - &["optimistic","sent_to_slow"], + &["optimistic","sent_to_slow","send_to_non_independent"], ) .unwrap(); @@ -469,9 +469,17 @@ pub fn inc_active_slots() { ACTIVE_SLOTS.inc(); } -pub fn inc_initiated_submissions(optimistic: bool, sent_to_slow_relays: bool) { +pub fn inc_initiated_submissions( + optimistic: bool, + sent_to_slow_relays: bool, + send_to_non_independent: bool, +) { INITIATED_SUBMISSIONS - .with_label_values(&[&optimistic.to_string(), &sent_to_slow_relays.to_string()]) + .with_label_values(&[ + &optimistic.to_string(), + &sent_to_slow_relays.to_string(), + &send_to_non_independent.to_string(), + ]) .inc(); } diff --git a/docs/CONFIG.md b/docs/CONFIG.md index d22ec76a5..dec43ec16 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -63,6 +63,8 @@ Every field has a default if omitted. |RelayConfig.use_gzip_for_submit|optional bool||false| |RelayConfig.optimistic|optional bool||false| |RelayConfig.interval_between_submissions_ms|optional int| Caps the submission rate to the relay|None| +|RelayConfig.is_fast|optional bool| Critical blocks (the ones containing orders with replacement id) will go only to fast relays.|true| +|RelayConfig.is_independent|optional bool| Big blocks (bid value > independent_bid_threshold_eth) will go only to independent relays.|true| |enabled_relays| vec["string"]| Extra hardcoded relays to add (see DEFAULT_RELAYS in [config.rs](../crates/rbuilder/src/live_builder/config.rs))|[]| |relay_secret_key|optional env/string|Secret key that will be used to sign normal submissions to the relay.|None| |optimistic_relay_secret_key|optional env/string|Secret key that will be used to sign optimistic submissions to the relay.|None| @@ -70,7 +72,7 @@ Every field has a default if omitted. |optimistic_max_bid_value_eth|string| Bids above this value will always be submitted in non-optimistic mode.|"0.0"| |cl_node_url|vec[env/stirng]| Array if urls to CL clients to get the new payload events|["http://127.0.0.1:3500"] |genesis_fork_version|optional string|Genesis fork version for the chain. If not provided it will be fetched from the beacon client.|None| - +|independent_bid_threshold_eth|optional string|Bids above this value will only go to independent relays.| "0"| ## Building algorithms rbuilder can multiple building algorithms and each algorithm can be instantiated multiple times with it's own set of parameters each time. Each instantiated algorithm starts with: From f110b7dc2c27da56f39bb4707ec3047a19c68747 Mon Sep 17 00:00:00 2001 From: Daniel Xifra Date: Wed, 30 Apr 2025 16:11:52 -0300 Subject: [PATCH 2/3] typo --- crates/rbuilder/src/primitives/mev_boost.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rbuilder/src/primitives/mev_boost.rs b/crates/rbuilder/src/primitives/mev_boost.rs index 433b80efa..88f9b8854 100644 --- a/crates/rbuilder/src/primitives/mev_boost.rs +++ b/crates/rbuilder/src/primitives/mev_boost.rs @@ -63,7 +63,7 @@ pub struct RelayConfig { pub priority: Option, /// Critical blocks (containing bundles with replacement ids) go only to fast relays. None -> true pub is_fast: Option, - /// Big blocks (bid > [L1Config::independent_bid_threshold_eth]) go only to independent relay. None -> true + /// Big blocks (bid > [L1Config::independent_bid_threshold_eth]) go only to independent relays. None -> true pub is_independent: Option, } From 5b3d6e8fdd0865228d6a6bc371509f29605f24a5 Mon Sep 17 00:00:00 2001 From: Daniel Xifra Date: Fri, 2 May 2025 13:26:18 -0300 Subject: [PATCH 3/3] improved comments --- .../rbuilder/src/live_builder/block_output/relay_submit.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/rbuilder/src/live_builder/block_output/relay_submit.rs b/crates/rbuilder/src/live_builder/block_output/relay_submit.rs index 36144afa0..0317ced81 100644 --- a/crates/rbuilder/src/live_builder/block_output/relay_submit.rs +++ b/crates/rbuilder/src/live_builder/block_output/relay_submit.rs @@ -370,6 +370,9 @@ fn submit_block_to_relays( } /// Creates a Fn to decide if the block should go to a relay. +/// The cfg defines 2 flags on relays: fast and independent. +/// If a block has replacement ids it should NOT go to a relay that is not fast since it needs fast cancellations. +/// If a block is expensive it should NOT go to a non independent relay. fn get_relay_filter_and_update_metrics( block: &Block, optimistic: bool, @@ -391,10 +394,10 @@ fn get_relay_filter_and_update_metrics( inc_initiated_submissions(optimistic, !only_fast, !only_independent); move |relay: &MevBoostRelayBidSubmitter| { if only_independent && !relay.is_independent() { - return false; + return false; // Sorry relay but this block is expensive and you are not independent :( } if only_fast && !relay.is_fast() { - return false; + return false; // Sorry relay but this block contains replacements and you are slow :( } true }