Zebra/zebra-network/src/config.rs

135 lines
4.7 KiB
Rust

use std::{collections::HashSet, net::SocketAddr, string::String, time::Duration};
use zebra_chain::parameters::Network;
/// Configuration for networking code.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields, default)]
pub struct Config {
/// The address on which this node should listen for connections.
pub listen_addr: SocketAddr,
/// The network to connect to.
pub network: Network,
/// A list of initial peers for the peerset when operating on
/// mainnet.
pub initial_mainnet_peers: HashSet<String>,
/// A list of initial peers for the peerset when operating on
/// testnet.
pub initial_testnet_peers: HashSet<String>,
/// The initial target size for the peer set.
///
/// If you have a slow network connection, and Zebra is having trouble
/// syncing, try reducing the peer set size. You can also reduce the peer
/// set size to reduce Zebra's bandwidth usage.
pub peerset_initial_target_size: usize,
/// How frequently we attempt to connect to a new peer.
pub new_peer_interval: Duration,
}
impl Config {
/// Concurrently resolves `peers` into zero or more IP addresses, with a timeout
/// of a few seconds on each DNS request.
///
/// If DNS resolution fails or times out for all peers, returns an empty list.
async fn parse_peers(peers: &HashSet<String>) -> HashSet<SocketAddr> {
use futures::stream::StreamExt;
let peer_addresses = peers
.iter()
.map(|s| Config::resolve_host(s))
.collect::<futures::stream::FuturesUnordered<_>>()
.concat()
.await;
if peer_addresses.is_empty() {
tracing::warn!(
?peers,
?peer_addresses,
"empty peer list after DNS resolution"
);
};
peer_addresses
}
/// Get the initial seed peers based on the configured network.
pub async fn initial_peers(&self) -> HashSet<SocketAddr> {
match self.network {
Network::Mainnet => Config::parse_peers(&self.initial_mainnet_peers).await,
Network::Testnet => Config::parse_peers(&self.initial_testnet_peers).await,
}
}
/// Resolves `host` into zero or more IP addresses.
///
/// If `host` is a DNS name, performs DNS resolution with a timeout of a few seconds.
/// If DNS resolution fails or times out, returns an empty list.
async fn resolve_host(host: &str) -> HashSet<SocketAddr> {
let fut = tokio::net::lookup_host(host);
let fut = tokio::time::timeout(crate::constants::DNS_LOOKUP_TIMEOUT, fut);
match fut.await {
Ok(Ok(ips)) => ips.collect(),
Ok(Err(e)) => {
tracing::info!(?host, ?e, "DNS error resolving peer IP address");
HashSet::new()
}
Err(e) => {
tracing::info!(?host, ?e, "DNS timeout resolving peer IP address");
HashSet::new()
}
}
}
}
impl Default for Config {
fn default() -> Config {
let mainnet_peers = [
"dnsseed.z.cash:8233",
"dnsseed.str4d.xyz:8233",
"mainnet.seeder.zfnd.org:8233",
"mainnet.is.yolo.money:8233",
]
.iter()
.map(|&s| String::from(s))
.collect();
let testnet_peers = [
"dnsseed.testnet.z.cash:18233",
"testnet.seeder.zfnd.org:18233",
"testnet.is.yolo.money:18233",
]
.iter()
.map(|&s| String::from(s))
.collect();
Config {
listen_addr: "0.0.0.0:8233"
.parse()
.expect("Hardcoded address should be parseable"),
network: Network::Mainnet,
initial_mainnet_peers: mainnet_peers,
initial_testnet_peers: testnet_peers,
new_peer_interval: Duration::from_secs(60),
// The default peerset target size should be large enough to ensure
// nodes have a reliable set of peers. But it should also be limited
// to a reasonable size, to avoid queueing too many in-flight block
// downloads. A large queue of in-flight block downloads can choke a
// constrained local network connection.
//
// We assume that Zebra nodes have at least 10 Mbps bandwidth.
// Therefore, a maximum-sized block can take up to 2 seconds to
// download. So a full default peer set adds up to 100 seconds worth
// of blocks to the queue.
//
// But the peer set for slow nodes is typically much smaller, due to
// the handshake RTT timeout.
peerset_initial_target_size: 50,
}
}
}