From 28b6d921c67e0a8dab3f4656f40f9f7518cd72ba Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 25 Sep 2020 01:52:39 +0000 Subject: [PATCH] Remove banned peers from DHT and track IPs (#1656) ## Issue Addressed #629 ## Proposed Changes This removes banned peers from the DHT and informs discovery to block the node_id and the known source IP's associated with this node. It has the capabilities of un banning this peer after a period of time. This also corrects the logic about banning specific IP addresses. We now use seen_ip addresses from libp2p rather than those sent to us via identify (which also include local addresses). --- Cargo.lock | 26 +-- beacon_node/eth2_libp2p/src/behaviour/mod.rs | 116 +++++------ beacon_node/eth2_libp2p/src/discovery/mod.rs | 31 ++- .../eth2_libp2p/src/peer_manager/mod.rs | 77 ++++++-- .../eth2_libp2p/src/peer_manager/peer_info.rs | 10 +- .../eth2_libp2p/src/peer_manager/peerdb.rs | 186 +++++++++--------- 6 files changed, 264 insertions(+), 182 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a86b5cca39..ca4e3fdde1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1240,9 +1240,9 @@ checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" [[package]] name = "discv5" -version = "0.1.0-alpha.10" +version = "0.1.0-alpha.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4cba1b485c16864edc11ccbf3abf5fbf1c26ce759ab36c32ee8e12638d50b0d" +checksum = "c68cb1b942aadd3bb3a13620c4d831c0aa49eda988cf8bcccfdfdc7ef69504a7" dependencies = [ "aes-gcm", "arrayvec", @@ -1253,17 +1253,17 @@ dependencies = [ "hex 0.4.2", "hkdf", "lazy_static", - "libp2p-core 0.20.1", + "libp2p-core 0.22.1", "libsecp256k1", "log 0.4.11", "lru_time_cache", "multihash", - "net2", "parking_lot 0.11.0", "rand 0.7.3", "rlp", "sha2 0.8.2", "smallvec 1.4.2", + "socket2", "tokio 0.2.22", "uint", "zeroize", @@ -2673,9 +2673,8 @@ dependencies = [ [[package]] name = "libp2p-core" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a694fd76d7c33a45a0e6e1525e9b9b5d11127c9c94e560ac0f8abba54ed80af" +version = "0.21.0" +source = "git+https://github.com/sigp/rust-libp2p?rev=03f998022ce2f566a6c6e6c4206bc0ce4d45109f#03f998022ce2f566a6c6e6c4206bc0ce4d45109f" dependencies = [ "asn1_der", "bs58", @@ -2688,8 +2687,8 @@ dependencies = [ "libsecp256k1", "log 0.4.11", "multihash", - "multistream-select 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.9.2", + "multistream-select 0.8.2 (git+https://github.com/sigp/rust-libp2p?rev=03f998022ce2f566a6c6e6c4206bc0ce4d45109f)", + "parity-multiaddr 0.9.1", "parking_lot 0.10.2", "pin-project", "prost", @@ -2707,8 +2706,9 @@ dependencies = [ [[package]] name = "libp2p-core" -version = "0.21.0" -source = "git+https://github.com/sigp/rust-libp2p?rev=03f998022ce2f566a6c6e6c4206bc0ce4d45109f#03f998022ce2f566a6c6e6c4206bc0ce4d45109f" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f13ba8c7df0768af2eb391696d562c7de88cc3a35122531aaa6a7d77754d25" dependencies = [ "asn1_der", "bs58", @@ -2721,8 +2721,8 @@ dependencies = [ "libsecp256k1", "log 0.4.11", "multihash", - "multistream-select 0.8.2 (git+https://github.com/sigp/rust-libp2p?rev=03f998022ce2f566a6c6e6c4206bc0ce4d45109f)", - "parity-multiaddr 0.9.1", + "multistream-select 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-multiaddr 0.9.2", "parking_lot 0.10.2", "pin-project", "prost", diff --git a/beacon_node/eth2_libp2p/src/behaviour/mod.rs b/beacon_node/eth2_libp2p/src/behaviour/mod.rs index cb9c367fbf..716af9eb5b 100644 --- a/beacon_node/eth2_libp2p/src/behaviour/mod.rs +++ b/beacon_node/eth2_libp2p/src/behaviour/mod.rs @@ -40,6 +40,59 @@ mod handler; const MAX_IDENTIFY_ADDRESSES: usize = 10; +/// Identifier of requests sent by a peer. +pub type PeerRequestId = (ConnectionId, SubstreamId); + +/// The types of events than can be obtained from polling the behaviour. +#[derive(Debug)] +pub enum BehaviourEvent { + /// We have successfully dialed and connected to a peer. + PeerDialed(PeerId), + /// A peer has successfully dialed and connected to us. + PeerConnected(PeerId), + /// A peer has disconnected. + PeerDisconnected(PeerId), + /// An RPC Request that was sent failed. + RPCFailed { + /// The id of the failed request. + id: RequestId, + /// The peer to which this request was sent. + peer_id: PeerId, + /// The error that occurred. + error: RPCError, + }, + RequestReceived { + /// The peer that sent the request. + peer_id: PeerId, + /// Identifier of the request. All responses to this request must use this id. + id: PeerRequestId, + /// Request the peer sent. + request: Request, + }, + ResponseReceived { + /// Peer that sent the response. + peer_id: PeerId, + /// Id of the request to which the peer is responding. + id: RequestId, + /// Response the peer sent. + response: Response, + }, + PubsubMessage { + /// The gossipsub message id. Used when propagating blocks after validation. + id: MessageId, + /// The peer from which we received this message, not the peer that published it. + source: PeerId, + /// The topics that this message was sent on. + topics: Vec, + /// The message itself. + message: PubsubMessage, + }, + /// Subscribed to peer for given topic + PeerSubscribed(PeerId, TopicHash), + /// Inform the network to send a Status to this peer. + StatusPeer(PeerId), +} + /// Builds the network behaviour that manages the core protocols of eth2. /// This core behaviour is managed by `Behaviour` which adds peer management to all core /// behaviours. @@ -837,13 +890,15 @@ impl NetworkBehaviour for Behaviour { // notify the peer manager of a successful connection match endpoint { - ConnectedPoint::Listener { .. } => { - self.peer_manager.connect_ingoing(&peer_id); + ConnectedPoint::Listener { send_back_addr, .. } => { + self.peer_manager + .connect_ingoing(&peer_id, send_back_addr.clone()); self.add_event(BehaviourEvent::PeerConnected(peer_id.clone())); debug!(self.log, "Connection established"; "peer_id" => peer_id.to_string(), "connection" => "Incoming"); } - ConnectedPoint::Dialer { .. } => { - self.peer_manager.connect_outgoing(&peer_id); + ConnectedPoint::Dialer { address } => { + self.peer_manager + .connect_outgoing(&peer_id, address.clone()); self.add_event(BehaviourEvent::PeerDialed(peer_id.clone())); debug!(self.log, "Connection established"; "peer_id" => peer_id.to_string(), "connection" => "Dialed"); } @@ -1061,59 +1116,6 @@ impl std::convert::From> for RPCCodedResponse { - /// We have successfully dialed and connected to a peer. - PeerDialed(PeerId), - /// A peer has successfully dialed and connected to us. - PeerConnected(PeerId), - /// A peer has disconnected. - PeerDisconnected(PeerId), - /// An RPC Request that was sent failed. - RPCFailed { - /// The id of the failed request. - id: RequestId, - /// The peer to which this request was sent. - peer_id: PeerId, - /// The error that occurred. - error: RPCError, - }, - RequestReceived { - /// The peer that sent the request. - peer_id: PeerId, - /// Identifier of the request. All responses to this request must use this id. - id: PeerRequestId, - /// Request the peer sent. - request: Request, - }, - ResponseReceived { - /// Peer that sent the response. - peer_id: PeerId, - /// Id of the request to which the peer is responding. - id: RequestId, - /// Response the peer sent. - response: Response, - }, - PubsubMessage { - /// The gossipsub message id. Used when propagating blocks after validation. - id: MessageId, - /// The peer from which we received this message, not the peer that published it. - source: PeerId, - /// The topics that this message was sent on. - topics: Vec, - /// The message itself. - message: PubsubMessage, - }, - /// Subscribed to peer for given topic - PeerSubscribed(PeerId, TopicHash), - /// Inform the network to send a Status to this peer. - StatusPeer(PeerId), -} - /// Persist metadata to disk pub fn save_metadata_to_disk(dir: &PathBuf, metadata: MetaData, log: &slog::Logger) { let _ = std::fs::create_dir_all(&dir); diff --git a/beacon_node/eth2_libp2p/src/discovery/mod.rs b/beacon_node/eth2_libp2p/src/discovery/mod.rs index 57b0b8abf2..b1a74b2d28 100644 --- a/beacon_node/eth2_libp2p/src/discovery/mod.rs +++ b/beacon_node/eth2_libp2p/src/discovery/mod.rs @@ -4,7 +4,7 @@ pub mod enr_ext; // Allow external use of the lighthouse ENR builder pub use enr::{build_enr, create_enr_builder_from_config, use_or_load_enr, CombinedKey, Eth2Enr}; -pub use enr_ext::{CombinedKeyExt, EnrExt}; +pub use enr_ext::{peer_id_to_node_id, CombinedKeyExt, EnrExt}; pub use libp2p::core::identity::Keypair; use crate::metrics; @@ -20,7 +20,7 @@ use ssz::{Decode, Encode}; use ssz_types::BitVector; use std::{ collections::{HashMap, VecDeque}, - net::SocketAddr, + net::{IpAddr, SocketAddr}, path::Path, pin::Pin, sync::Arc, @@ -436,6 +436,33 @@ impl Discovery { enr::save_enr_to_disk(Path::new(&self.enr_dir), &self.local_enr(), &self.log); } + // Bans a peer and it's associated seen IP addresses. + pub fn ban_peer(&mut self, peer_id: &PeerId, ip_addresses: Vec) { + // first try and convert the peer_id to a node_id. + if let Ok(node_id) = peer_id_to_node_id(peer_id) { + // If we could convert this peer id, remove it from the DHT and ban it from discovery. + self.discv5.ban_node(&node_id); + // Remove the node from the routing table. + self.discv5.remove_node(&node_id); + } + + for ip_address in ip_addresses { + self.discv5.ban_ip(ip_address); + } + } + + pub fn unban_peer(&mut self, peer_id: &PeerId, ip_addresses: Vec) { + // first try and convert the peer_id to a node_id. + if let Ok(node_id) = peer_id_to_node_id(peer_id) { + // If we could convert this peer id, remove it from the DHT and ban it from discovery. + self.discv5.permit_node(&node_id); + } + + for ip_address in ip_addresses { + self.discv5.permit_ip(ip_address); + } + } + /* Internal Functions */ /// Adds a subnet query if one doesn't exist. If a subnet query already exists, this diff --git a/beacon_node/eth2_libp2p/src/peer_manager/mod.rs b/beacon_node/eth2_libp2p/src/peer_manager/mod.rs index 963df78687..d528d7e69e 100644 --- a/beacon_node/eth2_libp2p/src/peer_manager/mod.rs +++ b/beacon_node/eth2_libp2p/src/peer_manager/mod.rs @@ -194,9 +194,9 @@ impl PeerManager { // Update the PeerDB state. if let Some(peer_id) = ban_peer.take() { - self.network_globals.peers.write().ban(&peer_id); + self.ban_peer(&peer_id); } else if let Some(peer_id) = unban_peer.take() { - self.network_globals.peers.write().unban(&peer_id); + self.unban_peer(&peer_id); } } @@ -312,19 +312,22 @@ impl PeerManager { /// Sets a peer as connected as long as their reputation allows it /// Informs if the peer was accepted - pub fn connect_ingoing(&mut self, peer_id: &PeerId) -> bool { - self.connect_peer(peer_id, ConnectingType::IngoingConnected) + pub fn connect_ingoing(&mut self, peer_id: &PeerId, multiaddr: Multiaddr) -> bool { + self.connect_peer(peer_id, ConnectingType::IngoingConnected { multiaddr }) } /// Sets a peer as connected as long as their reputation allows it /// Informs if the peer was accepted - pub fn connect_outgoing(&mut self, peer_id: &PeerId) -> bool { - self.connect_peer(peer_id, ConnectingType::OutgoingConnected) + pub fn connect_outgoing(&mut self, peer_id: &PeerId, multiaddr: Multiaddr) -> bool { + self.connect_peer(peer_id, ConnectingType::OutgoingConnected { multiaddr }) } /// Updates the database informing that a peer is being disconnected. pub fn _disconnecting_peer(&mut self, _peer_id: &PeerId) -> bool { // TODO: implement + // This informs the database that we are in the process of disconnecting the + // peer. Currently this state only exists for a short period of time before we force the + // disconnection. true } @@ -644,8 +647,12 @@ impl PeerManager { peerdb.dialing_peer(peer_id); return true; } - ConnectingType::IngoingConnected => peerdb.connect_outgoing(peer_id), - ConnectingType::OutgoingConnected => peerdb.connect_ingoing(peer_id), + ConnectingType::IngoingConnected { multiaddr } => { + peerdb.connect_outgoing(peer_id, multiaddr) + } + ConnectingType::OutgoingConnected { multiaddr } => { + peerdb.connect_ingoing(peer_id, multiaddr) + } } } @@ -683,12 +690,11 @@ impl PeerManager { /// NOTE: This is experimental and will likely be adjusted fn update_peer_scores(&mut self) { /* Check how long have peers been in this state and update their reputations if needed */ - let mut pdb = self.network_globals.peers.write(); let mut to_ban_peers = Vec::new(); let mut to_unban_peers = Vec::new(); - for (peer_id, info) in pdb.peers_mut() { + for (peer_id, info) in self.network_globals.peers.write().peers_mut() { let previous_state = info.score_state(); // Update scores info.score_update(); @@ -780,14 +786,51 @@ impl PeerManager { } // process banning peers for peer_id in to_ban_peers { - pdb.ban(&peer_id); + self.ban_peer(&peer_id); } // process unbanning peers for peer_id in to_unban_peers { - pdb.unban(&peer_id); + self.unban_peer(&peer_id); } } + /// Bans a peer. + /// + /// Records updates the peers connection status and updates the peer db as well as blocks the + /// peer from participating in discovery and removes them from the routing table. + fn ban_peer(&mut self, peer_id: &PeerId) { + let mut peer_db = self.network_globals.peers.write(); + peer_db.ban(peer_id); + let banned_ip_addresses = peer_db + .peer_info(peer_id) + .map(|info| { + info.seen_addresses + .iter() + .filter(|ip| peer_db.is_ip_banned(ip)) + .cloned() + .collect::>() + }) + .unwrap_or_default(); + + self.discovery.ban_peer(&peer_id, banned_ip_addresses); + } + + /// Unbans a peer. + /// + /// Records updates the peers connection status and updates the peer db as well as removes + /// previous bans from discovery. + fn unban_peer(&mut self, peer_id: &PeerId) { + let mut peer_db = self.network_globals.peers.write(); + peer_db.unban(&peer_id); + + let seen_ip_addresses = peer_db + .peer_info(peer_id) + .map(|info| info.seen_addresses.iter().cloned().collect::>()) + .unwrap_or_default(); + + self.discovery.unban_peer(&peer_id, seen_ip_addresses); + } + /// The Peer manager's heartbeat maintains the peer count and maintains peer reputations. /// /// It will request discovery queries if the peer count has not reached the desired number of @@ -894,7 +937,13 @@ enum ConnectingType { /// We are in the process of dialing this peer. Dialing, /// A peer has dialed us. - IngoingConnected, + IngoingConnected { + // The multiaddr the peer connected to us on. + multiaddr: Multiaddr, + }, /// We have successfully dialed a peer. - OutgoingConnected, + OutgoingConnected { + /// The multiaddr we dialed to reach the peer. + multiaddr: Multiaddr, + }, } diff --git a/beacon_node/eth2_libp2p/src/peer_manager/peer_info.rs b/beacon_node/eth2_libp2p/src/peer_manager/peer_info.rs index 2933cb7316..b62fba5045 100644 --- a/beacon_node/eth2_libp2p/src/peer_manager/peer_info.rs +++ b/beacon_node/eth2_libp2p/src/peer_manager/peer_info.rs @@ -7,6 +7,7 @@ use serde::{ ser::{SerializeStruct, Serializer}, Serialize, }; +use std::collections::HashSet; use std::net::IpAddr; use std::time::Instant; use types::{EthSpec, SubnetId}; @@ -24,8 +25,12 @@ pub struct PeerInfo { pub client: Client, /// Connection status of this peer pub connection_status: PeerConnectionStatus, - /// The known listening addresses of this peer. + /// The known listening addresses of this peer. This is given by identify and can be arbitrary + /// (including local IPs). pub listening_addresses: Vec, + /// This is addresses we have physically seen and this is what we use for banning/un-banning + /// peers. + pub seen_addresses: HashSet, /// The current syncing state of the peer. The state may be determined after it's initial /// connection. pub sync_status: PeerSyncStatus, @@ -47,7 +52,8 @@ impl Default for PeerInfo { score: Score::default(), client: Client::default(), connection_status: Default::default(), - listening_addresses: vec![], + listening_addresses: Vec::new(), + seen_addresses: HashSet::new(), sync_status: PeerSyncStatus::Unknown, meta_data: None, min_ttl: None, diff --git a/beacon_node/eth2_libp2p/src/peer_manager/peerdb.rs b/beacon_node/eth2_libp2p/src/peer_manager/peerdb.rs index 425cf4a37c..0f8774f7c9 100644 --- a/beacon_node/eth2_libp2p/src/peer_manager/peerdb.rs +++ b/beacon_node/eth2_libp2p/src/peer_manager/peerdb.rs @@ -1,7 +1,7 @@ use super::peer_info::{PeerConnectionStatus, PeerInfo}; use super::peer_sync_status::PeerSyncStatus; use super::score::{Score, ScoreState}; -use crate::multiaddr::Protocol; +use crate::multiaddr::{Multiaddr, Protocol}; use crate::rpc::methods::MetaData; use crate::PeerId; use rand::seq::SliceRandom; @@ -174,13 +174,14 @@ impl PeerDB { } fn ip_is_banned(&self, peer: &PeerInfo) -> bool { - peer.listening_addresses.iter().any(|addr| { - addr.iter().any(|p| match p { - Protocol::Ip4(ip) => self.banned_peers_count.ip_is_banned(&ip.into()), - Protocol::Ip6(ip) => self.banned_peers_count.ip_is_banned(&ip.into()), - _ => false, - }) - }) + peer.seen_addresses + .iter() + .any(|addr| self.banned_peers_count.ip_is_banned(addr)) + } + + /// Returns true if the IP is banned. + pub fn is_ip_banned(&self, ip: &IpAddr) -> bool { + self.banned_peers_count.ip_is_banned(ip) } /// Returns true if the Peer is either banned or in the disconnected state. @@ -361,7 +362,7 @@ impl PeerDB { } /// Sets a peer as connected with an ingoing connection. - pub fn connect_ingoing(&mut self, peer_id: &PeerId) { + pub fn connect_ingoing(&mut self, peer_id: &PeerId, multiaddr: Multiaddr) { let info = self.peers.entry(peer_id.clone()).or_default(); if info.connection_status.is_disconnected() { @@ -370,10 +371,19 @@ impl PeerDB { self.banned_peers_count .remove_banned_peer(&info.connection_status); info.connection_status.connect_ingoing(); + + // Add the seen ip address to the peer's info + if let Some(ip_addr) = multiaddr.iter().find_map(|p| match p { + Protocol::Ip4(ip) => Some(ip.into()), + Protocol::Ip6(ip) => Some(ip.into()), + _ => None, + }) { + info.seen_addresses.insert(ip_addr); + } } /// Sets a peer as connected with an outgoing connection. - pub fn connect_outgoing(&mut self, peer_id: &PeerId) { + pub fn connect_outgoing(&mut self, peer_id: &PeerId, multiaddr: Multiaddr) { let info = self.peers.entry(peer_id.clone()).or_default(); if info.connection_status.is_disconnected() { @@ -382,6 +392,15 @@ impl PeerDB { self.banned_peers_count .remove_banned_peer(&info.connection_status); info.connection_status.connect_outgoing(); + + // Add the seen ip address to the peer's info + if let Some(ip_addr) = multiaddr.iter().find_map(|p| match p { + Protocol::Ip4(ip) => Some(ip.into()), + Protocol::Ip6(ip) => Some(ip.into()), + _ => None, + }) { + info.seen_addresses.insert(ip_addr); + } } /// Sets the peer as disconnected. A banned peer remains banned @@ -411,20 +430,7 @@ impl PeerDB { } if !info.connection_status.is_banned() { info.connection_status - .ban( - info.listening_addresses - .iter() - .fold(Vec::new(), |mut v, a| { - for p in a { - match p { - Protocol::Ip4(ip) => v.push(ip.into()), - Protocol::Ip6(ip) => v.push(ip.into()), - _ => (), - } - } - v - }), - ); + .ban(info.seen_addresses.iter().cloned().collect()); self.banned_peers_count .add_banned_peer(&info.connection_status); } @@ -564,10 +570,10 @@ mod tests { let (n_in, n_out) = (10, 20); for _ in 0..n_in { - pdb.connect_ingoing(&random_peer); + pdb.connect_ingoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap()); } for _ in 0..n_out { - pdb.connect_outgoing(&random_peer); + pdb.connect_outgoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap()); } // the peer is known @@ -592,7 +598,7 @@ mod tests { for _ in 0..MAX_DC_PEERS + 1 { let p = PeerId::random(); - pdb.connect_ingoing(&p); + pdb.connect_ingoing(&p, "/ip4/0.0.0.0".parse().unwrap()); } assert_eq!(pdb.disconnected_peers, 0); @@ -609,7 +615,7 @@ mod tests { for _ in 0..MAX_BANNED_PEERS + 1 { let p = PeerId::random(); - pdb.connect_ingoing(&p); + pdb.connect_ingoing(&p, "/ip4/0.0.0.0".parse().unwrap()); } assert_eq!(pdb.banned_peers_count.banned_peers(), 0); @@ -627,9 +633,9 @@ mod tests { let p0 = PeerId::random(); let p1 = PeerId::random(); let p2 = PeerId::random(); - pdb.connect_ingoing(&p0); - pdb.connect_ingoing(&p1); - pdb.connect_ingoing(&p2); + pdb.connect_ingoing(&p0, "/ip4/0.0.0.0".parse().unwrap()); + pdb.connect_ingoing(&p1, "/ip4/0.0.0.0".parse().unwrap()); + pdb.connect_ingoing(&p2, "/ip4/0.0.0.0".parse().unwrap()); add_score(&mut pdb, &p0, 70.0); add_score(&mut pdb, &p1, 100.0); add_score(&mut pdb, &p2, 50.0); @@ -649,9 +655,9 @@ mod tests { let p0 = PeerId::random(); let p1 = PeerId::random(); let p2 = PeerId::random(); - pdb.connect_ingoing(&p0); - pdb.connect_ingoing(&p1); - pdb.connect_ingoing(&p2); + pdb.connect_ingoing(&p0, "/ip4/0.0.0.0".parse().unwrap()); + pdb.connect_ingoing(&p1, "/ip4/0.0.0.0".parse().unwrap()); + pdb.connect_ingoing(&p2, "/ip4/0.0.0.0".parse().unwrap()); add_score(&mut pdb, &p0, 70.0); add_score(&mut pdb, &p1, 100.0); add_score(&mut pdb, &p2, 50.0); @@ -669,18 +675,18 @@ mod tests { let random_peer = PeerId::random(); - pdb.connect_ingoing(&random_peer); + pdb.connect_ingoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap()); assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count()); dbg!("1"); - pdb.connect_ingoing(&random_peer); + pdb.connect_ingoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap()); assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count()); dbg!("1"); pdb.disconnect(&random_peer); assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count()); dbg!("1"); - pdb.connect_outgoing(&random_peer); + pdb.connect_outgoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap()); assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count()); dbg!("1"); pdb.disconnect(&random_peer); @@ -711,20 +717,20 @@ mod tests { let random_peer2 = PeerId::random(); let random_peer3 = PeerId::random(); - pdb.connect_ingoing(&random_peer); - pdb.connect_ingoing(&random_peer1); - pdb.connect_ingoing(&random_peer2); - pdb.connect_ingoing(&random_peer3); + pdb.connect_ingoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap()); + pdb.connect_ingoing(&random_peer1, "/ip4/0.0.0.0".parse().unwrap()); + pdb.connect_ingoing(&random_peer2, "/ip4/0.0.0.0".parse().unwrap()); + pdb.connect_ingoing(&random_peer3, "/ip4/0.0.0.0".parse().unwrap()); assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count()); assert_eq!( pdb.banned_peers_count.banned_peers(), pdb.banned_peers().count() ); - pdb.connect_ingoing(&random_peer); + pdb.connect_ingoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap()); pdb.disconnect(&random_peer1); pdb.ban(&random_peer2); - pdb.connect_ingoing(&random_peer3); + pdb.connect_ingoing(&random_peer3, "/ip4/0.0.0.0".parse().unwrap()); assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count()); assert_eq!( pdb.banned_peers_count.banned_peers(), @@ -737,7 +743,7 @@ mod tests { pdb.banned_peers().count() ); - pdb.connect_outgoing(&random_peer2); + pdb.connect_outgoing(&random_peer2, "/ip4/0.0.0.0".parse().unwrap()); assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count()); assert_eq!( pdb.banned_peers_count.banned_peers(), @@ -751,10 +757,10 @@ mod tests { ); pdb.ban(&random_peer3); - pdb.connect_ingoing(&random_peer1); + pdb.connect_ingoing(&random_peer1, "/ip4/0.0.0.0".parse().unwrap()); pdb.disconnect(&random_peer2); pdb.ban(&random_peer3); - pdb.connect_ingoing(&random_peer); + pdb.connect_ingoing(&random_peer, "/ip4/0.0.0.0".parse().unwrap()); assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count()); assert_eq!( pdb.banned_peers_count.banned_peers(), @@ -777,19 +783,14 @@ mod tests { assert_eq!(pdb.disconnected_peers, pdb.disconnected_peers().count()); } - fn connect_peer_with_ips(pdb: &mut PeerDB, ips: Vec>) -> PeerId { + fn connect_peer_with_ips(pdb: &mut PeerDB, ips: Vec) -> PeerId { let p = PeerId::random(); - pdb.connect_ingoing(&p); - pdb.peers.get_mut(&p).unwrap().listening_addresses = ips - .into_iter() - .map(|ip_addresses| { - let mut addr = Multiaddr::empty(); - for ip_address in ip_addresses { - addr.push(Protocol::from(ip_address)); - } - addr - }) - .collect(); + + for ip in ips { + let mut addr = Multiaddr::empty(); + addr.push(Protocol::from(ip)); + pdb.connect_ingoing(&p, addr); + } p } @@ -797,29 +798,29 @@ mod tests { fn test_ban_address() { let mut pdb = get_db(); - let ip1: IpAddr = Ipv4Addr::new(1, 2, 3, 4).into(); - let ip2: IpAddr = Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8).into(); - let ip3: IpAddr = Ipv4Addr::new(1, 2, 3, 5).into(); - let ip4: IpAddr = Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 9).into(); - let ip5: IpAddr = Ipv4Addr::new(2, 2, 3, 4).into(); + let ip1 = Ipv4Addr::new(1, 2, 3, 4).into(); + let ip2 = Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8).into(); + let ip3 = Ipv4Addr::new(1, 2, 3, 5).into(); + let ip4 = Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 9).into(); + let ip5 = Ipv4Addr::new(2, 2, 3, 4).into(); let mut peers = Vec::new(); for i in 0..BANNED_PEERS_PER_IP_THRESHOLD + 2 { peers.push(connect_peer_with_ips( &mut pdb, if i == 0 { - vec![vec![ip1], vec![ip2]] + vec![ip1, ip2] } else { - vec![vec![ip1, ip2], vec![ip3, ip4]] + vec![ip1, ip2, ip3, ip4] }, )); } - let p1 = connect_peer_with_ips(&mut pdb, vec![vec![ip1]]); - let p2 = connect_peer_with_ips(&mut pdb, vec![vec![ip2, ip5]]); - let p3 = connect_peer_with_ips(&mut pdb, vec![vec![ip3], vec![ip5]]); - let p4 = connect_peer_with_ips(&mut pdb, vec![vec![ip5, ip4]]); - let p5 = connect_peer_with_ips(&mut pdb, vec![vec![ip5]]); + let p1 = connect_peer_with_ips(&mut pdb, vec![ip1]); + let p2 = connect_peer_with_ips(&mut pdb, vec![ip2, ip5]); + let p3 = connect_peer_with_ips(&mut pdb, vec![ip3, ip5]); + let p4 = connect_peer_with_ips(&mut pdb, vec![ip5, ip4]); + let p5 = connect_peer_with_ips(&mut pdb, vec![ip5]); for p in &peers[..BANNED_PEERS_PER_IP_THRESHOLD + 1] { pdb.ban(p); @@ -872,66 +873,63 @@ mod tests { let mut peers = Vec::new(); for _ in 0..BANNED_PEERS_PER_IP_THRESHOLD + 1 { - peers.push(connect_peer_with_ips(&mut pdb, vec![vec![ip1]])); + peers.push(connect_peer_with_ips(&mut pdb, vec![ip1])); } - let p1 = connect_peer_with_ips(&mut pdb, vec![vec![ip1]]); - let p2 = connect_peer_with_ips(&mut pdb, vec![vec![ip2]]); + let p1 = connect_peer_with_ips(&mut pdb, vec![ip1]); + let p2 = connect_peer_with_ips(&mut pdb, vec![ip2]); - //ban all peers + // ban all peers for p in &peers { pdb.ban(p); } - //check ip is banned + // check ip is banned assert!(pdb.is_banned(&p1)); assert!(!pdb.is_banned(&p2)); - //change addresses of banned peers + // change addresses of banned peers for p in &peers { - pdb.peers.get_mut(p).unwrap().listening_addresses = - vec![Multiaddr::empty().with(Protocol::from(ip2))]; + let seen_addresses = &mut pdb.peers.get_mut(p).unwrap().seen_addresses; + seen_addresses.clear(); + seen_addresses.insert(ip2); } - //check still the same ip is banned + // check still the same ip is banned assert!(pdb.is_banned(&p1)); assert!(!pdb.is_banned(&p2)); - //unban a peer + // unban a peer pdb.unban(&peers[0]); - //check not banned anymore + // check not banned anymore assert!(!pdb.is_banned(&p1)); assert!(!pdb.is_banned(&p2)); - //check still not banned after new ban - pdb.ban(&peers[0]); - assert!(!pdb.is_banned(&p1)); - assert!(!pdb.is_banned(&p2)); - - //unban and reban all peers + // unban and reban all peers for p in &peers { pdb.unban(p); pdb.ban(p); } - //ip2 is now banned + // ip2 is now banned assert!(!pdb.is_banned(&p1)); assert!(pdb.is_banned(&p2)); - //change ips back again + // change ips back again for p in &peers { - pdb.peers.get_mut(p).unwrap().listening_addresses = - vec![Multiaddr::empty().with(Protocol::from(ip1))]; + let seen_addresses = &mut pdb.peers.get_mut(p).unwrap().seen_addresses; + seen_addresses.clear(); + seen_addresses.insert(ip1); } - //reban every peer except one + // reban every peer except one for p in &peers[1..] { pdb.unban(p); pdb.ban(p); } - //nothing is banned + // nothing is banned assert!(!pdb.is_banned(&p1)); assert!(!pdb.is_banned(&p2)); @@ -950,7 +948,7 @@ mod tests { let log = build_log(slog::Level::Debug, false); let mut pdb: PeerDB = PeerDB::new(vec![trusted_peer.clone()], &log); - pdb.connect_ingoing(&trusted_peer); + pdb.connect_ingoing(&trusted_peer, "/ip4/0.0.0.0".parse().unwrap()); // Check trusted status and score assert!(pdb.peer_info(&trusted_peer).unwrap().is_trusted);