1use crate::NodeType;
17use snarkvm::prelude::{Address, Network};
18use tracing::*;
19
20use std::{fmt, net::SocketAddr, time::Instant};
21
22#[derive(Clone, Debug)]
24pub enum Peer<N: Network> {
25 Candidate(CandidatePeer),
27 Connecting(ConnectingPeer),
29 Connected(ConnectedPeer<N>),
31}
32
33#[derive(Clone, Debug)]
35pub struct ConnectingPeer {
36 pub listener_addr: SocketAddr,
38 pub trusted: bool,
40}
41
42#[derive(Clone, Debug)]
44pub struct CandidatePeer {
45 pub listener_addr: SocketAddr,
47 pub trusted: bool,
49 pub last_height_seen: Option<u32>,
51 pub last_connection_attempt: Option<Instant>,
54 pub total_connection_attempts: u32,
56}
57
58#[derive(Clone, Debug)]
60pub struct ConnectedPeer<N: Network> {
61 pub listener_addr: SocketAddr,
63 pub connected_addr: SocketAddr,
65 pub connection_mode: ConnectionMode,
67 pub trusted: bool,
69 pub aleo_addr: Address<N>,
71 pub node_type: NodeType,
73 pub version: u32,
75 pub snarkos_sha: Option<[u8; 40]>,
77 pub last_height_seen: Option<u32>,
79 pub first_seen: Instant,
81 pub last_seen: Instant,
83}
84
85#[derive(Clone, Copy, Debug, PartialEq, Eq)]
87pub enum ConnectionMode {
88 Gateway,
89 Router,
90}
91
92impl fmt::Display for ConnectionMode {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 match self {
95 ConnectionMode::Gateway => write!(f, "Gateway"),
96 ConnectionMode::Router => write!(f, "Router"),
97 }
98 }
99}
100
101impl<N: Network> Peer<N> {
102 pub const fn new_candidate(listener_addr: SocketAddr, trusted: bool) -> Self {
104 Self::Candidate(CandidatePeer {
105 listener_addr,
106 trusted,
107 last_height_seen: None,
108 last_connection_attempt: None,
109 total_connection_attempts: 0,
110 })
111 }
112
113 pub const fn new_connecting(listener_addr: SocketAddr, trusted: bool) -> Self {
115 Self::Connecting(ConnectingPeer { listener_addr, trusted })
116 }
117
118 #[allow(clippy::too_many_arguments)]
120 pub fn upgrade_to_connected(
121 &mut self,
122 connected_addr: SocketAddr,
123 listener_port: u16,
124 aleo_address: Address<N>,
125 node_type: NodeType,
126 node_version: u32,
127 snarkos_sha: Option<[u8; 40]>,
128 connection_mode: ConnectionMode,
129 ) {
130 let timestamp = Instant::now();
131 let listener_addr = SocketAddr::from((connected_addr.ip(), listener_port));
132
133 if !matches!(self, Self::Connecting(_)) {
136 warn!(
137 "Peer '{listener_addr}' is being upgraded to Connected, but isn't Connecting \
138 - it is {}",
139 if self.is_connected() { "already Connected" } else { "only a Candidate" }
140 );
141 }
142
143 *self = Self::Connected(ConnectedPeer {
144 listener_addr,
145 connected_addr,
146 connection_mode,
147 aleo_addr: aleo_address,
148 node_type,
149 trusted: self.is_trusted(),
150 version: node_version,
151 snarkos_sha,
152 last_height_seen: None,
153 first_seen: timestamp,
154 last_seen: timestamp,
155 });
156 }
157
158 pub fn downgrade_to_candidate(&mut self, listener_addr: SocketAddr) {
160 *self = Self::Candidate(CandidatePeer {
161 listener_addr,
162 trusted: self.is_trusted(),
163 last_height_seen: self.last_height_seen(),
164 last_connection_attempt: None,
165 total_connection_attempts: 0,
166 });
167 }
168
169 pub fn node_type(&self) -> Option<NodeType> {
171 match self {
172 Self::Candidate(_) => None,
173 Self::Connecting(_) => None,
174 Self::Connected(peer) => Some(peer.node_type),
175 }
176 }
177
178 pub fn listener_addr(&self) -> SocketAddr {
180 match self {
181 Self::Candidate(p) => p.listener_addr,
182 Self::Connecting(p) => p.listener_addr,
183 Self::Connected(p) => p.listener_addr,
184 }
185 }
186
187 pub fn last_height_seen(&self) -> Option<u32> {
189 match self {
190 Self::Candidate(_) => None,
191 Self::Connecting(_) => None,
192 Self::Connected(peer) => peer.last_height_seen,
193 }
194 }
195
196 pub fn is_candidate(&self) -> bool {
198 matches!(self, Peer::Candidate(_))
199 }
200
201 pub fn is_connecting(&self) -> bool {
203 matches!(self, Peer::Connecting(_))
204 }
205
206 pub fn is_connected(&self) -> bool {
208 matches!(self, Peer::Connected(_))
209 }
210
211 pub fn is_trusted(&self) -> bool {
213 match self {
214 Self::Candidate(peer) => peer.trusted,
215 Self::Connecting(peer) => peer.trusted,
216 Self::Connected(peer) => peer.trusted,
217 }
218 }
219
220 pub fn update_last_seen(&mut self) {
222 if let Self::Connected(ConnectedPeer { last_seen, .. }) = self {
223 *last_seen = Instant::now();
224 }
225 }
226
227 pub fn as_connected(&self) -> Option<&ConnectedPeer<N>> {
230 match self {
231 Self::Connected(peer) => Some(peer),
232 _ => None,
233 }
234 }
235}
236
237impl<N: Network> ConnectedPeer<N> {
238 pub fn is_validator(&self) -> bool {
240 self.node_type == NodeType::Validator
241 }
242}