diff --git a/zebra-network/src/config.rs b/zebra-network/src/config.rs index 4096fea4f..eed42b60c 100644 --- a/zebra-network/src/config.rs +++ b/zebra-network/src/config.rs @@ -1,4 +1,7 @@ -use std::{net::SocketAddr, time::Duration}; +use std::{ + net::{SocketAddr, ToSocketAddrs}, + time::Duration, +}; use crate::network::Network; @@ -8,14 +11,23 @@ use crate::network::Network; 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, + /// The user-agent to advertise. pub user_agent: String, - /// A list of initial peers for the peerset. + + /// A list of initial peers for the peerset when operating on + /// mainnet. /// /// XXX this should be replaced with DNS names, not SocketAddrs - pub initial_peers: Vec, + pub initial_mainnet_peers: Vec, + + /// A list of initial peers for the peerset when operating on + /// testnet. + pub initial_testnet_peers: Vec, + /// The outgoing request buffer size for the peer set. pub peerset_request_buffer_size: usize, @@ -23,14 +35,35 @@ pub struct Config { // serializer, the Duration fields should come last. /// The default RTT estimate for peer responses, used in load-balancing. pub ewma_default_rtt: Duration, + /// The decay time for the exponentially-weighted moving average response time. pub ewma_decay_time: Duration, + /// The timeout for peer handshakes. pub handshake_timeout: Duration, + /// How frequently we attempt to connect to a new peer. pub new_peer_interval: Duration, } +impl Config { + fn parse_peers(peers: Vec) -> Vec { + peers + .iter() + .flat_map(|s| s.to_socket_addrs()) + .flatten() + .collect::>() + } + + /// Get the initial seed peers based on the configured network. + pub fn initial_peers(&self) -> Vec { + match self.network { + Network::Mainnet => self.initial_mainnet_peers.clone(), + Network::Testnet => self.initial_testnet_peers.clone(), + } + } +} + impl Default for Config { fn default() -> Config { Config { @@ -39,7 +72,12 @@ impl Default for Config { .expect("Hardcoded address should be parseable"), user_agent: crate::constants::USER_AGENT.to_owned(), network: Network::Mainnet, - initial_peers: Vec::new(), + initial_mainnet_peers: Config::parse_peers(vec![ + "dnsseed.z.cash:8233", + "dnsseed.str4d.xyz:8233", + "dnsseed.znodes.org:8233", + ]), + initial_testnet_peers: Config::parse_peers(vec!["dnsseed.testnet.z.cash:18233"]), ewma_default_rtt: Duration::from_secs(1), ewma_decay_time: Duration::from_secs(60), peerset_request_buffer_size: 1, diff --git a/zebra-network/src/peer_set.rs b/zebra-network/src/peer_set.rs index 2d5b70e6d..44ac0255b 100644 --- a/zebra-network/src/peer_set.rs +++ b/zebra-network/src/peer_set.rs @@ -103,7 +103,7 @@ where // 1. Initial peers, specified in the config. tokio::spawn(add_initial_peers( - config.initial_peers.clone(), + config.initial_peers(), connector.clone(), peerset_tx.clone(), )); diff --git a/zebrad/src/commands.rs b/zebrad/src/commands.rs index af1db925f..79d8e80bc 100644 --- a/zebrad/src/commands.rs +++ b/zebrad/src/commands.rs @@ -12,10 +12,13 @@ mod config; mod connect; +mod seed; mod start; mod version; -use self::{config::ConfigCmd, connect::ConnectCmd, start::StartCmd, version::VersionCmd}; +use self::{ + config::ConfigCmd, connect::ConnectCmd, seed::SeedCmd, start::StartCmd, version::VersionCmd, +}; use crate::config::ZebradConfig; use abscissa_core::{ config::Override, Command, Configurable, FrameworkError, Help, Options, Runnable, @@ -47,6 +50,10 @@ pub enum ZebradCmd { /// The `connect` subcommand #[options(help = "testing stub for dumping network messages")] Connect(ConnectCmd), + + /// The `seed` subcommand + #[options(help = "dns seeder")] + Seed(SeedCmd), } /// This trait allows you to define how application configuration is loaded. diff --git a/zebrad/src/commands/connect.rs b/zebrad/src/commands/connect.rs index 464ea0194..b24dc2893 100644 --- a/zebrad/src/commands/connect.rs +++ b/zebrad/src/commands/connect.rs @@ -66,9 +66,7 @@ impl ConnectCmd { 1, ); - let mut config = app_config().network.clone(); - - config.initial_peers = vec![self.addr]; + let config = app_config().network.clone(); let (mut peer_set, address_book) = zebra_network::init(config, node).await; diff --git a/zebrad/src/commands/seed.rs b/zebrad/src/commands/seed.rs new file mode 100644 index 000000000..f4bbf0662 --- /dev/null +++ b/zebrad/src/commands/seed.rs @@ -0,0 +1,99 @@ +//! `seed` subcommand - test stub for talking to zcashd + +use crate::{config::ZebradConfig, prelude::*}; + +use abscissa_core::{config, Command, FrameworkError, Options, Runnable}; + +/// `seed` subcommand +/// +/// A DNS seeder command to spider and collect as many valid peer +/// addresses as we can. +#[derive(Command, Debug, Options)] +pub struct SeedCmd { + /// Filter strings + #[options(free)] + filters: Vec, +} + +impl config::Override for SeedCmd { + // Process the given command line options, overriding settings + // from a configuration file using explicit flags taken from + // command-line arguments. + fn override_config(&self, mut config: ZebradConfig) -> Result { + if !self.filters.is_empty() { + config.tracing.filter = self.filters.join(","); + } + + Ok(config) + } +} + +impl Runnable for SeedCmd { + /// Start the application. + fn run(&self) { + use crate::components::tokio::TokioComponent; + + let wait = tokio::future::pending::<()>(); + // Combine the seed future with an infinite wait + // so that the program has to be explicitly killed and + // won't die before all tracing messages are written. + let fut = futures::future::join( + async { + match self.seed().await { + Ok(()) => {} + Err(e) => { + // Print any error that occurs. + error!(?e); + } + } + }, + wait, + ); + + let _ = app_reader() + .state() + .components + .get_downcast_ref::() + .expect("TokioComponent should be available") + .rt + .block_on(fut); + } +} + +impl SeedCmd { + async fn seed(&self) -> Result<(), failure::Error> { + use failure::Error; + use futures::stream::{FuturesUnordered, StreamExt}; + use tower::{buffer::Buffer, service_fn, Service, ServiceExt}; + use zebra_network::{AddressBook, Request, Response}; + + info!("begin tower-based peer handling test stub"); + + let node = Buffer::new( + service_fn(|req| { + async move { + info!(?req); + Ok::(Response::Ok) + } + }), + 1, + ); + + let config = app_config().network.clone(); + + // XXX How do I create a service above that answers questions + // about this specific address book? + let (mut peer_set, address_book) = zebra_network::init(config, node).await; + + // XXX Do not tell our DNS seed queries about gossiped addrs + // that we have not connected to before? + info!("waiting for peer_set ready"); + peer_set.ready().await.map_err(Error::from_boxed_compat)?; + + info!("peer_set became ready"); + + loop {} + + Ok(()) + } +}