more consistent handling of peers_preferred during startup (#3578)

This commit is contained in:
Antioch Peverell 2021-03-02 20:34:55 +00:00 committed by GitHub
parent 03b7518884
commit 4284458e17
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 43 deletions

View file

@ -529,6 +529,40 @@ impl Readable for PeerAddrs {
} }
} }
impl IntoIterator for PeerAddrs {
type Item = PeerAddr;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.peers.into_iter()
}
}
impl Default for PeerAddrs {
fn default() -> Self {
PeerAddrs { peers: vec![] }
}
}
impl PeerAddrs {
pub fn as_slice(&self) -> &[PeerAddr] {
self.peers.as_slice()
}
pub fn contains(&self, addr: &PeerAddr) -> bool {
self.peers.contains(addr)
}
pub fn difference(&self, other: &[PeerAddr]) -> PeerAddrs {
let peers = self
.peers
.iter()
.filter(|x| !other.contains(x))
.cloned()
.collect();
PeerAddrs { peers }
}
}
/// We found some issue in the communication, sending an error back, usually /// We found some issue in the communication, sending an error back, usually
/// followed by closing the connection. /// followed by closing the connection.
pub struct PeerError { pub struct PeerError {

View file

@ -27,6 +27,7 @@ use crate::core::core::hash::{Hash, Hashed};
use crate::core::core::{OutputIdentifier, Segment, SegmentIdentifier, TxKernel}; use crate::core::core::{OutputIdentifier, Segment, SegmentIdentifier, TxKernel};
use crate::core::global; use crate::core::global;
use crate::core::pow::Difficulty; use crate::core::pow::Difficulty;
use crate::msg::PeerAddrs;
use crate::peer::Peer; use crate::peer::Peer;
use crate::store::{PeerData, PeerStore, State}; use crate::store::{PeerData, PeerStore, State};
use crate::types::{ use crate::types::{
@ -322,8 +323,10 @@ impl Peers {
&self, &self,
max_inbound_count: usize, max_inbound_count: usize,
max_outbound_count: usize, max_outbound_count: usize,
preferred_peers: &[PeerAddr], config: P2PConfig,
) { ) {
let preferred_peers = config.peers_preferred.unwrap_or(PeerAddrs::default());
let mut rm = vec![]; let mut rm = vec![];
// build a list of peers to be cleaned up // build a list of peers to be cleaned up

View file

@ -19,6 +19,7 @@
use chrono::prelude::{DateTime, Utc}; use chrono::prelude::{DateTime, Utc};
use chrono::{Duration, MIN_DATE}; use chrono::{Duration, MIN_DATE};
use p2p::{msg::PeerAddrs, P2PConfig};
use rand::prelude::*; use rand::prelude::*;
use std::collections::HashMap; use std::collections::HashMap;
use std::net::ToSocketAddrs; use std::net::ToSocketAddrs;
@ -51,11 +52,9 @@ const TESTNET_DNS_SEEDS: &[&str] = &[
pub fn connect_and_monitor( pub fn connect_and_monitor(
p2p_server: Arc<p2p::Server>, p2p_server: Arc<p2p::Server>,
seed_list: Box<dyn Fn() -> Vec<PeerAddr> + Send>, seed_list: Box<dyn Fn() -> Vec<PeerAddr> + Send>,
preferred_peers: &[PeerAddr], config: P2PConfig,
stop_state: Arc<StopState>, stop_state: Arc<StopState>,
) -> std::io::Result<thread::JoinHandle<()>> { ) -> std::io::Result<thread::JoinHandle<()>> {
let preferred_peers = preferred_peers.to_vec();
thread::Builder::new() thread::Builder::new()
.name("seed".to_string()) .name("seed".to_string())
.spawn(move || { .spawn(move || {
@ -66,12 +65,7 @@ pub fn connect_and_monitor(
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
// check seeds first // check seeds first
connect_to_seeds_and_preferred_peers( connect_to_seeds_and_peers(peers.clone(), tx.clone(), seed_list, config);
peers.clone(),
tx.clone(),
seed_list,
&preferred_peers,
);
let mut prev = MIN_DATE.and_hms(0, 0, 0); let mut prev = MIN_DATE.and_hms(0, 0, 0);
let mut prev_expire_check = MIN_DATE.and_hms(0, 0, 0); let mut prev_expire_check = MIN_DATE.and_hms(0, 0, 0);
@ -109,12 +103,7 @@ pub fn connect_and_monitor(
); );
// monitor additional peers if we need to add more // monitor additional peers if we need to add more
monitor_peers( monitor_peers(peers.clone(), p2p_server.config.clone(), tx.clone());
peers.clone(),
p2p_server.config.clone(),
tx.clone(),
&preferred_peers,
);
prev = Utc::now(); prev = Utc::now();
start_attempt = cmp::min(6, start_attempt + 1); start_attempt = cmp::min(6, start_attempt + 1);
@ -137,12 +126,7 @@ pub fn connect_and_monitor(
}) })
} }
fn monitor_peers( fn monitor_peers(peers: Arc<p2p::Peers>, config: p2p::P2PConfig, tx: mpsc::Sender<PeerAddr>) {
peers: Arc<p2p::Peers>,
config: p2p::P2PConfig,
tx: mpsc::Sender<PeerAddr>,
preferred_peers: &[PeerAddr],
) {
// regularly check if we need to acquire more peers and if so, gets // regularly check if we need to acquire more peers and if so, gets
// them from db // them from db
let mut total_count = 0; let mut total_count = 0;
@ -195,7 +179,7 @@ fn monitor_peers(
peers.clean_peers( peers.clean_peers(
config.peer_max_inbound_count() as usize, config.peer_max_inbound_count() as usize,
config.peer_max_outbound_count() as usize, config.peer_max_outbound_count() as usize,
preferred_peers, config.clone(),
); );
if peers.enough_outbound_peers() { if peers.enough_outbound_peers() {
@ -221,13 +205,14 @@ fn monitor_peers(
} }
// Attempt to connect to any preferred peers. // Attempt to connect to any preferred peers.
for p in preferred_peers { let peers_preferred = config.peers_preferred.unwrap_or(PeerAddrs::default());
for p in peers_preferred {
if !connected_peers.is_empty() { if !connected_peers.is_empty() {
if !connected_peers.contains(p) { if !connected_peers.contains(&p) {
tx.send(*p).unwrap(); let _ = tx.send(p);
} }
} else { } else {
tx.send(*p).unwrap(); let _ = tx.send(p);
} }
} }
@ -261,33 +246,50 @@ fn monitor_peers(
// Check if we have any pre-existing peer in db. If so, start with those, // Check if we have any pre-existing peer in db. If so, start with those,
// otherwise use the seeds provided. // otherwise use the seeds provided.
fn connect_to_seeds_and_preferred_peers( fn connect_to_seeds_and_peers(
peers: Arc<p2p::Peers>, peers: Arc<p2p::Peers>,
tx: mpsc::Sender<PeerAddr>, tx: mpsc::Sender<PeerAddr>,
seed_list: Box<dyn Fn() -> Vec<PeerAddr>>, seed_list: Box<dyn Fn() -> Vec<PeerAddr>>,
peers_preferred: &[PeerAddr], config: P2PConfig,
) { ) {
let peers_deny = config.peers_deny.unwrap_or(PeerAddrs::default());
// If "peers_allow" is explicitly configured then just use this list
// remembering to filter out "peers_deny".
if let Some(peers) = config.peers_allow {
for addr in peers.difference(peers_deny.as_slice()) {
let _ = tx.send(addr);
}
return;
}
// Always try our "peers_preferred" remembering to filter out "peers_deny".
if let Some(peers) = config.peers_preferred {
for addr in peers.difference(peers_deny.as_slice()) {
let _ = tx.send(addr);
}
}
// check if we have some peers in db // check if we have some peers in db
// look for peers that are able to give us other peers (via PEER_LIST capability) // look for peers that are able to give us other peers (via PEER_LIST capability)
let peers = peers.find_peers(p2p::State::Healthy, p2p::Capabilities::PEER_LIST, 100); let peers = peers.find_peers(p2p::State::Healthy, p2p::Capabilities::PEER_LIST, 100);
// if so, get their addresses, otherwise use our seeds // if so, get their addresses, otherwise use our seeds
let mut peer_addrs = if peers.len() > 3 { let peer_addrs = if peers.len() > 3 {
peers.iter().map(|p| p.addr).collect::<Vec<_>>() peers.iter().map(|p| p.addr).collect::<Vec<_>>()
} else { } else {
seed_list() seed_list()
}; };
// If we have preferred peers add them to the initial list
peer_addrs.extend_from_slice(peers_preferred);
if peer_addrs.is_empty() { if peer_addrs.is_empty() {
warn!("No seeds were retrieved."); warn!("No seeds were retrieved.");
} }
// connect to this first set of addresses // connect to this initial set of peer addresses (either seeds or from our local db).
for addr in peer_addrs { for addr in peer_addrs {
tx.send(addr).unwrap(); if !peers_deny.as_slice().contains(&addr) {
let _ = tx.send(addr);
}
} }
} }

View file

@ -240,7 +240,7 @@ impl Server {
let mut connect_thread = None; let mut connect_thread = None;
if config.p2p_config.seeding_type != p2p::Seeding::Programmatic { if config.p2p_config.seeding_type != p2p::Seeding::Programmatic {
let seeder = match config.p2p_config.seeding_type { let seed_list = match config.p2p_config.seeding_type {
p2p::Seeding::None => { p2p::Seeding::None => {
warn!("No seed configured, will stay solo until connected to"); warn!("No seed configured, will stay solo until connected to");
seed::predefined_seeds(vec![]) seed::predefined_seeds(vec![])
@ -257,15 +257,10 @@ impl Server {
_ => unreachable!(), _ => unreachable!(),
}; };
let preferred_peers = match &config.p2p_config.peers_preferred {
Some(addrs) => addrs.peers.clone(),
None => vec![],
};
connect_thread = Some(seed::connect_and_monitor( connect_thread = Some(seed::connect_and_monitor(
p2p_server.clone(), p2p_server.clone(),
seeder, seed_list,
&preferred_peers, config.p2p_config.clone(),
stop_state.clone(), stop_state.clone(),
)?); )?);
} }