Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add client support for the lighthouse/peers route #4937

Open
wants to merge 8 commits into
base: unstable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ members = [
"common/oneshot_broadcast",
"common/pretty_reqwest_error",
"common/sensitive_url",
"common/serde_utils",
"common/slot_clock",
"common/system_health",
"common/task_executor",
Expand Down
1 change: 1 addition & 0 deletions beacon_node/lighthouse_network/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ authors = ["Sigma Prime <contact@sigmaprime.io>"]
edition = { workspace = true }

[dependencies]
serde_utils = { path = "../../common/serde_utils" }
discv5 = { workspace = true }
unsigned-varint = { version = "0.6", features = ["codec"] }
ssz_types = { workspace = true }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
//! Currently using identify to fingerprint.

use libp2p::identify::Info as IdentifyInfo;
use serde::Serialize;
use serde::{Deserialize, Serialize};
use strum::{AsRefStr, EnumIter, IntoStaticStr};

/// Various client and protocol information related to a node.
#[derive(Clone, Debug, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Client {
/// The client's name (Ex: lighthouse, prism, nimbus, etc)
pub kind: ClientKind,
Expand All @@ -21,7 +21,9 @@ pub struct Client {
pub agent_string: Option<String>,
}

#[derive(Clone, Copy, Debug, Serialize, PartialEq, AsRefStr, IntoStaticStr, EnumIter)]
#[derive(
Clone, Copy, Debug, Deserialize, Serialize, PartialEq, AsRefStr, IntoStaticStr, EnumIter,
)]
pub enum ClientKind {
/// A lighthouse node (the best kind).
Lighthouse,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use discv5::Enr;
use libp2p::core::multiaddr::{Multiaddr, Protocol};
use serde::{
ser::{SerializeStruct, Serializer},
Serialize,
Deserialize, Serialize,
};
use std::collections::HashSet;
use std::net::IpAddr;
Expand All @@ -16,8 +16,10 @@ use strum::AsRefStr;
use types::EthSpec;
use PeerConnectionStatus::*;

use serde_utils::approx_instant;

/// Information about a given connected peer.
#[derive(Clone, Debug, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(bound = "T: EthSpec")]
pub struct PeerInfo<T: EthSpec> {
/// The peers reputation
Expand All @@ -35,6 +37,7 @@ pub struct PeerInfo<T: EthSpec> {
/// The current syncing state of the peer. The state may be determined after it's initial
/// connection.
sync_status: SyncStatus,
#[serde(skip)]
/// The ENR subnet bitfield of the peer. This may be determined after it's initial
/// connection.
meta_data: Option<MetaData<T>>,
Expand Down Expand Up @@ -473,7 +476,7 @@ impl<T: EthSpec> PeerInfo<T> {
}

/// Connection Direction of connection.
#[derive(Debug, Clone, Serialize, AsRefStr)]
#[derive(Debug, Clone, Deserialize, Serialize, AsRefStr)]
#[strum(serialize_all = "snake_case")]
pub enum ConnectionDirection {
/// The connection was established by a peer dialing us.
Expand All @@ -483,7 +486,7 @@ pub enum ConnectionDirection {
}

/// Connection Status of the peer.
#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone, Default, Deserialize)]
pub enum PeerConnectionStatus {
/// The peer is connected.
Connected {
Expand All @@ -499,16 +502,19 @@ pub enum PeerConnectionStatus {
},
/// The peer has disconnected.
Disconnected {
#[serde(with = "approx_instant")]
/// last time the peer was connected or discovered.
since: Instant,
},
/// The peer has been banned and is disconnected.
Banned {
#[serde(with = "approx_instant")]
/// moment when the peer was banned.
since: Instant,
},
/// We are currently dialing this peer.
Dialing {
#[serde(with = "approx_instant")]
/// time since we last communicated with the peer.
since: Instant,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
//!
//! The scoring algorithms are currently experimental.
use crate::service::gossipsub_scoring_parameters::GREYLIST_THRESHOLD as GOSSIPSUB_GREYLIST_THRESHOLD;
use serde::Serialize;
use serde::{Deserialize, Serialize};
use std::time::Instant;
use strum::AsRefStr;
use tokio::time::Duration;

use serde_utils::approx_instant;

lazy_static! {
static ref HALFLIFE_DECAY: f64 = -(2.0f64.ln()) / SCORE_HALFLIFE;
}
Expand Down Expand Up @@ -124,7 +126,7 @@ impl std::fmt::Display for ScoreState {
///
/// This simplistic version consists of a global score per peer which decays to 0 over time. The
/// decay rate applies equally to positive and negative scores.
#[derive(PartialEq, Clone, Debug, Serialize)]
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct RealScore {
/// The global score.
// NOTE: In the future we may separate this into sub-scores involving the RPC, Gossipsub and
Expand All @@ -136,7 +138,7 @@ pub struct RealScore {
ignore_negative_gossipsub_score: bool,
score: f64,
/// The time the score was last updated to perform time-based adjustments such as score-decay.
#[serde(skip)]
#[serde(with = "approx_instant")]
last_updated: Instant,
}

Expand Down Expand Up @@ -261,7 +263,7 @@ impl RealScore {
}
}

#[derive(PartialEq, Clone, Debug, Serialize)]
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub enum Score {
Max,
Real(RealScore),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! Handles individual sync status for peers.

use serde::Serialize;
use serde::{Deserialize, Serialize};
use types::{Epoch, Hash256, Slot};

#[derive(Clone, Debug, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
/// The current sync status of the peer.
pub enum SyncStatus {
/// At the current state as our node or ahead of us.
Expand All @@ -19,7 +19,7 @@ pub enum SyncStatus {
}

/// A relevant peer's sync information.
#[derive(Clone, Debug, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SyncInfo {
pub head_slot: Slot,
pub head_root: Hash256,
Expand Down
4 changes: 2 additions & 2 deletions beacon_node/lighthouse_network/src/types/subnet.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use serde::Serialize;
use serde::{Deserialize, Serialize};
use std::time::Instant;
use types::{SubnetId, SyncSubnetId};

/// Represents a subnet on an attestation or sync committee `SubnetId`.
///
/// Used for subscribing to the appropriate gossipsub subnets and mark
/// appropriate metadata bitfields.
#[derive(Debug, Clone, Copy, Serialize, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Hash)]
pub enum Subnet {
/// Represents a gossipsub attestation subnet and the metadata `attnets` field.
Attestation(SubnetId),
Expand Down
21 changes: 12 additions & 9 deletions common/eth2/src/lighthouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
ok_or_error,
types::{
BeaconState, ChainSpec, DepositTreeSnapshot, Epoch, EthSpec, FinalizedExecutionBlock,
GenericResponse, ValidatorId,
GenericResponse, PeersData, ValidatorId,
},
BeaconNodeHttpClient, DepositData, Error, Eth1Data, Hash256, Slot, StateId, StatusCode,
};
Expand Down Expand Up @@ -41,7 +41,7 @@ four_byte_option_impl!(four_byte_option_hash256, Hash256);

/// Information returned by `peers` and `connected_peers`.
// TODO: this should be deserializable..
#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(bound = "T: EthSpec")]
pub struct Peer<T: EthSpec> {
/// The Peer's ID
Expand Down Expand Up @@ -413,13 +413,16 @@ impl BeaconNodeHttpClient {
self.get(path).await
}

/*
* Note:
*
* The `lighthouse/peers` endpoints do not have functions here. We are yet to implement
* `Deserialize` on the `PeerInfo` struct since it contains use of `Instant`. This could be
* fairly simply achieved, if desired.
*/
pub async fn get_lighthouse_peers(&self) -> Result<GenericResponse<PeersData>, Error> {
let mut path = self.server.full.clone();

path.path_segments_mut()
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
.push("lighthouse")
.push("peers");

self.get(path).await
}

/// `GET lighthouse/proto_array`
pub async fn get_lighthouse_proto_array(&self) -> Result<GenericResponse<ProtoArray>, Error> {
Expand Down
10 changes: 10 additions & 0 deletions common/serde_utils/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "serde_utils"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have an external package (ethereum_serde_utils) which defines a crate called serde_utils. I think we could either put this code there, give it a different crate name to avoid confusion, or put the Instant serialisation as a module in the lighthouse_network crate.

I think my preference is for the latter, as the Instant stuff is not really Ethereum-specific, and seems a bit too hacky (using SystemTime::now) to put in ethereum_serde_utils. Similarly, for future serde utils, if we deem them Ethereum-relevant we can put them in the extern crate, whereas if they're Lighthouse-specific we can keep them in-tree. Wdyt?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My preference is the former, although I understand your point about lack of Ethereum specificity (and concur). My issue with moving it to lighthouse_network is that, in my opinion, that crate is already too busy and this busyness complicates downstream use of the crate outside of Lighthouse. I already have some changes that I need to open a (separate) PR for that address some of this.

and seems a bit too hacky

I also agree here, but my desire for full client-side implementation of the HTTP API overrides this. This certainly isn't a nice solution but my feeling at the moment is that having missing routes is less nice than even this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok cool. I'm happy with putting it in ethereum_serde_utils. I thought it might break WASM compatibility (which seems to be something people want from our crates) but it seems it will compile fine and just panic on WASM, which is fine as it's completely optional (rust-lang/rust#48564).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wow, hadn't considered that WASM quirk before!

version = "0.1.0"
authors = ["Jack McPherson <jack@sigmaprime.io>"]
edition = { workspace = true }

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = { workspace = true }
27 changes: 27 additions & 0 deletions common/serde_utils/src/approx_instant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
/// Serialise and deserialise `std::time::Instant`s
///
/// Due to David Tolnay via: https://github.com/serde-rs/serde/issues/1375#issuecomment-419688068
use std::time::{Instant, SystemTime};

pub fn serialize<S>(instant: &Instant, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let system_now = SystemTime::now();
let instant_now = Instant::now();
let approx = system_now - (instant_now - *instant);
approx.serialize(serializer)
}

pub fn deserialize<'de, D>(deserializer: D) -> Result<Instant, D::Error>
where
D: Deserializer<'de>,
{
let de = SystemTime::deserialize(deserializer)?;
let system_now = SystemTime::now();
let instant_now = Instant::now();
let duration = system_now.duration_since(de).map_err(Error::custom)?;
let approx = instant_now - duration;
Ok(approx)
}
1 change: 1 addition & 0 deletions common/serde_utils/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod approx_instant;
Loading