Skip to content

Commit 4e18f8f

Browse files
authored
best bid is replaced with CompetitionBidContext (#826)
## 📝 Summary This PR improves the information we store in clickhouse about the blocks: - seen_competition_bid: Option<U256> is replaced by competition_bid_context: CompetitionBidContext which contains not only the competition bid we must beat but also it's time and relay and also time and relay of the competition bid that trigger our bid. - block_id: our internal unique block id - block_uses: how many times we already bidded for this block_id ## ✅ I have completed the following steps: * [X] Run `make lint` * [X] Run `make test` * [ ] Added tests (if applicable) * [X] Prayed to the god of coding that this does not contain any bugs.
1 parent c94ca25 commit 4e18f8f

File tree

15 files changed

+267
-54
lines changed

15 files changed

+267
-54
lines changed

crates/rbuilder-operator/src/bidding_service_wrapper/fast_streams/types.rs

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use iceoryx2_bb_container::byte_string::FixedSizeByteString;
77
use rbuilder::{
88
building::builders::BuiltBlockId,
99
live_builder::block_output::bidding_service_interface::{
10-
BuiltBlockDescriptorForSlotBidder, PayoutInfo, RelaySet, ScrapedRelayBlockBidWithStats,
11-
SlotBidderSealBidCommand,
10+
BidSourceInfo, BidWithInfo, BuiltBlockDescriptorForSlotBidder, CompetitionBidContext,
11+
PayoutInfo, RelaySet, ScrapedRelayBlockBidWithStats, SlotBidderSealBidCommand,
1212
},
1313
utils::{offset_datetime_to_timestamp_us, timestamp_us_to_offset_datetime},
1414
};
@@ -227,13 +227,92 @@ impl PayoutInfoRPC {
227227
}
228228
}
229229

230+
#[derive(Debug, Copy, Clone, ZeroCopySend)]
231+
#[type_name("BidSourceInfoRPC")]
232+
#[repr(C)]
233+
pub struct BidSourceInfoRPC {
234+
pub seen_time_us: u64,
235+
pub relay: FixedSizeByteString<MAX_RELAY_NAME_LENGTH>,
236+
}
237+
238+
impl From<BidSourceInfo> for BidSourceInfoRPC {
239+
fn from(value: BidSourceInfo) -> Self {
240+
Self {
241+
seen_time_us: offset_datetime_to_timestamp_us(value.seen_time),
242+
relay: FixedSizeByteString::<MAX_RELAY_NAME_LENGTH>::from_str_truncated(&value.relay),
243+
}
244+
}
245+
}
246+
247+
impl From<BidSourceInfoRPC> for BidSourceInfo {
248+
fn from(value: BidSourceInfoRPC) -> Self {
249+
Self {
250+
seen_time: timestamp_us_to_offset_datetime(value.seen_time_us),
251+
relay: value.relay.to_string(),
252+
}
253+
}
254+
}
255+
256+
#[derive(Debug, Copy, Clone, ZeroCopySend)]
257+
#[type_name("BidWithInfoRPC")]
258+
#[repr(C)]
259+
pub struct BidWithInfoRPC {
260+
pub value: [u8; U256_DATA_LENGTH],
261+
pub info: BidSourceInfoRPC,
262+
}
263+
264+
impl From<BidWithInfo> for BidWithInfoRPC {
265+
fn from(bid_with_info: BidWithInfo) -> Self {
266+
Self {
267+
value: bid_with_info.value.to_le_bytes(),
268+
info: bid_with_info.info.into(),
269+
}
270+
}
271+
}
272+
273+
impl From<BidWithInfoRPC> for BidWithInfo {
274+
fn from(bid_with_info: BidWithInfoRPC) -> Self {
275+
Self {
276+
value: U256::from_le_bytes(bid_with_info.value),
277+
info: bid_with_info.info.into(),
278+
}
279+
}
280+
}
281+
282+
/// Context about the competitions bids that we used to generate our bid.
283+
#[derive(Debug, Copy, Clone, ZeroCopySend)]
284+
#[type_name("CompetitionBidContextRPC")]
285+
#[repr(C)]
286+
pub struct CompetitionBidContextRPC {
287+
pub seen_competition_bid: Option<BidWithInfoRPC>,
288+
pub triggering_bid_source_info: Option<BidSourceInfoRPC>,
289+
}
290+
291+
impl From<CompetitionBidContext> for CompetitionBidContextRPC {
292+
fn from(value: CompetitionBidContext) -> Self {
293+
Self {
294+
seen_competition_bid: value.seen_competition_bid.map(|k| k.into()),
295+
triggering_bid_source_info: value.triggering_bid_source_info.map(|k| k.into()),
296+
}
297+
}
298+
}
299+
300+
impl From<CompetitionBidContextRPC> for CompetitionBidContext {
301+
fn from(value: CompetitionBidContextRPC) -> Self {
302+
Self {
303+
seen_competition_bid: value.seen_competition_bid.map(|k| k.into()),
304+
triggering_bid_source_info: value.triggering_bid_source_info.map(|k| k.into()),
305+
}
306+
}
307+
}
308+
230309
#[derive(Debug, Copy, Clone, ZeroCopySend)]
231310
#[type_name("SlotBidderSealBidCommandRPC")]
232311
#[repr(C)]
233312
pub struct SlotBidderSealBidCommandRPC {
234313
pub session_id: u64,
235314
pub block_id: u64,
236-
pub seen_competition_bid: Option<[u8; U256_DATA_LENGTH]>,
315+
pub competition_bid_context: CompetitionBidContextRPC,
237316
/// When this bid is a reaction so some event (eg: new block, new competition bid) we put here
238317
/// the creation time of that event so we can measure our reaction time.
239318
pub trigger_creation_time_us: Option<u64>,
@@ -263,7 +342,7 @@ impl SlotBidderSealBidCommandRPC {
263342
Some(Self {
264343
session_id: value.1,
265344
block_id: value.0.block_id.0,
266-
seen_competition_bid: value.0.seen_competition_bid.map(|k| k.to_le_bytes()),
345+
competition_bid_context: value.0.competition_bid_context.into(),
267346
trigger_creation_time_us: value
268347
.0
269348
.trigger_creation_time
@@ -283,7 +362,7 @@ impl SlotBidderSealBidCommandRPC {
283362
}
284363
Some(SlotBidderSealBidCommand {
285364
block_id: BuiltBlockId(val.block_id),
286-
seen_competition_bid: val.seen_competition_bid.map(|k| U256::from_le_bytes(k)),
365+
competition_bid_context: val.competition_bid_context.into(),
287366
trigger_creation_time: val
288367
.trigger_creation_time_us
289368
.map(timestamp_us_to_offset_datetime),

crates/rbuilder-operator/src/clickhouse.rs

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Clickhouse integration to save all the blocks we build and submit to relays.
22
3-
use std::{sync::Arc, time::Duration};
3+
use std::{collections::HashMap, sync::Arc, time::Duration};
44

55
use alloy_primitives::{utils::format_ether, Address, U256};
66
use alloy_rpc_types_beacon::relay::SubmitBlockRequest as AlloySubmitBlockRequest;
@@ -31,6 +31,10 @@ use crate::{flashbots_config::BuiltBlocksClickhouseConfig, metrics::ClickhouseMe
3131
#[derive(Debug, Clone, Serialize, Deserialize, Row)]
3232
pub struct BlockRow {
3333
pub block_number: u64,
34+
pub block_id: u64,
35+
/// Number of times this block_id was used by the builder to bid before this.
36+
/// Starts with 0 on the first bid.
37+
pub block_uses: u64,
3438
/// name of the node that submitted the block
3539
pub builder_name: String,
3640
/// git commit of the rbuilder running
@@ -70,6 +74,15 @@ pub struct BlockRow {
7074
pub delayed_payment_addresses: Vec<String>,
7175
pub sent_to_relay_at: i64,
7276
pub tx_hashes: Vec<String>,
77+
78+
/// Info about the bid that triggered the bid to be generated.
79+
/// Notice this may not be the top bid since a builder lowering it's bid could trigger a new bid
80+
/// against the new winner.
81+
pub triggering_bid_seen_time: Option<i64>,
82+
pub triggering_bid_relay: Option<String>,
83+
/// Info about the top bid among all relays we are trying to beat (best_relay_value)
84+
pub bid_to_beat_seen_time: Option<i64>,
85+
pub bid_to_beat_seen_relay: Option<String>,
7386
}
7487

7588
impl ClickhouseRowExt for BlockRow {
@@ -231,7 +244,6 @@ impl BidObserver for BuiltBlocksWriter {
231244
submit_block_request: Arc<AlloySubmitBlockRequest>,
232245
built_block_trace: Arc<BuiltBlockTrace>,
233246
builder_algorithm_name: String,
234-
best_bid_value: U256,
235247
_relays: &RelaySet,
236248
sent_to_relay_at: OffsetDateTime,
237249
) {
@@ -241,6 +253,9 @@ impl BidObserver for BuiltBlocksWriter {
241253
let rbuilder_commit = self.rbuilder_commit.clone();
242254
let builder_name = self.builder_name.clone();
243255
tokio::spawn(async move {
256+
// How many times we submitted this block_id to the relay.
257+
let mut block_uses = HashMap::new();
258+
244259
let submit_trace = submit_block_request.bid_trace();
245260
let execution_payload_v1 = match submit_block_request.as_ref() {
246261
AlloySubmitBlockRequest::Capella(request) => {
@@ -277,8 +292,41 @@ impl BidObserver for BuiltBlocksWriter {
277292
.iter()
278293
.flat_map(|res| res.tx_infos.iter().map(|info| info.tx.hash().to_string()))
279294
.collect();
295+
let block_uses = block_uses
296+
.entry(built_block_trace.build_block_id)
297+
.or_insert(0);
298+
299+
let (triggering_bid_seen_time, triggering_bid_relay) = built_block_trace
300+
.competition_bid_context
301+
.triggering_bid_source_info
302+
.as_ref()
303+
.map(|info| {
304+
(
305+
Some(offset_date_to_clickhouse_timestamp(info.seen_time)),
306+
Some(info.relay.clone()),
307+
)
308+
})
309+
.unwrap_or_default();
310+
311+
let (bid_to_beat_seen_time, bid_to_beat_seen_relay, best_relay_value) =
312+
built_block_trace
313+
.competition_bid_context
314+
.seen_competition_bid
315+
.as_ref()
316+
.map(|bid_with_info| {
317+
(
318+
Some(offset_date_to_clickhouse_timestamp(
319+
bid_with_info.info.seen_time,
320+
)),
321+
Some(bid_with_info.info.relay.clone()),
322+
Some(bid_with_info.value),
323+
)
324+
})
325+
.unwrap_or_default();
326+
280327
let block_row = BlockRow {
281328
block_number,
329+
block_id: built_block_trace.build_block_id.0,
282330
builder_name,
283331
rbuilder_commit,
284332
profit: format_ether(submit_trace.value),
@@ -302,7 +350,7 @@ impl BidObserver for BuiltBlocksWriter {
302350
sealed_at: offset_date_to_clickhouse_timestamp(built_block_trace.orders_sealed_at),
303351
algorithm: builder_algorithm_name,
304352
true_value: Some(built_block_trace.true_bid_value),
305-
best_relay_value: Some(best_bid_value),
353+
best_relay_value,
306354
block_value: Some(submit_trace.value),
307355
used_bundle_hashes,
308356
used_bundle_uuids,
@@ -312,7 +360,14 @@ impl BidObserver for BuiltBlocksWriter {
312360
delayed_payment_addresses,
313361
sent_to_relay_at: offset_date_to_clickhouse_timestamp(sent_to_relay_at),
314362
tx_hashes,
363+
block_uses: *block_uses,
364+
triggering_bid_seen_time,
365+
triggering_bid_relay,
366+
bid_to_beat_seen_time,
367+
bid_to_beat_seen_relay,
315368
};
369+
*block_uses += 1;
370+
316371
if let Err(err) = blocks_tx.try_send(block_row) {
317372
error!(?err, "Failed to send block to clickhouse");
318373
}

crates/rbuilder-operator/src/flashbots_config.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
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;
65
use alloy_rpc_types_beacon::relay::SubmitBlockRequest as AlloySubmitBlockRequest;
76
use alloy_signer_local::PrivateKeySigner;
87
use derivative::Derivative;
@@ -458,7 +457,6 @@ impl BidObserver for RbuilderOperatorBidObserver {
458457
submit_block_request: Arc<AlloySubmitBlockRequest>,
459458
built_block_trace: Arc<BuiltBlockTrace>,
460459
builder_algorithm_name: String,
461-
best_bid_value: U256,
462460
relays: &RelaySet,
463461
sent_to_relay_at: OffsetDateTime,
464462
) {
@@ -468,7 +466,6 @@ impl BidObserver for RbuilderOperatorBidObserver {
468466
submit_block_request.clone(),
469467
built_block_trace.clone(),
470468
builder_algorithm_name.clone(),
471-
best_bid_value,
472469
relays,
473470
sent_to_relay_at,
474471
)
@@ -479,7 +476,6 @@ impl BidObserver for RbuilderOperatorBidObserver {
479476
submit_block_request,
480477
built_block_trace,
481478
builder_algorithm_name,
482-
best_bid_value,
483479
relays,
484480
sent_to_relay_at,
485481
)

crates/rbuilder-operator/src/true_block_value_push/best_true_value_observer.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ impl BidObserver for BestTrueValueObserver {
7979
_submit_block_request: Arc<AlloySubmitBlockRequest>,
8080
built_block_trace: Arc<BuiltBlockTrace>,
8181
builder_algorithm_name: String,
82-
_best_bid_value: alloy_primitives::U256,
8382
_relays: &RelaySet,
8483
_sent_to_relay_at: OffsetDateTime,
8584
) {

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::{
1818
FinalizeRevertStateCurrentIteration, NullPartialBlockExecutionTracer, PartialBlock,
1919
PartialBlockExecutionTracer, ThreadBlockBuildingContext,
2020
},
21+
live_builder::block_output::bidding_service_interface::CompetitionBidContext,
2122
telemetry::{self, add_block_fill_time, add_order_simulation_time},
2223
utils::{check_block_hash_reader_health, elapsed_ms, HistoricalBlockError},
2324
};
@@ -74,7 +75,7 @@ pub trait BlockBuildingHelper: Send + Sync {
7475
local_ctx: &mut ThreadBlockBuildingContext,
7576
payout_tx_value: U256,
7677
subsidy: I256,
77-
seen_competition_bid: Option<U256>,
78+
competition_bid_context: CompetitionBidContext,
7879
) -> Result<FinalizeBlockResult, BlockBuildingHelperError>;
7980

8081
/// BuiltBlockTrace for current state.
@@ -99,7 +100,7 @@ pub trait BlockBuildingHelper: Send + Sync {
99100
local_ctx: &mut ThreadBlockBuildingContext,
100101
payout_tx_value: U256,
101102
subsidy: I256,
102-
seen_competition_bid: Option<U256>,
103+
competition_bid_context: CompetitionBidContext,
103104
) -> Result<FinalizeBlockResult, BlockBuildingHelperError>;
104105
}
105106

@@ -381,7 +382,7 @@ impl<
381382
local_ctx: &mut ThreadBlockBuildingContext,
382383
payout_tx_value: U256,
383384
subsidy: I256,
384-
seen_competition_bid: Option<U256>,
385+
competition_bid_context: CompetitionBidContext,
385386
adjust_finalized_block: bool,
386387
) -> Result<FinalizeBlockResult, BlockBuildingHelperError> {
387388
if adjust_finalized_block != self.finalize_adjustment_state.is_some() {
@@ -463,7 +464,7 @@ impl<
463464
self.built_block_trace.root_hash_time = finalized_block.root_hash_time;
464465
self.built_block_trace.finalize_time = start_time.elapsed();
465466
}
466-
self.built_block_trace.seen_competition_bid = seen_competition_bid;
467+
self.built_block_trace.competition_bid_context = competition_bid_context;
467468
Self::trace_finalized_block(
468469
&finalized_block,
469470
&self.builder_name,
@@ -601,13 +602,13 @@ impl<
601602
local_ctx: &mut ThreadBlockBuildingContext,
602603
payout_tx_value: U256,
603604
subsidy: I256,
604-
seen_competition_bid: Option<U256>,
605+
competition_bid_context: CompetitionBidContext,
605606
) -> Result<FinalizeBlockResult, BlockBuildingHelperError> {
606607
self.finalize_block_impl(
607608
local_ctx,
608609
payout_tx_value,
609610
subsidy,
610-
seen_competition_bid,
611+
competition_bid_context,
611612
false,
612613
)
613614
}
@@ -642,13 +643,13 @@ impl<
642643
local_ctx: &mut ThreadBlockBuildingContext,
643644
payout_tx_value: U256,
644645
subsidy: I256,
645-
seen_competition_bid: Option<U256>,
646+
competition_bid_context: CompetitionBidContext,
646647
) -> Result<FinalizeBlockResult, BlockBuildingHelperError> {
647648
self.finalize_block_impl(
648649
local_ctx,
649650
payout_tx_value,
650651
subsidy,
651-
seen_competition_bid,
652+
competition_bid_context,
652653
true,
653654
)
654655
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ impl BlockBuildingHelper for BlockBuildingHelperStatsLogger<'_> {
209209
_local_ctx: &mut crate::building::ThreadBlockBuildingContext,
210210
_payout_tx_value: alloy_primitives::U256,
211211
_subsidy: alloy_primitives::I256,
212-
_seen_competition_bid: Option<alloy_primitives::U256>,
212+
_competition_bid_context: crate::live_builder::block_output::bidding_service_interface::CompetitionBidContext,
213213
) -> Result<FinalizeBlockResult, BlockBuildingHelperError> {
214214
panic!("finalize_block not implemented. This is only for testing.");
215215
}
@@ -240,7 +240,7 @@ impl BlockBuildingHelper for BlockBuildingHelperStatsLogger<'_> {
240240
_local_ctx: &mut ThreadBlockBuildingContext,
241241
_payout_tx_value: U256,
242242
_subsidy: I256,
243-
_seen_competition_bid: Option<U256>,
243+
_competition_bid_context: crate::live_builder::block_output::bidding_service_interface::CompetitionBidContext,
244244
) -> Result<FinalizeBlockResult, BlockBuildingHelperError> {
245245
unimplemented!()
246246
}

0 commit comments

Comments
 (0)