use crate::NodeType;
use snarkvm::prelude::{Address, Network};
use tracing::*;
use std::{net::SocketAddr, time::Instant};
#[derive(Clone, Debug)]
pub enum Peer<N: Network> {
Candidate(CandidatePeer),
Connecting(ConnectingPeer),
Connected(ConnectedPeer<N>),
}
#[derive(Clone, Debug)]
pub struct ConnectingPeer {
pub listener_addr: SocketAddr,
pub trusted: bool,
}
#[derive(Clone, Debug)]
pub struct CandidatePeer {
pub listener_addr: SocketAddr,
pub trusted: bool,
pub last_height_seen: Option<u32>,
pub last_connection_attempt: Option<Instant>,
pub total_connection_attempts: u32,
}
#[derive(Clone, Debug)]
pub struct ConnectedPeer<N: Network> {
pub listener_addr: SocketAddr,
pub connected_addr: SocketAddr,
pub connection_mode: ConnectionMode,
pub trusted: bool,
pub aleo_addr: Address<N>,
pub node_type: NodeType,
pub version: u32,
pub snarkos_sha: Option<[u8; 40]>,
pub last_height_seen: Option<u32>,
pub first_seen: Instant,
pub last_seen: Instant,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ConnectionMode {
Gateway,
Router,
}
impl<N: Network> Peer<N> {
pub const fn new_candidate(listener_addr: SocketAddr, trusted: bool) -> Self {
Self::Candidate(CandidatePeer {
listener_addr,
trusted,
last_height_seen: None,
last_connection_attempt: None,
total_connection_attempts: 0,
})
}
pub const fn new_connecting(listener_addr: SocketAddr, trusted: bool) -> Self {
Self::Connecting(ConnectingPeer { listener_addr, trusted })
}
#[allow(clippy::too_many_arguments)]
pub fn upgrade_to_connected(
&mut self,
connected_addr: SocketAddr,
listener_port: u16,
aleo_address: Address<N>,
node_type: NodeType,
node_version: u32,
snarkos_sha: Option<[u8; 40]>,
connection_mode: ConnectionMode,
) {
let timestamp = Instant::now();
let listener_addr = SocketAddr::from((connected_addr.ip(), listener_port));
if !matches!(self, Self::Connecting(_)) {
warn!("Peer '{listener_addr}' is being upgraded to Connected, but isn't Connecting");
}
*self = Self::Connected(ConnectedPeer {
listener_addr,
connected_addr,
connection_mode,
aleo_addr: aleo_address,
node_type,
trusted: self.is_trusted(),
version: node_version,
snarkos_sha,
last_height_seen: None,
first_seen: timestamp,
last_seen: timestamp,
});
}
pub fn downgrade_to_candidate(&mut self, listener_addr: SocketAddr) {
*self = Self::Candidate(CandidatePeer {
listener_addr,
trusted: self.is_trusted(),
last_height_seen: self.last_height_seen(),
last_connection_attempt: None,
total_connection_attempts: 0,
});
}
pub fn node_type(&self) -> Option<NodeType> {
match self {
Self::Candidate(_) => None,
Self::Connecting(_) => None,
Self::Connected(peer) => Some(peer.node_type),
}
}
pub fn listener_addr(&self) -> SocketAddr {
match self {
Self::Candidate(p) => p.listener_addr,
Self::Connecting(p) => p.listener_addr,
Self::Connected(p) => p.listener_addr,
}
}
pub fn last_height_seen(&self) -> Option<u32> {
match self {
Self::Candidate(_) => None,
Self::Connecting(_) => None,
Self::Connected(peer) => peer.last_height_seen,
}
}
pub fn is_candidate(&self) -> bool {
matches!(self, Peer::Candidate(_))
}
pub fn is_connecting(&self) -> bool {
matches!(self, Peer::Connecting(_))
}
pub fn is_connected(&self) -> bool {
matches!(self, Peer::Connected(_))
}
pub fn is_trusted(&self) -> bool {
match self {
Self::Candidate(peer) => peer.trusted,
Self::Connecting(peer) => peer.trusted,
Self::Connected(peer) => peer.trusted,
}
}
pub fn update_last_seen(&mut self) {
if let Self::Connected(ConnectedPeer { last_seen, .. }) = self {
*last_seen = Instant::now();
}
}
}