kick stuck peer out of connected peers. (#1782)

* cherry-picking commit 7754adb8 from master for #1746
This commit is contained in:
Gary Yu 2018-10-18 10:04:05 +08:00 committed by GitHub
parent d65a9adb59
commit 53b10a083c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 31 additions and 1 deletions

View file

@ -66,6 +66,10 @@ pub const TESTNET2_INITIAL_DIFFICULTY: u64 = 1000;
/// a 30x Cuckoo adjustment factor
pub const TESTNET3_INITIAL_DIFFICULTY: u64 = 30000;
/// If a peer's last updated difficulty is 2 hours ago and its difficulty's lower than ours,
/// we're sure this peer is a stuck node, and we will kick out such kind of stuck peers.
pub const STUCK_PEER_KICK_TIME: i64 = 2 * 3600 * 1000;
/// Testnet 4 initial block difficulty
/// 1_000 times natural scale factor for cuckatoo29
pub const TESTNET4_INITIAL_DIFFICULTY: u64 = 1_000 * (2<<(29-24)) * 29;

View file

@ -102,6 +102,7 @@ impl Handshake {
total_difficulty: shake.total_difficulty,
height: 0,
last_seen: Utc::now(),
stuck_detector: Utc::now(),
})),
direction: Direction::Outbound,
};
@ -161,6 +162,7 @@ impl Handshake {
total_difficulty: hand.total_difficulty,
height: 0,
last_seen: Utc::now(),
stuck_detector: Utc::now(),
})),
direction: Direction::Inbound,
};

View file

@ -18,9 +18,9 @@ use std::sync::{Arc, RwLock};
use chrono::prelude::{DateTime, Utc};
use conn;
use core::core;
use core::core::hash::{Hash, Hashed};
use core::pow::Difficulty;
use core::{core, global};
use handshake::Handshake;
use msg::{self, BanReason, GetPeerAddrs, Locator, Ping, TxHashSetRequest};
use protocol::Protocol;
@ -140,6 +140,18 @@ impl Peer {
State::Banned == *self.state.read().unwrap()
}
/// Whether this peer is stuck on sync.
pub fn is_stuck(&self) -> (bool, Difficulty) {
let peer_live_info = self.info.live_info.read().unwrap();
let now = Utc::now().timestamp_millis();
// if last updated difficulty is 2 hours ago, we're sure this peer is a stuck node.
if now > peer_live_info.stuck_detector.timestamp_millis() + global::STUCK_PEER_KICK_TIME {
(true, peer_live_info.total_difficulty)
} else {
(false, peer_live_info.total_difficulty)
}
}
/// Set this peer status to banned
pub fn set_banned(&self) {
*self.state.write().unwrap() = State::Banned;

View file

@ -424,6 +424,14 @@ impl Peers {
} else if !peer.is_connected() {
debug!(LOGGER, "clean_peers {:?}, not connected", peer.info.addr);
rm.push(peer.clone());
} else {
let (stuck, diff) = peer.is_stuck();
if stuck && diff < self.adapter.total_difficulty() {
debug!(LOGGER, "clean_peers {:?}, stuck peer", peer.info.addr);
peer.stop();
let _ = self.update_state(peer.info.addr, State::Defunct);
rm.push(peer.clone());
}
}
}

View file

@ -241,6 +241,7 @@ pub struct PeerLiveInfo {
pub total_difficulty: Difficulty,
pub height: u64,
pub last_seen: DateTime<Utc>,
pub stuck_detector: DateTime<Utc>,
}
/// General information about a connected peer that's useful to other modules.
@ -274,6 +275,9 @@ impl PeerInfo {
/// Takes a write lock on the live_info.
pub fn update(&self, height: u64, total_difficulty: Difficulty) {
let mut live_info = self.live_info.write().unwrap();
if total_difficulty != live_info.total_difficulty {
live_info.stuck_detector = Utc::now();
}
live_info.height = height;
live_info.total_difficulty = total_difficulty;
live_info.last_seen = Utc::now()