mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: support trusted peer ids without address (#7155)
This commit is contained in:
@ -70,6 +70,11 @@ pub trait Peers: PeersInfo {
|
||||
self.add_peer_kind(peer, PeerKind::Basic, addr);
|
||||
}
|
||||
|
||||
/// Adds a trusted [PeerId] to the peer set.
|
||||
///
|
||||
/// This allows marking a peer as trusted without having to know the peer's address.
|
||||
fn add_trusted_peer_id(&self, peer: PeerId);
|
||||
|
||||
/// Adds a trusted peer to the peer set.
|
||||
fn add_trusted_peer(&self, peer: PeerId, addr: SocketAddr) {
|
||||
self.add_peer_kind(peer, PeerKind::Trusted, addr);
|
||||
@ -145,6 +150,18 @@ pub enum PeerKind {
|
||||
Trusted,
|
||||
}
|
||||
|
||||
impl PeerKind {
|
||||
/// Returns `true` if the peer is trusted.
|
||||
pub const fn is_trusted(&self) -> bool {
|
||||
matches!(self, PeerKind::Trusted)
|
||||
}
|
||||
|
||||
/// Returns `true` if the peer is basic.
|
||||
pub const fn is_basic(&self) -> bool {
|
||||
matches!(self, PeerKind::Basic)
|
||||
}
|
||||
}
|
||||
|
||||
/// Info about an active peer session.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PeerInfo {
|
||||
|
||||
@ -68,6 +68,8 @@ impl PeersInfo for NoopNetwork {
|
||||
}
|
||||
|
||||
impl Peers for NoopNetwork {
|
||||
fn add_trusted_peer_id(&self, _peer: PeerId) {}
|
||||
|
||||
fn add_peer_kind(&self, _peer: PeerId, _kind: PeerKind, _addr: SocketAddr) {}
|
||||
|
||||
async fn get_peers_by_kind(&self, _kind: PeerKind) -> Result<Vec<PeerInfo>, NetworkError> {
|
||||
|
||||
@ -547,6 +547,9 @@ where
|
||||
.swarm
|
||||
.sessions_mut()
|
||||
.send_message(&peer_id, PeerMessage::PooledTransactions(msg)),
|
||||
NetworkHandleMessage::AddTrustedPeerId(peer_id) => {
|
||||
self.swarm.state_mut().add_trusted_peer_id(peer_id);
|
||||
}
|
||||
NetworkHandleMessage::AddPeerAddress(peer, kind, addr) => {
|
||||
// only add peer if we are not shutting down
|
||||
if !self.swarm.is_shutting_down() {
|
||||
|
||||
@ -236,6 +236,10 @@ impl PeersInfo for NetworkHandle {
|
||||
}
|
||||
|
||||
impl Peers for NetworkHandle {
|
||||
fn add_trusted_peer_id(&self, peer: PeerId) {
|
||||
self.send_message(NetworkHandleMessage::AddTrustedPeerId(peer));
|
||||
}
|
||||
|
||||
/// Sends a message to the [`NetworkManager`](crate::NetworkManager) to add a peer to the known
|
||||
/// set, with the given kind.
|
||||
fn add_peer_kind(&self, peer: PeerId, kind: PeerKind, addr: SocketAddr) {
|
||||
@ -404,6 +408,8 @@ pub trait NetworkProtocols: Send + Sync {
|
||||
/// Internal messages that can be passed to the [`NetworkManager`](crate::NetworkManager).
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum NetworkHandleMessage {
|
||||
/// Marks a peer as trusted.
|
||||
AddTrustedPeerId(PeerId),
|
||||
/// Adds an address for a peer, including its ID, kind, and socket address.
|
||||
AddPeerAddress(PeerId, PeerKind, SocketAddr),
|
||||
/// Removes a peer from the peerset corresponding to the given kind.
|
||||
|
||||
@ -88,6 +88,11 @@ impl PeersHandle {
|
||||
pub struct PeersManager {
|
||||
/// All peers known to the network
|
||||
peers: HashMap<PeerId, Peer>,
|
||||
/// The set of trusted peer ids.
|
||||
///
|
||||
/// This tracks peer ids that are considered trusted, but for which we don't necessarily have
|
||||
/// an address: [Self::add_trusted_peer_id]
|
||||
trusted_peer_ids: HashSet<PeerId>,
|
||||
/// Copy of the sender half, so new [`PeersHandle`] can be created on demand.
|
||||
manager_tx: mpsc::UnboundedSender<PeerCommand>,
|
||||
/// Receiver half of the command channel.
|
||||
@ -143,8 +148,10 @@ impl PeersManager {
|
||||
let unban_interval = ban_duration.min(backoff_durations.low) / 2;
|
||||
|
||||
let mut peers = HashMap::with_capacity(trusted_nodes.len() + basic_nodes.len());
|
||||
let mut trusted_peer_ids = HashSet::with_capacity(trusted_nodes.len());
|
||||
|
||||
for NodeRecord { address, tcp_port, udp_port: _, id } in trusted_nodes {
|
||||
trusted_peer_ids.insert(id);
|
||||
peers.entry(id).or_insert_with(|| Peer::trusted(SocketAddr::from((address, tcp_port))));
|
||||
}
|
||||
|
||||
@ -154,6 +161,7 @@ impl PeersManager {
|
||||
|
||||
Self {
|
||||
peers,
|
||||
trusted_peer_ids,
|
||||
manager_tx,
|
||||
handle_rx: UnboundedReceiverStream::new(handle_rx),
|
||||
queued_actions: Default::default(),
|
||||
@ -283,9 +291,12 @@ impl PeersManager {
|
||||
return
|
||||
}
|
||||
value.state = PeerConnectionState::In;
|
||||
|
||||
let is_trusted = value.is_trusted() || self.trusted_peer_ids.contains(&peer_id);
|
||||
|
||||
// if a peer is not trusted and we don't have capacity for more inbound connections,
|
||||
// disconnecting the peer
|
||||
if !value.is_trusted() && !has_in_capacity {
|
||||
if !is_trusted && !has_in_capacity {
|
||||
self.queued_actions.push_back(PeerAction::Disconnect {
|
||||
peer_id,
|
||||
reason: Some(DisconnectReason::TooManyPeers),
|
||||
@ -300,8 +311,10 @@ impl PeersManager {
|
||||
entry.insert(peer);
|
||||
self.queued_actions.push_back(PeerAction::PeerAdded(peer_id));
|
||||
|
||||
let is_trusted = self.trusted_peer_ids.contains(&peer_id);
|
||||
|
||||
// disconnect the peer if we don't have capacity for more inbound connections
|
||||
if !has_in_capacity {
|
||||
if !is_trusted && !has_in_capacity {
|
||||
self.queued_actions.push_back(PeerAction::Disconnect {
|
||||
peer_id,
|
||||
reason: Some(DisconnectReason::TooManyPeers),
|
||||
@ -614,6 +627,11 @@ impl PeersManager {
|
||||
self.add_peer_kind(peer_id, PeerKind::Basic, addr, fork_id)
|
||||
}
|
||||
|
||||
/// Marks the given peer as trusted.
|
||||
pub(crate) fn add_trusted_peer_id(&mut self, peer_id: PeerId) {
|
||||
self.trusted_peer_ids.insert(peer_id);
|
||||
}
|
||||
|
||||
/// Called for a newly discovered trusted peer.
|
||||
///
|
||||
/// If the peer already exists, then the address and kind will be updated.
|
||||
@ -658,6 +676,10 @@ impl PeersManager {
|
||||
self.queued_actions.push_back(PeerAction::PeerAdded(peer_id));
|
||||
}
|
||||
}
|
||||
|
||||
if kind.is_trusted() {
|
||||
self.trusted_peer_ids.insert(peer_id);
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the tracked node from the set.
|
||||
@ -695,8 +717,9 @@ impl PeersManager {
|
||||
}
|
||||
|
||||
let peer = entry.get_mut();
|
||||
|
||||
peer.kind = PeerKind::Basic;
|
||||
|
||||
self.trusted_peer_ids.remove(&peer_id);
|
||||
}
|
||||
|
||||
/// Returns the idle peer with the highest reputation.
|
||||
@ -2015,6 +2038,72 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn accept_incoming_trusted_unknown_peer_address() {
|
||||
let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 99)), 8008);
|
||||
let mut peers = PeersManager::new(PeersConfig::test().with_max_inbound(2));
|
||||
|
||||
// saturate the inbound slots
|
||||
for i in 0..peers.connection_info.max_inbound {
|
||||
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, i as u8)), 8008);
|
||||
assert!(peers.on_incoming_pending_session(socket_addr.ip()).is_ok());
|
||||
let peer_id = PeerId::random();
|
||||
peers.on_incoming_session_established(peer_id, addr);
|
||||
|
||||
match event!(peers) {
|
||||
PeerAction::PeerAdded(id) => {
|
||||
assert_eq!(id, peer_id);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
// try to connect untrusted peer
|
||||
let untrusted = PeerId::random();
|
||||
let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 99)), 8008);
|
||||
assert!(peers.on_incoming_pending_session(socket_addr.ip()).is_ok());
|
||||
peers.on_incoming_session_established(untrusted, socket_addr);
|
||||
|
||||
match event!(peers) {
|
||||
PeerAction::PeerAdded(id) => {
|
||||
assert_eq!(id, untrusted);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
match event!(peers) {
|
||||
PeerAction::Disconnect { peer_id, reason } => {
|
||||
assert_eq!(peer_id, untrusted);
|
||||
assert_eq!(reason, Some(DisconnectReason::TooManyPeers));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
// try to connect trusted peer
|
||||
let trusted = PeerId::random();
|
||||
peers.add_trusted_peer_id(trusted);
|
||||
|
||||
let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 100)), 8008);
|
||||
assert!(peers.on_incoming_pending_session(socket_addr.ip()).is_ok());
|
||||
peers.on_incoming_session_established(trusted, socket_addr);
|
||||
|
||||
match event!(peers) {
|
||||
PeerAction::PeerAdded(id) => {
|
||||
assert_eq!(id, trusted);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
poll_fn(|cx| {
|
||||
assert!(peers.poll(cx).is_pending());
|
||||
Poll::Ready(())
|
||||
})
|
||||
.await;
|
||||
|
||||
let peer = peers.peers.get(&trusted).unwrap();
|
||||
assert_eq!(peer.state, PeerConnectionState::In);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_already_connected() {
|
||||
let peer = PeerId::random();
|
||||
|
||||
@ -267,6 +267,11 @@ where
|
||||
self.discovery.ban(peer_id, ip)
|
||||
}
|
||||
|
||||
/// Marks the given peer as trusted.
|
||||
pub(crate) fn add_trusted_peer_id(&mut self, peer_id: PeerId) {
|
||||
self.peers_manager.add_trusted_peer_id(peer_id)
|
||||
}
|
||||
|
||||
/// Adds a peer and its address with the given kind to the peerset.
|
||||
pub(crate) fn add_peer_kind(&mut self, peer_id: PeerId, kind: PeerKind, addr: SocketAddr) {
|
||||
self.peers_manager.add_peer_kind(peer_id, kind, addr, None)
|
||||
|
||||
Reference in New Issue
Block a user