diff --git a/client/src/client.rs b/client/src/client.rs index 2e18c26c..5e4e0a3e 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -301,7 +301,7 @@ impl> Client { if config.protocol.connect.is_empty() && peers.is_empty() { log::info!("Address book is empty. Trying DNS seeds.."); peers.seed( - network.seeds().iter().map(|s| (*s, network.port())), + network.seeds().iter().map(|s| (s.as_str(), network.port())), Source::Dns, )?; peers.flush()?; diff --git a/common/src/network.rs b/common/src/network.rs index dc4af0e8..928bf64d 100644 --- a/common/src/network.rs +++ b/common/src/network.rs @@ -1,4 +1,5 @@ //! Bitcoin peer network. Eg. *Mainnet*. +use std::vec; use bitcoin::blockdata::block::{Block, BlockHeader}; use bitcoin::consensus::params::Params; @@ -99,29 +100,52 @@ impl Network { } } + /// Return the flag generated by the composition of the service flags. + fn service_flags(&self, services: &[ServiceFlags]) -> String { + let combination: u64 = services.iter().map(|service| service.as_u64()).sum(); + format!("x{:x}", combination) + } + /// DNS seeds. Used to bootstrap the client's address book. - pub fn seeds(&self) -> &[&str] { - match self { - Network::Mainnet => &[ - "seed.bitcoin.sipa.be", // Pieter Wuille - "dnsseed.bluematt.me", // Matt Corallo - "dnsseed.bitcoin.dashjr.org", // Luke Dashjr - "seed.bitcoinstats.com", // Christian Decker - "seed.bitcoin.jonasschnelli.ch", // Jonas Schnelli - "seed.btc.petertodd.org", // Peter Todd - "seed.bitcoin.sprovoost.nl", // Sjors Provoost - "dnsseed.emzy.de", // Stephan Oeste - "seed.bitcoin.wiz.biz", // Jason Maurice - "seed.cloudhead.io", // Alexis Sellier + pub fn seeds(&self) -> Vec { + let seed_list = match self { + Network::Mainnet => vec![ + "seed.bitcoin.sipa.be", // Pieter Wuille + "dnsseed.bluematt.me", // Matt Corallo + "dnsseed.bitcoin.dashjr.org", // Luke Dashjr + "seed.bitcoinstats.com", // Christian Decker + // "seed.bitcoin.jonasschnelli.ch", // Jonas Schnelli + "seed.btc.petertodd.org", // Peter Todd + "seed.bitcoin.sprovoost.nl", // Sjors Provoost + "dnsseed.emzy.de", // Stephan Oeste + "seed.bitcoin.wiz.biz", // Jason Maurice + "seed.cloudhead.io", // Alexis Sellier ], - Network::Testnet => &[ + Network::Testnet => vec![ "testnet-seed.bitcoin.jonasschnelli.ch", "seed.tbtc.petertodd.org", "seed.testnet.bitcoin.sprovoost.nl", "testnet-seed.bluematt.me", ], - Network::Regtest => &[], // No seeds + Network::Regtest => vec![], // No seeds + }; + + // We index this array by a step = 2, so + // each new seed has the following rules + // index i: Contains the dns with service flag + // index i + 1 Contains the pure dns without service flag + // the step size it is the number of feature typology supported + // in this case are 2, because we support ANY, and NETWORK + COMPACT_FILTERS + let mut feature_seeds = Vec::new(); + let flag = self.service_flags(&[ServiceFlags::NETWORK, ServiceFlags::COMPACT_FILTERS]); + for seed in seed_list.iter() { + // Adding dns seed with service flag + let feature_seed = format!("{}.{}", flag, seed); + feature_seeds.push(feature_seed); + // Adding dns seed without service flag + feature_seeds.push(seed.to_string()); } + feature_seeds } } diff --git a/common/src/p2p/peer.rs b/common/src/p2p/peer.rs index f9f9cb10..6a58dec0 100644 --- a/common/src/p2p/peer.rs +++ b/common/src/p2p/peer.rs @@ -1,12 +1,12 @@ //! Shared peer types. +use log::debug; use std::io; use std::net; -use microserde as serde; - use bitcoin::network::address::Address; use bitcoin::network::constants::ServiceFlags; +use microserde as serde; use crate::block::time::LocalTime; @@ -40,15 +40,19 @@ pub trait Store { /// Seed the peer store with addresses. /// Fails if *none* of the seeds could be resolved to addresses. - fn seed( + fn seed( &mut self, - seeds: impl Iterator, + mut seeds: impl Iterator, source: Source, ) -> io::Result<()> { - let mut error = None; + let mut fail = false; let mut success = false; - - for seed in seeds { + // TODO: Introduce a step that mean how many combination + // of services flags we need to try before check the seeds without + // services flags. + // for the moment it is 2, but we need a more general solution. + while let Some(seed) = seeds.next() { + debug!("Resolving DNS seed {:?}", seed); match seed.to_socket_addrs() { Ok(addrs) => { success = true; @@ -62,18 +66,23 @@ pub trait Store { ), ); } + // skip the item in position +1 because it is a recovered seed + // in case we receive a failure in match branch + if !fail { + seeds.next(); + } + fail = false; + } + Err(err) => { + debug!("Error During DNS seed resolution {:?}", err); + fail = true; } - Err(err) => error = Some(err), } } - - if success { - return Ok(()); - } - if let Some(err) = error { + if !success { return Err(io::Error::new( io::ErrorKind::Other, - format!("seeds failed to resolve: {}", err), + "All seeds failed to resolve", )); } Ok(())