prefer outbound peers when syncing (consistently) (#3521)

but use inbound peer for header and body sync if necessary
sync state from inbound peer if no outbound peers to sync from
This commit is contained in:
Antioch Peverell 2020-12-15 19:11:51 +00:00 committed by GitHub
parent acba73bf40
commit 1baa59c44d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 69 additions and 44 deletions

View file

@ -128,13 +128,6 @@ impl Peers {
self.iter().connected().by_addr(addr) self.iter().connected().by_addr(addr)
} }
pub fn max_peer_difficulty(&self) -> Difficulty {
self.iter()
.connected()
.max_difficulty()
.unwrap_or(Difficulty::zero())
}
pub fn is_banned(&self, peer_addr: PeerAddr) -> bool { pub fn is_banned(&self, peer_addr: PeerAddr) -> bool {
if let Ok(peer) = self.store.get_peer(peer_addr) { if let Ok(peer) = self.store.get_peer(peer_addr) {
return peer.flags == State::Banned; return peer.flags == State::Banned;

View file

@ -26,6 +26,7 @@ use std::sync::{mpsc, Arc};
use std::{cmp, str, thread, time}; use std::{cmp, str, thread, time};
use crate::core::global; use crate::core::global;
use crate::core::pow::Difficulty;
use crate::p2p; use crate::p2p;
use crate::p2p::types::PeerAddr; use crate::p2p::types::PeerAddr;
use crate::p2p::ChainAdapter; use crate::p2p::ChainAdapter;
@ -172,15 +173,10 @@ fn monitor_peers(
total_count += 1; total_count += 1;
} }
let peers_count = peers.iter().connected().count(); let peers_iter = || peers.iter().connected();
let peers_count = peers_iter().count();
let max_diff = peers.max_peer_difficulty(); let max_diff = peers_iter().max_difficulty().unwrap_or(Difficulty::zero());
let most_work_count = peers let most_work_count = peers_iter().with_difficulty(|x| x >= max_diff).count();
.iter()
.outbound()
.with_difficulty(|x| x >= max_diff)
.connected()
.count();
debug!( debug!(
"monitor_peers: on {}:{}, {} connected ({} most_work). \ "monitor_peers: on {}:{}, {} connected ({} most_work). \

View file

@ -93,14 +93,25 @@ impl BodySync {
let head = self.chain.head()?; let head = self.chain.head()?;
// Find connected peers with strictly greater difficulty than us. // Find connected peers with strictly greater difficulty than us.
let peers: Vec<_> = self let peers_iter = || {
.peers self.peers
.iter() .iter()
.outbound() .with_difficulty(|x| x > head.total_difficulty)
.with_difficulty(|x| x > head.total_difficulty) .connected()
.connected() };
.into_iter()
.collect(); // We prefer outbound peers with greater difficulty.
let mut peers: Vec<_> = peers_iter().outbound().into_iter().collect();
if peers.is_empty() {
debug!("no outbound peers with more work, considering inbound");
peers = peers_iter().inbound().into_iter().collect();
}
// If we have no peers (outbound or inbound) then we are done for now.
if peers.is_empty() {
debug!("no peers (inbound or outbound) with more work");
return Ok(false);
}
// if we have 5 peers to sync from then ask for 50 blocks total (peer_count * // if we have 5 peers to sync from then ask for 50 blocks total (peer_count *
// 10) max will be 80 if all 8 peers are advertising more work // 10) max will be 80 if all 8 peers are advertising more work

View file

@ -19,6 +19,7 @@ use std::sync::Arc;
use crate::chain::{self, SyncState, SyncStatus}; use crate::chain::{self, SyncState, SyncStatus};
use crate::common::types::Error; use crate::common::types::Error;
use crate::core::core::hash::{Hash, Hashed}; use crate::core::core::hash::{Hash, Hashed};
use crate::core::pow::Difficulty;
use crate::p2p::{self, types::ReasonForBan, Capabilities, Peer}; use crate::p2p::{self, types::ReasonForBan, Capabilities, Peer};
pub struct HeaderSync { pub struct HeaderSync {
@ -170,15 +171,23 @@ impl HeaderSync {
fn header_sync(&mut self) -> Option<Arc<Peer>> { fn header_sync(&mut self) -> Option<Arc<Peer>> {
if let Ok(header_head) = self.chain.header_head() { if let Ok(header_head) = self.chain.header_head() {
let max_diff = self.peers.max_peer_difficulty(); let peers_iter = || {
let peer = self self.peers
.peers .iter()
.iter() .with_capabilities(Capabilities::HEADER_HIST)
.outbound() .connected()
.with_capabilities(Capabilities::HEADER_HIST) };
.with_difficulty(|x| x >= max_diff)
.connected() // Filter peers further based on max difficulty.
.choose_random(); let max_diff = peers_iter().max_difficulty().unwrap_or(Difficulty::zero());
let peers_iter = || peers_iter().with_difficulty(|x| x >= max_diff);
// Choose a random "most work" peer, preferring outbound if at all possible.
let peer = peers_iter().outbound().choose_random().or_else(|| {
warn!("no suitable outbound peer for header sync, considering inbound");
peers_iter().inbound().choose_random()
});
if let Some(peer) = peer { if let Some(peer) = peer {
if peer.info.total_difficulty() > header_head.total_difficulty { if peer.info.total_difficulty() > header_head.total_difficulty {
return self.request_headers(peer); return self.request_headers(peer);

View file

@ -19,6 +19,7 @@ use std::sync::Arc;
use crate::chain::{self, SyncState, SyncStatus}; use crate::chain::{self, SyncState, SyncStatus};
use crate::core::core::hash::Hashed; use crate::core::core::hash::Hashed;
use crate::core::global; use crate::core::global;
use crate::core::pow::Difficulty;
use crate::p2p::{self, Capabilities, Peer}; use crate::p2p::{self, Capabilities, Peer};
/// Fast sync has 3 "states": /// Fast sync has 3 "states":
@ -158,15 +159,23 @@ impl StateSync {
let mut txhashset_height = header_head.height.saturating_sub(threshold); let mut txhashset_height = header_head.height.saturating_sub(threshold);
txhashset_height = txhashset_height.saturating_sub(txhashset_height % archive_interval); txhashset_height = txhashset_height.saturating_sub(txhashset_height % archive_interval);
let max_diff = self.peers.max_peer_difficulty(); let peers_iter = || {
let peer = self self.peers
.peers .iter()
.iter() .with_capabilities(Capabilities::TXHASHSET_HIST)
.outbound() .connected()
.with_capabilities(Capabilities::TXHASHSET_HIST) };
.with_difficulty(|x| x >= max_diff)
.connected() // Filter peers further based on max difficulty.
.choose_random(); let max_diff = peers_iter().max_difficulty().unwrap_or(Difficulty::zero());
let peers_iter = || peers_iter().with_difficulty(|x| x >= max_diff);
// Choose a random "most work" peer, preferring outbound if at all possible.
let peer = peers_iter().outbound().choose_random().or_else(|| {
warn!("no suitable outbound peer for state sync, considering inbound");
peers_iter().inbound().choose_random()
});
if let Some(peer) = peer { if let Some(peer) = peer {
// ask for txhashset at state_sync_threshold // ask for txhashset at state_sync_threshold
let mut txhashset_head = self let mut txhashset_head = self

View file

@ -231,11 +231,18 @@ impl SyncRunner {
let mut is_syncing = self.sync_state.is_syncing(); let mut is_syncing = self.sync_state.is_syncing();
// Find a peer with greatest known difficulty. // Find a peer with greatest known difficulty.
let max_diff = self.peers.max_peer_difficulty(); // Consider all peers, both inbound and outbound.
// We will prioritize syncing against outbound peers exclusively when possible.
// But we do support syncing against an inbound peer if greater work than any outbound peers.
let max_diff = self
.peers
.iter()
.connected()
.max_difficulty()
.unwrap_or(Difficulty::zero());
let peer = self let peer = self
.peers .peers
.iter() .iter()
.outbound()
.with_difficulty(|x| x >= max_diff) .with_difficulty(|x| x >= max_diff)
.connected() .connected()
.choose_random(); .choose_random();