Skip to content

Commit e76370b

Browse files
authored
Report mev blocker to blocks processor, allow filtering signers for refunds (#746)
## 📝 Summary * report mev blocker signer to blocks processor * add `backets_ignored_signers` to config and redistribution ## 💡 Motivation and Context <!--- (Optional) Why is this change required? What problem does it solve? Remove this section if not applicable. --> --- ## ✅ I have completed the following steps: * [ ] Run `make lint` * [ ] Run `make test` * [ ] Added tests (if applicable)
1 parent 8d839a6 commit e76370b

File tree

7 files changed

+61
-11
lines changed

7 files changed

+61
-11
lines changed

crates/rbuilder-operator/src/blocks_processor.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use serde_with::{serde_as, DisplayFromStr};
2020
use std::{sync::Arc, time::Duration};
2121
use time::format_description::well_known;
2222
use tracing::{error, warn, Span};
23-
use uuid::Uuid;
2423

2524
use crate::metrics::inc_submit_block_errors;
2625

@@ -67,7 +66,7 @@ struct BlocksProcessorHeader {
6766
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
6867
#[serde(rename_all = "camelCase")]
6968
pub struct BlockProcessorDelayedPayments {
70-
pub source: Uuid,
69+
pub source: String,
7170
pub value: U256,
7271
pub address: Address,
7372
}
@@ -177,7 +176,7 @@ impl<HttpClientType: ClientT> BlocksProcessorClient<HttpClientType> {
177176

178177
let used_share_bundles = Self::get_used_sbundles(built_block_trace);
179178

180-
let delayed_payments = built_block_trace
179+
let mut delayed_payments: Vec<_> = built_block_trace
181180
.included_orders
182181
.iter()
183182
.filter_map(|res| {
@@ -200,12 +199,17 @@ impl<HttpClientType: ClientT> BlocksProcessorClient<HttpClientType> {
200199
};
201200

202201
Some(BlockProcessorDelayedPayments {
203-
source: bundle_uuid,
202+
source: bundle_uuid.to_string(),
204203
value: delayed_kickback.payout_value,
205204
address: delayed_kickback.recipient,
206205
})
207206
})
208207
.collect();
208+
delayed_payments.push(BlockProcessorDelayedPayments {
209+
source: "mev_blocker".into(),
210+
value: built_block_trace.mev_blocker_price,
211+
address: Address::ZERO,
212+
});
209213

210214
let params: ConsumeBuiltBlockRequest = (
211215
header,
@@ -379,6 +383,8 @@ fn backoff() -> Backoff {
379383

380384
#[cfg(test)]
381385
mod tests {
386+
use uuid::Uuid;
387+
382388
use super::*;
383389

384390
#[test]
@@ -402,13 +408,27 @@ mod tests {
402408
let value = BlockProcessorDelayedPayments {
403409
address: alloy_primitives::address!("93Ea7cB31f76B982601321b2A0d93Ec9A948236D"),
404410
value: U256::from(16),
405-
source: Uuid::try_parse("ff7b2232-b30d-4889-9258-c3632ba4bfc0").unwrap(),
411+
source: Uuid::try_parse("ff7b2232-b30d-4889-9258-c3632ba4bfc0")
412+
.unwrap()
413+
.to_string(),
406414
};
407415

408416
let value_str = serde_json::to_string(&value).unwrap();
409417

410418
let expected_str = r#"{"source":"ff7b2232-b30d-4889-9258-c3632ba4bfc0","value":"0x10","address":"0x93ea7cb31f76b982601321b2a0d93ec9a948236d"}"#;
411419

412420
assert_eq!(value_str, expected_str);
421+
422+
let value = BlockProcessorDelayedPayments {
423+
address: Address::ZERO,
424+
value: U256::from(16),
425+
source: "mev_blocker".into(),
426+
};
427+
428+
let value_str = serde_json::to_string(&value).unwrap();
429+
430+
let expected_str = r#"{"source":"mev_blocker","value":"0x10","address":"0x0000000000000000000000000000000000000000"}"#;
431+
432+
assert_eq!(value_str, expected_str);
413433
}
414434
}

crates/rbuilder-operator/src/flashbots_config.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//! 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.
33
//! @Pending make this copy/paste generic code on the library
44
5-
use alloy_primitives::U256;
5+
use alloy_primitives::{Address, U256};
66
use alloy_signer_local::PrivateKeySigner;
77
use derivative::Derivative;
88
use eyre::Context;
@@ -112,6 +112,10 @@ pub struct FlashbotsConfig {
112112
/// For production we always need some tbv push (since it's used by smart-multiplexing.) so:
113113
/// !Some(key_registration_url) => Some(tbv_push_redis)
114114
tbv_push_redis: Option<TBVPushRedisConfig>,
115+
116+
/// Bundles with refund identity or signer set to these will not receive any redistributions.
117+
#[serde(default)]
118+
pub backtest_ignored_signers: Vec<Address>,
115119
}
116120

117121
impl LiveBuilderConfig for FlashbotsConfig {

crates/rbuilder/src/backtest/backtest_build_range.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ fn spawn_block_fetcher(
431431
as u64,
432432
)) {
433433
Ok(mut block) => {
434-
block.filter_out_ignored_signers(&ignored_signers);
434+
block.filter_out_ignored_signers(&ignored_signers, false);
435435
Some(block)
436436
}
437437
Err(err) => {

crates/rbuilder/src/backtest/mod.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,19 @@ impl BlockData {
199199
});
200200
}
201201

202-
pub fn filter_out_ignored_signers(&mut self, ignored_signers: &[Address]) {
202+
pub fn filter_out_ignored_signers(
203+
&mut self,
204+
ignored_signers: &[Address],
205+
use_refund_identity: bool,
206+
) {
203207
self.available_orders.retain(|orders| {
204208
let order = &orders.order;
205-
let signer = if let Some(signer) = order.signer() {
209+
let signer = if use_refund_identity {
210+
order.metadata().refund_identity.or_else(|| order.signer())
211+
} else {
212+
order.signer()
213+
};
214+
let signer = if let Some(signer) = signer {
206215
signer
207216
} else {
208217
return true;

crates/rbuilder/src/backtest/redistribute/mod.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ pub fn calc_redistributions<P, ConfigType>(
125125
block_data: BlockData,
126126
distribute_to_mempool_txs: bool,
127127
blocklist: BlockList,
128+
ignored_signers: &[Address],
128129
) -> eyre::Result<RedistributionBlockOutput>
129130
where
130131
P: StateProviderFactory + Clone + 'static,
@@ -133,14 +134,21 @@ where
133134
let _block_span = info_span!("block", block = block_data.block_number).entered();
134135
let protect_signers = config.base_config().backtest_protect_bundle_signers.clone();
135136

136-
info!(?protect_signers, "Protect signers");
137+
info!(
138+
?protect_signers,
139+
?ignored_signers,
140+
blocklist_len = blocklist.len(),
141+
distribute_to_mempool_txs,
142+
"Started to calculate redistribution"
143+
);
144+
137145
if protect_signers.is_empty() {
138146
warn!("Protect signers are not set");
139147
}
140148

141149
let start = Instant::now();
142150
let (onchain_block_profit, block_data, built_block_data) =
143-
prepare_block_data(config, block_data)?;
151+
prepare_block_data(config, block_data, ignored_signers)?;
144152

145153
let included_orders_available =
146154
get_available_orders(&block_data, &built_block_data, distribute_to_mempool_txs);
@@ -269,6 +277,7 @@ where
269277
fn prepare_block_data<ConfigType>(
270278
config: &ConfigType,
271279
mut block_data: BlockData,
280+
ignored_signers: &[Address],
272281
) -> eyre::Result<(U256, BlockData, BuiltBlockData)>
273282
where
274283
ConfigType: LiveBuilderConfig,
@@ -296,6 +305,7 @@ where
296305
// @TODO filter cancellations properly, for this we need actual cancellations in the backtest data
297306
// filter bundles made out of mempool txs
298307
block_data.filter_bundles_from_mempool();
308+
block_data.filter_out_ignored_signers(ignored_signers, true);
299309

300310
let filtered = orders_before_filtering - block_data.available_orders.len();
301311

@@ -355,6 +365,9 @@ fn get_available_orders(
355365
Some(OrderFilteredReason::MempoolTxs) => {
356366
info!(order = ?id, "Included order was filtered because all txs are from mempool");
357367
}
368+
Some(OrderFilteredReason::Signer) => {
369+
info!(order = ?id, "Included order was filtered because signer is explicitly ignored");
370+
}
358371
Some(reason) => {
359372
error!(order = ?id, ?reason, "Included order was filtered from available orders");
360373
}

crates/rbuilder/src/building/builders/block_building_helper.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ impl<
354354

355355
self.built_block_trace.bid_value = max(bid_value, fee_recipient_balance_diff);
356356
self.built_block_trace.true_bid_value = true_value;
357+
self.built_block_trace.mev_blocker_price = self.building_context().mev_blocker_price;
357358
Ok(())
358359
}
359360

crates/rbuilder/src/building/built_block_trace.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ pub struct BuiltBlockTrace {
2222
pub coinbase_reward: U256,
2323
/// True block value (coinbase balance delta) excluding the cost of the payout to validator
2424
pub true_bid_value: U256,
25+
/// Amount that is left out on the coinbase to pay for mev blocker orderflow
26+
pub mev_blocker_price: U256,
2527
/// Timestamp of the moment we stopped considering new orders for this block.
2628
pub orders_closed_at: OffsetDateTime,
2729
/// UnfinishedBuiltBlocksInput chose this block as the best block and sent it downstream
@@ -75,6 +77,7 @@ impl BuiltBlockTrace {
7577
bid_value: U256::from(0),
7678
coinbase_reward: U256::from(0),
7779
true_bid_value: U256::from(0),
80+
mev_blocker_price: U256::from(0),
7881
orders_closed_at: OffsetDateTime::now_utc(),
7982
orders_sealed_at: OffsetDateTime::now_utc(),
8083
fill_time: Duration::from_secs(0),

0 commit comments

Comments
 (0)