reth_network_types/peers/
mod.rs1pub mod addr;
2pub mod config;
3pub mod kind;
4pub mod reputation;
5pub mod state;
6
7pub use config::{ConnectionsConfig, PeersConfig};
8pub use reputation::{Reputation, ReputationChange, ReputationChangeKind, ReputationChangeWeights};
9
10use alloy_eip2124::ForkId;
11use reth_network_peers::{NodeRecord, PeerId};
12use std::time::{Duration, Instant};
13use tracing::trace;
14
15use crate::{
16 is_banned_reputation, PeerAddr, PeerConnectionState, PeerKind, ReputationChangeOutcome,
17 DEFAULT_REPUTATION,
18};
19
20#[derive(Debug, Clone)]
22pub struct Peer {
23 pub addr: PeerAddr,
25 pub reputation: i32,
27 pub state: PeerConnectionState,
29 pub connected_at: Option<Instant>,
31 pub fork_id: Option<Box<ForkId>>,
33 pub remove_after_disconnect: bool,
35 pub kind: PeerKind,
37 pub backed_off: bool,
39 pub severe_backoff_counter: u8,
42}
43
44impl Peer {
47 pub fn new(addr: PeerAddr) -> Self {
49 Self::with_state(addr, Default::default())
50 }
51
52 pub fn trusted(addr: PeerAddr) -> Self {
54 Self { kind: PeerKind::Trusted, ..Self::new(addr) }
55 }
56
57 pub const fn reputation(&self) -> i32 {
59 self.reputation
60 }
61
62 pub fn mark_connected(&mut self) {
64 self.connected_at = Some(Instant::now());
65 }
66
67 pub const fn mark_disconnected(&mut self) {
69 self.connected_at = None;
70 }
71
72 pub fn connected_for_at_least(&self, now: Instant, min_uptime: Duration) -> bool {
74 self.connected_at
75 .is_some_and(|connected_at| now.saturating_duration_since(connected_at) >= min_uptime)
76 }
77
78 pub fn with_state(addr: PeerAddr, state: PeerConnectionState) -> Self {
80 Self {
81 addr,
82 state,
83 connected_at: None,
84 reputation: DEFAULT_REPUTATION,
85 fork_id: None,
86 remove_after_disconnect: false,
87 kind: Default::default(),
88 backed_off: false,
89 severe_backoff_counter: 0,
90 }
91 }
92
93 pub fn with_kind(addr: PeerAddr, kind: PeerKind) -> Self {
95 Self { kind, ..Self::new(addr) }
96 }
97
98 pub const fn reset_reputation(&mut self) -> ReputationChangeOutcome {
101 self.reputation = DEFAULT_REPUTATION;
102
103 ReputationChangeOutcome::None
104 }
105
106 pub fn apply_reputation(
108 &mut self,
109 reputation: i32,
110 kind: ReputationChangeKind,
111 ) -> ReputationChangeOutcome {
112 let previous = self.reputation;
113 self.reputation = previous.saturating_add(reputation);
115
116 trace!(target: "net::peers", reputation=%self.reputation, banned=%self.is_banned(), ?kind, "applied reputation change");
117
118 if self.state.is_connected() && self.is_banned() {
119 self.state.disconnect();
120 return ReputationChangeOutcome::DisconnectAndBan
121 }
122
123 if self.is_banned() && !is_banned_reputation(previous) {
124 return ReputationChangeOutcome::Ban
125 }
126
127 if !self.is_banned() && is_banned_reputation(previous) {
128 return ReputationChangeOutcome::Unban
129 }
130
131 ReputationChangeOutcome::None
132 }
133
134 #[inline]
136 pub const fn is_banned(&self) -> bool {
137 is_banned_reputation(self.reputation)
138 }
139
140 #[inline]
142 pub const fn is_backed_off(&self) -> bool {
143 self.backed_off
144 }
145
146 #[inline]
148 pub const fn unban(&mut self) {
149 self.reputation = DEFAULT_REPUTATION
150 }
151
152 #[inline]
154 pub const fn is_trusted(&self) -> bool {
155 matches!(self.kind, PeerKind::Trusted)
156 }
157
158 #[inline]
160 pub const fn is_static(&self) -> bool {
161 matches!(self.kind, PeerKind::Static)
162 }
163}
164
165#[derive(Debug, Clone, PartialEq, Eq)]
170#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
171pub struct PersistedPeerInfo {
172 pub record: NodeRecord,
174 pub kind: PeerKind,
176 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
178 pub fork_id: Option<ForkId>,
179 pub reputation: i32,
181}
182
183impl PersistedPeerInfo {
184 pub const fn peer_id(&self) -> PeerId {
186 self.record.id
187 }
188
189 pub const fn from_node_record(record: NodeRecord) -> Self {
191 Self { record, kind: PeerKind::Basic, fork_id: None, reputation: DEFAULT_REPUTATION }
192 }
193}