From 89283f9a1f752653e04095d60e10e6b2e81e9a27 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Thu, 24 Oct 2019 16:28:42 -0400 Subject: [PATCH 01/15] Default init seed nodes based on network choice And more flushed out but incomplete --- zebra-network/src/config.rs | 46 ++++++++++++++-- zebra-network/src/peer_set.rs | 2 +- zebrad/src/commands.rs | 9 +++- zebrad/src/commands/connect.rs | 4 +- zebrad/src/commands/seed.rs | 99 ++++++++++++++++++++++++++++++++++ 5 files changed, 151 insertions(+), 9 deletions(-) create mode 100644 zebrad/src/commands/seed.rs diff --git a/zebra-network/src/config.rs b/zebra-network/src/config.rs index 4096fea4f48..eed42b60c60 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 2d5b70e6d2a..44ac0255be8 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 af1db925f9c..79d8e80bccd 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 464ea019435..b24dc289303 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 00000000000..f4bbf066233 --- /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(()) + } +} From 064c2acdefd97d68d571b244b95605d3590f4da5 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Fri, 25 Oct 2019 23:54:44 -0400 Subject: [PATCH 02/15] Keep sets of initial peers as Strings in config file --- zebra-network/src/config.rs | 31 +++++++++++++++++++++---------- zebrad/src/commands.rs | 2 ++ zebrad/src/commands/config.rs | 2 +- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/zebra-network/src/config.rs b/zebra-network/src/config.rs index eed42b60c60..587dd085804 100644 --- a/zebra-network/src/config.rs +++ b/zebra-network/src/config.rs @@ -1,5 +1,6 @@ use std::{ net::{SocketAddr, ToSocketAddrs}, + string::String, time::Duration, }; @@ -22,11 +23,11 @@ pub struct Config { /// mainnet. /// /// XXX this should be replaced with DNS names, not SocketAddrs - pub initial_mainnet_peers: Vec, + pub initial_mainnet_peers: Vec, /// A list of initial peers for the peerset when operating on /// testnet. - pub initial_testnet_peers: Vec, + pub initial_testnet_peers: Vec, /// The outgoing request buffer size for the peer set. pub peerset_request_buffer_size: usize, @@ -58,26 +59,36 @@ impl Config { /// 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(), + Network::Mainnet => Config::parse_peers(self.initial_mainnet_peers.clone()), + Network::Testnet => Config::parse_peers(self.initial_testnet_peers.clone()), } } } impl Default for Config { fn default() -> Config { + let mainnet_peers = [ + "dnsseed.z.cash:8233", + "dnsseed.str4d.xyz:8233", + "dnsseed.znodes.org:8233", + ] + .iter() + .map(|&s| String::from(s)) + .collect(); + + let testnet_peers = ["dnsseed.testnet.z.cash:18233"] + .iter() + .map(|&s| String::from(s)) + .collect(); + Config { listen_addr: "127.0.0.1:28233" .parse() .expect("Hardcoded address should be parseable"), user_agent: crate::constants::USER_AGENT.to_owned(), network: Network::Mainnet, - 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"]), + initial_mainnet_peers: mainnet_peers, + initial_testnet_peers: testnet_peers, ewma_default_rtt: Duration::from_secs(1), ewma_decay_time: Duration::from_secs(60), peerset_request_buffer_size: 1, diff --git a/zebrad/src/commands.rs b/zebrad/src/commands.rs index 79d8e80bccd..09f7592e901 100644 --- a/zebrad/src/commands.rs +++ b/zebrad/src/commands.rs @@ -9,6 +9,8 @@ //! //! See the `impl Configurable` below for how to specify the path to the //! application's configuration file. +// TODO: update the list of commands above or find a way to keep it +// automatically up to date. mod config; mod connect; diff --git a/zebrad/src/commands/config.rs b/zebrad/src/commands/config.rs index ab3ae8ba827..730af4d0c53 100644 --- a/zebrad/src/commands/config.rs +++ b/zebrad/src/commands/config.rs @@ -27,7 +27,7 @@ impl Runnable for ConfigCmd { # can be found in Rustdoc. XXX add link to rendered docs. " - .to_owned(); + .to_owned(); // The default name and location of the config file is defined in ../commands.rs output += &toml::to_string_pretty(&default_config) .expect("default config should be serializable"); match self.output_file { From 9f94f838fb1f266cd94721032e245cd8a1a75056 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Tue, 5 Nov 2019 19:40:18 -0500 Subject: [PATCH 03/15] Add SeedService This may need some cleaning up, but this is the first iteration to appease the compiler. --- zebrad/src/commands/seed.rs | 58 +++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/zebrad/src/commands/seed.rs b/zebrad/src/commands/seed.rs index f4bbf066233..0ac7352a714 100644 --- a/zebrad/src/commands/seed.rs +++ b/zebrad/src/commands/seed.rs @@ -1,5 +1,11 @@ //! `seed` subcommand - test stub for talking to zcashd +use std::{ + future::Future, + pin::Pin, + task::{Context, Poll}, +}; + use crate::{config::ZebradConfig, prelude::*}; use abscissa_core::{config, Command, FrameworkError, Options, Runnable}; @@ -63,21 +69,48 @@ impl Runnable for SeedCmd { 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 futures::stream::StreamExt; + use tower::{buffer::Buffer, 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, - ); + struct SeedService { + address_book: Option, + } + + impl SeedService { + fn set_address_book(&mut self, address_book: AddressBook) { + self.address_book = Some(address_book); + } + } + + impl Service for SeedService { + type Response = Response; + type Error = Error; + type Future = + Pin> + Send + 'static>>; + + fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll> { + Ok(()).into() + } + + fn call(&mut self, req: Request) -> Self::Future { + let response = match req { + Request::GetPeers => match &self.address_book { + Some(address_book) => Ok::(Response::Peers( + address_book.peers().collect(), + )), + _ => Ok::(Response::Ok), + }, + _ => Ok::(Response::Ok), + }; + + return Box::pin(futures::future::ready(response)); + } + } + + let node = Buffer::new(SeedService { address_book: None }, 1); let config = app_config().network.clone(); @@ -92,7 +125,8 @@ impl SeedCmd { info!("peer_set became ready"); - loop {} + let eternity = tokio::future::pending::<()>(); + eternity.await; Ok(()) } From 31b4496d07323264baf8c679821b22fb1dc0b7e9 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Thu, 7 Nov 2019 16:12:18 -0500 Subject: [PATCH 04/15] seed command seems to be functional Moved SeedService out of the command closure Command currently spawns a tokio task to DOS the seed service with `Request::GetPeers` every second. Pertains to #54 --- zebra-network/src/peer/server.rs | 1 + zebrad/src/commands/seed.rs | 123 ++++++++++++++++++++----------- 2 files changed, 81 insertions(+), 43 deletions(-) diff --git a/zebra-network/src/peer/server.rs b/zebra-network/src/peer/server.rs index f77827709c4..743ca6b664c 100644 --- a/zebra-network/src/peer/server.rs +++ b/zebra-network/src/peer/server.rs @@ -304,6 +304,7 @@ where // and try to construct an appropriate request object. let req = match msg { Message::Addr(addrs) => Some(Request::PushPeers(addrs)), + Message::GetAddr => Some(Request::GetPeers), _ => { debug!("unhandled message type"); None diff --git a/zebrad/src/commands/seed.rs b/zebrad/src/commands/seed.rs index 0ac7352a714..78e82d2ecd5 100644 --- a/zebrad/src/commands/seed.rs +++ b/zebrad/src/commands/seed.rs @@ -3,12 +3,69 @@ use std::{ future::Future, pin::Pin, + sync::{Arc, Mutex}, task::{Context, Poll}, }; +use abscissa_core::{config, Command, FrameworkError, Options, Runnable}; +use futures::stream::StreamExt; +use tower::{buffer::Buffer, Service, ServiceExt}; +use zebra_network::{AddressBook, BoxedStdError, Request, Response}; + use crate::{config::ZebradConfig, prelude::*}; -use abscissa_core::{config, Command, FrameworkError, Options, Runnable}; +#[derive(Clone)] +struct SeedService { + address_book: Option>>, +} + +impl SeedService { + fn set_address_book(&mut self, address_book: Arc>) { + debug!("Settings SeedService.address_book: {:?}", address_book); + self.address_book = Some(address_book); + } +} + +impl Service for SeedService { + type Response = Response; + type Error = BoxedStdError; + type Future = + Pin> + Send + 'static>>; + + fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll> { + Ok(()).into() + } + + fn call(&mut self, req: Request) -> Self::Future { + info!("SeedService handling a request: {:?}", req); + + match &self.address_book { + Some(address_book) => trace!( + "SeedService address_book total: {:?}", + address_book.lock().unwrap().len() + ), + _ => (), + }; + + let response = match req { + Request::GetPeers => match &self.address_book { + Some(address_book) => { + info!("Responding to GetPeers"); + + Ok::(Response::Peers( + address_book.lock().unwrap().peers().collect(), + )) + } + _ => Ok::(Response::Ok), + }, + _ => Ok::(Response::Ok), + }; + + info!("SeedService response: {:?}", response); + + return Box::pin(futures::future::ready(response)); + } +} /// `seed` subcommand /// @@ -30,6 +87,7 @@ impl config::Override for SeedCmd { config.tracing.filter = self.filters.join(","); } + info!("{:?}", config); Ok(config) } } @@ -69,54 +127,18 @@ impl Runnable for SeedCmd { impl SeedCmd { async fn seed(&self) -> Result<(), failure::Error> { use failure::Error; - use futures::stream::StreamExt; - use tower::{buffer::Buffer, Service, ServiceExt}; - use zebra_network::{AddressBook, Request, Response}; info!("begin tower-based peer handling test stub"); - struct SeedService { - address_book: Option, - } - - impl SeedService { - fn set_address_book(&mut self, address_book: AddressBook) { - self.address_book = Some(address_book); - } - } - - impl Service for SeedService { - type Response = Response; - type Error = Error; - type Future = - Pin> + Send + 'static>>; - - fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll> { - Ok(()).into() - } - - fn call(&mut self, req: Request) -> Self::Future { - let response = match req { - Request::GetPeers => match &self.address_book { - Some(address_book) => Ok::(Response::Peers( - address_book.peers().collect(), - )), - _ => Ok::(Response::Ok), - }, - _ => Ok::(Response::Ok), - }; - - return Box::pin(futures::future::ready(response)); - } - } - - let node = Buffer::new(SeedService { address_book: None }, 1); + let mut seed_service = SeedService { address_book: None }; + // let node = Buffer::new(seed_service, 1); let config = app_config().network.clone(); + info!("{:?}", config); - // 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; + let (mut peer_set, address_book) = zebra_network::init(config, seed_service.clone()).await; + + seed_service.set_address_book(address_book.clone()); // XXX Do not tell our DNS seed queries about gossiped addrs // that we have not connected to before? @@ -125,6 +147,21 @@ impl SeedCmd { info!("peer_set became ready"); + use std::time::Duration; + use tokio::timer::Interval; + + //#[cfg(dos)] + // Fire GetPeers requests at ourselves, for testing. + tokio::spawn(async move { + let mut interval_stream = Interval::new_interval(Duration::from_secs(1)); + + loop { + interval_stream.next().await; + + let _ = seed_service.call(Request::GetPeers); + } + }); + let eternity = tokio::future::pending::<()>(); eternity.await; From 2c42a83771def67f962956957bcfd4a46dcfc559 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Mon, 11 Nov 2019 18:08:59 -0500 Subject: [PATCH 05/15] Yay, SeedService makes a remote 'connect' happy --- zebrad/src/commands/seed.rs | 97 +++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 36 deletions(-) diff --git a/zebrad/src/commands/seed.rs b/zebrad/src/commands/seed.rs index 78e82d2ecd5..330f95291b9 100644 --- a/zebrad/src/commands/seed.rs +++ b/zebrad/src/commands/seed.rs @@ -8,22 +8,26 @@ use std::{ }; use abscissa_core::{config, Command, FrameworkError, Options, Runnable}; -use futures::stream::StreamExt; +use futures::channel::oneshot; use tower::{buffer::Buffer, Service, ServiceExt}; use zebra_network::{AddressBook, BoxedStdError, Request, Response}; use crate::{config::ZebradConfig, prelude::*}; -#[derive(Clone)] -struct SeedService { - address_book: Option>>, +/// Whether our `SeedService` is poll_ready or not. +#[derive(Debug)] +enum SeederState { + /// + TempState, + /// + AwaitingAddressBook(oneshot::Receiver>>), + /// + Ready(Arc>), } -impl SeedService { - fn set_address_book(&mut self, address_book: Arc>) { - debug!("Settings SeedService.address_book: {:?}", address_book); - self.address_book = Some(address_book); - } +#[derive(Debug)] +struct SeedService { + state: SeederState, } impl Service for SeedService { @@ -32,33 +36,51 @@ impl Service for SeedService { type Future = Pin> + Send + 'static>>; - fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll> { - Ok(()).into() + fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { + info!("State: {:?}", self.state); + + let mut poll_result = Poll::Pending; + + // We want to be able to consume the state, but it's behind a mutable + // reference, so we can't move it out of self without swapping in a + // placeholder, even if we immediately overwrite the placeholder. + let tmp_state = std::mem::replace(&mut self.state, SeederState::TempState); + + self.state = match tmp_state { + SeederState::AwaitingAddressBook(mut rx) => match rx.try_recv() { + Ok(Some(address_book)) => { + info!("Message received! {:?}", address_book); + poll_result = Poll::Ready(Ok(())); + SeederState::Ready(address_book) + } + _ => SeederState::AwaitingAddressBook(rx), + }, + SeederState::Ready(_) => { + poll_result = Poll::Ready(Ok(())); + tmp_state + } + SeederState::TempState => tmp_state, + }; + + return poll_result; } fn call(&mut self, req: Request) -> Self::Future { info!("SeedService handling a request: {:?}", req); - match &self.address_book { - Some(address_book) => trace!( - "SeedService address_book total: {:?}", - address_book.lock().unwrap().len() - ), - _ => (), - }; + let response = match (req, &self.state) { + (Request::GetPeers, SeederState::Ready(address_book)) => { + info!("Responding to GetPeers"); - let response = match req { - Request::GetPeers => match &self.address_book { - Some(address_book) => { - info!("Responding to GetPeers"); + Ok::(Response::Peers( + address_book.lock().unwrap().peers().collect(), + )) + } + _ => { + trace!("Where is my address_book??? {:?}", &self.state); - Ok::(Response::Peers( - address_book.lock().unwrap().peers().collect(), - )) - } - _ => Ok::(Response::Ok), - }, - _ => Ok::(Response::Ok), + Ok::(Response::Ok) + } }; info!("SeedService response: {:?}", response); @@ -71,7 +93,7 @@ impl Service for SeedService { /// /// A DNS seeder command to spider and collect as many valid peer /// addresses as we can. -#[derive(Command, Debug, Options)] +#[derive(Command, Debug, Default, Options)] pub struct SeedCmd { /// Filter strings #[options(free)] @@ -130,15 +152,17 @@ impl SeedCmd { info!("begin tower-based peer handling test stub"); - let mut seed_service = SeedService { address_book: None }; - // let node = Buffer::new(seed_service, 1); + let (addressbook_tx, addressbook_rx) = oneshot::channel(); + let seed_service = SeedService { + state: SeederState::AwaitingAddressBook(addressbook_rx), + }; + let node = Buffer::new(seed_service, 1); let config = app_config().network.clone(); - info!("{:?}", config); - let (mut peer_set, address_book) = zebra_network::init(config, seed_service.clone()).await; + let (mut peer_set, address_book) = zebra_network::init(config, node).await; - seed_service.set_address_book(address_book.clone()); + let _ = addressbook_tx.send(address_book); // XXX Do not tell our DNS seed queries about gossiped addrs // that we have not connected to before? @@ -147,10 +171,11 @@ impl SeedCmd { info!("peer_set became ready"); + #[cfg(dos)] use std::time::Duration; use tokio::timer::Interval; - //#[cfg(dos)] + #[cfg(dos)] // Fire GetPeers requests at ourselves, for testing. tokio::spawn(async move { let mut interval_stream = Interval::new_interval(Duration::from_secs(1)); From 3cf17102f04badd176f3ca2b130b8e4c2ff56bbc Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Mon, 11 Nov 2019 20:41:46 -0500 Subject: [PATCH 06/15] Clean up some logging and comments on seed service --- zebrad/src/commands/seed.rs | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/zebrad/src/commands/seed.rs b/zebrad/src/commands/seed.rs index 330f95291b9..2a93df85634 100644 --- a/zebrad/src/commands/seed.rs +++ b/zebrad/src/commands/seed.rs @@ -17,11 +17,11 @@ use crate::{config::ZebradConfig, prelude::*}; /// Whether our `SeedService` is poll_ready or not. #[derive(Debug)] enum SeederState { - /// + // This is kinda gross but ¯\_(ツ)_/¯ TempState, - /// + /// Waiting for the address book to be shared with us via the oneshot channel. AwaitingAddressBook(oneshot::Receiver>>), - /// + /// Address book received, ready to service requests. Ready(Arc>), } @@ -37,7 +37,7 @@ impl Service for SeedService { Pin> + Send + 'static>>; fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { - info!("State: {:?}", self.state); + debug!("SeedService.state: {:?}", self.state); let mut poll_result = Poll::Pending; @@ -49,10 +49,17 @@ impl Service for SeedService { self.state = match tmp_state { SeederState::AwaitingAddressBook(mut rx) => match rx.try_recv() { Ok(Some(address_book)) => { - info!("Message received! {:?}", address_book); + info!( + "SeedService received address_book via oneshot {:?}", + address_book + ); poll_result = Poll::Ready(Ok(())); SeederState::Ready(address_book) } + // Sets self.state to a new instance of what it + // already was; we can't just return `tmp_state` + // because we've plucked it apart via `rx` and moved + // parts around already in this block. _ => SeederState::AwaitingAddressBook(rx), }, SeederState::Ready(_) => { @@ -70,21 +77,19 @@ impl Service for SeedService { let response = match (req, &self.state) { (Request::GetPeers, SeederState::Ready(address_book)) => { - info!("Responding to GetPeers"); - + debug!( + "address_book.len(): {:?}", + address_book.lock().unwrap().len() + ); + info!("SeedService responding to GetPeers"); Ok::(Response::Peers( address_book.lock().unwrap().peers().collect(), )) } - _ => { - trace!("Where is my address_book??? {:?}", &self.state); - - Ok::(Response::Ok) - } + _ => Ok::(Response::Ok), }; info!("SeedService response: {:?}", response); - return Box::pin(futures::future::ready(response)); } } @@ -109,7 +114,6 @@ impl config::Override for SeedCmd { config.tracing.filter = self.filters.join(","); } - info!("{:?}", config); Ok(config) } } @@ -164,8 +168,6 @@ impl SeedCmd { let _ = addressbook_tx.send(address_book); - // 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)?; From 61ba79bae7e8e349cc25322e2387ae96261350ac Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Tue, 12 Nov 2019 13:20:01 -0500 Subject: [PATCH 07/15] Remove to-fix comment --- zebra-network/src/config.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/zebra-network/src/config.rs b/zebra-network/src/config.rs index 587dd085804..3203d0916b8 100644 --- a/zebra-network/src/config.rs +++ b/zebra-network/src/config.rs @@ -21,8 +21,6 @@ pub struct Config { /// A list of initial peers for the peerset when operating on /// mainnet. - /// - /// XXX this should be replaced with DNS names, not SocketAddrs pub initial_mainnet_peers: Vec, /// A list of initial peers for the peerset when operating on From 4cecf4873d5e15fd2b67204977de0a8726bf23c5 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Tue, 12 Nov 2019 13:22:24 -0500 Subject: [PATCH 08/15] Remove autogenerated Abscissa doc comments --- zebrad/src/commands.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/zebrad/src/commands.rs b/zebrad/src/commands.rs index 09f7592e901..e3101f047c5 100644 --- a/zebrad/src/commands.rs +++ b/zebrad/src/commands.rs @@ -1,16 +1,4 @@ //! Zebrad Subcommands -//! -//! This is where you specify the subcommands of your application. -//! -//! The default application comes with two subcommands: -//! -//! - `start`: launches the application -//! - `version`: print application version -//! -//! See the `impl Configurable` below for how to specify the path to the -//! application's configuration file. -// TODO: update the list of commands above or find a way to keep it -// automatically up to date. mod config; mod connect; From 9aaaa0ec74dd238690da7b95bf74c2b92ce678c8 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Tue, 12 Nov 2019 13:40:04 -0500 Subject: [PATCH 09/15] Update `seed` subcommand description Co-Authored-By: Henry de Valence --- zebrad/src/commands/seed.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebrad/src/commands/seed.rs b/zebrad/src/commands/seed.rs index 2a93df85634..08374db1035 100644 --- a/zebrad/src/commands/seed.rs +++ b/zebrad/src/commands/seed.rs @@ -1,4 +1,4 @@ -//! `seed` subcommand - test stub for talking to zcashd +//! `seed` subcommand - runs a dns seeder use std::{ future::Future, From 2a28178571774cd99a917efd4234bc4bd8846cf3 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Tue, 12 Nov 2019 15:00:56 -0500 Subject: [PATCH 10/15] Clean up SeedService.poll_ready with a 'ref mut' Co-Authored-By: Henry de Valence --- zebrad/src/commands/seed.rs | 40 +++++++++++++------------------------ 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/zebrad/src/commands/seed.rs b/zebrad/src/commands/seed.rs index 08374db1035..adb1b58ac13 100644 --- a/zebrad/src/commands/seed.rs +++ b/zebrad/src/commands/seed.rs @@ -17,8 +17,6 @@ use crate::{config::ZebradConfig, prelude::*}; /// Whether our `SeedService` is poll_ready or not. #[derive(Debug)] enum SeederState { - // This is kinda gross but ¯\_(ツ)_/¯ - TempState, /// Waiting for the address book to be shared with us via the oneshot channel. AwaitingAddressBook(oneshot::Receiver>>), /// Address book received, ready to service requests. @@ -39,37 +37,27 @@ impl Service for SeedService { fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { debug!("SeedService.state: {:?}", self.state); - let mut poll_result = Poll::Pending; - - // We want to be able to consume the state, but it's behind a mutable - // reference, so we can't move it out of self without swapping in a - // placeholder, even if we immediately overwrite the placeholder. - let tmp_state = std::mem::replace(&mut self.state, SeederState::TempState); - - self.state = match tmp_state { - SeederState::AwaitingAddressBook(mut rx) => match rx.try_recv() { + match self.state { + SeederState::Ready(_) => return Poll::Ready(Ok(())), + SeederState::AwaitingAddressBook(ref mut rx) => match rx.try_recv() { + Err(e) => { + error!("SeedService oneshot sender dropped: {:?}", e); + return Poll::Ready(Err(e.into())); + } + Ok(None) => { + debug!("SeedService got a message with `None` in it. 🤔"); + return Poll::Pending; + } Ok(Some(address_book)) => { info!( "SeedService received address_book via oneshot {:?}", address_book ); - poll_result = Poll::Ready(Ok(())); - SeederState::Ready(address_book) + self.state = SeederState::Ready(address_book); + return Poll::Ready(Ok(())); } - // Sets self.state to a new instance of what it - // already was; we can't just return `tmp_state` - // because we've plucked it apart via `rx` and moved - // parts around already in this block. - _ => SeederState::AwaitingAddressBook(rx), }, - SeederState::Ready(_) => { - poll_result = Poll::Ready(Ok(())); - tmp_state - } - SeederState::TempState => tmp_state, - }; - - return poll_result; + } } fn call(&mut self, req: Request) -> Self::Future { From 99fb7820e21fa54103413d64a5eca5825039d83c Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Tue, 12 Nov 2019 15:17:35 -0500 Subject: [PATCH 11/15] Update `Ok(None)` case logging. --- zebrad/src/commands/seed.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebrad/src/commands/seed.rs b/zebrad/src/commands/seed.rs index adb1b58ac13..68fd2c1df9a 100644 --- a/zebrad/src/commands/seed.rs +++ b/zebrad/src/commands/seed.rs @@ -45,7 +45,7 @@ impl Service for SeedService { return Poll::Ready(Err(e.into())); } Ok(None) => { - debug!("SeedService got a message with `None` in it. 🤔"); + trace!("SeedService hasn't received a message via the oneshot yet."); return Poll::Pending; } Ok(Some(address_book)) => { From e9ac1ce9f57445638c80d8a31983cb255eab0d22 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Tue, 12 Nov 2019 15:37:56 -0500 Subject: [PATCH 12/15] Update tracing invocation to be better manipulated Co-Authored-By: Henry de Valence --- zebrad/src/commands/seed.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/zebrad/src/commands/seed.rs b/zebrad/src/commands/seed.rs index 68fd2c1df9a..493e4325974 100644 --- a/zebrad/src/commands/seed.rs +++ b/zebrad/src/commands/seed.rs @@ -65,10 +65,7 @@ impl Service for SeedService { let response = match (req, &self.state) { (Request::GetPeers, SeederState::Ready(address_book)) => { - debug!( - "address_book.len(): {:?}", - address_book.lock().unwrap().len() - ); + debug!(address_book.len = address_book.lock().unwrap().len()); info!("SeedService responding to GetPeers"); Ok::(Response::Peers( address_book.lock().unwrap().peers().collect(), From aa6f8538a75ba74a0fb0a4bff4ecfc10aed5897a Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Tue, 12 Nov 2019 16:27:35 -0500 Subject: [PATCH 13/15] Remove config override, not needed --- zebrad/src/commands/seed.rs | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/zebrad/src/commands/seed.rs b/zebrad/src/commands/seed.rs index 493e4325974..10de643de96 100644 --- a/zebrad/src/commands/seed.rs +++ b/zebrad/src/commands/seed.rs @@ -83,25 +83,9 @@ impl Service for SeedService { /// /// A DNS seeder command to spider and collect as many valid peer /// addresses as we can. +// This is not a unit-like struct because it makes Command and Options sad. #[derive(Command, Debug, Default, 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) - } -} +pub struct SeedCmd {} impl Runnable for SeedCmd { /// Start the application. From fa2866ed0f098e823f6b3de937cdf7fcb7e86730 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Tue, 12 Nov 2019 16:36:56 -0500 Subject: [PATCH 14/15] Unwrap address_book in call(), which relies on poll_ready giving a positive response first, otherwise panic Co-Authored-By: Henry de Valence --- zebrad/src/commands/seed.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/zebrad/src/commands/seed.rs b/zebrad/src/commands/seed.rs index 10de643de96..bb8603d73e9 100644 --- a/zebrad/src/commands/seed.rs +++ b/zebrad/src/commands/seed.rs @@ -63,8 +63,14 @@ impl Service for SeedService { fn call(&mut self, req: Request) -> Self::Future { info!("SeedService handling a request: {:?}", req); - let response = match (req, &self.state) { - (Request::GetPeers, SeederState::Ready(address_book)) => { + let address_book = if let SeederState::Ready(address_book) = &self.state { + address_book + } else { + panic!("SeedService::call without SeedService::poll_ready"); + }; + + let response = match req { + Request::GetPeers => { debug!(address_book.len = address_book.lock().unwrap().len()); info!("SeedService responding to GetPeers"); Ok::(Response::Peers( From 6615b8bd3a30d3a300d8b23f9c53214c61992f6b Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Tue, 12 Nov 2019 16:46:06 -0500 Subject: [PATCH 15/15] Remove special wait, unneeded for seed Co-Authored-By: Henry de Valence --- zebrad/src/commands/seed.rs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/zebrad/src/commands/seed.rs b/zebrad/src/commands/seed.rs index bb8603d73e9..7d7fdba677f 100644 --- a/zebrad/src/commands/seed.rs +++ b/zebrad/src/commands/seed.rs @@ -98,30 +98,13 @@ impl Runnable for SeedCmd { 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); + .block_on(self.seed()); } }