1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//! Tracks peer discovery for [`Discv5`](crate::Discv5).
use metrics::{Counter, Gauge};
use reth_metrics::Metrics;

use crate::NetworkStackId;

/// Information tracked by [`Discv5`](crate::Discv5).
#[derive(Debug, Default, Clone)]
pub struct Discv5Metrics {
    /// Frequency of networks advertised in discovered peers' node records.
    pub discovered_peers_advertised_networks: AdvertisedChainMetrics,
    /// Tracks discovered peers.
    pub discovered_peers: DiscoveredPeersMetrics,
}

/// Tracks discovered peers.
#[derive(Metrics, Clone)]
#[metrics(scope = "discv5")]
pub struct DiscoveredPeersMetrics {
    ////////////////////////////////////////////////////////////////////////////////////////////////
    // Kbuckets
    ////////////////////////////////////////////////////////////////////////////////////////////////
    /// Total peers currently in [`discv5::Discv5`]'s kbuckets.
    kbucket_peers_raw_total: Gauge,
    /// Total discovered peers that are inserted into [`discv5::Discv5`]'s kbuckets.
    ///
    /// This is a subset of the total established sessions, in which all peers advertise a udp
    /// socket in their node record which is reachable from the local node. Only these peers make
    /// it into [`discv5::Discv5`]'s kbuckets and will hence be included in queries.
    ///
    /// Note: the definition of 'discovered' is not exactly synonymous in `reth_discv4::Discv4`.
    inserted_kbucket_peers_raw_total: Counter,

    ////////////////////////////////////////////////////////////////////////////////////////////////
    // Sessions
    ////////////////////////////////////////////////////////////////////////////////////////////////
    /// Total peers currently connected to [`discv5::Discv5`].
    sessions_raw_total: Gauge,
    /// Total number of sessions established by [`discv5::Discv5`].
    established_sessions_raw_total: Counter,
    /// Total number of sessions established by [`discv5::Discv5`], with peers that don't advertise
    /// a socket which is reachable from the local node in their node record.
    ///
    /// These peers can't make it into [`discv5::Discv5`]'s kbuckets, and hence won't be part of
    /// queries (neither shared with peers in NODES responses, nor queried for peers with FINDNODE
    /// requests).
    established_sessions_unreachable_enr_total: Counter,
    /// Total number of sessions established by [`discv5::Discv5`], that pass configured
    /// [`filter`](crate::filter) rules.
    established_sessions_custom_filtered_total: Counter,
    /// Total number of unverifiable ENRs discovered by [`discv5::Discv5`].
    ///
    /// These are peers that fail [`discv5::Discv5`] session establishment, because the UDP socket
    /// they're making a connection from doesn't match the UDP socket advertised in their ENR.
    /// These peers will be denied a session (and hence can't make it into kbuckets) until they
    /// have update their ENR, to reflect their actual UDP socket.
    unverifiable_enrs_raw_total: Counter,
}

impl DiscoveredPeersMetrics {
    /// Sets current total number of peers in [`discv5::Discv5`]'s kbuckets.
    pub fn set_total_kbucket_peers(&self, num: usize) {
        self.kbucket_peers_raw_total.set(num as f64)
    }

    /// Increments the number of kbucket insertions in [`discv5::Discv5`].
    pub fn increment_kbucket_insertions(&self, num: u64) {
        self.inserted_kbucket_peers_raw_total.increment(num)
    }

    /// Sets current total number of peers connected to [`discv5::Discv5`].
    pub fn set_total_sessions(&self, num: usize) {
        self.sessions_raw_total.set(num as f64)
    }

    /// Increments number of sessions established by [`discv5::Discv5`].
    pub fn increment_established_sessions_raw(&self, num: u64) {
        self.established_sessions_raw_total.increment(num)
    }

    /// Increments number of sessions established by [`discv5::Discv5`], with peers that don't have
    /// a reachable node record.
    pub fn increment_established_sessions_unreachable_enr(&self, num: u64) {
        self.established_sessions_unreachable_enr_total.increment(num)
    }

    /// Increments number of sessions established by [`discv5::Discv5`], that pass configured
    /// [`filter`](crate::filter) rules.
    pub fn increment_established_sessions_filtered(&self, num: u64) {
        self.established_sessions_custom_filtered_total.increment(num)
    }

    /// Increments number of unverifiable ENRs discovered by [`discv5::Discv5`]. These are peers
    /// that fail session establishment because their advertised UDP socket doesn't match the
    /// socket they are making the connection from.
    pub fn increment_unverifiable_enrs_raw_total(&self, num: u64) {
        self.unverifiable_enrs_raw_total.increment(num)
    }
}

/// Tracks frequency of networks that are advertised by discovered peers.
///
/// Peers advertise the chain they belong to as a kv-pair in their node record, using the network
/// as key.
#[derive(Metrics, Clone)]
#[metrics(scope = "discv5")]
pub struct AdvertisedChainMetrics {
    /// Frequency of node records with a kv-pair with [`OPEL`](NetworkStackId::OPEL) as
    /// key.
    opel: Counter,

    /// Frequency of node records with a kv-pair with [`OPSTACK`](NetworkStackId::OPSTACK) as
    /// key.
    opstack: Counter,

    /// Frequency of node records with a kv-pair with [`ETH`](NetworkStackId::ETH) as key.
    eth: Counter,

    /// Frequency of node records with a kv-pair with [`ETH2`](NetworkStackId::ETH2) as key.
    eth2: Counter,
}

impl AdvertisedChainMetrics {
    /// Counts each recognised network stack type that is advertised on node record, once.
    pub fn increment_once_by_network_type(&self, enr: &discv5::Enr) {
        if enr.get_raw_rlp(NetworkStackId::OPEL).is_some() {
            self.opel.increment(1u64)
        }
        if enr.get_raw_rlp(NetworkStackId::OPSTACK).is_some() {
            self.opstack.increment(1u64)
        }
        if enr.get_raw_rlp(NetworkStackId::ETH).is_some() {
            self.eth.increment(1u64)
        }
        if enr.get_raw_rlp(NetworkStackId::ETH2).is_some() {
            self.eth2.increment(1u64)
        }
    }
}