diff --git a/beacon_node/beacon_chain/src/beacon_chain_builder.rs b/beacon_node/beacon_chain/src/beacon_chain_builder.rs index ef25c33ec..2a3537020 100644 --- a/beacon_node/beacon_chain/src/beacon_chain_builder.rs +++ b/beacon_node/beacon_chain/src/beacon_chain_builder.rs @@ -87,7 +87,7 @@ impl BeaconChainBuilder { } pub fn http_bootstrap(server: &str, spec: ChainSpec, log: Logger) -> Result { - let bootstrapper = Bootstrapper::from_server_string(server.to_string()) + let bootstrapper = Bootstrapper::connect(server.to_string(), &log) .map_err(|e| format!("Failed to initialize bootstrap client: {}", e))?; let (genesis_state, genesis_block) = bootstrapper diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index f2c56c524..6a13a9aae 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -310,7 +310,7 @@ impl<'a> ConfigBuilder<'a> { server: &str, port: Option, ) -> Result<()> { - let bootstrapper = Bootstrapper::from_server_string(server.to_string())?; + let bootstrapper = Bootstrapper::connect(server.to_string(), &self.log)?; if let Some(server_multiaddr) = bootstrapper.best_effort_multiaddr(port) { info!( @@ -347,7 +347,7 @@ impl<'a> ConfigBuilder<'a> { /// Imports an `Eth2Config` from `server`, returning an error if this fails. pub fn import_bootstrap_eth2_config(&mut self, server: &str) -> Result<()> { - let bootstrapper = Bootstrapper::from_server_string(server.to_string())?; + let bootstrapper = Bootstrapper::connect(server.to_string(), &self.log)?; self.update_eth2_config(bootstrapper.eth2_config()?); diff --git a/eth2/utils/lighthouse_bootstrap/Cargo.toml b/eth2/utils/lighthouse_bootstrap/Cargo.toml index 3f48505b8..cfc4c6baf 100644 --- a/eth2/utils/lighthouse_bootstrap/Cargo.toml +++ b/eth2/utils/lighthouse_bootstrap/Cargo.toml @@ -13,3 +13,4 @@ reqwest = "0.9" url = "1.2" types = { path = "../../types" } serde = "1.0" +slog = { version = "^2.2.3" , features = ["max_level_trace", "release_max_level_trace"] } diff --git a/eth2/utils/lighthouse_bootstrap/src/lib.rs b/eth2/utils/lighthouse_bootstrap/src/lib.rs index dc70c6d21..92a587ff2 100644 --- a/eth2/utils/lighthouse_bootstrap/src/lib.rs +++ b/eth2/utils/lighthouse_bootstrap/src/lib.rs @@ -5,11 +5,16 @@ use eth2_libp2p::{ }; use reqwest::{Error as HttpError, Url}; use serde::Deserialize; +use slog::{error, Logger}; use std::borrow::Cow; use std::net::Ipv4Addr; +use std::time::Duration; use types::{BeaconBlock, BeaconState, Checkpoint, EthSpec, Hash256, Slot}; use url::Host; +pub const RETRY_SLEEP_MILLIS: u64 = 100; +pub const RETRY_WARN_INTERVAL: u64 = 30; + #[derive(Debug)] enum Error { InvalidUrl, @@ -31,11 +36,35 @@ pub struct Bootstrapper { } impl Bootstrapper { - /// Parses the given `server` as a URL, instantiating `Self`. - pub fn from_server_string(server: String) -> Result { - Ok(Self { + /// Parses the given `server` as a URL, instantiating `Self` and blocking until a connection + /// can be made with the server. + /// + /// Never times out. + pub fn connect(server: String, log: &Logger) -> Result { + let bootstrapper = Self { url: Url::parse(&server).map_err(|e| format!("Invalid bootstrap server url: {}", e))?, - }) + }; + + let mut retry_count = 0; + loop { + match bootstrapper.enr() { + Ok(_) => break, + Err(_) => { + if retry_count % RETRY_WARN_INTERVAL == 0 { + error!( + log, + "Failed to contact bootstrap server"; + "retry_count" => retry_count, + "retry_delay_millis" => RETRY_SLEEP_MILLIS, + ); + } + retry_count += 1; + std::thread::sleep(Duration::from_millis(RETRY_SLEEP_MILLIS)); + } + } + } + + Ok(bootstrapper) } /// Build a multiaddr using the HTTP server URL that is not guaranteed to be correct. diff --git a/validator_client/src/main.rs b/validator_client/src/main.rs index d5d2fc27f..39b2e3eae 100644 --- a/validator_client/src/main.rs +++ b/validator_client/src/main.rs @@ -247,10 +247,13 @@ fn process_testnet_subcommand( ) -> Result<(ClientConfig, Eth2Config)> { let eth2_config = if cli_args.is_present("bootstrap") { info!(log, "Connecting to bootstrap server"); - let bootstrapper = Bootstrapper::from_server_string(format!( - "http://{}:{}", - client_config.server, client_config.server_http_port - ))?; + let bootstrapper = Bootstrapper::connect( + format!( + "http://{}:{}", + client_config.server, client_config.server_http_port + ), + &log, + )?; let eth2_config = bootstrapper.eth2_config()?;