From d3f9078bd1d77552097695430ae9a3c6fb6e5716 Mon Sep 17 00:00:00 2001 From: Vitaly Drogan Date: Fri, 3 Oct 2025 17:09:31 +0200 Subject: [PATCH 1/3] report mev-blocker price to blocks processor --- .../rbuilder-operator/src/blocks_processor.rs | 30 +++++++++++++++---- .../builders/block_building_helper.rs | 1 + .../src/building/built_block_trace.rs | 3 ++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/crates/rbuilder-operator/src/blocks_processor.rs b/crates/rbuilder-operator/src/blocks_processor.rs index 563610b93..d57e56c84 100644 --- a/crates/rbuilder-operator/src/blocks_processor.rs +++ b/crates/rbuilder-operator/src/blocks_processor.rs @@ -20,7 +20,6 @@ use serde_with::{serde_as, DisplayFromStr}; use std::{sync::Arc, time::Duration}; use time::format_description::well_known; use tracing::{error, warn, Span}; -use uuid::Uuid; use crate::metrics::inc_submit_block_errors; @@ -67,7 +66,7 @@ struct BlocksProcessorHeader { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] #[serde(rename_all = "camelCase")] pub struct BlockProcessorDelayedPayments { - pub source: Uuid, + pub source: String, pub value: U256, pub address: Address, } @@ -177,7 +176,7 @@ impl BlocksProcessorClient { let used_share_bundles = Self::get_used_sbundles(built_block_trace); - let delayed_payments = built_block_trace + let mut delayed_payments: Vec<_> = built_block_trace .included_orders .iter() .filter_map(|res| { @@ -200,12 +199,17 @@ impl BlocksProcessorClient { }; Some(BlockProcessorDelayedPayments { - source: bundle_uuid, + source: bundle_uuid.to_string(), value: delayed_kickback.payout_value, address: delayed_kickback.recipient, }) }) .collect(); + delayed_payments.push(BlockProcessorDelayedPayments { + source: "mev_blocker".into(), + value: built_block_trace.mev_blocker_price, + address: Address::ZERO, + }); let params: ConsumeBuiltBlockRequest = ( header, @@ -379,6 +383,8 @@ fn backoff() -> Backoff { #[cfg(test)] mod tests { + use uuid::Uuid; + use super::*; #[test] @@ -402,7 +408,9 @@ mod tests { let value = BlockProcessorDelayedPayments { address: alloy_primitives::address!("93Ea7cB31f76B982601321b2A0d93Ec9A948236D"), value: U256::from(16), - source: Uuid::try_parse("ff7b2232-b30d-4889-9258-c3632ba4bfc0").unwrap(), + source: Uuid::try_parse("ff7b2232-b30d-4889-9258-c3632ba4bfc0") + .unwrap() + .to_string(), }; let value_str = serde_json::to_string(&value).unwrap(); @@ -410,5 +418,17 @@ mod tests { let expected_str = r#"{"source":"ff7b2232-b30d-4889-9258-c3632ba4bfc0","value":"0x10","address":"0x93ea7cb31f76b982601321b2a0d93ec9a948236d"}"#; assert_eq!(value_str, expected_str); + + let value = BlockProcessorDelayedPayments { + address: Address::ZERO, + value: U256::from(16), + source: "mev_blocker".into(), + }; + + let value_str = serde_json::to_string(&value).unwrap(); + + let expected_str = r#"{"source":"mev_blocker","value":"0x10","address":"0x0000000000000000000000000000000000000000"}"#; + + assert_eq!(value_str, expected_str); } } diff --git a/crates/rbuilder/src/building/builders/block_building_helper.rs b/crates/rbuilder/src/building/builders/block_building_helper.rs index d547c3d7e..c38877cf6 100644 --- a/crates/rbuilder/src/building/builders/block_building_helper.rs +++ b/crates/rbuilder/src/building/builders/block_building_helper.rs @@ -354,6 +354,7 @@ impl< self.built_block_trace.bid_value = max(bid_value, fee_recipient_balance_diff); self.built_block_trace.true_bid_value = true_value; + self.built_block_trace.mev_blocker_price = self.building_context().mev_blocker_price; Ok(()) } diff --git a/crates/rbuilder/src/building/built_block_trace.rs b/crates/rbuilder/src/building/built_block_trace.rs index bf2ad332e..880c30999 100644 --- a/crates/rbuilder/src/building/built_block_trace.rs +++ b/crates/rbuilder/src/building/built_block_trace.rs @@ -22,6 +22,8 @@ pub struct BuiltBlockTrace { pub coinbase_reward: U256, /// True block value (coinbase balance delta) excluding the cost of the payout to validator pub true_bid_value: U256, + /// Amount that is left out on the coinbase to pay for mev blocker oderflow + pub mev_blocker_price: U256, /// Timestamp of the moment we stopped considering new orders for this block. pub orders_closed_at: OffsetDateTime, /// UnfinishedBuiltBlocksInput chose this block as the best block and sent it downstream @@ -75,6 +77,7 @@ impl BuiltBlockTrace { bid_value: U256::from(0), coinbase_reward: U256::from(0), true_bid_value: U256::from(0), + mev_blocker_price: U256::from(0), orders_closed_at: OffsetDateTime::now_utc(), orders_sealed_at: OffsetDateTime::now_utc(), fill_time: Duration::from_secs(0), From 6e214cef4971c072856e0ad179c0cbc465765de0 Mon Sep 17 00:00:00 2001 From: Vitaly Drogan Date: Fri, 3 Oct 2025 17:48:29 +0200 Subject: [PATCH 2/3] allow signers ignore for redistribution --- .../rbuilder-operator/src/flashbots_config.rs | 6 +++++- .../src/backtest/backtest_build_range.rs | 2 +- crates/rbuilder/src/backtest/mod.rs | 9 +++++++-- .../rbuilder/src/backtest/redistribute/mod.rs | 17 +++++++++++++++-- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/crates/rbuilder-operator/src/flashbots_config.rs b/crates/rbuilder-operator/src/flashbots_config.rs index 47acb5270..15bf8d9aa 100644 --- a/crates/rbuilder-operator/src/flashbots_config.rs +++ b/crates/rbuilder-operator/src/flashbots_config.rs @@ -2,7 +2,7 @@ //! This code has lots of copy/paste from the example config but it's not really copy/paste since we use our own private types. //! @Pending make this copy/paste generic code on the library -use alloy_primitives::U256; +use alloy_primitives::{Address, U256}; use alloy_signer_local::PrivateKeySigner; use derivative::Derivative; use eyre::Context; @@ -112,6 +112,10 @@ pub struct FlashbotsConfig { /// For production we always need some tbv push (since it's used by smart-multiplexing.) so: /// !Some(key_registration_url) => Some(tbv_push_redis) tbv_push_redis: Option, + + /// Bundles with refund identity or signer set to these will not receive any redistributions. + #[serde(default)] + pub backtest_ignored_signers: Vec
, } impl LiveBuilderConfig for FlashbotsConfig { diff --git a/crates/rbuilder/src/backtest/backtest_build_range.rs b/crates/rbuilder/src/backtest/backtest_build_range.rs index 62a80d299..905f4cd8e 100644 --- a/crates/rbuilder/src/backtest/backtest_build_range.rs +++ b/crates/rbuilder/src/backtest/backtest_build_range.rs @@ -431,7 +431,7 @@ fn spawn_block_fetcher( as u64, )) { Ok(mut block) => { - block.filter_out_ignored_signers(&ignored_signers); + block.filter_out_ignored_signers(&ignored_signers, false); Some(block) } Err(err) => { diff --git a/crates/rbuilder/src/backtest/mod.rs b/crates/rbuilder/src/backtest/mod.rs index 698fe63a5..1cc7d758c 100644 --- a/crates/rbuilder/src/backtest/mod.rs +++ b/crates/rbuilder/src/backtest/mod.rs @@ -199,10 +199,15 @@ impl BlockData { }); } - pub fn filter_out_ignored_signers(&mut self, ignored_signers: &[Address]) { + pub fn filter_out_ignored_signers(&mut self, ignored_signers: &[Address], use_refund_identity: bool) { self.available_orders.retain(|orders| { let order = &orders.order; - let signer = if let Some(signer) = order.signer() { + let signer = if use_refund_identity { + order.metadata().refund_identity.or_else(|| order.signer()) + } else { + order.signer() + }; + let signer = if let Some(signer) = signer { signer } else { return true; diff --git a/crates/rbuilder/src/backtest/redistribute/mod.rs b/crates/rbuilder/src/backtest/redistribute/mod.rs index d62410e15..31fda51d1 100644 --- a/crates/rbuilder/src/backtest/redistribute/mod.rs +++ b/crates/rbuilder/src/backtest/redistribute/mod.rs @@ -125,6 +125,7 @@ pub fn calc_redistributions( block_data: BlockData, distribute_to_mempool_txs: bool, blocklist: BlockList, + ignored_signers: &[Address], ) -> eyre::Result where P: StateProviderFactory + Clone + 'static, @@ -133,14 +134,21 @@ where let _block_span = info_span!("block", block = block_data.block_number).entered(); let protect_signers = config.base_config().backtest_protect_bundle_signers.clone(); - info!(?protect_signers, "Protect signers"); + info!( + ?protect_signers, + ?ignored_signers, + blocklist_len = blocklist.len(), + distribute_to_mempool_txs, + "Started to calculate redistribution" + ); + if protect_signers.is_empty() { warn!("Protect signers are not set"); } let start = Instant::now(); let (onchain_block_profit, block_data, built_block_data) = - prepare_block_data(config, block_data)?; + prepare_block_data(config, block_data, ignored_signers)?; let included_orders_available = get_available_orders(&block_data, &built_block_data, distribute_to_mempool_txs); @@ -269,6 +277,7 @@ where fn prepare_block_data( config: &ConfigType, mut block_data: BlockData, + ignored_signers: &[Address], ) -> eyre::Result<(U256, BlockData, BuiltBlockData)> where ConfigType: LiveBuilderConfig, @@ -296,6 +305,7 @@ where // @TODO filter cancellations properly, for this we need actual cancellations in the backtest data // filter bundles made out of mempool txs block_data.filter_bundles_from_mempool(); + block_data.filter_out_ignored_signers(ignored_signers, true); let filtered = orders_before_filtering - block_data.available_orders.len(); @@ -354,6 +364,9 @@ fn get_available_orders( None => match block_data.filtered_orders.get(id) { Some(OrderFilteredReason::MempoolTxs) => { info!(order = ?id, "Included order was filtered because all txs are from mempool"); + }, + Some(OrderFilteredReason::Signer) => { + info!(order = ?id, "Included order was filtered because signer is explicitly ignored"); } Some(reason) => { error!(order = ?id, ?reason, "Included order was filtered from available orders"); From 20e072b3b416310b0d94f14d9c35487c9f3f3458 Mon Sep 17 00:00:00 2001 From: Vitaly Drogan Date: Tue, 7 Oct 2025 12:20:28 +0200 Subject: [PATCH 3/3] fmt all crates --- crates/rbuilder/src/backtest/mod.rs | 16 ++++++++++------ crates/rbuilder/src/backtest/redistribute/mod.rs | 12 ++++++------ .../building/builders/block_building_helper.rs | 2 +- .../rbuilder/src/building/built_block_trace.rs | 4 ++-- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/crates/rbuilder/src/backtest/mod.rs b/crates/rbuilder/src/backtest/mod.rs index 1cc7d758c..1727a142d 100644 --- a/crates/rbuilder/src/backtest/mod.rs +++ b/crates/rbuilder/src/backtest/mod.rs @@ -199,14 +199,18 @@ impl BlockData { }); } - pub fn filter_out_ignored_signers(&mut self, ignored_signers: &[Address], use_refund_identity: bool) { + pub fn filter_out_ignored_signers( + &mut self, + ignored_signers: &[Address], + use_refund_identity: bool, + ) { self.available_orders.retain(|orders| { let order = &orders.order; - let signer = if use_refund_identity { - order.metadata().refund_identity.or_else(|| order.signer()) - } else { - order.signer() - }; + let signer = if use_refund_identity { + order.metadata().refund_identity.or_else(|| order.signer()) + } else { + order.signer() + }; let signer = if let Some(signer) = signer { signer } else { diff --git a/crates/rbuilder/src/backtest/redistribute/mod.rs b/crates/rbuilder/src/backtest/redistribute/mod.rs index 31fda51d1..69ad349af 100644 --- a/crates/rbuilder/src/backtest/redistribute/mod.rs +++ b/crates/rbuilder/src/backtest/redistribute/mod.rs @@ -135,11 +135,11 @@ where let protect_signers = config.base_config().backtest_protect_bundle_signers.clone(); info!( - ?protect_signers, - ?ignored_signers, - blocklist_len = blocklist.len(), - distribute_to_mempool_txs, - "Started to calculate redistribution" + ?protect_signers, + ?ignored_signers, + blocklist_len = blocklist.len(), + distribute_to_mempool_txs, + "Started to calculate redistribution" ); if protect_signers.is_empty() { @@ -364,7 +364,7 @@ fn get_available_orders( None => match block_data.filtered_orders.get(id) { Some(OrderFilteredReason::MempoolTxs) => { info!(order = ?id, "Included order was filtered because all txs are from mempool"); - }, + } Some(OrderFilteredReason::Signer) => { info!(order = ?id, "Included order was filtered because signer is explicitly ignored"); } diff --git a/crates/rbuilder/src/building/builders/block_building_helper.rs b/crates/rbuilder/src/building/builders/block_building_helper.rs index c38877cf6..3acc5124d 100644 --- a/crates/rbuilder/src/building/builders/block_building_helper.rs +++ b/crates/rbuilder/src/building/builders/block_building_helper.rs @@ -354,7 +354,7 @@ impl< self.built_block_trace.bid_value = max(bid_value, fee_recipient_balance_diff); self.built_block_trace.true_bid_value = true_value; - self.built_block_trace.mev_blocker_price = self.building_context().mev_blocker_price; + self.built_block_trace.mev_blocker_price = self.building_context().mev_blocker_price; Ok(()) } diff --git a/crates/rbuilder/src/building/built_block_trace.rs b/crates/rbuilder/src/building/built_block_trace.rs index 880c30999..9dbe433b1 100644 --- a/crates/rbuilder/src/building/built_block_trace.rs +++ b/crates/rbuilder/src/building/built_block_trace.rs @@ -22,7 +22,7 @@ pub struct BuiltBlockTrace { pub coinbase_reward: U256, /// True block value (coinbase balance delta) excluding the cost of the payout to validator pub true_bid_value: U256, - /// Amount that is left out on the coinbase to pay for mev blocker oderflow + /// Amount that is left out on the coinbase to pay for mev blocker orderflow pub mev_blocker_price: U256, /// Timestamp of the moment we stopped considering new orders for this block. pub orders_closed_at: OffsetDateTime, @@ -77,7 +77,7 @@ impl BuiltBlockTrace { bid_value: U256::from(0), coinbase_reward: U256::from(0), true_bid_value: U256::from(0), - mev_blocker_price: U256::from(0), + mev_blocker_price: U256::from(0), orders_closed_at: OffsetDateTime::now_utc(), orders_sealed_at: OffsetDateTime::now_utc(), fill_time: Duration::from_secs(0),