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