diff --git a/p2p/src/peer.rs b/p2p/src/peer.rs index e61e2115..69f073cc 100644 --- a/p2p/src/peer.rs +++ b/p2p/src/peer.rs @@ -13,7 +13,6 @@ // limitations under the License. use crate::util::{Mutex, RwLock}; -use chrono::Duration; use lru_cache::LruCache; use std::fmt; use std::fs::File; @@ -52,7 +51,6 @@ const MAX_PEER_MSG_PER_MIN: u64 = 500; enum State { Connected, Banned, - Blocked(DateTime, u32), } pub struct Peer { @@ -194,45 +192,6 @@ impl Peer { State::Banned == *self.state.read() } - /// Whether this peer has been blocked. - pub fn is_blocked(&self) -> bool { - match *self.state.read() { - State::Blocked(expiry, _) => expiry > Utc::now(), - _ => false, - } - } - - /// Set this peer status to blocked. - pub fn set_blocked(&self) { - if self.is_blocked() { - return; - } - let times = { - match *self.state.read() { - State::Blocked(_, times) => times + 1, - _ => 1, - } - }; - let duration = match times { - 1 => 60, // 1m - 2 => 180, // 3m - _ => 600, // 10m - }; - let expiry = Utc::now() + Duration::seconds(duration); - *self.state.write() = State::Blocked(expiry, times); - debug!( - "state_sync: block peer {} for {} times: {}", - self.info.addr, duration, times - ); - } - - /// Unblock blocked peer. - pub fn unblock(&self) { - if self.is_blocked() { - *self.state.write() = State::Connected; - } - } - /// Whether this peer is stuck on sync. pub fn is_stuck(&self) -> (bool, Difficulty) { let peer_live_info = self.info.live_info.read(); diff --git a/p2p/src/peers.rs b/p2p/src/peers.rs index cdfe134b..77431a5e 100644 --- a/p2p/src/peers.rs +++ b/p2p/src/peers.rs @@ -45,6 +45,7 @@ pub struct Peers { pub adapter: Arc, store: PeerStore, peers: RwLock>>, + blocked: RwLock, u32)>>, config: P2PConfig, } @@ -55,6 +56,7 @@ impl Peers { store, config, peers: RwLock::new(HashMap::new()), + blocked: RwLock::new(HashMap::new()), } } @@ -450,32 +452,55 @@ impl Peers { } } - /// Temporary block a peer without banning it. - pub fn block_peer(&self, peer_addr: PeerAddr, reason: &str) -> Result<(), Error> { - let peers = self.peers.try_read_for(LOCK_TIMEOUT).ok_or_else(|| { - error!("block_peer: failed to get peers lock"); - Error::PeerException - })?; - match peers.get(&peer_addr) { - None => Err(Error::PeerNotFound), - Some(peer) => { - warn!("blocking peer {} ({})", peer_addr, reason); - peer.set_blocked(); - Ok(()) + /// Whether this peer has been blocked. + pub fn is_blocked(&self, peer_addr: PeerAddr) -> bool { + match self.blocked.try_read_for(LOCK_TIMEOUT) { + Some(peers) => match peers.get(&peer_addr) { + None => false, + Some((expiry, _)) => expiry > &Utc::now(), + }, + None => { + error!("is_blocked: failed to get peers lock"); + false } } } - /// Unblock blocked peers. - pub fn unblock_peers(&self) -> Result<(), Error> { - let peers = self.peers.try_read_for(LOCK_TIMEOUT).ok_or_else(|| { - error!("unblock_peers: failed to get peers lock"); + /// Temporary block a peer without banning it. + pub fn block_peer(&self, peer_addr: PeerAddr, reason: &str) -> Result<(), Error> { + let mut blocked = self.blocked.try_write_for(LOCK_TIMEOUT).ok_or_else(|| { + error!("block_peer: failed to get blocked lock"); Error::PeerException })?; - let peers = peers.iter().into_iter(); - let _ = peers - .filter(|(_, peer)| peer.is_blocked()) - .for_each(|(_, peer)| peer.unblock()); + + let times = { + match blocked.get(&peer_addr) { + Some((_, times)) => times + 1, + None => 1, + } + }; + let duration = match times { + 1 => 60, // 1m + 2 => 180, // 3m + _ => 600, // 10m + }; + let expiry = Utc::now() + Duration::seconds(duration); + blocked.insert(peer_addr, (expiry, times)); + + warn!( + "state_sync: block peer {} ({}) for {} times: {}", + peer_addr, reason, duration, times + ); + Ok(()) + } + + /// Unblock all blocked peers. + pub fn unblock_peers(&self) -> Result<(), Error> { + let mut blocked = self.blocked.try_write_for(LOCK_TIMEOUT).ok_or_else(|| { + error!("unblock_peers: failed to get blocked lock"); + Error::PeerException + })?; + blocked.clear(); Ok(()) } @@ -839,13 +864,6 @@ impl>> PeersIter { } } - /// Filter non-blocked peers. - pub fn non_blocked(self) -> PeersIter>> { - PeersIter { - iter: self.iter.filter(|p| !p.is_blocked()), - } - } - /// Filter peers with the provided difficulty comparison fn. /// /// with_difficulty(|x| x > diff)