Improve peer status handling

This commit is contained in:
Paul Hauner 2019-03-25 15:30:46 +11:00
parent 708d9b5674
commit ebb9ced0a4
No known key found for this signature in database
GPG Key ID: D362883A9218FCC6
2 changed files with 81 additions and 35 deletions

View File

@ -4,7 +4,7 @@ use crate::service::{NetworkMessage, OutgoingMessage};
use crate::sync::SimpleSync; use crate::sync::SimpleSync;
use crossbeam_channel::{unbounded as channel, Sender}; use crossbeam_channel::{unbounded as channel, Sender};
use eth2_libp2p::{ use eth2_libp2p::{
rpc::{IncomingGossip, RPCRequest, RPCResponse}, rpc::{methods::GoodbyeReason, IncomingGossip, RPCRequest, RPCResponse},
PeerId, RPCEvent, PeerId, RPCEvent,
}; };
use futures::future; use futures::future;
@ -199,7 +199,8 @@ impl MessageHandler {
.on_block_gossip(peer_id, message, &mut self.network_context) .on_block_gossip(peer_id, message, &mut self.network_context)
} }
IncomingGossip::Attestation(message) => { IncomingGossip::Attestation(message) => {
// self.sync
.on_attestation_gossip(peer_id, message, &mut self.network_context)
} }
} }
} }
@ -226,7 +227,8 @@ impl NetworkContext {
} }
} }
pub fn disconnect(&self, _peer_id: PeerId) { pub fn disconnect(&mut self, peer_id: PeerId, reason: GoodbyeReason) {
self.send_rpc_request(peer_id, RPCRequest::Goodbye(reason))
// TODO: disconnect peers. // TODO: disconnect peers.
} }

View File

@ -27,9 +27,9 @@ pub struct PeerSyncInfo {
} }
impl PeerSyncInfo { impl PeerSyncInfo {
/// Returns `true` if the peer is on the same chain as `other`. /// Returns `true` if the has a different network ID to `other`.
fn is_on_same_chain(&self, other: Self) -> bool { fn has_different_network_id_to(&self, other: Self) -> bool {
self.network_id == other.network_id self.network_id != other.network_id
} }
/// Returns `true` if the peer has a higher finalized epoch than `other`. /// Returns `true` if the peer has a higher finalized epoch than `other`.
@ -41,19 +41,6 @@ impl PeerSyncInfo {
fn has_higher_best_slot_than(&self, other: Self) -> bool { fn has_higher_best_slot_than(&self, other: Self) -> bool {
self.best_slot > other.best_slot self.best_slot > other.best_slot
} }
/// Returns the `PeerStatus` of `self` in relation to `other`.
pub fn status_compared_to(&self, other: Self) -> PeerStatus {
if self.has_higher_finalized_epoch_than(other) {
PeerStatus::HigherFinalizedEpoch
} else if !self.is_on_same_chain(other) {
PeerStatus::OnDifferentChain
} else if self.has_higher_best_slot_than(other) {
PeerStatus::HigherBestSlot
} else {
PeerStatus::NotInteresting
}
}
} }
/// The status of a peers view on the chain, relative to some other view of the chain (presumably /// The status of a peers view on the chain, relative to some other view of the chain (presumably
@ -61,7 +48,9 @@ impl PeerSyncInfo {
#[derive(PartialEq, Clone, Copy, Debug)] #[derive(PartialEq, Clone, Copy, Debug)]
pub enum PeerStatus { pub enum PeerStatus {
/// The peer is on a completely different chain. /// The peer is on a completely different chain.
OnDifferentChain, DifferentNetworkId,
/// The peer lists a finalized epoch for which we have a different root.
FinalizedEpochNotInChain,
/// The peer has a higher finalized epoch. /// The peer has a higher finalized epoch.
HigherFinalizedEpoch, HigherFinalizedEpoch,
/// The peer has a higher best slot. /// The peer has a higher best slot.
@ -70,6 +59,18 @@ pub enum PeerStatus {
NotInteresting, NotInteresting,
} }
impl PeerStatus {
pub fn should_handshake(&self) -> bool {
match self {
PeerStatus::DifferentNetworkId => false,
PeerStatus::FinalizedEpochNotInChain => false,
PeerStatus::HigherFinalizedEpoch => true,
PeerStatus::HigherBestSlot => true,
PeerStatus::NotInteresting => true,
}
}
}
impl From<HelloMessage> for PeerSyncInfo { impl From<HelloMessage> for PeerSyncInfo {
fn from(hello: HelloMessage) -> PeerSyncInfo { fn from(hello: HelloMessage) -> PeerSyncInfo {
PeerSyncInfo { PeerSyncInfo {
@ -183,6 +184,51 @@ impl SimpleSync {
self.process_hello(peer_id, hello, network); self.process_hello(peer_id, hello, network);
} }
/// Returns a `PeerStatus` for some peer.
fn peer_status(&self, peer: PeerSyncInfo) -> PeerStatus {
let local = PeerSyncInfo::from(&self.chain);
if peer.has_different_network_id_to(local) {
return PeerStatus::DifferentNetworkId;
}
if local.has_higher_finalized_epoch_than(peer) {
let peer_finalized_slot = peer
.latest_finalized_epoch
.start_slot(self.chain.get_spec().slots_per_epoch);
let local_roots = self.chain.get_block_roots(peer_finalized_slot, 1, 0);
if let Ok(local_roots) = local_roots {
if let Some(local_root) = local_roots.get(0) {
if *local_root != peer.latest_finalized_root {
return PeerStatus::FinalizedEpochNotInChain;
}
} else {
error!(
self.log,
"Cannot get root for peer finalized slot.";
"error" => "empty roots"
);
}
} else {
error!(
self.log,
"Cannot get root for peer finalized slot.";
"error" => format!("{:?}", local_roots)
);
}
}
if peer.has_higher_finalized_epoch_than(local) {
PeerStatus::HigherFinalizedEpoch
} else if peer.has_higher_best_slot_than(local) {
PeerStatus::HigherBestSlot
} else {
PeerStatus::NotInteresting
}
}
/// Process a `Hello` message, requesting new blocks if appropriate. /// Process a `Hello` message, requesting new blocks if appropriate.
/// ///
/// Disconnects the peer if required. /// Disconnects the peer if required.
@ -196,26 +242,22 @@ impl SimpleSync {
let remote = PeerSyncInfo::from(hello); let remote = PeerSyncInfo::from(hello);
let local = PeerSyncInfo::from(&self.chain); let local = PeerSyncInfo::from(&self.chain);
let remote_status = remote.status_compared_to(local); let remote_status = self.peer_status(remote);
// network id must match if remote_status.should_handshake() {
if remote_status != PeerStatus::OnDifferentChain {
info!(self.log, "HandshakeSuccess"; "peer" => format!("{:?}", peer_id)); info!(self.log, "HandshakeSuccess"; "peer" => format!("{:?}", peer_id));
self.known_peers.insert(peer_id.clone(), remote); self.known_peers.insert(peer_id.clone(), remote);
} else {
info!(
self.log, "HandshakeFailure";
"peer" => format!("{:?}", peer_id),
"reason" => "network_id"
);
network.disconnect(peer_id.clone(), GoodbyeReason::IrreleventNetwork);
} }
// TODO: boot peer if finalization is wrong. // If required, send requests for blocks.
match remote_status { match remote_status {
PeerStatus::OnDifferentChain => {
info!(
self.log, "Failure";
"peer" => format!("{:?}", peer_id),
"reason" => "network_id"
);
network.disconnect(peer_id);
}
PeerStatus::HigherFinalizedEpoch => { PeerStatus::HigherFinalizedEpoch => {
let start_slot = remote let start_slot = remote
.latest_finalized_epoch .latest_finalized_epoch
@ -243,6 +285,8 @@ impl SimpleSync {
network, network,
); );
} }
PeerStatus::FinalizedEpochNotInChain => {}
PeerStatus::DifferentNetworkId => {}
PeerStatus::NotInteresting => {} PeerStatus::NotInteresting => {}
} }
} }
@ -541,7 +585,7 @@ impl SimpleSync {
"sender_peer_id" => format!("{:?}", sender), "sender_peer_id" => format!("{:?}", sender),
"reason" => format!("{:?}", outcome), "reason" => format!("{:?}", outcome),
); );
network.disconnect(sender); network.disconnect(sender, GoodbyeReason::Fault);
} }
// If this results to true, the item will be removed from the queue. // If this results to true, the item will be removed from the queue.