Adds peers and connected_peers to lighthouse http API (#1030)

This commit is contained in:
Age Manning 2020-04-21 23:27:49 +10:00 committed by GitHub
parent fa7147f7c5
commit 9e42a851e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 249 additions and 18 deletions

View File

@ -3,9 +3,10 @@
//! Currently using identify to fingerprint. //! Currently using identify to fingerprint.
use libp2p::identify::IdentifyInfo; use libp2p::identify::IdentifyInfo;
use serde::Serialize;
#[derive(Debug)]
/// Various client and protocol information related to a node. /// Various client and protocol information related to a node.
#[derive(Clone, Debug, Serialize)]
pub struct Client { pub struct Client {
/// The client's name (Ex: lighthouse, prism, nimbus, etc) /// The client's name (Ex: lighthouse, prism, nimbus, etc)
pub kind: ClientKind, pub kind: ClientKind,
@ -19,7 +20,7 @@ pub struct Client {
pub agent_string: Option<String>, pub agent_string: Option<String>,
} }
#[derive(Debug)] #[derive(Clone, Debug, Serialize)]
pub enum ClientKind { pub enum ClientKind {
/// A lighthouse node (the best kind). /// A lighthouse node (the best kind).
Lighthouse, Lighthouse,
@ -125,6 +126,11 @@ fn client_from_agent_version(agent_version: &str) -> (ClientKind, String, String
} }
(kind, version, os_version) (kind, version, os_version)
} }
Some("github.com") => {
let kind = ClientKind::Prysm;
let unknown = String::from("unknown");
(kind, unknown.clone(), unknown)
}
_ => { _ => {
let unknown = String::from("unknown"); let unknown = String::from("unknown");
(ClientKind::Unknown, unknown.clone(), unknown) (ClientKind::Unknown, unknown.clone(), unknown)

View File

@ -2,12 +2,17 @@ use super::client::Client;
use super::peerdb::{Rep, DEFAULT_REPUTATION}; use super::peerdb::{Rep, DEFAULT_REPUTATION};
use crate::rpc::MetaData; use crate::rpc::MetaData;
use crate::Multiaddr; use crate::Multiaddr;
use serde::{
ser::{SerializeStructVariant, Serializer},
Serialize,
};
use std::time::Instant; use std::time::Instant;
use types::{EthSpec, Slot, SubnetId}; use types::{EthSpec, Slot, SubnetId};
use PeerConnectionStatus::*; use PeerConnectionStatus::*;
/// Information about a given connected peer. /// Information about a given connected peer.
#[derive(Debug)] #[derive(Clone, Debug, Serialize)]
#[serde(bound = "T: EthSpec")]
pub struct PeerInfo<T: EthSpec> { pub struct PeerInfo<T: EthSpec> {
/// The connection status of the peer /// The connection status of the peer
_status: PeerStatus, _status: PeerStatus,
@ -54,7 +59,7 @@ impl<T: EthSpec> PeerInfo<T> {
} }
} }
#[derive(Debug)] #[derive(Clone, Debug, Serialize)]
pub enum PeerStatus { pub enum PeerStatus {
/// The peer is healthy /// The peer is healthy
Healthy, Healthy,
@ -69,7 +74,7 @@ impl Default for PeerStatus {
} }
/// Connection Status of the peer /// Connection Status of the peer
#[derive(Debug, Clone)] #[derive(Clone, Debug)]
pub enum PeerConnectionStatus { pub enum PeerConnectionStatus {
Connected { Connected {
/// number of ingoing connections /// number of ingoing connections
@ -86,12 +91,41 @@ pub enum PeerConnectionStatus {
since: Instant, since: Instant,
}, },
Unknown { Unknown {
/// time since we know of this peer /// time since we last saw this peer
since: Instant, since: Instant,
}, },
} }
#[derive(Debug, Clone, PartialEq)] /// Serialization for http requests.
impl Serialize for PeerConnectionStatus {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
Connected { n_in, n_out } => {
let mut s = serializer.serialize_struct_variant("", 0, "Connected", 2)?;
s.serialize_field("in", n_in)?;
s.serialize_field("out", n_out)?;
s.end()
}
Disconnected { since } => {
let mut s = serializer.serialize_struct_variant("", 1, "Disconnected", 1)?;
s.serialize_field("since", &since.elapsed().as_secs())?;
s.end()
}
Banned { since } => {
let mut s = serializer.serialize_struct_variant("", 2, "Banned", 1)?;
s.serialize_field("since", &since.elapsed().as_secs())?;
s.end()
}
Unknown { since } => {
let mut s = serializer.serialize_struct_variant("", 3, "Unknown", 1)?;
s.serialize_field("since", &since.elapsed().as_secs())?;
s.end()
}
}
}
}
#[derive(Clone, Debug, Serialize)]
pub enum PeerSyncStatus { pub enum PeerSyncStatus {
/// At the current state as our node or ahead of us. /// At the current state as our node or ahead of us.
Synced { Synced {

View File

@ -41,8 +41,13 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
.map_or(DEFAULT_REPUTATION, |info| info.reputation) .map_or(DEFAULT_REPUTATION, |info| info.reputation)
} }
/// Returns an iterator over all peers in the db.
pub fn peers(&self) -> impl Iterator<Item = (&PeerId, &PeerInfo<TSpec>)> {
self.peers.iter()
}
/// Gives the ids of all known peers. /// Gives the ids of all known peers.
pub fn peers(&self) -> impl Iterator<Item = &PeerId> { pub fn peer_ids(&self) -> impl Iterator<Item = &PeerId> {
self.peers.keys() self.peers.keys()
} }
@ -66,7 +71,14 @@ impl<TSpec: EthSpec> PeerDB<TSpec> {
} }
/// Gives the ids of all known connected peers. /// Gives the ids of all known connected peers.
pub fn connected_peers(&self) -> impl Iterator<Item = &PeerId> { pub fn connected_peers(&self) -> impl Iterator<Item = (&PeerId, &PeerInfo<TSpec>)> {
self.peers
.iter()
.filter(|(_, info)| info.connection_status.is_connected())
}
/// Gives the ids of all known connected peers.
pub fn connected_peer_ids(&self) -> impl Iterator<Item = &PeerId> {
self.peers self.peers
.iter() .iter()
.filter(|(_, info)| info.connection_status.is_connected()) .filter(|(_, info)| info.connection_status.is_connected())
@ -373,7 +385,7 @@ mod tests {
} }
assert_eq!(pdb.n_dc, 0); assert_eq!(pdb.n_dc, 0);
for p in pdb.connected_peers().cloned().collect::<Vec<_>>() { for p in pdb.connected_peer_ids().cloned().collect::<Vec<_>>() {
pdb.disconnect(&p); pdb.disconnect(&p);
} }

View File

@ -1,6 +1,7 @@
//! Available RPC methods types and ids. //! Available RPC methods types and ids.
use crate::types::EnrBitfield; use crate::types::EnrBitfield;
use serde::Serialize;
use ssz_derive::{Decode, Encode}; use ssz_derive::{Decode, Encode};
use types::{Epoch, EthSpec, Hash256, SignedBeaconBlock, Slot}; use types::{Epoch, EthSpec, Hash256, SignedBeaconBlock, Slot};
@ -37,7 +38,8 @@ pub struct Ping {
} }
/// The METADATA response structure. /// The METADATA response structure.
#[derive(Encode, Decode, Clone, Debug, PartialEq)] #[derive(Encode, Decode, Clone, Debug, PartialEq, Serialize)]
#[serde(bound = "T: EthSpec")]
pub struct MetaData<T: EthSpec> { pub struct MetaData<T: EthSpec> {
/// A sequential counter indicating when data gets modified. /// A sequential counter indicating when data gets modified.
pub seq_number: u64, pub seq_number: u64,

View File

@ -80,7 +80,7 @@ impl<TSpec: EthSpec> NetworkGlobals<TSpec> {
/// Returns the number of libp2p connected peers. /// Returns the number of libp2p connected peers.
pub fn connected_peers(&self) -> usize { pub fn connected_peers(&self) -> usize {
self.peers.read().connected_peers().count() self.peers.read().connected_peer_ids().count()
} }
/// Returns in the node is syncing. /// Returns in the node is syncing.

View File

@ -2,12 +2,57 @@
use crate::response_builder::ResponseBuilder; use crate::response_builder::ResponseBuilder;
use crate::ApiResult; use crate::ApiResult;
use eth2_libp2p::NetworkGlobals; use eth2_libp2p::{NetworkGlobals, PeerInfo};
use hyper::{Body, Request}; use hyper::{Body, Request};
use serde::Serialize;
use std::sync::Arc; use std::sync::Arc;
use types::EthSpec; use types::EthSpec;
/// The syncing state of the beacon node. /// The syncing state of the beacon node.
pub fn syncing<T: EthSpec>(req: Request<Body>, network: Arc<NetworkGlobals<T>>) -> ApiResult { pub fn syncing<T: EthSpec>(
ResponseBuilder::new(&req)?.body_no_ssz(&network.sync_state()) req: Request<Body>,
network_globals: Arc<NetworkGlobals<T>>,
) -> ApiResult {
ResponseBuilder::new(&req)?.body_no_ssz(&network_globals.sync_state())
}
/// Returns all known peers and corresponding information
pub fn peers<T: EthSpec>(req: Request<Body>, network_globals: Arc<NetworkGlobals<T>>) -> ApiResult {
let peers: Vec<Peer<T>> = network_globals
.peers
.read()
.peers()
.map(|(peer_id, peer_info)| Peer {
peer_id: peer_id.to_string(),
peer_info: peer_info.clone(),
})
.collect();
ResponseBuilder::new(&req)?.body_no_ssz(&peers)
}
/// Returns all known connected peers and their corresponding information
pub fn connected_peers<T: EthSpec>(
req: Request<Body>,
network_globals: Arc<NetworkGlobals<T>>,
) -> ApiResult {
let peers: Vec<Peer<T>> = network_globals
.peers
.read()
.connected_peers()
.map(|(peer_id, peer_info)| Peer {
peer_id: peer_id.to_string(),
peer_info: peer_info.clone(),
})
.collect();
ResponseBuilder::new(&req)?.body_no_ssz(&peers)
}
/// Information returned by `peers` and `connected_peers`.
#[derive(Clone, Debug, Serialize)]
#[serde(bound = "T: EthSpec")]
struct Peer<T: EthSpec> {
/// The Peer's ID
peer_id: String,
/// The PeerInfo associated with the peer.
peer_info: PeerInfo<T>,
} }

View File

@ -65,7 +65,7 @@ pub fn get_peer_list<T: BeaconChainTypes>(
let connected_peers: Vec<String> = network let connected_peers: Vec<String> = network
.peers .peers
.read() .read()
.connected_peers() .connected_peer_ids()
.map(PeerId::to_string) .map(PeerId::to_string)
.collect(); .collect();
ResponseBuilder::new(&req)?.body_no_ssz(&connected_peers) ResponseBuilder::new(&req)?.body_no_ssz(&connected_peers)

View File

@ -203,7 +203,6 @@ pub fn route<T: BeaconChainTypes>(
(&Method::GET, "/advanced/operation_pool") => { (&Method::GET, "/advanced/operation_pool") => {
into_boxfut(advanced::get_operation_pool::<T>(req, beacon_chain)) into_boxfut(advanced::get_operation_pool::<T>(req, beacon_chain))
} }
(&Method::GET, "/metrics") => into_boxfut(metrics::get_prometheus::<T>( (&Method::GET, "/metrics") => into_boxfut(metrics::get_prometheus::<T>(
req, req,
beacon_chain, beacon_chain,
@ -215,7 +214,12 @@ pub fn route<T: BeaconChainTypes>(
(&Method::GET, "/lighthouse/syncing") => { (&Method::GET, "/lighthouse/syncing") => {
into_boxfut(lighthouse::syncing::<T::EthSpec>(req, network_globals)) into_boxfut(lighthouse::syncing::<T::EthSpec>(req, network_globals))
} }
(&Method::GET, "/lighthouse/peers") => {
into_boxfut(lighthouse::peers::<T::EthSpec>(req, network_globals))
}
(&Method::GET, "/lighthouse/connected_peers") => into_boxfut(
lighthouse::connected_peers::<T::EthSpec>(req, network_globals),
),
_ => Box::new(futures::future::err(ApiError::NotFound( _ => Box::new(futures::future::err(ApiError::NotFound(
"Request path and/or method not found.".to_owned(), "Request path and/or method not found.".to_owned(),
))), ))),

View File

@ -7,6 +7,8 @@ The `/lighthouse` endpoints provide lighthouse-specific information about the be
HTTP Path | Description | HTTP Path | Description |
| --- | -- | | --- | -- |
[`/lighthouse/syncing`](#lighthousesyncing) | Get the node's syncing status [`/lighthouse/syncing`](#lighthousesyncing) | Get the node's syncing status
[`/lighthouse/peers`](#lighthousepeers) | Get the peers info known by the beacon node
[`/lighthouse/connected_peers`](#lighthousepeers) | Get the connected_peers known by the beacon node
## `/lighthouse/syncing` ## `/lighthouse/syncing`
@ -52,3 +54,129 @@ If the node is synced
"Synced" "Synced"
} }
``` ```
## `/lighthouse/peers`
Get all known peers info from the beacon node.
### HTTP Specification
| Property | Specification |
| --- |--- |
Path | `/lighthouse/peers`
Method | GET
JSON Encoding | Object
Query Parameters | None
Typical Responses | 200
### Example Response
```json
[
{
"peer_id" : "16Uiu2HAmTEinipUS3haxqucrn7d7SmCKx5XzAVbAZCiNW54ncynG",
"peer_info" : {
"_status" : "Healthy",
"client" : {
"agent_string" : "github.com/libp2p/go-libp2p",
"kind" : "Prysm",
"os_version" : "unknown",
"protocol_version" : "ipfs/0.1.0",
"version" : "unknown"
},
"connection_status" : {
"Disconnected" : {
"since" : 3
}
},
"listening_addresses" : [
"/ip4/10.3.58.241/tcp/9001",
"/ip4/35.172.14.146/tcp/9001",
"/ip4/35.172.14.146/tcp/9001"
],
"meta_data" : {
"attnets" : "0x0000000000000000",
"seq_number" : 0
},
"reputation" : 20,
"sync_status" : {
"Synced" : {
"status_head_slot" : 18146
}
}
}
},
{
"peer_id" : "16Uiu2HAm8XZfPv3YjktCjitSRtfS7UfHfEvpiUyHrdiX6uAD55xZ",
"peer_info" : {
"_status" : "Healthy",
"client" : {
"agent_string" : null,
"kind" : "Unknown",
"os_version" : "unknown",
"protocol_version" : "unknown",
"version" : "unknown"
},
"connection_status" : {
"Disconnected" : {
"since" : 5
}
},
"listening_addresses" : [],
"meta_data" : {
"attnets" : "0x0900000000000000",
"seq_number" : 0
},
"reputation" : 20,
"sync_status" : "Unknown"
}
},
]
```
## `/lighthouse/connected_peers`
Get all known peers info from the beacon node.
### HTTP Specification
| Property | Specification |
| --- |--- |
Path | `/lighthouse/connected_peers`
Method | GET
JSON Encoding | Object
Query Parameters | None
Typical Responses | 200
### Example Response
```json
[
{
"peer_id" : "16Uiu2HAm8XZfPv3YjktCjitSRtfS7UfHfEvpiUyHrdiX6uAD55xZ",
"peer_info" : {
"_status" : "Healthy",
"client" : {
"agent_string" : null,
"kind" : "Unknown",
"os_version" : "unknown",
"protocol_version" : "unknown",
"version" : "unknown"
},
"connection_status" : {
"Connected" : {
"in" : 5,
"out" : 2
}
},
"listening_addresses" : [],
"meta_data" : {
"attnets" : "0x0900000000000000",
"seq_number" : 0
},
"reputation" : 20,
"sync_status" : "Unknown"
}
},
]
```