1use std::time::Duration;
23use crate::EngineApiError;
4use alloy_rpc_types_engine::{ForkchoiceUpdated, PayloadStatus, PayloadStatusEnum};
5use metrics::{Counter, Gauge, Histogram};
6use reth_metrics::Metrics;
78/// All beacon consensus engine metrics
9#[derive(Default)]
10pub(crate) struct EngineApiMetrics {
11/// Engine API latency metrics
12pub(crate) latency: EngineApiLatencyMetrics,
13/// Engine API forkchoiceUpdated response type metrics
14pub(crate) fcu_response: ForkchoiceUpdatedResponseMetrics,
15/// Engine API newPayload response type metrics
16pub(crate) new_payload_response: NewPayloadStatusResponseMetrics,
17/// Blob-related metrics
18pub(crate) blob_metrics: BlobMetrics,
19}
2021/// Beacon consensus engine latency metrics.
22#[derive(Metrics)]
23#[metrics(scope = "engine.rpc")]
24pub(crate) struct EngineApiLatencyMetrics {
25/// Latency for `engine_newPayloadV1`
26pub(crate) new_payload_v1: Histogram,
27/// Latency for `engine_newPayloadV2`
28pub(crate) new_payload_v2: Histogram,
29/// Latency for `engine_newPayloadV3`
30pub(crate) new_payload_v3: Histogram,
31/// Latency for `engine_newPayloadV4`
32pub(crate) new_payload_v4: Histogram,
33/// Latency for `engine_forkchoiceUpdatedV1`
34pub(crate) fork_choice_updated_v1: Histogram,
35/// Latency for `engine_forkchoiceUpdatedV2`
36pub(crate) fork_choice_updated_v2: Histogram,
37/// Latency for `engine_forkchoiceUpdatedV3`
38pub(crate) fork_choice_updated_v3: Histogram,
39/// Time diff between `engine_newPayloadV*` and the next FCU
40pub(crate) new_payload_forkchoice_updated_time_diff: Histogram,
41/// Latency for `engine_getPayloadV1`
42pub(crate) get_payload_v1: Histogram,
43/// Latency for `engine_getPayloadV2`
44pub(crate) get_payload_v2: Histogram,
45/// Latency for `engine_getPayloadV3`
46pub(crate) get_payload_v3: Histogram,
47/// Latency for `engine_getPayloadV4`
48pub(crate) get_payload_v4: Histogram,
49/// Latency for `engine_getPayloadBodiesByRangeV1`
50pub(crate) get_payload_bodies_by_range_v1: Histogram,
51/// Latency for `engine_getPayloadBodiesByHashV1`
52pub(crate) get_payload_bodies_by_hash_v1: Histogram,
53/// Latency for `engine_exchangeTransitionConfigurationV1`
54pub(crate) exchange_transition_configuration: Histogram,
55/// Latency for `engine_getBlobsV1`
56pub(crate) get_blobs_v1: Histogram,
57}
5859/// 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.
64pub(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).
67pub(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).
70pub(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).
73pub(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).
76pub(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`].
79pub(crate) forkchoice_updated_error: Counter,
80}
8182/// 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.
87pub(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).
90pub(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).
93pub(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).
96pub(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).
99pub(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`].
102pub(crate) new_payload_error: Counter,
103/// The total gas of valid new payload messages received.
104pub(crate) new_payload_total_gas: Histogram,
105/// The gas per second of valid new payload messages received.
106pub(crate) new_payload_gas_per_second: Histogram,
107/// Latency for the last `engine_newPayloadV*` call
108pub(crate) new_payload_last: Gauge,
109}
110111#[derive(Metrics)]
112#[metrics(scope = "engine.rpc.blobs")]
113pub(crate) struct BlobMetrics {
114/// Count of blobs successfully retrieved
115pub(crate) blob_count: Counter,
116/// Count of blob misses
117pub(crate) blob_misses: Counter,
118}
119120impl NewPayloadStatusResponseMetrics {
121/// Increment the newPayload counter based on the given rpc result
122pub(crate) fn update_response_metrics(
123&self,
124 result: &Result<PayloadStatus, EngineApiError>,
125 gas_used: u64,
126 time: Duration,
127 ) {
128self.new_payload_last.set(time);
129match result {
130Ok(status) => match status.status {
131 PayloadStatusEnum::Valid => {
132self.new_payload_valid.increment(1);
133self.new_payload_total_gas.record(gas_usedas f64);
134self.new_payload_gas_per_second.record(gas_usedas 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 },
140Err(_) => self.new_payload_error.increment(1),
141 }
142self.new_payload_messages.increment(1);
143 }
144}
145146impl ForkchoiceUpdatedResponseMetrics {
147/// Increment the forkchoiceUpdated counter based on the given rpc result
148pub(crate) fn update_response_metrics(
149&self,
150 result: &Result<ForkchoiceUpdated, EngineApiError>,
151 ) {
152match result {
153Ok(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 },
159Err(_) => self.forkchoice_updated_error.increment(1),
160 }
161self.forkchoice_updated_messages.increment(1);
162 }
163}