diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index bd51f8620..09f4749ea 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -55,7 +55,7 @@ where impl BeaconChainTypes for CommonTypes where L: LmdGhost + 'static, - E: EthSpec + 'static, + E: EthSpec, { type Store = MemoryStore; type SlotClock = TestingSlotClock; @@ -70,7 +70,7 @@ where pub struct BeaconChainHarness where L: LmdGhost + 'static, - E: EthSpec + 'static, + E: EthSpec, { pub chain: BeaconChain>, pub keypairs: Vec, diff --git a/beacon_node/client/src/beacon_chain_types.rs b/beacon_node/client/src/beacon_chain_types.rs index adea8c7b5..5168c067a 100644 --- a/beacon_node/client/src/beacon_chain_types.rs +++ b/beacon_node/client/src/beacon_chain_types.rs @@ -39,7 +39,7 @@ pub struct ClientType { impl BeaconChainTypes for ClientType where S: Store + 'static, - E: EthSpec + 'static + Clone, + E: EthSpec, { type Store = S; type SlotClock = SystemTimeSlotClock; diff --git a/beacon_node/client/src/bootstrapper.rs b/beacon_node/client/src/bootstrapper.rs index 19f13e2da..c94d9a51d 100644 --- a/beacon_node/client/src/bootstrapper.rs +++ b/beacon_node/client/src/bootstrapper.rs @@ -3,9 +3,10 @@ use eth2_libp2p::{ Enr, }; use reqwest::{Error as HttpError, Url}; +use serde::Deserialize; use std::borrow::Cow; use std::net::Ipv4Addr; -use types::{BeaconBlock, BeaconState, Checkpoint, EthSpec, Slot}; +use types::{BeaconBlock, BeaconState, Checkpoint, EthSpec, Hash256, Slot}; use url::Host; #[derive(Debug)] @@ -46,7 +47,7 @@ impl Bootstrapper { /// `/ipv4/192.168.0.1/tcp/9000` if the server advertises a listening address of /// `/ipv4/172.0.0.1/tcp/9000`. pub fn best_effort_multiaddr(&self) -> Option { - let tcp_port = self.first_listening_tcp_port()?; + let tcp_port = self.listen_port().ok()?; let mut multiaddr = Multiaddr::with_capacity(2); @@ -61,17 +62,6 @@ impl Bootstrapper { Some(multiaddr) } - /// Reads the server's listening libp2p addresses and returns the first TCP port protocol it - /// finds, if any. - fn first_listening_tcp_port(&self) -> Option { - self.listen_addresses().ok()?.iter().find_map(|multiaddr| { - multiaddr.iter().find_map(|protocol| match protocol { - Protocol::Tcp(port) => Some(port), - _ => None, - }) - }) - } - /// Returns the IPv4 address of the server URL, unless it contains a FQDN. pub fn server_ipv4_addr(&self) -> Option { match self.url.host()? { @@ -86,9 +76,8 @@ impl Bootstrapper { } /// Returns the servers listening libp2p addresses. - pub fn listen_addresses(&self) -> Result, String> { - get_listen_addresses(self.url.clone()) - .map_err(|e| format!("Unable to get listen addresses: {:?}", e)) + pub fn listen_port(&self) -> Result { + get_listen_port(self.url.clone()).map_err(|e| format!("Unable to get listen port: {:?}", e)) } /// Returns the genesis block and state. @@ -96,9 +85,11 @@ impl Bootstrapper { let genesis_slot = Slot::new(0); let block = get_block(self.url.clone(), genesis_slot) - .map_err(|e| format!("Unable to get genesis block: {:?}", e))?; + .map_err(|e| format!("Unable to get genesis block: {:?}", e))? + .beacon_block; let state = get_state(self.url.clone(), genesis_slot) - .map_err(|e| format!("Unable to get genesis state: {:?}", e))?; + .map_err(|e| format!("Unable to get genesis state: {:?}", e))? + .beacon_state; Ok((state, block)) } @@ -111,9 +102,11 @@ impl Bootstrapper { .map_err(|e| format!("Unable to get finalized slot: {:?}", e))?; let block = get_block(self.url.clone(), finalized_slot) - .map_err(|e| format!("Unable to get finalized block: {:?}", e))?; + .map_err(|e| format!("Unable to get finalized block: {:?}", e))? + .beacon_block; let state = get_state(self.url.clone(), finalized_slot) - .map_err(|e| format!("Unable to get finalized state: {:?}", e))?; + .map_err(|e| format!("Unable to get finalized state: {:?}", e))? + .beacon_state; Ok((state, block)) } @@ -144,7 +137,14 @@ fn get_finalized_slot(mut url: Url, slots_per_epoch: u64) -> Result Ok(checkpoint.epoch.start_slot(slots_per_epoch)) } -fn get_state(mut url: Url, slot: Slot) -> Result, Error> { +#[derive(Deserialize)] +#[serde(bound = "T: EthSpec")] +pub struct StateResponse { + pub root: Hash256, + pub beacon_state: BeaconState, +} + +fn get_state(mut url: Url, slot: Slot) -> Result, Error> { url.path_segments_mut() .map(|mut url| { url.push("beacon").push("state"); @@ -160,7 +160,14 @@ fn get_state(mut url: Url, slot: Slot) -> Result, Err .map_err(Into::into) } -fn get_block(mut url: Url, slot: Slot) -> Result, Error> { +#[derive(Deserialize)] +#[serde(bound = "T: EthSpec")] +pub struct BlockResponse { + pub root: Hash256, + pub beacon_block: BeaconBlock, +} + +fn get_block(mut url: Url, slot: Slot) -> Result, Error> { url.path_segments_mut() .map(|mut url| { url.push("beacon").push("block"); @@ -179,7 +186,7 @@ fn get_block(mut url: Url, slot: Slot) -> Result, Err fn get_enr(mut url: Url) -> Result { url.path_segments_mut() .map(|mut url| { - url.push("node").push("network").push("enr"); + url.push("network").push("enr"); }) .map_err(|_| Error::InvalidUrl)?; @@ -189,10 +196,10 @@ fn get_enr(mut url: Url) -> Result { .map_err(Into::into) } -fn get_listen_addresses(mut url: Url) -> Result, Error> { +fn get_listen_port(mut url: Url) -> Result { url.path_segments_mut() .map(|mut url| { - url.push("node").push("network").push("listen_addresses"); + url.push("network").push("listen_port"); }) .map_err(|_| Error::InvalidUrl)?; diff --git a/beacon_node/eth2-libp2p/src/service.rs b/beacon_node/eth2-libp2p/src/service.rs index e1e112e2d..e208dbeca 100644 --- a/beacon_node/eth2-libp2p/src/service.rs +++ b/beacon_node/eth2-libp2p/src/service.rs @@ -16,7 +16,7 @@ use libp2p::core::{ upgrade::{InboundUpgradeExt, OutboundUpgradeExt}, }; use libp2p::{core, secio, PeerId, Swarm, Transport}; -use slog::{debug, info, trace, warn}; +use slog::{crit, debug, info, trace, warn}; use std::fs::File; use std::io::prelude::*; use std::io::{Error, ErrorKind}; @@ -69,10 +69,15 @@ impl Service { log_address.push(Protocol::P2p(local_peer_id.clone().into())); info!(log, "Listening on: {}", log_address); } - Err(err) => warn!( - log, - "Cannot listen on: {} because: {:?}", listen_multiaddr, err - ), + Err(err) => { + crit!( + log, + "Unable to listen on libp2p address"; + "error" => format!("{:?}", err), + "listen_multiaddr" => format!("{}", listen_multiaddr), + ); + return Err("Libp2p was unable to listen on the given listen address.".into()); + } }; // attempt to connect to user-input libp2p nodes diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index dc7e94140..152f4dc77 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -18,6 +18,7 @@ use tokio::sync::{mpsc, oneshot}; /// Service that handles communication between internal services and the eth2_libp2p network service. pub struct Service { libp2p_service: Arc>, + libp2p_port: u16, _libp2p_exit: oneshot::Sender<()>, _network_send: mpsc::UnboundedSender, _phantom: PhantomData, //message_handler: MessageHandler, @@ -56,6 +57,7 @@ impl Service { )?; let network_service = Service { libp2p_service, + libp2p_port: config.libp2p_port, _libp2p_exit: libp2p_exit, _network_send: network_send.clone(), _phantom: PhantomData, @@ -87,6 +89,11 @@ impl Service { .collect() } + /// Returns the libp2p port that this node has been configured to listen using. + pub fn listen_port(&self) -> u16 { + self.libp2p_port + } + /// Returns the number of libp2p connected peers. pub fn connected_peers(&self) -> usize { self.libp2p_service.lock().swarm.connected_peers() diff --git a/beacon_node/rest_api/src/beacon.rs b/beacon_node/rest_api/src/beacon.rs index 4e3cc02fd..1c66a2819 100644 --- a/beacon_node/rest_api/src/beacon.rs +++ b/beacon_node/rest_api/src/beacon.rs @@ -8,7 +8,7 @@ use store::Store; use types::{BeaconBlock, BeaconState, EthSpec, Hash256, Slot}; #[derive(Serialize)] -struct HeadResponse { +pub struct HeadResponse { pub slot: Slot, pub block_root: Hash256, pub state_root: Hash256, @@ -35,7 +35,7 @@ pub fn get_head(req: Request) -> ApiResult #[derive(Serialize)] #[serde(bound = "T: EthSpec")] -struct BlockResponse { +pub struct BlockResponse { pub root: Hash256, pub beacon_block: BeaconBlock, } @@ -106,7 +106,7 @@ pub fn get_block_root(req: Request) -> ApiR #[derive(Serialize)] #[serde(bound = "T: EthSpec")] -struct StateResponse { +pub struct StateResponse { pub root: Hash256, pub beacon_state: BeaconState, } diff --git a/beacon_node/rest_api/src/lib.rs b/beacon_node/rest_api/src/lib.rs index 354b23403..964dd7998 100644 --- a/beacon_node/rest_api/src/lib.rs +++ b/beacon_node/rest_api/src/lib.rs @@ -13,7 +13,6 @@ mod url_query; use beacon_chain::{BeaconChain, BeaconChainTypes}; use client_network::Service as NetworkService; -pub use config::Config as ApiConfig; use hyper::rt::Future; use hyper::service::service_fn_ok; use hyper::{Body, Method, Response, Server, StatusCode}; @@ -24,6 +23,9 @@ use std::sync::Arc; use tokio::runtime::TaskExecutor; use url_query::UrlQuery; +pub use beacon::{BlockResponse, HeadResponse, StateResponse}; +pub use config::Config as ApiConfig; + #[derive(PartialEq, Debug)] pub enum ApiError { MethodNotAllowed(String), @@ -134,6 +136,7 @@ pub fn start_server( (&Method::GET, "/network/peer_count") => network::get_peer_count::(req), (&Method::GET, "/network/peer_id") => network::get_peer_id::(req), (&Method::GET, "/network/peers") => network::get_peer_list::(req), + (&Method::GET, "/network/listen_port") => network::get_listen_port::(req), (&Method::GET, "/network/listen_addresses") => { network::get_listen_addresses::(req) } diff --git a/beacon_node/rest_api/src/network.rs b/beacon_node/rest_api/src/network.rs index daded9d3d..a3e4c5ee7 100644 --- a/beacon_node/rest_api/src/network.rs +++ b/beacon_node/rest_api/src/network.rs @@ -21,6 +21,21 @@ pub fn get_listen_addresses(req: Request) -> ApiResul ))) } +/// HTTP handle to return the list of libp2p multiaddr the client is listening on. +/// +/// Returns a list of `Multiaddr`, serialized according to their `serde` impl. +pub fn get_listen_port(req: Request) -> ApiResult { + let network = req + .extensions() + .get::>>() + .ok_or_else(|| ApiError::ServerError("NetworkService extension missing".to_string()))?; + + Ok(success_response(Body::from( + serde_json::to_string(&network.listen_port()) + .map_err(|e| ApiError::ServerError(format!("Unable to serialize port: {:?}", e)))?, + ))) +} + /// HTTP handle to return the Discv5 ENR from the client's libp2p service. /// /// ENR is encoded as base64 string.