diff --git a/crates/rbuilder/benches/benchmarks/mev_boost.rs b/crates/rbuilder/benches/benchmarks/mev_boost.rs
index 25c1059ec..a1ef4ff82 100644
--- a/crates/rbuilder/benches/benchmarks/mev_boost.rs
+++ b/crates/rbuilder/benches/benchmarks/mev_boost.rs
@@ -10,6 +10,7 @@ use rbuilder::mev_boost::{
use reth::primitives::SealedBlock;
use reth_chainspec::SEPOLIA;
use reth_primitives::kzg::Blob;
+use ssz::Encode;
use std::{fs, path::PathBuf, sync::Arc};
fn mev_boost_serialize_submit_block(data: DenebSubmitBlockRequest) {
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 77784f96f..4406cab9e 100644
--- a/crates/rbuilder/src/live_builder/block_output/relay_submit.rs
+++ b/crates/rbuilder/src/live_builder/block_output/relay_submit.rs
@@ -8,10 +8,10 @@ use crate::{
},
primitives::mev_boost::{MevBoostRelayBidSubmitter, MevBoostRelayID},
telemetry::{
- add_relay_submit_time, add_subsidy_value, inc_conn_relay_errors,
- inc_failed_block_simulations, inc_initiated_submissions, inc_other_relay_errors,
- inc_relay_accepted_submissions, inc_subsidized_blocks, inc_too_many_req_relay_errors,
- mark_submission_start_time,
+ add_relay_submission_stats, add_relay_submit_time, add_subsidy_value,
+ inc_conn_relay_errors, inc_failed_block_simulations, inc_initiated_submissions,
+ inc_other_relay_errors, inc_relay_accepted_submissions, inc_subsidized_blocks,
+ inc_too_many_req_relay_errors, mark_submission_start_time,
},
utils::{duration_ms, error_storage::store_error_event},
};
@@ -203,6 +203,7 @@ async fn run_submit_to_relays_job(
top_competitor_bid: block.trace.seen_competition_bid,
},
order_ids: executed_orders.map(|o| o.id()).collect(),
+ sealed_at: block.trace.orders_sealed_at,
};
let submission_span = info_span!(
@@ -402,10 +403,11 @@ async fn submit_bid_to_the_relay(
};
let submit_time = submit_start.elapsed();
match relay_result {
- Ok(()) => {
+ Ok(stats) => {
trace!("Block submitted to the relay successfully");
add_relay_submit_time(relay.id(), submit_time);
inc_relay_accepted_submissions(relay.id(), optimistic);
+ add_relay_submission_stats(relay.id(), stats);
}
Err(SubmitBlockErr::PayloadDelivered | SubmitBlockErr::PastSlot) => {
trace!("Block already delivered by the relay, cancelling");
diff --git a/crates/rbuilder/src/live_builder/order_input/mod.rs b/crates/rbuilder/src/live_builder/order_input/mod.rs
index e5ebf9b59..6b96aeb19 100644
--- a/crates/rbuilder/src/live_builder/order_input/mod.rs
+++ b/crates/rbuilder/src/live_builder/order_input/mod.rs
@@ -20,7 +20,10 @@ use jsonrpsee::RpcModule;
use parking_lot::Mutex;
use std::{net::Ipv4Addr, path::PathBuf, sync::Arc, time::Duration};
use std::{path::Path, time::Instant};
-use tokio::{sync::mpsc, task::JoinHandle};
+use tokio::{
+ sync::mpsc,
+ task::{spawn_blocking, JoinHandle},
+};
use tokio_util::sync::CancellationToken;
use tracing::{debug, error, info, trace, warn};
@@ -202,7 +205,7 @@ pub async fn start_orderpool_jobs
(
header_receiver: mpsc::Receiver,
) -> eyre::Result<(JoinHandle<()>, OrderPoolSubscriber)>
where
- P: StateProviderFactory + 'static,
+ P: StateProviderFactory + Clone + 'static,
{
if config.ignore_cancellable_orders {
warn!("ignore_cancellable_orders is set to true, some order input is ignored");
@@ -332,7 +335,7 @@ async fn spawn_clean_orderpool_job(
global_cancellation: CancellationToken,
) -> eyre::Result>
where
- P: StateProviderFactory + 'static,
+ P: StateProviderFactory + Clone + 'static,
{
let mut header_receiver: mpsc::Receiver = header_receiver;
@@ -343,32 +346,38 @@ where
tokio::select! {
header = header_receiver.recv() => {
if let Some(header) = header {
- let current_block = header.number;
- set_current_block(current_block);
- let state = match provider_factory.latest() {
- Ok(state) => state,
- Err(err) => {
- error!("Failed to get latest state: {}", err);
- // @Metric error count
- continue;
- }
- };
-
- let mut orderpool = orderpool.lock();
- let start = Instant::now();
-
- orderpool.head_updated(current_block, &state);
-
- let update_time = start.elapsed();
- let (tx_count, bundle_count) = orderpool.content_count();
- set_ordepool_count(tx_count, bundle_count);
- debug!(
- current_block,
- tx_count,
- bundle_count,
- update_time_ms = update_time.as_millis(),
- "Cleaned orderpool",
- );
+ let provider_factory = provider_factory.clone();
+ let orderpool = orderpool.clone();
+ let res = spawn_blocking(move || {
+ let current_block = header.number;
+ set_current_block(current_block);
+ let state = match provider_factory.latest() {
+ Ok(state) => state,
+ Err(err) => {
+ error!(?err, "Failed to get latest state");
+ return;
+ }
+ };
+
+ let mut orderpool = orderpool.lock();
+ let start = Instant::now();
+
+ orderpool.head_updated(current_block, &state);
+
+ let update_time = start.elapsed();
+ let (tx_count, bundle_count) = orderpool.content_count();
+ set_ordepool_count(tx_count, bundle_count);
+ debug!(
+ current_block,
+ tx_count,
+ bundle_count,
+ update_time_ms = update_time.as_millis(),
+ "Cleaned orderpool",
+ );
+ }).await;
+ if let Err(err) = res {
+ error!(?err, "Clean orderpool error");
+ }
} else {
info!("Clean orderpool job: channel ended");
if !global_cancellation.is_cancelled(){
diff --git a/crates/rbuilder/src/mev_boost/mod.rs b/crates/rbuilder/src/mev_boost/mod.rs
index 2cf5b0d49..379aa20a8 100644
--- a/crates/rbuilder/src/mev_boost/mod.rs
+++ b/crates/rbuilder/src/mev_boost/mod.rs
@@ -5,6 +5,8 @@ pub mod rpc;
pub mod sign_payload;
pub mod submission;
+use crate::utils::{offset_datetime_to_timestamp_us, timestamp_now_us};
+
use super::utils::u256decimal_serde_helper;
use alloy_primitives::{Address, BlockHash, Bytes, U256};
@@ -18,8 +20,13 @@ use reqwest::{
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr};
use ssz::Encode;
-use std::{io::Write, str::FromStr};
+use std::{
+ io::Write,
+ str::FromStr,
+ time::{Duration, Instant},
+};
use submission::{SubmitBlockRequestNoBlobs, SubmitBlockRequestWithMetadata};
+use tokio::task::spawn_blocking;
use url::Url;
pub use error::*;
@@ -28,6 +35,8 @@ pub use sign_payload::*;
const TOTAL_PAYMENT_HEADER: &str = "Total-Payment";
const BUNDLE_HASHES_HEADER: &str = "Bundle-Hashes";
const TOP_BID_HEADER: &str = "Top-Bid";
+const SUBMIT_START_TIME_US: &str = "Submit-Start-Time-Us";
+const BLOCK_SEAL_TIME_US: &str = "Block-Seal-Time-Us";
const BLOXROUTE_SHARE_HEADER: &str = "share";
const BLOXROUTE_BUILDER_VALUE_HEADER: &str = "builder-value";
@@ -357,6 +366,22 @@ impl std::fmt::Debug for SubmitBlockErr {
}
}
+#[derive(Debug, Clone, Default)]
+pub struct RelaySubmitStats {
+ /// time spent between starting submission and doing request
+ pub send_preparation_time: Duration,
+ /// time spent compressing payload using gzip, its counted in send_preparation_time
+ pub send_compression_time: Duration,
+ /// time spent writing request
+ pub send_write_request_time: Duration,
+ /// time spent reading response
+ pub send_read_request_time: Duration,
+ /// size in bytes of original payload (before compression if present)
+ pub original_payload_size: usize,
+ /// size in bytes of sent payload (after compression if present)
+ pub sent_payload_size: usize,
+}
+
// Data API
impl RelayClient {
async fn get_one_delivered_payload(
@@ -508,7 +533,9 @@ impl RelayClient {
gzip: bool,
fake_relay: bool,
cancellations: bool,
+ stats: &mut RelaySubmitStats,
) -> Result {
+ let preparation_start = Instant::now();
let url = {
let mut url = self.url.clone();
url.set_path("/relay/v1/builder/blocks");
@@ -544,20 +571,28 @@ impl RelayClient {
self.add_auth_headers(&mut headers)
.map_err(|_| SubmitBlockErr::InvalidHeader)?;
+ stats.original_payload_size = body_data.len();
+ let compression_start = Instant::now();
// GZIP
if gzip {
headers.insert(
CONTENT_ENCODING,
HeaderValue::from_static(GZIP_CONTENT_ENCODING),
);
- let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
- encoder
- .write_all(&body_data)
- .map_err(|e| SubmitBlockErr::RPCSerializationError(e.to_string()))?;
- body_data = encoder
- .finish()
- .map_err(|e| SubmitBlockErr::RPCSerializationError(e.to_string()))?;
+ body_data = spawn_blocking(move || {
+ let mut encoder = GzEncoder::new(Vec::new(), Compression::fast());
+ encoder
+ .write_all(&body_data)
+ .map_err(|e| SubmitBlockErr::RPCSerializationError(e.to_string()))?;
+ encoder
+ .finish()
+ .map_err(|e| SubmitBlockErr::RPCSerializationError(e.to_string()))
+ })
+ .await
+ .map_err(|e| SubmitBlockErr::RPCSerializationError(e.to_string()))??;
}
+ stats.sent_payload_size = body_data.len();
+ stats.send_compression_time = compression_start.elapsed();
// Set bloxroute specific headers.
if self.is_bloxroute {
@@ -613,12 +648,24 @@ impl RelayClient {
};
builder = builder.header(BUNDLE_HASHES_HEADER, bundle_ids);
}
+
+ builder = builder
+ .header(SUBMIT_START_TIME_US, timestamp_now_us().to_string())
+ .header(
+ BLOCK_SEAL_TIME_US,
+ offset_datetime_to_timestamp_us(submission_with_metadata.metadata.sealed_at),
+ );
}
- Ok(builder
+ stats.send_preparation_time = preparation_start.elapsed();
+ let send_start = Instant::now();
+ let response = builder
.send()
.await
- .map_err(|e| RelayError::RequestError(e.into()))?)
+ .map_err(|e| RelayError::RequestError(e.into()))?;
+ stats.send_write_request_time = send_start.elapsed();
+
+ Ok(response)
}
/// Submits the block (call_relay_submit_block) and processes some special errors.
@@ -629,12 +676,19 @@ impl RelayClient {
gzip: bool,
fake_relay: bool,
cancellations: bool,
- ) -> Result<(), SubmitBlockErr> {
+ ) -> Result {
+ let mut stats = RelaySubmitStats::default();
let resp = self
- .call_relay_submit_block(data, ssz, gzip, fake_relay, cancellations)
+ .call_relay_submit_block(data, ssz, gzip, fake_relay, cancellations, &mut stats)
.await?;
+
+ let read_start = Instant::now();
let status = resp.status();
+ // always read full body to reuse TCP connection
+ let body_result = resp.bytes().await;
+ stats.send_read_request_time = read_start.elapsed();
+
if status == StatusCode::TOO_MANY_REQUESTS {
return Err(RelayError::TooManyRequests.into());
}
@@ -642,17 +696,14 @@ impl RelayClient {
return Err(RelayError::ConnectionError.into());
}
- let data = resp
- .bytes()
- .await
- .map_err(|e| RelayError::RequestError(e.into()))?;
+ let data = body_result.map_err(|e| RelayError::RequestError(e.into()))?;
if status == StatusCode::OK && data.as_ref() == b"" {
- return Ok(());
+ return Ok(stats);
}
match serde_json::from_slice::>(&data) {
- Ok(RelayResponse::Ok(_)) => Ok(()),
+ Ok(RelayResponse::Ok(_)) => Ok(stats),
Ok(RelayResponse::Error(error)) => {
let msg = error.message.as_str();
match msg {
@@ -690,11 +741,11 @@ impl RelayClient {
// bloxroute returns empty response in this format which we handle here because its not valid
// jsonrpc response
if data.as_ref() == b"{}\n" {
- return Ok(());
+ return Ok(stats);
}
let data_string = String::from_utf8_lossy(&data).to_string();
if is_ignorable_relay_error(status, &data_string) {
- Ok(())
+ Ok(stats)
} else {
Err(RelayError::UnknownRelayError(status, data_string).into())
}
@@ -725,6 +776,7 @@ impl RelayClient {
#[cfg(test)]
mod tests {
use submission::{BidMetadata, BidValueMetadata};
+ use time::OffsetDateTime;
use super::{rpc::TestDataGenerator, *};
use crate::mev_boost::{
@@ -884,6 +936,7 @@ mod tests {
top_competitor_bid: None,
},
order_ids: vec![],
+ sealed_at: OffsetDateTime::now_utc(),
},
};
relay
diff --git a/crates/rbuilder/src/mev_boost/submission.rs b/crates/rbuilder/src/mev_boost/submission.rs
index 10a5f12f5..29f06d524 100644
--- a/crates/rbuilder/src/mev_boost/submission.rs
+++ b/crates/rbuilder/src/mev_boost/submission.rs
@@ -8,6 +8,7 @@ use alloy_rpc_types_engine::{BlobsBundleV1, ExecutionPayloadV2, ExecutionPayload
use derive_more::Deref;
use serde::{Deserialize, Serialize};
use ssz::DecodeError;
+use time::OffsetDateTime;
use super::adjustment::BidAdjustmentData;
use crate::primitives::OrderId;
@@ -367,6 +368,7 @@ impl ssz::Decode for CapellaSubmitBlockRequest {
pub struct BidMetadata {
pub value: BidValueMetadata,
pub order_ids: Vec,
+ pub sealed_at: OffsetDateTime,
}
#[derive(Clone, Copy, Default, Debug)]
diff --git a/crates/rbuilder/src/primitives/mev_boost.rs b/crates/rbuilder/src/primitives/mev_boost.rs
index b72ed550c..19a49fea1 100644
--- a/crates/rbuilder/src/primitives/mev_boost.rs
+++ b/crates/rbuilder/src/primitives/mev_boost.rs
@@ -1,6 +1,6 @@
use crate::mev_boost::{
- submission::SubmitBlockRequestWithMetadata, RelayClient, RelayError, SubmitBlockErr,
- ValidatorSlotData,
+ submission::SubmitBlockRequestWithMetadata, RelayClient, RelayError, RelaySubmitStats,
+ SubmitBlockErr, ValidatorSlotData,
};
use alloy_primitives::{utils::parse_ether, Address, U256};
use governor::{DefaultDirectRateLimiter, Quota, RateLimiter};
@@ -192,7 +192,7 @@ impl MevBoostRelayBidSubmitter {
pub async fn submit_block(
&self,
data: &SubmitBlockRequestWithMetadata,
- ) -> Result<(), SubmitBlockErr> {
+ ) -> Result {
self.client
.submit_block(
data,
diff --git a/crates/rbuilder/src/telemetry/metrics/mod.rs b/crates/rbuilder/src/telemetry/metrics/mod.rs
index 68f90e30f..07b285744 100644
--- a/crates/rbuilder/src/telemetry/metrics/mod.rs
+++ b/crates/rbuilder/src/telemetry/metrics/mod.rs
@@ -9,6 +9,7 @@
use crate::{
building::BuiltBlockTrace,
live_builder::block_list_provider::{blocklist_hash, BlockList},
+ mev_boost::RelaySubmitStats,
primitives::mev_boost::MevBoostRelayID,
utils::{build_info::Version, duration_ms},
};
@@ -337,6 +338,23 @@ register_metrics! {
)
.unwrap();
+ /// Relay submission request
+
+ pub static RELAY_SUBMIT_BLOCK_SIZE: HistogramVec = HistogramVec::new(
+ HistogramOpts::new("relay_submit_block_size", "Size of the block that is submitted to the relay before and after compression. (bytes)")
+ .buckets(linear_buckets_range(1.0, 5_000_000.0, 500)),
+ &["compression"]
+ )
+ .unwrap();
+
+
+ pub static RELAY_SUBMIT_REQUEST_STEP_TIME: HistogramVec = HistogramVec::new(
+ HistogramOpts::new("relay_submit_request_step_time", "Time for different steps when doing request to the relay (ms)")
+ .buckets(exponential_buckets_range(0.01, 3000.0, 300)),
+ &["relay", "step"]
+ )
+ .unwrap();
+
}
// This function should be called periodically to reset histogram metrics.
@@ -375,6 +393,8 @@ pub fn reset_histogram_metrics() {
ORDER_SIM_END_TO_FIRST_BUILD_STARTED_MIN_TIME.reset();
BLOCK_FILL_START_SEAL_END_TIME.reset();
BLOCK_SEAL_END_SUBMIT_START_TIME.reset();
+ RELAY_SUBMIT_BLOCK_SIZE.reset();
+ RELAY_SUBMIT_REQUEST_STEP_TIME.reset();
}
pub(super) fn set_version(version: Version) {
@@ -521,6 +541,27 @@ pub fn add_relay_submit_time(relay: &MevBoostRelayID, duration: Duration) {
.observe(duration_ms(duration));
}
+pub fn add_relay_submission_stats(relay: &MevBoostRelayID, stats: RelaySubmitStats) {
+ RELAY_SUBMIT_BLOCK_SIZE
+ .with_label_values(&["false"])
+ .observe(stats.original_payload_size as f64);
+ RELAY_SUBMIT_BLOCK_SIZE
+ .with_label_values(&["true"])
+ .observe(stats.sent_payload_size as f64);
+ RELAY_SUBMIT_REQUEST_STEP_TIME
+ .with_label_values(&[relay.as_str(), "preparation"])
+ .observe(duration_ms(stats.send_preparation_time));
+ RELAY_SUBMIT_REQUEST_STEP_TIME
+ .with_label_values(&[relay.as_str(), "compression"])
+ .observe(duration_ms(stats.send_compression_time));
+ RELAY_SUBMIT_REQUEST_STEP_TIME
+ .with_label_values(&[relay.as_str(), "write"])
+ .observe(duration_ms(stats.send_write_request_time));
+ RELAY_SUBMIT_REQUEST_STEP_TIME
+ .with_label_values(&[relay.as_str(), "read"])
+ .observe(duration_ms(stats.send_read_request_time));
+}
+
const BIG_RPC_DATA_THRESHOLD: usize = 50000;
const BIG_RPC_DATA_TEXT: &str = ">50K";
const SMALL_RPC_DATA_TEXT: &str = "<=50K";
diff --git a/crates/rbuilder/src/utils/mod.rs b/crates/rbuilder/src/utils/mod.rs
index c8ee9aa50..7ba663759 100644
--- a/crates/rbuilder/src/utils/mod.rs
+++ b/crates/rbuilder/src/utils/mod.rs
@@ -113,6 +113,13 @@ pub fn timestamp_now_ms() -> u64 {
.unwrap_or_default()
}
+/// Returns unix timestamp in microseconds
+pub fn timestamp_now_us() -> u64 {
+ (time::OffsetDateTime::now_utc().unix_timestamp_nanos() / 1_000)
+ .try_into()
+ .unwrap_or_default()
+}
+
pub fn gen_uid() -> u64 {
rand::random()
}
diff --git a/crates/test-relay/src/main.rs b/crates/test-relay/src/main.rs
index 31d50dfb1..2b10dc9d6 100644
--- a/crates/test-relay/src/main.rs
+++ b/crates/test-relay/src/main.rs
@@ -1,6 +1,6 @@
use crate::validation_api_client::ValidationAPIClient;
use ahash::HashMap;
-use metrics::spawn_metrics_server;
+use metrics::{reset_histogram_metrics_test_relay, spawn_metrics_server};
use rbuilder::{
beacon_api_client::Client,
mev_boost::RelayClient,
@@ -8,7 +8,7 @@ use rbuilder::{
utils::tracing::{setup_tracing_subscriber, LoggerConfig},
};
use relay::spawn_relay_server;
-use std::net::SocketAddr;
+use std::{net::SocketAddr, time::Duration};
use tokio_util::sync::CancellationToken;
use url::Url;
@@ -19,6 +19,8 @@ pub mod metrics;
pub mod relay;
pub mod validation_api_client;
+const HISTOGRAM_RESET_TIME: Duration = Duration::from_secs(60 * 10); // 10 min
+
#[derive(Parser, Debug)]
struct Cli {
#[clap(
@@ -89,6 +91,11 @@ async fn main() -> eyre::Result<()> {
};
setup_tracing_subscriber(config)?;
+ tokio::spawn(async {
+ tokio::time::sleep(HISTOGRAM_RESET_TIME).await;
+ reset_histogram_metrics_test_relay();
+ });
+
spawn_metrics_server(cli.metrics_address);
let cl_clients = cli
diff --git a/crates/test-relay/src/metrics.rs b/crates/test-relay/src/metrics.rs
index 7491067b3..344b2677c 100644
--- a/crates/test-relay/src/metrics.rs
+++ b/crates/test-relay/src/metrics.rs
@@ -69,6 +69,12 @@ register_metrics! {
.buckets(exponential_buckets_range(1.0, 3000.0, 100)),
&[],
).unwrap();
+
+ pub static TIME_TO_RECEIVE: HistogramVec = HistogramVec::new(
+ HistogramOpts::new("time_to_receive", "Time from builder to relay receiving block (ms)")
+ .buckets(exponential_buckets_range(1.0, 10000.0, 500)),
+ &["builder", "kind"],
+ ).unwrap();
}
pub fn inc_payloads_received(builder: &str) {
@@ -107,6 +113,16 @@ pub fn add_payload_validation_time(duration: Duration) {
.observe(duration_ms(duration));
}
+pub fn add_time_to_receive(delta_us: u64, builder: &str, kind: &str) {
+ if delta_us == 0 {
+ return;
+ }
+
+ TIME_TO_RECEIVE
+ .with_label_values(&[builder, kind])
+ .observe(delta_us as f64 / 1000.0);
+}
+
pub fn spawn_metrics_server(address: SocketAddr) {
let metrics_route = warp::path!("debug" / "metrics" / "prometheus").and_then(metrics_handler);
tokio::spawn(warp::serve(metrics_route).run(address));
@@ -115,3 +131,10 @@ pub fn spawn_metrics_server(address: SocketAddr) {
async fn metrics_handler() -> Result {
Ok(gather_prometheus_metrics(®ISTRY))
}
+
+pub fn reset_histogram_metrics_test_relay() {
+ WINNER_ADVANTAGE.reset();
+ PAYLOAD_PROCESSING_TIME.reset();
+ PAYLOAD_VALIDATION_TIME.reset();
+ TIME_TO_RECEIVE.reset();
+}
diff --git a/crates/test-relay/src/relay.rs b/crates/test-relay/src/relay.rs
index 34f8eb90a..b24d636d2 100644
--- a/crates/test-relay/src/relay.rs
+++ b/crates/test-relay/src/relay.rs
@@ -1,7 +1,7 @@
use crate::{
metrics::{
- add_payload_processing_time, add_payload_validation_time, add_winning_bid,
- inc_payload_validation_errors, inc_payloads_received, inc_relay_errors,
+ add_payload_processing_time, add_payload_validation_time, add_time_to_receive,
+ add_winning_bid, inc_payload_validation_errors, inc_payloads_received, inc_relay_errors,
},
validation_api_client::{ValidationAPIClient, ValidationError},
};
@@ -18,6 +18,7 @@ use rbuilder::{
},
mev_boost::submission::SubmitBlockRequest,
primitives::mev_boost::MevBoostRelaySlotInfoProvider,
+ utils::timestamp_now_us,
};
use serde::{Deserialize, Serialize};
use ssz::Decode as _;
@@ -129,10 +130,25 @@ pub fn spawn_relay_server(
.and(body::bytes())
.and(warp::header::("content-type"))
.and(warp::header::optional::("content-encoding"))
+ .and(warp::header::optional::("Submit-Start-Time-Us"))
+ .and(warp::header::optional::("Block-Seal-Time-Us"))
.then(
- |state: RelayState, query, body, content_type, content_encoding| async move {
+ |state: RelayState,
+ query,
+ body,
+ content_type,
+ content_encoding,
+ submit_start_timestamp_us,
+ block_seal_timestamp_us| async move {
state
- .handle_block(query, body, content_type, content_encoding)
+ .handle_block(
+ query,
+ body,
+ content_type,
+ content_encoding,
+ submit_start_timestamp_us,
+ block_seal_timestamp_us,
+ )
.await
},
);
@@ -176,8 +192,12 @@ impl RelayState {
body: Bytes,
content_type: String,
content_encoding: Option,
+ submit_start_timestamp_us: Option,
+ block_seal_timestamp_us: Option,
) -> Box {
let processing_start = Instant::now();
+ let start_timestamp_us = timestamp_now_us();
+
let cancel = match query.cancellations {
Some(1) => true,
Some(0) | None => false,
@@ -240,6 +260,25 @@ impl RelayState {
inc_payloads_received(&builder_id);
+ if let Some(builder_ts) = block_seal_timestamp_us {
+ add_time_to_receive(
+ start_timestamp_us
+ .checked_sub(builder_ts)
+ .unwrap_or_default(),
+ &builder_id,
+ "seal_end",
+ );
+ }
+ if let Some(builder_ts) = submit_start_timestamp_us {
+ add_time_to_receive(
+ start_timestamp_us
+ .checked_sub(builder_ts)
+ .unwrap_or_default(),
+ &builder_id,
+ "submit_start",
+ );
+ }
+
let (withdrawals_root, registered_gas_limit, parent_beacon_block_root) = {
let pending_slot = self.pending_slot_data.lock();
let pending_slot = if pending_slot.is_some() {