mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-17 03:42:46 +00:00
v0.11.1 Network update (#989)
* Minor log bumps * Initial building of extended RPC methods * Wire in extended RPC methods * Merge initial peer management template * Add a PeerDB and give the peer manager some basic functions * Initial connection of peer manager * Add peer manager to lighthouse * Connect peer manager with new RPC methods * Correct tests and metadata RPC Co-authored-by: Diva <divma@protonmail.com>
This commit is contained in:
@@ -2,7 +2,8 @@ use crate::rpc::methods::*;
|
||||
use crate::rpc::{
|
||||
codec::base::OutboundCodec,
|
||||
protocol::{
|
||||
ProtocolId, RPCError, RPC_BLOCKS_BY_RANGE, RPC_BLOCKS_BY_ROOT, RPC_GOODBYE, RPC_STATUS,
|
||||
ProtocolId, RPCError, RPC_BLOCKS_BY_RANGE, RPC_BLOCKS_BY_ROOT, RPC_GOODBYE, RPC_META_DATA,
|
||||
RPC_PING, RPC_STATUS,
|
||||
},
|
||||
};
|
||||
use crate::rpc::{ErrorMessage, RPCErrorResponse, RPCRequest, RPCResponse};
|
||||
@@ -48,6 +49,8 @@ impl<TSpec: EthSpec> Encoder for SSZInboundCodec<TSpec> {
|
||||
RPCResponse::Status(res) => res.as_ssz_bytes(),
|
||||
RPCResponse::BlocksByRange(res) => res.as_ssz_bytes(),
|
||||
RPCResponse::BlocksByRoot(res) => res.as_ssz_bytes(),
|
||||
RPCResponse::Pong(res) => res.data.as_ssz_bytes(),
|
||||
RPCResponse::MetaData(res) => res.as_ssz_bytes(),
|
||||
},
|
||||
RPCErrorResponse::InvalidRequest(err) => err.as_ssz_bytes(),
|
||||
RPCErrorResponse::ServerError(err) => err.as_ssz_bytes(),
|
||||
@@ -103,6 +106,24 @@ impl<TSpec: EthSpec> Decoder for SSZInboundCodec<TSpec> {
|
||||
}))),
|
||||
_ => unreachable!("Cannot negotiate an unknown version"),
|
||||
},
|
||||
RPC_PING => match self.protocol.version.as_str() {
|
||||
"1" => Ok(Some(RPCRequest::Status(StatusMessage::from_ssz_bytes(
|
||||
&packet,
|
||||
)?))),
|
||||
_ => unreachable!("Cannot negotiate an unknown version"),
|
||||
},
|
||||
RPC_META_DATA => match self.protocol.version.as_str() {
|
||||
"1" => {
|
||||
if packet.len() > 0 {
|
||||
Err(RPCError::Custom(
|
||||
"Get metadata request should be empty".into(),
|
||||
))
|
||||
} else {
|
||||
Ok(Some(RPCRequest::MetaData(PhantomData)))
|
||||
}
|
||||
}
|
||||
_ => unreachable!("Cannot negotiate an unknown version"),
|
||||
},
|
||||
_ => unreachable!("Cannot negotiate an unknown protocol"),
|
||||
},
|
||||
Ok(None) => Ok(None),
|
||||
@@ -146,7 +167,8 @@ impl<TSpec: EthSpec> Encoder for SSZOutboundCodec<TSpec> {
|
||||
RPCRequest::Goodbye(req) => req.as_ssz_bytes(),
|
||||
RPCRequest::BlocksByRange(req) => req.as_ssz_bytes(),
|
||||
RPCRequest::BlocksByRoot(req) => req.block_roots.as_ssz_bytes(),
|
||||
RPCRequest::Phantom(_) => unreachable!("Never encode phantom data"),
|
||||
RPCRequest::Ping(req) => req.as_ssz_bytes(),
|
||||
RPCRequest::MetaData(_) => return Ok(()), // no metadata to encode
|
||||
};
|
||||
// length-prefix
|
||||
self.inner
|
||||
@@ -189,6 +211,18 @@ impl<TSpec: EthSpec> Decoder for SSZOutboundCodec<TSpec> {
|
||||
)), // cannot have an empty block message.
|
||||
_ => unreachable!("Cannot negotiate an unknown version"),
|
||||
},
|
||||
RPC_PING => match self.protocol.version.as_str() {
|
||||
"1" => Err(RPCError::Custom(
|
||||
"PING stream terminated unexpectedly".into(),
|
||||
)), // cannot have an empty block message.
|
||||
_ => unreachable!("Cannot negotiate an unknown version"),
|
||||
},
|
||||
RPC_META_DATA => match self.protocol.version.as_str() {
|
||||
"1" => Err(RPCError::Custom(
|
||||
"Metadata stream terminated unexpectedly".into(),
|
||||
)), // cannot have an empty block message.
|
||||
_ => unreachable!("Cannot negotiate an unknown version"),
|
||||
},
|
||||
_ => unreachable!("Cannot negotiate an unknown protocol"),
|
||||
}
|
||||
} else {
|
||||
@@ -219,6 +253,18 @@ impl<TSpec: EthSpec> Decoder for SSZOutboundCodec<TSpec> {
|
||||
)))),
|
||||
_ => unreachable!("Cannot negotiate an unknown version"),
|
||||
},
|
||||
RPC_PING => match self.protocol.version.as_str() {
|
||||
"1" => Ok(Some(RPCResponse::Pong(Ping {
|
||||
data: u64::from_ssz_bytes(&raw_bytes)?,
|
||||
}))),
|
||||
_ => unreachable!("Cannot negotiate an unknown version"),
|
||||
},
|
||||
RPC_META_DATA => match self.protocol.version.as_str() {
|
||||
"1" => Ok(Some(RPCResponse::MetaData(MetaData::from_ssz_bytes(
|
||||
&raw_bytes,
|
||||
)?))),
|
||||
_ => unreachable!("Cannot negotiate an unknown version"),
|
||||
},
|
||||
_ => unreachable!("Cannot negotiate an unknown protocol"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//! Available RPC methods types and ids.
|
||||
|
||||
use crate::types::EnrBitfield;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use types::{Epoch, EthSpec, Hash256, SignedBeaconBlock, Slot};
|
||||
|
||||
@@ -28,6 +29,22 @@ pub struct StatusMessage {
|
||||
pub head_slot: Slot,
|
||||
}
|
||||
|
||||
/// The PING request/response message.
|
||||
#[derive(Encode, Decode, Clone, Debug, PartialEq)]
|
||||
pub struct Ping {
|
||||
/// The metadata sequence number.
|
||||
pub data: u64,
|
||||
}
|
||||
|
||||
/// The METADATA response structure.
|
||||
#[derive(Encode, Decode, Clone, Debug, PartialEq)]
|
||||
pub struct MetaData<T: EthSpec> {
|
||||
/// A sequential counter indicating when data gets modified.
|
||||
pub seq_number: u64,
|
||||
/// The persistent subnet bitfield.
|
||||
pub attnets: EnrBitfield<T>,
|
||||
}
|
||||
|
||||
/// The reason given for a `Goodbye` message.
|
||||
///
|
||||
/// Note: any unknown `u64::into(n)` will resolve to `Goodbye::Unknown` for any unknown `n`,
|
||||
@@ -136,6 +153,12 @@ pub enum RPCResponse<T: EthSpec> {
|
||||
|
||||
/// A response to a get BLOCKS_BY_ROOT request.
|
||||
BlocksByRoot(Box<SignedBeaconBlock<T>>),
|
||||
|
||||
/// A PONG response to a PING request.
|
||||
Pong(Ping),
|
||||
|
||||
/// A response to a META_DATA request.
|
||||
MetaData(MetaData<T>),
|
||||
}
|
||||
|
||||
/// Indicates which response is being terminated by a stream termination response.
|
||||
@@ -202,6 +225,8 @@ impl<T: EthSpec> RPCErrorResponse<T> {
|
||||
RPCResponse::Status(_) => false,
|
||||
RPCResponse::BlocksByRange(_) => true,
|
||||
RPCResponse::BlocksByRoot(_) => true,
|
||||
RPCResponse::Pong(_) => false,
|
||||
RPCResponse::MetaData(_) => false,
|
||||
},
|
||||
RPCErrorResponse::InvalidRequest(_) => true,
|
||||
RPCErrorResponse::ServerError(_) => true,
|
||||
@@ -249,6 +274,8 @@ impl<T: EthSpec> std::fmt::Display for RPCResponse<T> {
|
||||
RPCResponse::BlocksByRoot(block) => {
|
||||
write!(f, "BlocksByRoot: BLock slot: {}", block.message.slot)
|
||||
}
|
||||
RPCResponse::Pong(ping) => write!(f, "Pong: {}", ping.data),
|
||||
RPCResponse::MetaData(metadata) => write!(f, "Metadata: {}", metadata.seq_number),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,10 +13,11 @@ use libp2p::swarm::{
|
||||
};
|
||||
use libp2p::{Multiaddr, PeerId};
|
||||
pub use methods::{
|
||||
ErrorMessage, RPCErrorResponse, RPCResponse, RequestId, ResponseTermination, StatusMessage,
|
||||
ErrorMessage, MetaData, RPCErrorResponse, RPCResponse, RequestId, ResponseTermination,
|
||||
StatusMessage,
|
||||
};
|
||||
pub use protocol::{RPCError, RPCProtocol, RPCRequest};
|
||||
use slog::o;
|
||||
use slog::{debug, o};
|
||||
use std::marker::PhantomData;
|
||||
use std::time::Duration;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
@@ -120,9 +121,18 @@ where
|
||||
// if initialised the connection, report this upwards to send the HELLO request
|
||||
if let ConnectedPoint::Dialer { .. } = connected_point {
|
||||
self.events.push(NetworkBehaviourAction::GenerateEvent(
|
||||
RPCMessage::PeerDialed(peer_id),
|
||||
RPCMessage::PeerDialed(peer_id.clone()),
|
||||
));
|
||||
}
|
||||
|
||||
// find the peer's meta-data
|
||||
debug!(self.log, "Requesting new peer's metadata"; "peer_id" => format!("{}",peer_id));
|
||||
let rpc_event =
|
||||
RPCEvent::Request(RequestId::from(0usize), RPCRequest::MetaData(PhantomData));
|
||||
self.events.push(NetworkBehaviourAction::SendEvent {
|
||||
peer_id,
|
||||
event: rpc_event,
|
||||
});
|
||||
}
|
||||
|
||||
fn inject_disconnected(&mut self, peer_id: &PeerId, _: ConnectedPoint) {
|
||||
|
||||
@@ -9,24 +9,21 @@ use crate::rpc::{
|
||||
},
|
||||
methods::ResponseTermination,
|
||||
};
|
||||
use futures::{
|
||||
future::{self, FutureResult},
|
||||
sink, stream, Sink, Stream,
|
||||
};
|
||||
use futures::future::*;
|
||||
use futures::{future, sink, stream, Sink, Stream};
|
||||
use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeInfo};
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::time::Duration;
|
||||
use tokio::codec::Framed;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tokio::prelude::*;
|
||||
use tokio::timer::timeout;
|
||||
use tokio::util::FutureExt;
|
||||
use tokio_io_timeout::TimeoutStream;
|
||||
use types::EthSpec;
|
||||
|
||||
/// The maximum bytes that can be sent across the RPC.
|
||||
const MAX_RPC_SIZE: usize = 4_194_304; // 4M
|
||||
const MAX_RPC_SIZE: usize = 1_048_576; // 1M
|
||||
/// The protocol prefix the RPC protocol id.
|
||||
const PROTOCOL_PREFIX: &str = "/eth2/beacon_chain/req";
|
||||
/// Time allowed for the first byte of a request to arrive before we time out (Time To First Byte).
|
||||
@@ -44,6 +41,10 @@ pub const RPC_GOODBYE: &str = "goodbye";
|
||||
pub const RPC_BLOCKS_BY_RANGE: &str = "beacon_blocks_by_range";
|
||||
/// The `BlocksByRoot` protocol name.
|
||||
pub const RPC_BLOCKS_BY_ROOT: &str = "beacon_blocks_by_root";
|
||||
/// The `Ping` protocol name.
|
||||
pub const RPC_PING: &str = "ping";
|
||||
/// The `MetaData` protocol name.
|
||||
pub const RPC_META_DATA: &str = "metadata";
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RPCProtocol<TSpec: EthSpec> {
|
||||
@@ -54,18 +55,21 @@ impl<TSpec: EthSpec> UpgradeInfo for RPCProtocol<TSpec> {
|
||||
type Info = ProtocolId;
|
||||
type InfoIter = Vec<Self::Info>;
|
||||
|
||||
/// The list of supported RPC protocols for Lighthouse.
|
||||
fn protocol_info(&self) -> Self::InfoIter {
|
||||
vec![
|
||||
ProtocolId::new(RPC_STATUS, "1", "ssz"),
|
||||
ProtocolId::new(RPC_GOODBYE, "1", "ssz"),
|
||||
ProtocolId::new(RPC_BLOCKS_BY_RANGE, "1", "ssz"),
|
||||
ProtocolId::new(RPC_BLOCKS_BY_ROOT, "1", "ssz"),
|
||||
ProtocolId::new(RPC_PING, "1", "ssz"),
|
||||
ProtocolId::new(RPC_META_DATA, "1", "ssz"),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks the types in a protocol id.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ProtocolId {
|
||||
/// The rpc message type/name.
|
||||
pub message_name: String,
|
||||
@@ -125,13 +129,16 @@ where
|
||||
type Output = InboundOutput<TSocket, TSpec>;
|
||||
type Error = RPCError;
|
||||
|
||||
type Future = future::AndThen<
|
||||
future::MapErr<
|
||||
timeout::Timeout<stream::StreamFuture<InboundFramed<TSocket, TSpec>>>,
|
||||
FnMapErr<TSocket, TSpec>,
|
||||
>,
|
||||
type Future = future::Either<
|
||||
FutureResult<InboundOutput<TSocket, TSpec>, RPCError>,
|
||||
FnAndThen<TSocket, TSpec>,
|
||||
future::AndThen<
|
||||
future::MapErr<
|
||||
timeout::Timeout<stream::StreamFuture<InboundFramed<TSocket, TSpec>>>,
|
||||
FnMapErr<TSocket, TSpec>,
|
||||
>,
|
||||
FutureResult<InboundOutput<TSocket, TSpec>, RPCError>,
|
||||
FnAndThen<TSocket, TSpec>,
|
||||
>,
|
||||
>;
|
||||
|
||||
fn upgrade_inbound(
|
||||
@@ -141,22 +148,36 @@ where
|
||||
) -> Self::Future {
|
||||
match protocol.encoding.as_str() {
|
||||
"ssz" | _ => {
|
||||
let protocol_name = protocol.message_name.clone();
|
||||
let ssz_codec = BaseInboundCodec::new(SSZInboundCodec::new(protocol, MAX_RPC_SIZE));
|
||||
let codec = InboundCodec::SSZ(ssz_codec);
|
||||
let mut timed_socket = TimeoutStream::new(socket);
|
||||
timed_socket.set_read_timeout(Some(Duration::from_secs(TTFB_TIMEOUT)));
|
||||
Framed::new(timed_socket, codec)
|
||||
.into_future()
|
||||
.timeout(Duration::from_secs(REQUEST_TIMEOUT))
|
||||
.map_err(RPCError::from as FnMapErr<TSocket, TSpec>)
|
||||
.and_then({
|
||||
|(req, stream)| match req {
|
||||
Some(req) => futures::future::ok((req, stream)),
|
||||
None => futures::future::err(RPCError::Custom(
|
||||
"Stream terminated early".into(),
|
||||
)),
|
||||
}
|
||||
} as FnAndThen<TSocket, TSpec>)
|
||||
|
||||
let socket = Framed::new(timed_socket, codec);
|
||||
|
||||
// MetaData requests should be empty, return the stream
|
||||
if protocol_name == RPC_META_DATA {
|
||||
futures::future::Either::A(futures::future::ok((
|
||||
RPCRequest::MetaData(PhantomData),
|
||||
socket,
|
||||
)))
|
||||
} else {
|
||||
futures::future::Either::B(
|
||||
socket
|
||||
.into_future()
|
||||
.timeout(Duration::from_secs(REQUEST_TIMEOUT))
|
||||
.map_err(RPCError::from as FnMapErr<TSocket, TSpec>)
|
||||
.and_then({
|
||||
|(req, stream)| match req {
|
||||
Some(request) => futures::future::ok((request, stream)),
|
||||
None => futures::future::err(RPCError::Custom(
|
||||
"Stream terminated early".into(),
|
||||
)),
|
||||
}
|
||||
} as FnAndThen<TSocket, TSpec>),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,7 +194,8 @@ pub enum RPCRequest<TSpec: EthSpec> {
|
||||
Goodbye(GoodbyeReason),
|
||||
BlocksByRange(BlocksByRangeRequest),
|
||||
BlocksByRoot(BlocksByRootRequest),
|
||||
Phantom(PhantomData<TSpec>),
|
||||
Ping(Ping),
|
||||
MetaData(PhantomData<TSpec>),
|
||||
}
|
||||
|
||||
impl<TSpec: EthSpec> UpgradeInfo for RPCRequest<TSpec> {
|
||||
@@ -195,7 +217,8 @@ impl<TSpec: EthSpec> RPCRequest<TSpec> {
|
||||
RPCRequest::Goodbye(_) => vec![ProtocolId::new(RPC_GOODBYE, "1", "ssz")],
|
||||
RPCRequest::BlocksByRange(_) => vec![ProtocolId::new(RPC_BLOCKS_BY_RANGE, "1", "ssz")],
|
||||
RPCRequest::BlocksByRoot(_) => vec![ProtocolId::new(RPC_BLOCKS_BY_ROOT, "1", "ssz")],
|
||||
RPCRequest::Phantom(_) => Vec::new(),
|
||||
RPCRequest::Ping(_) => vec![ProtocolId::new(RPC_PING, "1", "ssz")],
|
||||
RPCRequest::MetaData(_) => vec![ProtocolId::new(RPC_META_DATA, "1", "ssz")],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +232,8 @@ impl<TSpec: EthSpec> RPCRequest<TSpec> {
|
||||
RPCRequest::Goodbye(_) => false,
|
||||
RPCRequest::BlocksByRange(_) => true,
|
||||
RPCRequest::BlocksByRoot(_) => true,
|
||||
RPCRequest::Phantom(_) => unreachable!("Phantom should never be initialised"),
|
||||
RPCRequest::Ping(_) => true,
|
||||
RPCRequest::MetaData(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +245,8 @@ impl<TSpec: EthSpec> RPCRequest<TSpec> {
|
||||
RPCRequest::Goodbye(_) => false,
|
||||
RPCRequest::BlocksByRange(_) => true,
|
||||
RPCRequest::BlocksByRoot(_) => true,
|
||||
RPCRequest::Phantom(_) => unreachable!("Phantom should never be initialised"),
|
||||
RPCRequest::Ping(_) => false,
|
||||
RPCRequest::MetaData(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +260,8 @@ impl<TSpec: EthSpec> RPCRequest<TSpec> {
|
||||
RPCRequest::BlocksByRoot(_) => ResponseTermination::BlocksByRoot,
|
||||
RPCRequest::Status(_) => unreachable!(),
|
||||
RPCRequest::Goodbye(_) => unreachable!(),
|
||||
RPCRequest::Phantom(_) => unreachable!("Phantom should never be initialised"),
|
||||
RPCRequest::Ping(_) => unreachable!(),
|
||||
RPCRequest::MetaData(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -361,7 +387,8 @@ impl<TSpec: EthSpec> std::fmt::Display for RPCRequest<TSpec> {
|
||||
RPCRequest::Goodbye(reason) => write!(f, "Goodbye: {}", reason),
|
||||
RPCRequest::BlocksByRange(req) => write!(f, "Blocks by range: {}", req),
|
||||
RPCRequest::BlocksByRoot(req) => write!(f, "Blocks by root: {:?}", req),
|
||||
RPCRequest::Phantom(_) => unreachable!("Phantom should never be initialised"),
|
||||
RPCRequest::Ping(ping) => write!(f, "Ping: {}", ping.data),
|
||||
RPCRequest::MetaData(_) => write!(f, "MetaData request"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user