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!("Peer '{listener_addr}' is being upgraded to Connected, but isn't Connecting");
137 }
138
139 *self = Self::Connected(ConnectedPeer {
140 listener_addr,
141 connected_addr,
142 connection_mode,
143 aleo_addr: aleo_address,
144 node_type,
145 trusted: self.is_trusted(),
146 version: node_version,
147 snarkos_sha,
148 last_height_seen: None,
149 first_seen: timestamp,
150 last_seen: timestamp,
151 });
152 }
153
154 pub fn downgrade_to_candidate(&mut self, listener_addr: SocketAddr) {
156 *self = Self::Candidate(CandidatePeer {
157 listener_addr,
158 trusted: self.is_trusted(),
159 last_height_seen: self.last_height_seen(),
160 last_connection_attempt: None,
161 total_connection_attempts: 0,
162 });
163 }
164
165 pub fn node_type(&self) -> Option<NodeType> {
167 match self {
168 Self::Candidate(_) => None,
169 Self::Connecting(_) => None,
170 Self::Connected(peer) => Some(peer.node_type),
171 }
172 }
173
174 pub fn listener_addr(&self) -> SocketAddr {
176 match self {
177 Self::Candidate(p) => p.listener_addr,
178 Self::Connecting(p) => p.listener_addr,
179 Self::Connected(p) => p.listener_addr,
180 }
181 }
182
183 pub fn last_height_seen(&self) -> Option<u32> {
185 match self {
186 Self::Candidate(_) => None,
187 Self::Connecting(_) => None,
188 Self::Connected(peer) => peer.last_height_seen,
189 }
190 }
191
192 pub fn is_candidate(&self) -> bool {
194 matches!(self, Peer::Candidate(_))
195 }
196
197 pub fn is_connecting(&self) -> bool {
199 matches!(self, Peer::Connecting(_))
200 }
201
202 pub fn is_connected(&self) -> bool {
204 matches!(self, Peer::Connected(_))
205 }
206
207 pub fn is_trusted(&self) -> bool {
209 match self {
210 Self::Candidate(peer) => peer.trusted,
211 Self::Connecting(peer) => peer.trusted,
212 Self::Connected(peer) => peer.trusted,
213 }
214 }
215
216 pub fn update_last_seen(&mut self) {
218 if let Self::Connected(ConnectedPeer { last_seen, .. }) = self {
219 *last_seen = Instant::now();
220 }
221 }
222
223 pub fn as_connected(&self) -> Option<&ConnectedPeer<N>> {
226 match self {
227 Self::Connected(peer) => Some(peer),
228 _ => None,
229 }
230 }
231}
232
233impl<N: Network> ConnectedPeer<N> {
234 pub fn is_validator(&self) -> bool {
236 self.node_type == NodeType::Validator
237 }
238}