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<N>),
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<N: Network> {
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 pub last_known_aleo_addr: Option<Address<N>>,
59}
60
61#[derive(Clone, Debug)]
63pub struct ConnectedPeer<N: Network> {
64 pub listener_addr: SocketAddr,
66 pub connected_addr: SocketAddr,
68 pub connection_mode: ConnectionMode,
70 pub trusted: bool,
72 pub aleo_addr: Address<N>,
74 pub node_type: NodeType,
76 pub version: u32,
78 pub snarkos_sha: Option<[u8; 40]>,
80 pub last_height_seen: Option<u32>,
82 pub first_seen: Instant,
84 pub last_seen: Instant,
86}
87
88#[derive(Clone, Copy, Debug, PartialEq, Eq)]
90pub enum ConnectionMode {
91 Gateway,
92 Router,
93}
94
95impl fmt::Display for ConnectionMode {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 match self {
98 ConnectionMode::Gateway => write!(f, "Gateway"),
99 ConnectionMode::Router => write!(f, "Router"),
100 }
101 }
102}
103
104impl<N: Network> Peer<N> {
105 pub fn new_candidate(listener_addr: SocketAddr, trusted: bool) -> Self {
107 Self::Candidate(CandidatePeer {
108 listener_addr,
109 trusted,
110 last_height_seen: None,
111 last_connection_attempt: None,
112 total_connection_attempts: 0,
113 last_known_aleo_addr: None,
114 })
115 }
116
117 pub const fn new_connecting(listener_addr: SocketAddr, trusted: bool) -> Self {
119 Self::Connecting(ConnectingPeer { listener_addr, trusted })
120 }
121
122 #[allow(clippy::too_many_arguments)]
124 pub fn upgrade_to_connected(
125 &mut self,
126 connected_addr: SocketAddr,
127 listener_port: u16,
128 aleo_address: Address<N>,
129 node_type: NodeType,
130 node_version: u32,
131 snarkos_sha: Option<[u8; 40]>,
132 connection_mode: ConnectionMode,
133 ) {
134 let timestamp = Instant::now();
135 let listener_addr = SocketAddr::from((connected_addr.ip(), listener_port));
136
137 if !matches!(self, Self::Connecting(_)) {
140 warn!(
141 "Peer '{listener_addr}' is being upgraded to Connected, but isn't Connecting \
142 - it is {}",
143 if self.is_connected() { "already Connected" } else { "only a Candidate" }
144 );
145 }
146
147 *self = Self::Connected(ConnectedPeer {
148 listener_addr,
149 connected_addr,
150 connection_mode,
151 aleo_addr: aleo_address,
152 node_type,
153 trusted: self.is_trusted(),
154 version: node_version,
155 snarkos_sha,
156 last_height_seen: None,
157 first_seen: timestamp,
158 last_seen: timestamp,
159 });
160 }
161
162 pub fn downgrade_to_candidate(&mut self, listener_addr: SocketAddr) {
164 let last_known_aleo_addr = match self {
165 Self::Connected(p) => Some(p.aleo_addr),
166 _ => None,
167 };
168
169 *self = Self::Candidate(CandidatePeer {
170 listener_addr,
171 trusted: self.is_trusted(),
172 last_height_seen: self.last_height_seen(),
173 last_connection_attempt: None,
174 total_connection_attempts: 0,
175 last_known_aleo_addr,
176 });
177 }
178
179 pub fn node_type(&self) -> Option<NodeType> {
181 match self {
182 Self::Candidate(_) => None,
183 Self::Connecting(_) => None,
184 Self::Connected(peer) => Some(peer.node_type),
185 }
186 }
187
188 pub fn listener_addr(&self) -> SocketAddr {
190 match self {
191 Self::Candidate(p) => p.listener_addr,
192 Self::Connecting(p) => p.listener_addr,
193 Self::Connected(p) => p.listener_addr,
194 }
195 }
196
197 pub fn last_height_seen(&self) -> Option<u32> {
199 match self {
200 Self::Candidate(_) => None,
201 Self::Connecting(_) => None,
202 Self::Connected(peer) => peer.last_height_seen,
203 }
204 }
205
206 pub fn is_candidate(&self) -> bool {
208 matches!(self, Peer::Candidate(_))
209 }
210
211 pub fn is_connecting(&self) -> bool {
213 matches!(self, Peer::Connecting(_))
214 }
215
216 pub fn is_connected(&self) -> bool {
218 matches!(self, Peer::Connected(_))
219 }
220
221 pub fn is_trusted(&self) -> bool {
223 match self {
224 Self::Candidate(peer) => peer.trusted,
225 Self::Connecting(peer) => peer.trusted,
226 Self::Connected(peer) => peer.trusted,
227 }
228 }
229
230 pub fn update_last_seen(&mut self) {
232 if let Self::Connected(ConnectedPeer { last_seen, .. }) = self {
233 *last_seen = Instant::now();
234 }
235 }
236
237 pub fn as_connected(&self) -> Option<&ConnectedPeer<N>> {
240 match self {
241 Self::Connected(peer) => Some(peer),
242 _ => None,
243 }
244 }
245}
246
247impl<N: Network> ConnectedPeer<N> {
248 pub fn is_validator(&self) -> bool {
250 self.node_type == NodeType::Validator
251 }
252}