reth_network/metrics.rs
1use metrics::Histogram;
2use reth_eth_wire::DisconnectReason;
3use reth_ethereum_primitives::TxType;
4use reth_metrics::{
5 metrics::{Counter, Gauge},
6 Metrics,
7};
8
9/// Scope for monitoring transactions sent from the manager to the tx manager
10pub(crate) const NETWORK_POOL_TRANSACTIONS_SCOPE: &str = "network.pool.transactions";
11
12/// Metrics for the entire network, handled by `NetworkManager`
13#[derive(Metrics)]
14#[metrics(scope = "network")]
15pub struct NetworkMetrics {
16 /// Number of currently connected peers
17 pub(crate) connected_peers: Gauge,
18
19 /// Number of currently backed off peers
20 pub(crate) backed_off_peers: Gauge,
21
22 /// Number of peers known to the node
23 pub(crate) tracked_peers: Gauge,
24
25 /// Number of active incoming connections
26 pub(crate) incoming_connections: Gauge,
27
28 /// Number of active outgoing connections
29 pub(crate) outgoing_connections: Gauge,
30
31 /// Number of currently pending outgoing connections
32 pub(crate) pending_outgoing_connections: Gauge,
33
34 /// Total number of pending connections, incoming and outgoing.
35 pub(crate) total_pending_connections: Gauge,
36
37 /// Total Number of incoming connections handled
38 pub(crate) total_incoming_connections: Counter,
39
40 /// Total Number of outgoing connections established
41 pub(crate) total_outgoing_connections: Counter,
42
43 /// Number of invalid/malformed messages received from peers
44 pub(crate) invalid_messages_received: Counter,
45
46 /// Number of Eth Requests dropped due to channel being at full capacity
47 pub(crate) total_dropped_eth_requests_at_full_capacity: Counter,
48
49 /// Number of transaction events dropped due to the tx manager channel being at full capacity
50 pub(crate) total_dropped_tx_events_at_full_capacity: Counter,
51
52 /* ================ POLL DURATION ================ */
53
54 /* -- Total poll duration of `NetworksManager` future -- */
55 /// Duration in seconds of call to
56 /// [`NetworkManager`](crate::NetworkManager)'s poll function.
57 ///
58 /// True duration of this call, should be sum of the accumulated durations of calling nested
59 // items.
60 pub(crate) duration_poll_network_manager: Gauge,
61
62 /* -- Poll duration of items nested in `NetworkManager` future -- */
63 /// Time spent streaming messages sent over the [`NetworkHandle`](crate::NetworkHandle), which
64 /// can be cloned and shared via [`NetworkManager::handle`](crate::NetworkManager::handle), in
65 /// one call to poll the [`NetworkManager`](crate::NetworkManager) future. At least
66 /// [`TransactionsManager`](crate::transactions::TransactionsManager) holds this handle.
67 ///
68 /// Duration in seconds.
69 pub(crate) acc_duration_poll_network_handle: Gauge,
70 /// Time spent polling [`Swarm`](crate::swarm::Swarm), in one call to poll the
71 /// [`NetworkManager`](crate::NetworkManager) future.
72 ///
73 /// Duration in seconds.
74 pub(crate) acc_duration_poll_swarm: Gauge,
75}
76
77/// Metrics for closed sessions, split by direction.
78#[derive(Debug)]
79pub struct ClosedSessionsMetrics {
80 /// Sessions closed from active (established) connections.
81 pub active: Counter,
82 /// Sessions closed from incoming pending connections.
83 pub incoming_pending: Counter,
84 /// Sessions closed from outgoing pending connections.
85 pub outgoing_pending: Counter,
86}
87
88impl Default for ClosedSessionsMetrics {
89 fn default() -> Self {
90 Self {
91 active: metrics::counter!("network_closed_sessions", "direction" => "active"),
92 incoming_pending: metrics::counter!("network_closed_sessions", "direction" => "incoming_pending"),
93 outgoing_pending: metrics::counter!("network_closed_sessions", "direction" => "outgoing_pending"),
94 }
95 }
96}
97
98/// Metrics for pending session failures, split by direction.
99#[derive(Debug)]
100pub struct PendingSessionFailureMetrics {
101 /// Failures on incoming pending sessions.
102 pub inbound: Counter,
103 /// Failures on outgoing pending sessions.
104 pub outbound: Counter,
105}
106
107impl Default for PendingSessionFailureMetrics {
108 fn default() -> Self {
109 Self {
110 inbound: metrics::counter!("network_pending_session_failures", "direction" => "inbound"),
111 outbound: metrics::counter!("network_pending_session_failures", "direction" => "outbound"),
112 }
113 }
114}
115
116/// Metrics for backed off peers, split by reason.
117#[derive(Metrics)]
118#[metrics(scope = "network.backed_off_peers")]
119pub struct BackedOffPeersMetrics {
120 /// Peers backed off because they reported too many peers.
121 pub too_many_peers: Counter,
122 /// Peers backed off after a graceful session close.
123 pub graceful_close: Counter,
124 /// Peers backed off due to connection or protocol errors.
125 pub connection_error: Counter,
126}
127
128impl BackedOffPeersMetrics {
129 /// Increments the counter for the given backoff reason.
130 pub fn increment_for_reason(&self, reason: crate::peers::BackoffReason) {
131 match reason {
132 crate::peers::BackoffReason::TooManyPeers => self.too_many_peers.increment(1),
133 crate::peers::BackoffReason::GracefulClose => self.graceful_close.increment(1),
134 crate::peers::BackoffReason::ConnectionError => self.connection_error.increment(1),
135 }
136 }
137}
138
139/// Metrics for `SessionManager`
140#[derive(Metrics)]
141#[metrics(scope = "network")]
142pub struct SessionManagerMetrics {
143 /// Number of successful outgoing dial attempts.
144 pub(crate) total_dial_successes: Counter,
145 /// Number of dropped outgoing peer messages.
146 pub(crate) total_outgoing_peer_messages_dropped: Counter,
147 /// Number of queued outgoing messages
148 pub(crate) queued_outgoing_messages: Gauge,
149 /// Total number of broadcast messages sent via the unbounded overflow channel.
150 pub(crate) total_unbounded_broadcast_msgs: Counter,
151}
152
153/// Metrics for the [`TransactionsManager`](crate::transactions::TransactionsManager).
154#[derive(Metrics)]
155#[metrics(scope = "network")]
156pub struct TransactionsManagerMetrics {
157 /* ================ BROADCAST ================ */
158 /// Total number of propagated transactions
159 pub(crate) propagated_transactions: Counter,
160 /// Total number of reported bad transactions
161 pub(crate) reported_bad_transactions: Counter,
162
163 /* -- Freq txns already marked as seen by peer -- */
164 /// Total number of messages from a peer, announcing transactions that have already been
165 /// marked as seen by that peer.
166 pub(crate) messages_with_hashes_already_seen_by_peer: Counter,
167 /// Total number of messages from a peer, with transaction that have already been marked as
168 /// seen by that peer.
169 pub(crate) messages_with_transactions_already_seen_by_peer: Counter,
170 /// Total number of occurrences, of a peer announcing a transaction that has already been
171 /// marked as seen by that peer.
172 pub(crate) occurrences_hash_already_seen_by_peer: Counter,
173 /// Total number of times a transaction is seen from a peer, that has already been marked as
174 /// seen by that peer.
175 pub(crate) occurrences_of_transaction_already_seen_by_peer: Counter,
176
177 /* -- Freq txns already in pool -- */
178 /// Total number of times a hash is announced that is already in the local pool.
179 pub(crate) occurrences_hashes_already_in_pool: Counter,
180 /// Total number of times a transaction is sent that is already in the local pool.
181 pub(crate) occurrences_transactions_already_in_pool: Counter,
182
183 /* ================ POOL IMPORTS ================ */
184 /// Number of transactions about to be imported into the pool.
185 pub(crate) pending_pool_imports: Gauge,
186 /// Total number of bad imports, imports that fail because the transaction is badly formed
187 /// (i.e. have no chance of passing validation, unlike imports that fail due to e.g. nonce
188 /// gaps).
189 pub(crate) bad_imports: Counter,
190 /// Number of inflight requests at which the
191 /// [`TransactionPool`](reth_transaction_pool::TransactionPool) is considered to be at
192 /// capacity. Note, this is not a limit to the number of inflight requests, but a health
193 /// measure.
194 pub(crate) capacity_pending_pool_imports: Counter,
195 /// Total number of transactions ignored because pending pool imports are at capacity.
196 pub(crate) skipped_transactions_pending_pool_imports_at_capacity: Counter,
197 /// The time it took to prepare transactions for import. This is mostly sender recovery.
198 pub(crate) pool_import_prepare_duration: Histogram,
199
200 /* ================ POLL DURATION ================ */
201
202 /* -- Total poll duration of `TransactionsManager` future -- */
203 /// Duration in seconds of call to
204 /// [`TransactionsManager`](crate::transactions::TransactionsManager)'s poll function.
205 ///
206 /// Updating metrics could take time, so the true duration of this call could
207 /// be longer than the sum of the accumulated durations of polling nested items.
208 pub(crate) duration_poll_tx_manager: Gauge,
209
210 /* -- Poll duration of items nested in `TransactionsManager` future -- */
211 /// Accumulated time spent streaming session updates and updating peers accordingly, in
212 /// one call to poll the [`TransactionsManager`](crate::transactions::TransactionsManager)
213 /// future.
214 ///
215 /// Duration in seconds.
216 pub(crate) acc_duration_poll_network_events: Gauge,
217 /// Accumulated time spent flushing the queue of batched pending pool imports into pool, in
218 /// one call to poll the [`TransactionsManager`](crate::transactions::TransactionsManager)
219 /// future.
220 ///
221 /// Duration in seconds.
222 pub(crate) acc_duration_poll_pending_pool_imports: Gauge,
223 /// Accumulated time spent streaming transaction and announcement broadcast, queueing for
224 /// pool import or requesting respectively, in one call to poll the
225 /// [`TransactionsManager`](crate::transactions::TransactionsManager) future.
226 ///
227 /// Duration in seconds.
228 pub(crate) acc_duration_poll_transaction_events: Gauge,
229 /// Accumulated time spent streaming fetch events, queueing for pool import on successful
230 /// fetch, in one call to poll the
231 /// [`TransactionsManager`](crate::transactions::TransactionsManager) future.
232 ///
233 /// Duration in seconds.
234 pub(crate) acc_duration_poll_fetch_events: Gauge,
235 /// Accumulated time spent streaming and propagating transactions that were successfully
236 /// imported into the pool, in one call to poll the
237 /// [`TransactionsManager`](crate::transactions::TransactionsManager) future.
238 ///
239 /// Duration in seconds.
240 pub(crate) acc_duration_poll_imported_transactions: Gauge,
241 /// Accumulated time spent assembling and sending requests for hashes fetching pending, in
242 /// one call to poll the [`TransactionsManager`](crate::transactions::TransactionsManager)
243 /// future.
244 ///
245 /// Duration in seconds.
246 pub(crate) acc_duration_fetch_pending_hashes: Gauge,
247 /// Accumulated time spent streaming commands and propagating, fetching and serving
248 /// transactions accordingly, in one call to poll the
249 /// [`TransactionsManager`](crate::transactions::TransactionsManager) future.
250 ///
251 /// Duration in seconds.
252 pub(crate) acc_duration_poll_commands: Gauge,
253}
254
255/// Metrics for the [`TransactionsManager`](crate::transactions::TransactionsManager).
256#[derive(Metrics)]
257#[metrics(scope = "network")]
258pub struct TransactionFetcherMetrics {
259 /// Currently active outgoing [`GetPooledTransactions`](reth_eth_wire::GetPooledTransactions)
260 /// requests.
261 pub(crate) inflight_transaction_requests: Gauge,
262 /// Number of inflight requests at which the
263 /// [`TransactionFetcher`](crate::transactions::TransactionFetcher) is considered to be at
264 /// capacity. Note, this is not a limit to the number of inflight requests, but a health
265 /// measure.
266 pub(crate) capacity_inflight_requests: Counter,
267 /// Hashes in currently active outgoing
268 /// [`GetPooledTransactions`](reth_eth_wire::GetPooledTransactions) requests.
269 pub(crate) hashes_inflight_transaction_requests: Gauge,
270 /// How often we failed to send a request to the peer because the channel was full.
271 pub(crate) egress_peer_channel_full: Counter,
272 /// Total number of hashes pending fetch.
273 pub(crate) hashes_pending_fetch: Gauge,
274 /// Total number of fetched transactions.
275 pub(crate) fetched_transactions: Counter,
276 /// Total number of transactions that were received in
277 /// [`PooledTransactions`](reth_eth_wire::PooledTransactions) responses, that weren't
278 /// requested.
279 pub(crate) unsolicited_transactions: Counter,
280 /* ================ SEARCH DURATION ================ */
281 /// Time spent searching for an idle peer in call to
282 /// [`TransactionFetcher::find_any_idle_fallback_peer_for_any_pending_hash`](crate::transactions::TransactionFetcher::find_any_idle_fallback_peer_for_any_pending_hash).
283 ///
284 /// Duration in seconds.
285 pub(crate) duration_find_idle_fallback_peer_for_any_pending_hash: Gauge,
286
287 /// Time spent searching for hashes pending fetch, announced by a given peer in
288 /// [`TransactionFetcher::fill_request_from_hashes_pending_fetch`](crate::transactions::TransactionFetcher::fill_request_from_hashes_pending_fetch).
289 ///
290 /// Duration in seconds.
291 pub(crate) duration_fill_request_from_hashes_pending_fetch: Gauge,
292}
293
294/// Measures the duration of executing the given code block. The duration is added to the given
295/// accumulator value passed as a mutable reference.
296#[macro_export]
297macro_rules! duration_metered_exec {
298 ($code:expr, $acc:expr) => {{
299 let start = reth_primitives_traits::FastInstant::now();
300
301 let res = $code;
302
303 $acc += start.elapsed();
304
305 res
306 }};
307}
308
309/// Direction-aware wrapper for disconnect metrics.
310///
311/// Tracks disconnect reasons for inbound and outbound connections separately, in addition to
312/// the combined (legacy) counters.
313#[derive(Debug, Default)]
314pub(crate) struct DirectionalDisconnectMetrics {
315 /// Combined disconnect metrics (all directions).
316 pub(crate) total: DisconnectMetrics,
317 /// Disconnect metrics for inbound connections only.
318 pub(crate) inbound: InboundDisconnectMetrics,
319 /// Disconnect metrics for outbound connections only.
320 pub(crate) outbound: OutboundDisconnectMetrics,
321}
322
323impl DirectionalDisconnectMetrics {
324 /// Increments disconnect counters for an inbound connection.
325 pub(crate) fn increment_inbound(&self, reason: DisconnectReason) {
326 self.total.increment(reason);
327 self.inbound.increment(reason);
328 }
329
330 /// Increments disconnect counters for an outbound connection.
331 pub(crate) fn increment_outbound(&self, reason: DisconnectReason) {
332 self.total.increment(reason);
333 self.outbound.increment(reason);
334 }
335}
336
337/// Metrics for Disconnection types
338///
339/// These are just counters, and ideally we would implement these metrics on a peer-by-peer basis,
340/// in that we do not double-count peers for `TooManyPeers` if we make an outgoing connection and
341/// get disconnected twice
342#[derive(Metrics)]
343#[metrics(scope = "network")]
344pub struct DisconnectMetrics {
345 /// Number of peer disconnects due to `DisconnectRequested` (0x00)
346 pub(crate) disconnect_requested: Counter,
347
348 /// Number of peer disconnects due to `TcpSubsystemError` (0x01)
349 pub(crate) tcp_subsystem_error: Counter,
350
351 /// Number of peer disconnects due to `ProtocolBreach` (0x02)
352 pub(crate) protocol_breach: Counter,
353
354 /// Number of peer disconnects due to `UselessPeer` (0x03)
355 pub(crate) useless_peer: Counter,
356
357 /// Number of peer disconnects due to `TooManyPeers` (0x04)
358 pub(crate) too_many_peers: Counter,
359
360 /// Number of peer disconnects due to `AlreadyConnected` (0x05)
361 pub(crate) already_connected: Counter,
362
363 /// Number of peer disconnects due to `IncompatibleP2PProtocolVersion` (0x06)
364 pub(crate) incompatible: Counter,
365
366 /// Number of peer disconnects due to `NullNodeIdentity` (0x07)
367 pub(crate) null_node_identity: Counter,
368
369 /// Number of peer disconnects due to `ClientQuitting` (0x08)
370 pub(crate) client_quitting: Counter,
371
372 /// Number of peer disconnects due to `UnexpectedHandshakeIdentity` (0x09)
373 pub(crate) unexpected_identity: Counter,
374
375 /// Number of peer disconnects due to `ConnectedToSelf` (0x0a)
376 pub(crate) connected_to_self: Counter,
377
378 /// Number of peer disconnects due to `PingTimeout` (0x0b)
379 pub(crate) ping_timeout: Counter,
380
381 /// Number of peer disconnects due to `SubprotocolSpecific` (0x10)
382 pub(crate) subprotocol_specific: Counter,
383}
384
385impl DisconnectMetrics {
386 /// Increments the proper counter for the given disconnect reason
387 pub(crate) fn increment(&self, reason: DisconnectReason) {
388 match reason {
389 DisconnectReason::DisconnectRequested => self.disconnect_requested.increment(1),
390 DisconnectReason::TcpSubsystemError => self.tcp_subsystem_error.increment(1),
391 DisconnectReason::ProtocolBreach => self.protocol_breach.increment(1),
392 DisconnectReason::UselessPeer => self.useless_peer.increment(1),
393 DisconnectReason::TooManyPeers => self.too_many_peers.increment(1),
394 DisconnectReason::AlreadyConnected => self.already_connected.increment(1),
395 DisconnectReason::IncompatibleP2PProtocolVersion => self.incompatible.increment(1),
396 DisconnectReason::NullNodeIdentity => self.null_node_identity.increment(1),
397 DisconnectReason::ClientQuitting => self.client_quitting.increment(1),
398 DisconnectReason::UnexpectedHandshakeIdentity => self.unexpected_identity.increment(1),
399 DisconnectReason::ConnectedToSelf => self.connected_to_self.increment(1),
400 DisconnectReason::PingTimeout => self.ping_timeout.increment(1),
401 DisconnectReason::SubprotocolSpecific => self.subprotocol_specific.increment(1),
402 }
403 }
404}
405
406/// Disconnect metrics scoped to inbound connections only.
407///
408/// These counters track disconnect reasons exclusively for sessions that were initiated by
409/// remote peers connecting to this node. This helps operators distinguish between being rejected
410/// by remote peers (outbound) vs rejecting incoming peers (inbound).
411#[derive(Metrics)]
412#[metrics(scope = "network.inbound")]
413pub struct InboundDisconnectMetrics {
414 /// Number of inbound peer disconnects due to `DisconnectRequested` (0x00)
415 pub(crate) disconnect_requested: Counter,
416
417 /// Number of inbound peer disconnects due to `TcpSubsystemError` (0x01)
418 pub(crate) tcp_subsystem_error: Counter,
419
420 /// Number of inbound peer disconnects due to `ProtocolBreach` (0x02)
421 pub(crate) protocol_breach: Counter,
422
423 /// Number of inbound peer disconnects due to `UselessPeer` (0x03)
424 pub(crate) useless_peer: Counter,
425
426 /// Number of inbound peer disconnects due to `TooManyPeers` (0x04)
427 pub(crate) too_many_peers: Counter,
428
429 /// Number of inbound peer disconnects due to `AlreadyConnected` (0x05)
430 pub(crate) already_connected: Counter,
431
432 /// Number of inbound peer disconnects due to `IncompatibleP2PProtocolVersion` (0x06)
433 pub(crate) incompatible: Counter,
434
435 /// Number of inbound peer disconnects due to `NullNodeIdentity` (0x07)
436 pub(crate) null_node_identity: Counter,
437
438 /// Number of inbound peer disconnects due to `ClientQuitting` (0x08)
439 pub(crate) client_quitting: Counter,
440
441 /// Number of inbound peer disconnects due to `UnexpectedHandshakeIdentity` (0x09)
442 pub(crate) unexpected_identity: Counter,
443
444 /// Number of inbound peer disconnects due to `ConnectedToSelf` (0x0a)
445 pub(crate) connected_to_self: Counter,
446
447 /// Number of inbound peer disconnects due to `PingTimeout` (0x0b)
448 pub(crate) ping_timeout: Counter,
449
450 /// Number of inbound peer disconnects due to `SubprotocolSpecific` (0x10)
451 pub(crate) subprotocol_specific: Counter,
452}
453
454impl InboundDisconnectMetrics {
455 /// Increments the proper counter for the given disconnect reason
456 pub(crate) fn increment(&self, reason: DisconnectReason) {
457 match reason {
458 DisconnectReason::DisconnectRequested => self.disconnect_requested.increment(1),
459 DisconnectReason::TcpSubsystemError => self.tcp_subsystem_error.increment(1),
460 DisconnectReason::ProtocolBreach => self.protocol_breach.increment(1),
461 DisconnectReason::UselessPeer => self.useless_peer.increment(1),
462 DisconnectReason::TooManyPeers => self.too_many_peers.increment(1),
463 DisconnectReason::AlreadyConnected => self.already_connected.increment(1),
464 DisconnectReason::IncompatibleP2PProtocolVersion => self.incompatible.increment(1),
465 DisconnectReason::NullNodeIdentity => self.null_node_identity.increment(1),
466 DisconnectReason::ClientQuitting => self.client_quitting.increment(1),
467 DisconnectReason::UnexpectedHandshakeIdentity => self.unexpected_identity.increment(1),
468 DisconnectReason::ConnectedToSelf => self.connected_to_self.increment(1),
469 DisconnectReason::PingTimeout => self.ping_timeout.increment(1),
470 DisconnectReason::SubprotocolSpecific => self.subprotocol_specific.increment(1),
471 }
472 }
473}
474
475/// Disconnect metrics scoped to outbound connections only.
476///
477/// These counters track disconnect reasons exclusively for sessions that this node initiated
478/// by dialing out to remote peers. A high `too_many_peers` count here indicates remote peers
479/// are rejecting our connection attempts because they are full.
480#[derive(Metrics)]
481#[metrics(scope = "network.outbound")]
482pub struct OutboundDisconnectMetrics {
483 /// Number of outbound peer disconnects due to `DisconnectRequested` (0x00)
484 pub(crate) disconnect_requested: Counter,
485
486 /// Number of outbound peer disconnects due to `TcpSubsystemError` (0x01)
487 pub(crate) tcp_subsystem_error: Counter,
488
489 /// Number of outbound peer disconnects due to `ProtocolBreach` (0x02)
490 pub(crate) protocol_breach: Counter,
491
492 /// Number of outbound peer disconnects due to `UselessPeer` (0x03)
493 pub(crate) useless_peer: Counter,
494
495 /// Number of outbound peer disconnects due to `TooManyPeers` (0x04)
496 pub(crate) too_many_peers: Counter,
497
498 /// Number of outbound peer disconnects due to `AlreadyConnected` (0x05)
499 pub(crate) already_connected: Counter,
500
501 /// Number of outbound peer disconnects due to `IncompatibleP2PProtocolVersion` (0x06)
502 pub(crate) incompatible: Counter,
503
504 /// Number of outbound peer disconnects due to `NullNodeIdentity` (0x07)
505 pub(crate) null_node_identity: Counter,
506
507 /// Number of outbound peer disconnects due to `ClientQuitting` (0x08)
508 pub(crate) client_quitting: Counter,
509
510 /// Number of outbound peer disconnects due to `UnexpectedHandshakeIdentity` (0x09)
511 pub(crate) unexpected_identity: Counter,
512
513 /// Number of outbound peer disconnects due to `ConnectedToSelf` (0x0a)
514 pub(crate) connected_to_self: Counter,
515
516 /// Number of outbound peer disconnects due to `PingTimeout` (0x0b)
517 pub(crate) ping_timeout: Counter,
518
519 /// Number of outbound peer disconnects due to `SubprotocolSpecific` (0x10)
520 pub(crate) subprotocol_specific: Counter,
521}
522
523impl OutboundDisconnectMetrics {
524 /// Increments the proper counter for the given disconnect reason
525 pub(crate) fn increment(&self, reason: DisconnectReason) {
526 match reason {
527 DisconnectReason::DisconnectRequested => self.disconnect_requested.increment(1),
528 DisconnectReason::TcpSubsystemError => self.tcp_subsystem_error.increment(1),
529 DisconnectReason::ProtocolBreach => self.protocol_breach.increment(1),
530 DisconnectReason::UselessPeer => self.useless_peer.increment(1),
531 DisconnectReason::TooManyPeers => self.too_many_peers.increment(1),
532 DisconnectReason::AlreadyConnected => self.already_connected.increment(1),
533 DisconnectReason::IncompatibleP2PProtocolVersion => self.incompatible.increment(1),
534 DisconnectReason::NullNodeIdentity => self.null_node_identity.increment(1),
535 DisconnectReason::ClientQuitting => self.client_quitting.increment(1),
536 DisconnectReason::UnexpectedHandshakeIdentity => self.unexpected_identity.increment(1),
537 DisconnectReason::ConnectedToSelf => self.connected_to_self.increment(1),
538 DisconnectReason::PingTimeout => self.ping_timeout.increment(1),
539 DisconnectReason::SubprotocolSpecific => self.subprotocol_specific.increment(1),
540 }
541 }
542}
543
544/// Metrics for the `EthRequestHandler`
545#[derive(Metrics)]
546#[metrics(scope = "network")]
547pub struct EthRequestHandlerMetrics {
548 /// Number of `GetBlockHeaders` requests received
549 pub(crate) eth_headers_requests_received_total: Counter,
550
551 /// Number of `GetReceipts` requests received
552 pub(crate) eth_receipts_requests_received_total: Counter,
553
554 /// Number of `GetBlockBodies` requests received
555 pub(crate) eth_bodies_requests_received_total: Counter,
556
557 /// Number of `GetNodeData` requests received
558 pub(crate) eth_node_data_requests_received_total: Counter,
559
560 /// Duration in seconds of call to poll
561 /// [`EthRequestHandler`](crate::eth_requests::EthRequestHandler).
562 pub(crate) acc_duration_poll_eth_req_handler: Gauge,
563}
564
565/// Eth67 announcement metrics, track entries by `TxType`
566#[derive(Metrics)]
567#[metrics(scope = "network.transaction_fetcher")]
568pub struct AnnouncedTxTypesMetrics {
569 /// Histogram for tracking frequency of legacy transaction type
570 pub(crate) legacy: Histogram,
571
572 /// Histogram for tracking frequency of EIP-2930 transaction type
573 pub(crate) eip2930: Histogram,
574
575 /// Histogram for tracking frequency of EIP-1559 transaction type
576 pub(crate) eip1559: Histogram,
577
578 /// Histogram for tracking frequency of EIP-4844 transaction type
579 pub(crate) eip4844: Histogram,
580
581 /// Histogram for tracking frequency of EIP-7702 transaction type
582 pub(crate) eip7702: Histogram,
583
584 /// Histogram for tracking frequency of unknown/other transaction types
585 pub(crate) other: Histogram,
586}
587
588/// Counts the number of transactions by their type in a block or collection.
589///
590/// This struct keeps track of the count of different transaction types
591/// as defined by various Ethereum Improvement Proposals (EIPs).
592#[derive(Debug, Default)]
593pub struct TxTypesCounter {
594 /// Count of legacy transactions (pre-EIP-2718).
595 pub(crate) legacy: usize,
596
597 /// Count of transactions conforming to EIP-2930 (Optional access lists).
598 pub(crate) eip2930: usize,
599
600 /// Count of transactions conforming to EIP-1559 (Fee market change).
601 pub(crate) eip1559: usize,
602
603 /// Count of transactions conforming to EIP-4844 (Shard Blob Transactions).
604 pub(crate) eip4844: usize,
605
606 /// Count of transactions conforming to EIP-7702 (Restricted Storage Windows).
607 pub(crate) eip7702: usize,
608
609 /// Count of unknown/other transaction types not matching any known EIP.
610 pub(crate) other: usize,
611}
612
613impl TxTypesCounter {
614 pub(crate) const fn increase_by_tx_type(&mut self, tx_type: TxType) {
615 match tx_type {
616 TxType::Legacy => {
617 self.legacy += 1;
618 }
619 TxType::Eip2930 => {
620 self.eip2930 += 1;
621 }
622 TxType::Eip1559 => {
623 self.eip1559 += 1;
624 }
625 TxType::Eip4844 => {
626 self.eip4844 += 1;
627 }
628 TxType::Eip7702 => {
629 self.eip7702 += 1;
630 }
631 }
632 }
633
634 pub(crate) const fn increase_other(&mut self) {
635 self.other += 1;
636 }
637}
638
639impl AnnouncedTxTypesMetrics {
640 /// Update metrics during announcement validation, by examining each announcement entry based on
641 /// `TxType`
642 pub(crate) fn update_eth68_announcement_metrics(&self, tx_types_counter: TxTypesCounter) {
643 self.legacy.record(tx_types_counter.legacy as f64);
644 self.eip2930.record(tx_types_counter.eip2930 as f64);
645 self.eip1559.record(tx_types_counter.eip1559 as f64);
646 self.eip4844.record(tx_types_counter.eip4844 as f64);
647 self.eip7702.record(tx_types_counter.eip7702 as f64);
648 self.other.record(tx_types_counter.other as f64);
649 }
650}