diff --git a/crates/rbuilder-primitives/src/mev_boost/mod.rs b/crates/rbuilder-primitives/src/mev_boost/mod.rs index 073a9f6ca..9372855f3 100644 --- a/crates/rbuilder-primitives/src/mev_boost/mod.rs +++ b/crates/rbuilder-primitives/src/mev_boost/mod.rs @@ -203,6 +203,7 @@ pub struct BloxrouteRegionalEndpoint { #[derive(Clone, Debug)] pub struct BidMetadata { + pub sequence: u64, pub value: BidValueMetadata, pub order_ids: Vec, pub bundle_hashes: Vec, diff --git a/crates/rbuilder-primitives/src/mev_boost/submit_header.rs b/crates/rbuilder-primitives/src/mev_boost/submit_header.rs index 961bccd13..70f625135 100644 --- a/crates/rbuilder-primitives/src/mev_boost/submit_header.rs +++ b/crates/rbuilder-primitives/src/mev_boost/submit_header.rs @@ -1,12 +1,22 @@ use crate::mev_boost::{ adjustment::BidAdjustmentDataV2, ssz_roots::{calculate_transactions_root_ssz, calculate_withdrawals_root_ssz}, + BidMetadata, }; use alloy_primitives::{Address, Bloom, Bytes, B256, U256}; use alloy_rpc_types_beacon::{relay::BidTrace, requests::ExecutionRequestsV4, BlsSignature}; use alloy_rpc_types_engine::ExecutionPayloadV3; use serde_with::{serde_as, DisplayFromStr}; +/// Optimistic V3 bid submission with metadata. +#[derive(Clone, Debug)] +pub struct SubmitHeaderRequestWithMetadata { + /// Header submission. + pub submission: SubmitHeaderRequest, + /// Bid metadata. + pub metadata: BidMetadata, +} + /// Optimistic V3 bid submission. #[derive( PartialEq, @@ -18,7 +28,7 @@ use serde_with::{serde_as, DisplayFromStr}; ssz_derive::Encode, ssz_derive::Decode, )] -pub struct HeaderSubmissionOptimisticV3 { +pub struct SubmitHeaderRequest { /// URL pointing to the builder's server endpoint for retrieving /// the full block payload if this header is selected. pub url: Vec, 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 9a52f3676..71e206d7a 100644 --- a/crates/rbuilder/src/live_builder/block_output/relay_submit.rs +++ b/crates/rbuilder/src/live_builder/block_output/relay_submit.rs @@ -23,13 +23,14 @@ use rbuilder_primitives::{ built_block::{block_to_execution_payload, SignedBuiltBlock}, mev_boost::{ BidAdjustmentData, BidMetadata, BidValueMetadata, ExecutionPayloadHeaderElectra, - HeaderSubmission, HeaderSubmissionElectra, HeaderSubmissionOptimisticV3, MevBoostRelayID, - SignedHeaderSubmission, SubmitBlockRequest, SubmitBlockRequestWithMetadata, - ValidatorSlotData, + HeaderSubmission, HeaderSubmissionElectra, MevBoostRelayID, SignedHeaderSubmission, + SubmitBlockRequest, SubmitBlockRequestWithMetadata, SubmitHeaderRequest, + SubmitHeaderRequestWithMetadata, ValidatorSlotData, }, }; use reth_chainspec::ChainSpec; use std::sync::Arc; +use time::OffsetDateTime; use tokio::{ sync::{broadcast, Notify}, time::Instant, @@ -192,12 +193,15 @@ async fn run_submit_to_relays_job( } }); + // SAFETY: UNIX timestamp in nanos won't exceed u64::MAX until year 2554 + let sequence = OffsetDateTime::now_utc().unix_timestamp_nanos() as u64; let executed_orders = block .trace .included_orders .iter() .flat_map(|exec_res| exec_res.order.original_orders()); let bid_metadata = BidMetadata { + sequence, value: BidValueMetadata { coinbase_reward: block.trace.coinbase_reward, top_competitor_bid: block.trace.seen_competition_bid, @@ -362,7 +366,7 @@ fn create_optimistic_v3_request( request: &SubmitBlockRequest, maybe_adjustment_data: Option<&BidAdjustmentData>, adjustment_data_required: bool, -) -> eyre::Result { +) -> eyre::Result { let maybe_adjustment_data_v2 = maybe_adjustment_data.map(|d| d.clone().into_v2()); if maybe_adjustment_data_v2.is_none() && adjustment_data_required { eyre::bail!("adjustment data is required") @@ -393,7 +397,7 @@ fn create_optimistic_v3_request( }; let tx_count = request.execution_payload_v1().transactions.len(); - Ok(HeaderSubmissionOptimisticV3 { + Ok(SubmitHeaderRequest { url: builder_url.to_vec(), tx_count: tx_count as u32, submission: SignedHeaderSubmission { @@ -444,7 +448,10 @@ fn submit_block_to_relays( maybe_adjustment_data, relay.optimistic_v3_bid_adjustment_required(), ) - .map(|request| (config.clone(), request)) + .map(|request| (config.clone(), SubmitHeaderRequestWithMetadata { + submission: request, + metadata: bid_metadata.clone() + })) .inspect_err(|error| { error!(parent: submission_span, ?error, "Unable to create optimistic V3 request"); }) @@ -489,7 +496,7 @@ fn submit_block_to_relays( async fn submit_bid_to_the_relay( relay: &MevBoostRelayBidSubmitter, submit_block_request: SubmitBlockRequestWithMetadata, - optimistic_v3_request: Option<(OptimisticV3Config, HeaderSubmissionOptimisticV3)>, + optimistic_v3_request: Option<(OptimisticV3Config, SubmitHeaderRequestWithMetadata)>, registration: ValidatorSlotData, optimistic: bool, cancel: CancellationToken, diff --git a/crates/rbuilder/src/mev_boost/mod.rs b/crates/rbuilder/src/mev_boost/mod.rs index 0b418bc41..2b00c9772 100644 --- a/crates/rbuilder/src/mev_boost/mod.rs +++ b/crates/rbuilder/src/mev_boost/mod.rs @@ -4,8 +4,8 @@ use alloy_rpc_types_beacon::BlsPublicKey; use flate2::{write::GzEncoder, Compression}; use governor::{DefaultDirectRateLimiter, Quota, RateLimiter}; use rbuilder_primitives::mev_boost::{ - HeaderSubmissionOptimisticV3, KnownRelay, MevBoostRelayID, RelayMode, - SubmitBlockRequestNoBlobs, SubmitBlockRequestWithMetadata, ValidatorRegistration, + KnownRelay, MevBoostRelayID, RelayMode, SubmitBlockRequestNoBlobs, + SubmitBlockRequestWithMetadata, SubmitHeaderRequestWithMetadata, ValidatorRegistration, ValidatorSlotData, MEV_BOOST_SLOT_INFO_REQUEST_TIMEOUT, }; use reqwest::{ @@ -35,6 +35,7 @@ const BUNDLE_HASHES_HEADER: &str = "Bundle-Hashes"; const TOP_BID_HEADER: &str = "Top-Bid"; const BLOXROUTE_SHARE_HEADER: &str = "share"; const BLOXROUTE_BUILDER_VALUE_HEADER: &str = "builder-value"; +const X_SEQUENCE_HEADER: &str = "x-sequence"; const JSON_CONTENT_TYPE: &str = "application/json"; const SSZ_CONTENT_TYPE: &str = "application/octet-stream"; @@ -335,7 +336,7 @@ impl MevBoostRelayBidSubmitter { pub async fn submit_optimistic_v3( &self, - data: HeaderSubmissionOptimisticV3, + data: SubmitHeaderRequestWithMetadata, registration: ValidatorSlotData, ) -> Result<(), SubmitBlockErr> { self.client @@ -692,6 +693,7 @@ impl RelayClient { } = submission_with_metadata; let mut headers = HeaderMap::new(); + headers.insert(X_SEQUENCE_HEADER, metadata.sequence.into()); self.add_auth_headers(&mut headers) .map_err(|_| SubmitBlockErr::InvalidHeader)?; @@ -889,11 +891,17 @@ impl RelayClient { pub async fn submit_optimistic_v3( &self, - request: &HeaderSubmissionOptimisticV3, + request: &SubmitHeaderRequestWithMetadata, registration: &ValidatorSlotData, cancellations: bool, ) -> Result<(), SubmitBlockErr> { + let SubmitHeaderRequestWithMetadata { + submission, + metadata, + } = request; + let mut headers = HeaderMap::new(); + headers.insert(X_SEQUENCE_HEADER, metadata.sequence.into()); self.add_auth_headers(&mut headers) .map_err(|_| SubmitBlockErr::InvalidHeader)?; @@ -902,7 +910,7 @@ impl RelayClient { url.query_pairs_mut() .append_pair("cancellations", if cancellations { "1" } else { "0" }); - let body = request.as_ssz_bytes(); + let body = submission.as_ssz_bytes(); headers.insert(CONTENT_TYPE, HeaderValue::from_static(SSZ_CONTENT_TYPE)); let response = self @@ -1262,6 +1270,7 @@ mod tests { let sub_relay = SubmitBlockRequestWithMetadata { submission, metadata: BidMetadata { + sequence: 0, value: BidValueMetadata { coinbase_reward: Default::default(), top_competitor_bid: None,