reth_rpc_engine_api/
metrics.rs

1use std::time::Duration;
2
3use crate::EngineApiError;
4use alloy_rpc_types_engine::{ForkchoiceUpdated, PayloadStatus, PayloadStatusEnum};
5use metrics::{Counter, Gauge, Histogram};
6use reth_metrics::Metrics;
7
8/// All beacon consensus engine metrics
9#[derive(Default)]
10pub(crate) struct EngineApiMetrics {
11    /// Engine API latency metrics
12    pub(crate) latency: EngineApiLatencyMetrics,
13    /// Engine API forkchoiceUpdated response type metrics
14    pub(crate) fcu_response: ForkchoiceUpdatedResponseMetrics,
15    /// Engine API newPayload response type metrics
16    pub(crate) new_payload_response: NewPayloadStatusResponseMetrics,
17    /// Blob-related metrics
18    pub(crate) blob_metrics: BlobMetrics,
19}
20
21/// Beacon consensus engine latency metrics.
22#[derive(Metrics)]
23#[metrics(scope = "engine.rpc")]
24pub(crate) struct EngineApiLatencyMetrics {
25    /// Latency for `engine_newPayloadV1`
26    pub(crate) new_payload_v1: Histogram,
27    /// Latency for `engine_newPayloadV2`
28    pub(crate) new_payload_v2: Histogram,
29    /// Latency for `engine_newPayloadV3`
30    pub(crate) new_payload_v3: Histogram,
31    /// Latency for `engine_newPayloadV4`
32    pub(crate) new_payload_v4: Histogram,
33    /// Latency for `engine_forkchoiceUpdatedV1`
34    pub(crate) fork_choice_updated_v1: Histogram,
35    /// Latency for `engine_forkchoiceUpdatedV2`
36    pub(crate) fork_choice_updated_v2: Histogram,
37    /// Latency for `engine_forkchoiceUpdatedV3`
38    pub(crate) fork_choice_updated_v3: Histogram,
39    /// Time diff between `engine_newPayloadV*` and the next FCU
40    pub(crate) new_payload_forkchoice_updated_time_diff: Histogram,
41    /// Latency for `engine_getPayloadV1`
42    pub(crate) get_payload_v1: Histogram,
43    /// Latency for `engine_getPayloadV2`
44    pub(crate) get_payload_v2: Histogram,
45    /// Latency for `engine_getPayloadV3`
46    pub(crate) get_payload_v3: Histogram,
47    /// Latency for `engine_getPayloadV4`
48    pub(crate) get_payload_v4: Histogram,
49    /// Latency for `engine_getPayloadBodiesByRangeV1`
50    pub(crate) get_payload_bodies_by_range_v1: Histogram,
51    /// Latency for `engine_getPayloadBodiesByHashV1`
52    pub(crate) get_payload_bodies_by_hash_v1: Histogram,
53    /// Latency for `engine_exchangeTransitionConfigurationV1`
54    pub(crate) exchange_transition_configuration: Histogram,
55    /// Latency for `engine_getBlobsV1`
56    pub(crate) get_blobs_v1: Histogram,
57}
58
59/// Metrics for engine API forkchoiceUpdated responses.
60#[derive(Metrics)]
61#[metrics(scope = "engine.rpc")]
62pub(crate) struct ForkchoiceUpdatedResponseMetrics {
63    /// The total count of forkchoice updated messages received.
64    pub(crate) forkchoice_updated_messages: Counter,
65    /// The total count of forkchoice updated messages that we responded to with
66    /// [`Invalid`](alloy_rpc_types_engine::PayloadStatusEnum#Invalid).
67    pub(crate) forkchoice_updated_invalid: Counter,
68    /// The total count of forkchoice updated messages that we responded to with
69    /// [`Valid`](alloy_rpc_types_engine::PayloadStatusEnum#Valid).
70    pub(crate) forkchoice_updated_valid: Counter,
71    /// The total count of forkchoice updated messages that we responded to with
72    /// [`Syncing`](alloy_rpc_types_engine::PayloadStatusEnum#Syncing).
73    pub(crate) forkchoice_updated_syncing: Counter,
74    /// The total count of forkchoice updated messages that we responded to with
75    /// [`Accepted`](alloy_rpc_types_engine::PayloadStatusEnum#Accepted).
76    pub(crate) forkchoice_updated_accepted: Counter,
77    /// The total count of forkchoice updated messages that were unsuccessful, i.e. we responded
78    /// with an error type that is not a [`PayloadStatusEnum`].
79    pub(crate) forkchoice_updated_error: Counter,
80}
81
82/// Metrics for engine API newPayload responses.
83#[derive(Metrics)]
84#[metrics(scope = "engine.rpc")]
85pub(crate) struct NewPayloadStatusResponseMetrics {
86    /// The total count of new payload messages received.
87    pub(crate) new_payload_messages: Counter,
88    /// The total count of new payload messages that we responded to with
89    /// [Invalid](alloy_rpc_types_engine::PayloadStatusEnum#Invalid).
90    pub(crate) new_payload_invalid: Counter,
91    /// The total count of new payload messages that we responded to with
92    /// [Valid](alloy_rpc_types_engine::PayloadStatusEnum#Valid).
93    pub(crate) new_payload_valid: Counter,
94    /// The total count of new payload messages that we responded to with
95    /// [Syncing](alloy_rpc_types_engine::PayloadStatusEnum#Syncing).
96    pub(crate) new_payload_syncing: Counter,
97    /// The total count of new payload messages that we responded to with
98    /// [Accepted](alloy_rpc_types_engine::PayloadStatusEnum#Accepted).
99    pub(crate) new_payload_accepted: Counter,
100    /// The total count of new payload messages that were unsuccessful, i.e. we responded with an
101    /// error type that is not a [`PayloadStatusEnum`].
102    pub(crate) new_payload_error: Counter,
103    /// The total gas of valid new payload messages received.
104    pub(crate) new_payload_total_gas: Histogram,
105    /// The gas per second of valid new payload messages received.
106    pub(crate) new_payload_gas_per_second: Histogram,
107    /// Latency for the last `engine_newPayloadV*` call
108    pub(crate) new_payload_last: Gauge,
109}
110
111#[derive(Metrics)]
112#[metrics(scope = "engine.rpc.blobs")]
113pub(crate) struct BlobMetrics {
114    /// Count of blobs successfully retrieved
115    pub(crate) blob_count: Counter,
116    /// Count of blob misses
117    pub(crate) blob_misses: Counter,
118}
119
120impl NewPayloadStatusResponseMetrics {
121    /// Increment the newPayload counter based on the given rpc result
122    pub(crate) fn update_response_metrics(
123        &self,
124        result: &Result<PayloadStatus, EngineApiError>,
125        gas_used: u64,
126        time: Duration,
127    ) {
128        self.new_payload_last.set(time);
129        match result {
130            Ok(status) => match status.status {
131                PayloadStatusEnum::Valid => {
132                    self.new_payload_valid.increment(1);
133                    self.new_payload_total_gas.record(gas_used as f64);
134                    self.new_payload_gas_per_second.record(gas_used as f64 / time.as_secs_f64());
135                }
136                PayloadStatusEnum::Syncing => self.new_payload_syncing.increment(1),
137                PayloadStatusEnum::Accepted => self.new_payload_accepted.increment(1),
138                PayloadStatusEnum::Invalid { .. } => self.new_payload_invalid.increment(1),
139            },
140            Err(_) => self.new_payload_error.increment(1),
141        }
142        self.new_payload_messages.increment(1);
143    }
144}
145
146impl ForkchoiceUpdatedResponseMetrics {
147    /// Increment the forkchoiceUpdated counter based on the given rpc result
148    pub(crate) fn update_response_metrics(
149        &self,
150        result: &Result<ForkchoiceUpdated, EngineApiError>,
151    ) {
152        match result {
153            Ok(status) => match status.payload_status.status {
154                PayloadStatusEnum::Valid => self.forkchoice_updated_valid.increment(1),
155                PayloadStatusEnum::Syncing => self.forkchoice_updated_syncing.increment(1),
156                PayloadStatusEnum::Accepted => self.forkchoice_updated_accepted.increment(1),
157                PayloadStatusEnum::Invalid { .. } => self.forkchoice_updated_invalid.increment(1),
158            },
159            Err(_) => self.forkchoice_updated_error.increment(1),
160        }
161        self.forkchoice_updated_messages.increment(1);
162    }
163}