diff --git a/Cargo.lock b/Cargo.lock index d3fcd59e79..0f6a62647a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8790,6 +8790,7 @@ dependencies = [ "jsonrpsee-core", "jsonrpsee-types", "metrics", + "parking_lot", "reth-beacon-consensus", "reth-chainspec", "reth-engine-primitives", diff --git a/crates/rpc/rpc-engine-api/Cargo.toml b/crates/rpc/rpc-engine-api/Cargo.toml index 00503f2c1d..62d1eea322 100644 --- a/crates/rpc/rpc-engine-api/Cargo.toml +++ b/crates/rpc/rpc-engine-api/Cargo.toml @@ -45,6 +45,7 @@ jsonrpsee-types.workspace = true serde.workspace = true thiserror.workspace = true tracing.workspace = true +parking_lot.workspace = true [dev-dependencies] reth-ethereum-engine-primitives.workspace = true diff --git a/crates/rpc/rpc-engine-api/src/engine_api.rs b/crates/rpc/rpc-engine-api/src/engine_api.rs index 20eeb390ac..a017c50678 100644 --- a/crates/rpc/rpc-engine-api/src/engine_api.rs +++ b/crates/rpc/rpc-engine-api/src/engine_api.rs @@ -10,6 +10,7 @@ use alloy_rpc_types_engine::{ }; use async_trait::async_trait; use jsonrpsee_core::RpcResult; +use parking_lot::Mutex; use reth_beacon_consensus::BeaconConsensusEngineHandle; use reth_chainspec::{EthereumHardforks, Hardforks}; use reth_engine_primitives::{EngineTypes, EngineValidator}; @@ -67,6 +68,8 @@ struct EngineApiInner>, } impl @@ -102,6 +105,7 @@ where capabilities, tx_pool, validator, + latest_new_payload_response: Mutex::new(None), }); Self { inner } } @@ -140,11 +144,13 @@ where self.inner .validator .validate_version_specific_fields(EngineApiMessageVersion::V1, payload_or_attrs)?; + Ok(self .inner .beacon_consensus .new_payload(payload, ExecutionPayloadSidecar::none()) - .await?) + .await + .inspect(|_| self.inner.on_new_payload_response())?) } /// See also @@ -164,7 +170,8 @@ where .inner .beacon_consensus .new_payload(payload, ExecutionPayloadSidecar::none()) - .await?) + .await + .inspect(|_| self.inner.on_new_payload_response())?) } /// See also @@ -194,7 +201,8 @@ where parent_beacon_block_root, }), ) - .await?) + .await + .inspect(|_| self.inner.on_new_payload_response())?) } /// See also @@ -225,7 +233,8 @@ where execution_requests, ), ) - .await?) + .await + .inspect(|_| self.inner.on_new_payload_response())?) } /// Sends a message to the beacon consensus engine to update the fork choice _without_ @@ -598,6 +607,8 @@ where state: ForkchoiceState, payload_attrs: Option, ) -> EngineApiResult { + self.inner.record_elapsed_time_on_fcu(); + if let Some(ref attrs) = payload_attrs { let attr_validation_res = self.inner.validator.ensure_well_formed_attributes(version, attrs); @@ -631,6 +642,26 @@ where } } +impl + EngineApiInner +where + EngineT: EngineTypes, +{ + /// Tracks the elapsed time between the new payload response and the received forkchoice update + /// request. + fn record_elapsed_time_on_fcu(&self) { + if let Some(start_time) = self.latest_new_payload_response.lock().take() { + let elapsed_time = start_time.elapsed(); + self.metrics.latency.new_payload_forkchoice_updated_time_diff.record(elapsed_time); + } + } + + /// Updates the timestamp for the latest new payload response. + fn on_new_payload_response(&self) { + self.latest_new_payload_response.lock().replace(Instant::now()); + } +} + #[async_trait] impl EngineApiServer for EngineApi diff --git a/crates/rpc/rpc-engine-api/src/metrics.rs b/crates/rpc/rpc-engine-api/src/metrics.rs index 8d0106f9dd..9325ce2677 100644 --- a/crates/rpc/rpc-engine-api/src/metrics.rs +++ b/crates/rpc/rpc-engine-api/src/metrics.rs @@ -34,6 +34,8 @@ pub(crate) struct EngineApiLatencyMetrics { pub(crate) fork_choice_updated_v2: Histogram, /// Latency for `engine_forkchoiceUpdatedV3` pub(crate) fork_choice_updated_v3: Histogram, + /// Time diff between `engine_newPayloadV*` and the next FCU + pub(crate) new_payload_forkchoice_updated_time_diff: Histogram, /// Latency for `engine_getPayloadV1` pub(crate) get_payload_v1: Histogram, /// Latency for `engine_getPayloadV2`