Added LightClientBootstrap V1 (#3711)
## Issue Addressed Partially addresses #3651 ## Proposed Changes Adds server-side support for light_client_bootstrap_v1 topic ## Additional Info This PR, creates each time a bootstrap without using cache, I do not know how necessary a cache is in this case as this topic is not supposed to be called frequently and IMHO we can just prevent abuse by using the limiter, but let me know what you think or if there is any caveat to this, or if it is necessary only for the sake of good practice. Co-authored-by: Pawan Dhananjay <pawandhananjay@gmail.com>
This commit is contained in:
parent
bf533c8e42
commit
d5a2de759b
@ -47,8 +47,6 @@ pub struct ChainConfig {
|
|||||||
pub count_unrealized_full: CountUnrealizedFull,
|
pub count_unrealized_full: CountUnrealizedFull,
|
||||||
/// Optionally set timeout for calls to checkpoint sync endpoint.
|
/// Optionally set timeout for calls to checkpoint sync endpoint.
|
||||||
pub checkpoint_sync_url_timeout: u64,
|
pub checkpoint_sync_url_timeout: u64,
|
||||||
/// Whether to enable the light client server protocol.
|
|
||||||
pub enable_light_client_server: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ChainConfig {
|
impl Default for ChainConfig {
|
||||||
@ -70,7 +68,6 @@ impl Default for ChainConfig {
|
|||||||
paranoid_block_proposal: false,
|
paranoid_block_proposal: false,
|
||||||
count_unrealized_full: CountUnrealizedFull::default(),
|
count_unrealized_full: CountUnrealizedFull::default(),
|
||||||
checkpoint_sync_url_timeout: 60,
|
checkpoint_sync_url_timeout: 60,
|
||||||
enable_light_client_server: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,6 +130,9 @@ pub struct Config {
|
|||||||
|
|
||||||
/// Whether metrics are enabled.
|
/// Whether metrics are enabled.
|
||||||
pub metrics_enabled: bool,
|
pub metrics_enabled: bool,
|
||||||
|
|
||||||
|
/// Whether light client protocols should be enabled.
|
||||||
|
pub enable_light_client_server: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
@ -207,6 +210,7 @@ impl Default for Config {
|
|||||||
shutdown_after_sync: false,
|
shutdown_after_sync: false,
|
||||||
topics: Vec::new(),
|
topics: Vec::new(),
|
||||||
metrics_enabled: false,
|
metrics_enabled: false,
|
||||||
|
enable_light_client_server: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -501,6 +501,7 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
|||||||
Protocol::Ping => PeerAction::MidToleranceError,
|
Protocol::Ping => PeerAction::MidToleranceError,
|
||||||
Protocol::BlocksByRange => PeerAction::MidToleranceError,
|
Protocol::BlocksByRange => PeerAction::MidToleranceError,
|
||||||
Protocol::BlocksByRoot => PeerAction::MidToleranceError,
|
Protocol::BlocksByRoot => PeerAction::MidToleranceError,
|
||||||
|
Protocol::LightClientBootstrap => PeerAction::LowToleranceError,
|
||||||
Protocol::Goodbye => PeerAction::LowToleranceError,
|
Protocol::Goodbye => PeerAction::LowToleranceError,
|
||||||
Protocol::MetaData => PeerAction::LowToleranceError,
|
Protocol::MetaData => PeerAction::LowToleranceError,
|
||||||
Protocol::Status => PeerAction::LowToleranceError,
|
Protocol::Status => PeerAction::LowToleranceError,
|
||||||
@ -517,6 +518,7 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
|||||||
Protocol::BlocksByRange => return,
|
Protocol::BlocksByRange => return,
|
||||||
Protocol::BlocksByRoot => return,
|
Protocol::BlocksByRoot => return,
|
||||||
Protocol::Goodbye => return,
|
Protocol::Goodbye => return,
|
||||||
|
Protocol::LightClientBootstrap => return,
|
||||||
Protocol::MetaData => PeerAction::LowToleranceError,
|
Protocol::MetaData => PeerAction::LowToleranceError,
|
||||||
Protocol::Status => PeerAction::LowToleranceError,
|
Protocol::Status => PeerAction::LowToleranceError,
|
||||||
}
|
}
|
||||||
@ -531,6 +533,7 @@ impl<TSpec: EthSpec> PeerManager<TSpec> {
|
|||||||
Protocol::Ping => PeerAction::LowToleranceError,
|
Protocol::Ping => PeerAction::LowToleranceError,
|
||||||
Protocol::BlocksByRange => PeerAction::MidToleranceError,
|
Protocol::BlocksByRange => PeerAction::MidToleranceError,
|
||||||
Protocol::BlocksByRoot => PeerAction::MidToleranceError,
|
Protocol::BlocksByRoot => PeerAction::MidToleranceError,
|
||||||
|
Protocol::LightClientBootstrap => return,
|
||||||
Protocol::Goodbye => return,
|
Protocol::Goodbye => return,
|
||||||
Protocol::MetaData => return,
|
Protocol::MetaData => return,
|
||||||
Protocol::Status => return,
|
Protocol::Status => return,
|
||||||
|
@ -16,8 +16,8 @@ use std::marker::PhantomData;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio_util::codec::{Decoder, Encoder};
|
use tokio_util::codec::{Decoder, Encoder};
|
||||||
use types::{
|
use types::{
|
||||||
EthSpec, ForkContext, ForkName, SignedBeaconBlock, SignedBeaconBlockAltair,
|
light_client_bootstrap::LightClientBootstrap, EthSpec, ForkContext, ForkName, Hash256,
|
||||||
SignedBeaconBlockBase, SignedBeaconBlockMerge,
|
SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockMerge,
|
||||||
};
|
};
|
||||||
use unsigned_varint::codec::Uvi;
|
use unsigned_varint::codec::Uvi;
|
||||||
|
|
||||||
@ -70,6 +70,7 @@ impl<TSpec: EthSpec> Encoder<RPCCodedResponse<TSpec>> for SSZSnappyInboundCodec<
|
|||||||
RPCResponse::Status(res) => res.as_ssz_bytes(),
|
RPCResponse::Status(res) => res.as_ssz_bytes(),
|
||||||
RPCResponse::BlocksByRange(res) => res.as_ssz_bytes(),
|
RPCResponse::BlocksByRange(res) => res.as_ssz_bytes(),
|
||||||
RPCResponse::BlocksByRoot(res) => res.as_ssz_bytes(),
|
RPCResponse::BlocksByRoot(res) => res.as_ssz_bytes(),
|
||||||
|
RPCResponse::LightClientBootstrap(res) => res.as_ssz_bytes(),
|
||||||
RPCResponse::Pong(res) => res.data.as_ssz_bytes(),
|
RPCResponse::Pong(res) => res.data.as_ssz_bytes(),
|
||||||
RPCResponse::MetaData(res) =>
|
RPCResponse::MetaData(res) =>
|
||||||
// Encode the correct version of the MetaData response based on the negotiated version.
|
// Encode the correct version of the MetaData response based on the negotiated version.
|
||||||
@ -230,6 +231,7 @@ impl<TSpec: EthSpec> Encoder<OutboundRequest<TSpec>> for SSZSnappyOutboundCodec<
|
|||||||
OutboundRequest::BlocksByRoot(req) => req.block_roots.as_ssz_bytes(),
|
OutboundRequest::BlocksByRoot(req) => req.block_roots.as_ssz_bytes(),
|
||||||
OutboundRequest::Ping(req) => req.as_ssz_bytes(),
|
OutboundRequest::Ping(req) => req.as_ssz_bytes(),
|
||||||
OutboundRequest::MetaData(_) => return Ok(()), // no metadata to encode
|
OutboundRequest::MetaData(_) => return Ok(()), // no metadata to encode
|
||||||
|
OutboundRequest::LightClientBootstrap(req) => req.as_ssz_bytes(),
|
||||||
};
|
};
|
||||||
// SSZ encoded bytes should be within `max_packet_size`
|
// SSZ encoded bytes should be within `max_packet_size`
|
||||||
if bytes.len() > self.max_packet_size {
|
if bytes.len() > self.max_packet_size {
|
||||||
@ -472,7 +474,11 @@ fn handle_v1_request<T: EthSpec>(
|
|||||||
Protocol::Ping => Ok(Some(InboundRequest::Ping(Ping {
|
Protocol::Ping => Ok(Some(InboundRequest::Ping(Ping {
|
||||||
data: u64::from_ssz_bytes(decoded_buffer)?,
|
data: u64::from_ssz_bytes(decoded_buffer)?,
|
||||||
}))),
|
}))),
|
||||||
|
Protocol::LightClientBootstrap => Ok(Some(InboundRequest::LightClientBootstrap(
|
||||||
|
LightClientBootstrapRequest {
|
||||||
|
root: Hash256::from_ssz_bytes(decoded_buffer)?,
|
||||||
|
},
|
||||||
|
))),
|
||||||
// MetaData requests return early from InboundUpgrade and do not reach the decoder.
|
// MetaData requests return early from InboundUpgrade and do not reach the decoder.
|
||||||
// Handle this case just for completeness.
|
// Handle this case just for completeness.
|
||||||
Protocol::MetaData => {
|
Protocol::MetaData => {
|
||||||
@ -544,6 +550,9 @@ fn handle_v1_response<T: EthSpec>(
|
|||||||
Protocol::MetaData => Ok(Some(RPCResponse::MetaData(MetaData::V1(
|
Protocol::MetaData => Ok(Some(RPCResponse::MetaData(MetaData::V1(
|
||||||
MetaDataV1::from_ssz_bytes(decoded_buffer)?,
|
MetaDataV1::from_ssz_bytes(decoded_buffer)?,
|
||||||
)))),
|
)))),
|
||||||
|
Protocol::LightClientBootstrap => Ok(Some(RPCResponse::LightClientBootstrap(
|
||||||
|
LightClientBootstrap::from_ssz_bytes(decoded_buffer)?,
|
||||||
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -867,6 +876,9 @@ mod tests {
|
|||||||
OutboundRequest::MetaData(metadata) => {
|
OutboundRequest::MetaData(metadata) => {
|
||||||
assert_eq!(decoded, InboundRequest::MetaData(metadata))
|
assert_eq!(decoded, InboundRequest::MetaData(metadata))
|
||||||
}
|
}
|
||||||
|
OutboundRequest::LightClientBootstrap(bootstrap) => {
|
||||||
|
assert_eq!(decoded, InboundRequest::LightClientBootstrap(bootstrap))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,9 @@ use std::ops::Deref;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use strum::IntoStaticStr;
|
use strum::IntoStaticStr;
|
||||||
use superstruct::superstruct;
|
use superstruct::superstruct;
|
||||||
use types::{Epoch, EthSpec, Hash256, SignedBeaconBlock, Slot};
|
use types::{
|
||||||
|
light_client_bootstrap::LightClientBootstrap, Epoch, EthSpec, Hash256, SignedBeaconBlock, Slot,
|
||||||
|
};
|
||||||
|
|
||||||
/// Maximum number of blocks in a single request.
|
/// Maximum number of blocks in a single request.
|
||||||
pub type MaxRequestBlocks = U1024;
|
pub type MaxRequestBlocks = U1024;
|
||||||
@ -243,6 +245,9 @@ pub enum RPCResponse<T: EthSpec> {
|
|||||||
/// A response to a get BLOCKS_BY_ROOT request.
|
/// A response to a get BLOCKS_BY_ROOT request.
|
||||||
BlocksByRoot(Arc<SignedBeaconBlock<T>>),
|
BlocksByRoot(Arc<SignedBeaconBlock<T>>),
|
||||||
|
|
||||||
|
/// A response to a get LIGHTCLIENT_BOOTSTRAP request.
|
||||||
|
LightClientBootstrap(LightClientBootstrap<T>),
|
||||||
|
|
||||||
/// A PONG response to a PING request.
|
/// A PONG response to a PING request.
|
||||||
Pong(Ping),
|
Pong(Ping),
|
||||||
|
|
||||||
@ -273,6 +278,12 @@ pub enum RPCCodedResponse<T: EthSpec> {
|
|||||||
StreamTermination(ResponseTermination),
|
StreamTermination(ResponseTermination),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request a light_client_bootstrap for lightclients peers.
|
||||||
|
#[derive(Encode, Decode, Clone, Debug, PartialEq)]
|
||||||
|
pub struct LightClientBootstrapRequest {
|
||||||
|
pub root: Hash256,
|
||||||
|
}
|
||||||
|
|
||||||
/// The code assigned to an erroneous `RPCResponse`.
|
/// The code assigned to an erroneous `RPCResponse`.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, IntoStaticStr)]
|
#[derive(Debug, Clone, Copy, PartialEq, IntoStaticStr)]
|
||||||
#[strum(serialize_all = "snake_case")]
|
#[strum(serialize_all = "snake_case")]
|
||||||
@ -321,6 +332,7 @@ impl<T: EthSpec> RPCCodedResponse<T> {
|
|||||||
RPCResponse::BlocksByRoot(_) => true,
|
RPCResponse::BlocksByRoot(_) => true,
|
||||||
RPCResponse::Pong(_) => false,
|
RPCResponse::Pong(_) => false,
|
||||||
RPCResponse::MetaData(_) => false,
|
RPCResponse::MetaData(_) => false,
|
||||||
|
RPCResponse::LightClientBootstrap(_) => false,
|
||||||
},
|
},
|
||||||
RPCCodedResponse::Error(_, _) => true,
|
RPCCodedResponse::Error(_, _) => true,
|
||||||
// Stream terminations are part of responses that have chunks
|
// Stream terminations are part of responses that have chunks
|
||||||
@ -355,6 +367,7 @@ impl<T: EthSpec> RPCResponse<T> {
|
|||||||
RPCResponse::BlocksByRoot(_) => Protocol::BlocksByRoot,
|
RPCResponse::BlocksByRoot(_) => Protocol::BlocksByRoot,
|
||||||
RPCResponse::Pong(_) => Protocol::Ping,
|
RPCResponse::Pong(_) => Protocol::Ping,
|
||||||
RPCResponse::MetaData(_) => Protocol::MetaData,
|
RPCResponse::MetaData(_) => Protocol::MetaData,
|
||||||
|
RPCResponse::LightClientBootstrap(_) => Protocol::LightClientBootstrap,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -390,6 +403,9 @@ impl<T: EthSpec> std::fmt::Display for RPCResponse<T> {
|
|||||||
}
|
}
|
||||||
RPCResponse::Pong(ping) => write!(f, "Pong: {}", ping.data),
|
RPCResponse::Pong(ping) => write!(f, "Pong: {}", ping.data),
|
||||||
RPCResponse::MetaData(metadata) => write!(f, "Metadata: {}", metadata.seq_number()),
|
RPCResponse::MetaData(metadata) => write!(f, "Metadata: {}", metadata.seq_number()),
|
||||||
|
RPCResponse::LightClientBootstrap(bootstrap) => {
|
||||||
|
write!(f, "LightClientBootstrap Slot: {}", bootstrap.header.slot)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,8 @@ pub(crate) use protocol::{InboundRequest, RPCProtocol};
|
|||||||
|
|
||||||
pub use handler::SubstreamId;
|
pub use handler::SubstreamId;
|
||||||
pub use methods::{
|
pub use methods::{
|
||||||
BlocksByRangeRequest, BlocksByRootRequest, GoodbyeReason, MaxRequestBlocks,
|
BlocksByRangeRequest, BlocksByRootRequest, GoodbyeReason, LightClientBootstrapRequest,
|
||||||
RPCResponseErrorCode, ResponseTermination, StatusMessage, MAX_REQUEST_BLOCKS,
|
MaxRequestBlocks, RPCResponseErrorCode, ResponseTermination, StatusMessage, MAX_REQUEST_BLOCKS,
|
||||||
};
|
};
|
||||||
pub(crate) use outbound::OutboundRequest;
|
pub(crate) use outbound::OutboundRequest;
|
||||||
pub use protocol::{max_rpc_size, Protocol, RPCError};
|
pub use protocol::{max_rpc_size, Protocol, RPCError};
|
||||||
@ -108,18 +108,24 @@ pub struct RPC<Id: ReqId, TSpec: EthSpec> {
|
|||||||
/// Queue of events to be processed.
|
/// Queue of events to be processed.
|
||||||
events: Vec<NetworkBehaviourAction<RPCMessage<Id, TSpec>, RPCHandler<Id, TSpec>>>,
|
events: Vec<NetworkBehaviourAction<RPCMessage<Id, TSpec>, RPCHandler<Id, TSpec>>>,
|
||||||
fork_context: Arc<ForkContext>,
|
fork_context: Arc<ForkContext>,
|
||||||
|
enable_light_client_server: bool,
|
||||||
/// Slog logger for RPC behaviour.
|
/// Slog logger for RPC behaviour.
|
||||||
log: slog::Logger,
|
log: slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Id: ReqId, TSpec: EthSpec> RPC<Id, TSpec> {
|
impl<Id: ReqId, TSpec: EthSpec> RPC<Id, TSpec> {
|
||||||
pub fn new(fork_context: Arc<ForkContext>, log: slog::Logger) -> Self {
|
pub fn new(
|
||||||
|
fork_context: Arc<ForkContext>,
|
||||||
|
enable_light_client_server: bool,
|
||||||
|
log: slog::Logger,
|
||||||
|
) -> Self {
|
||||||
let log = log.new(o!("service" => "libp2p_rpc"));
|
let log = log.new(o!("service" => "libp2p_rpc"));
|
||||||
let limiter = RPCRateLimiterBuilder::new()
|
let limiter = RPCRateLimiterBuilder::new()
|
||||||
.n_every(Protocol::MetaData, 2, Duration::from_secs(5))
|
.n_every(Protocol::MetaData, 2, Duration::from_secs(5))
|
||||||
.n_every(Protocol::Ping, 2, Duration::from_secs(10))
|
.n_every(Protocol::Ping, 2, Duration::from_secs(10))
|
||||||
.n_every(Protocol::Status, 5, Duration::from_secs(15))
|
.n_every(Protocol::Status, 5, Duration::from_secs(15))
|
||||||
.one_every(Protocol::Goodbye, Duration::from_secs(10))
|
.one_every(Protocol::Goodbye, Duration::from_secs(10))
|
||||||
|
.one_every(Protocol::LightClientBootstrap, Duration::from_secs(10))
|
||||||
.n_every(
|
.n_every(
|
||||||
Protocol::BlocksByRange,
|
Protocol::BlocksByRange,
|
||||||
methods::MAX_REQUEST_BLOCKS,
|
methods::MAX_REQUEST_BLOCKS,
|
||||||
@ -132,6 +138,7 @@ impl<Id: ReqId, TSpec: EthSpec> RPC<Id, TSpec> {
|
|||||||
limiter,
|
limiter,
|
||||||
events: Vec::new(),
|
events: Vec::new(),
|
||||||
fork_context,
|
fork_context,
|
||||||
|
enable_light_client_server,
|
||||||
log,
|
log,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,6 +195,7 @@ where
|
|||||||
RPCProtocol {
|
RPCProtocol {
|
||||||
fork_context: self.fork_context.clone(),
|
fork_context: self.fork_context.clone(),
|
||||||
max_rpc_size: max_rpc_size(&self.fork_context),
|
max_rpc_size: max_rpc_size(&self.fork_context),
|
||||||
|
enable_light_client_server: self.enable_light_client_server,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
|
@ -38,6 +38,7 @@ pub enum OutboundRequest<TSpec: EthSpec> {
|
|||||||
Goodbye(GoodbyeReason),
|
Goodbye(GoodbyeReason),
|
||||||
BlocksByRange(OldBlocksByRangeRequest),
|
BlocksByRange(OldBlocksByRangeRequest),
|
||||||
BlocksByRoot(BlocksByRootRequest),
|
BlocksByRoot(BlocksByRootRequest),
|
||||||
|
LightClientBootstrap(LightClientBootstrapRequest),
|
||||||
Ping(Ping),
|
Ping(Ping),
|
||||||
MetaData(PhantomData<TSpec>),
|
MetaData(PhantomData<TSpec>),
|
||||||
}
|
}
|
||||||
@ -84,9 +85,12 @@ impl<TSpec: EthSpec> OutboundRequest<TSpec> {
|
|||||||
ProtocolId::new(Protocol::MetaData, Version::V2, Encoding::SSZSnappy),
|
ProtocolId::new(Protocol::MetaData, Version::V2, Encoding::SSZSnappy),
|
||||||
ProtocolId::new(Protocol::MetaData, Version::V1, Encoding::SSZSnappy),
|
ProtocolId::new(Protocol::MetaData, Version::V1, Encoding::SSZSnappy),
|
||||||
],
|
],
|
||||||
|
// Note: This match arm is technically unreachable as we only respond to light client requests
|
||||||
|
// that we generate from the beacon state.
|
||||||
|
// We do not make light client rpc requests from the beacon node
|
||||||
|
OutboundRequest::LightClientBootstrap(_) => vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* These functions are used in the handler for stream management */
|
/* These functions are used in the handler for stream management */
|
||||||
|
|
||||||
/// Number of responses expected for this request.
|
/// Number of responses expected for this request.
|
||||||
@ -98,6 +102,7 @@ impl<TSpec: EthSpec> OutboundRequest<TSpec> {
|
|||||||
OutboundRequest::BlocksByRoot(req) => req.block_roots.len() as u64,
|
OutboundRequest::BlocksByRoot(req) => req.block_roots.len() as u64,
|
||||||
OutboundRequest::Ping(_) => 1,
|
OutboundRequest::Ping(_) => 1,
|
||||||
OutboundRequest::MetaData(_) => 1,
|
OutboundRequest::MetaData(_) => 1,
|
||||||
|
OutboundRequest::LightClientBootstrap(_) => 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +115,7 @@ impl<TSpec: EthSpec> OutboundRequest<TSpec> {
|
|||||||
OutboundRequest::BlocksByRoot(_) => Protocol::BlocksByRoot,
|
OutboundRequest::BlocksByRoot(_) => Protocol::BlocksByRoot,
|
||||||
OutboundRequest::Ping(_) => Protocol::Ping,
|
OutboundRequest::Ping(_) => Protocol::Ping,
|
||||||
OutboundRequest::MetaData(_) => Protocol::MetaData,
|
OutboundRequest::MetaData(_) => Protocol::MetaData,
|
||||||
|
OutboundRequest::LightClientBootstrap(_) => Protocol::LightClientBootstrap,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,6 +127,7 @@ impl<TSpec: EthSpec> OutboundRequest<TSpec> {
|
|||||||
// variants that have `multiple_responses()` can have values.
|
// variants that have `multiple_responses()` can have values.
|
||||||
OutboundRequest::BlocksByRange(_) => ResponseTermination::BlocksByRange,
|
OutboundRequest::BlocksByRange(_) => ResponseTermination::BlocksByRange,
|
||||||
OutboundRequest::BlocksByRoot(_) => ResponseTermination::BlocksByRoot,
|
OutboundRequest::BlocksByRoot(_) => ResponseTermination::BlocksByRoot,
|
||||||
|
OutboundRequest::LightClientBootstrap(_) => unreachable!(),
|
||||||
OutboundRequest::Status(_) => unreachable!(),
|
OutboundRequest::Status(_) => unreachable!(),
|
||||||
OutboundRequest::Goodbye(_) => unreachable!(),
|
OutboundRequest::Goodbye(_) => unreachable!(),
|
||||||
OutboundRequest::Ping(_) => unreachable!(),
|
OutboundRequest::Ping(_) => unreachable!(),
|
||||||
@ -178,6 +185,9 @@ impl<TSpec: EthSpec> std::fmt::Display for OutboundRequest<TSpec> {
|
|||||||
OutboundRequest::BlocksByRoot(req) => write!(f, "Blocks by root: {:?}", req),
|
OutboundRequest::BlocksByRoot(req) => write!(f, "Blocks by root: {:?}", req),
|
||||||
OutboundRequest::Ping(ping) => write!(f, "Ping: {}", ping.data),
|
OutboundRequest::Ping(ping) => write!(f, "Ping: {}", ping.data),
|
||||||
OutboundRequest::MetaData(_) => write!(f, "MetaData request"),
|
OutboundRequest::MetaData(_) => write!(f, "MetaData request"),
|
||||||
|
OutboundRequest::LightClientBootstrap(bootstrap) => {
|
||||||
|
write!(f, "Lightclient Bootstrap: {}", bootstrap.root)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,6 +153,8 @@ pub enum Protocol {
|
|||||||
Ping,
|
Ping,
|
||||||
/// The `MetaData` protocol name.
|
/// The `MetaData` protocol name.
|
||||||
MetaData,
|
MetaData,
|
||||||
|
/// The `LightClientBootstrap` protocol name.
|
||||||
|
LightClientBootstrap,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RPC Versions
|
/// RPC Versions
|
||||||
@ -179,6 +181,7 @@ impl std::fmt::Display for Protocol {
|
|||||||
Protocol::BlocksByRoot => "beacon_blocks_by_root",
|
Protocol::BlocksByRoot => "beacon_blocks_by_root",
|
||||||
Protocol::Ping => "ping",
|
Protocol::Ping => "ping",
|
||||||
Protocol::MetaData => "metadata",
|
Protocol::MetaData => "metadata",
|
||||||
|
Protocol::LightClientBootstrap => "light_client_bootstrap",
|
||||||
};
|
};
|
||||||
f.write_str(repr)
|
f.write_str(repr)
|
||||||
}
|
}
|
||||||
@ -207,6 +210,7 @@ impl std::fmt::Display for Version {
|
|||||||
pub struct RPCProtocol<TSpec: EthSpec> {
|
pub struct RPCProtocol<TSpec: EthSpec> {
|
||||||
pub fork_context: Arc<ForkContext>,
|
pub fork_context: Arc<ForkContext>,
|
||||||
pub max_rpc_size: usize,
|
pub max_rpc_size: usize,
|
||||||
|
pub enable_light_client_server: bool,
|
||||||
pub phantom: PhantomData<TSpec>,
|
pub phantom: PhantomData<TSpec>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +220,7 @@ impl<TSpec: EthSpec> UpgradeInfo for RPCProtocol<TSpec> {
|
|||||||
|
|
||||||
/// The list of supported RPC protocols for Lighthouse.
|
/// The list of supported RPC protocols for Lighthouse.
|
||||||
fn protocol_info(&self) -> Self::InfoIter {
|
fn protocol_info(&self) -> Self::InfoIter {
|
||||||
vec![
|
let mut supported_protocols = vec![
|
||||||
ProtocolId::new(Protocol::Status, Version::V1, Encoding::SSZSnappy),
|
ProtocolId::new(Protocol::Status, Version::V1, Encoding::SSZSnappy),
|
||||||
ProtocolId::new(Protocol::Goodbye, Version::V1, Encoding::SSZSnappy),
|
ProtocolId::new(Protocol::Goodbye, Version::V1, Encoding::SSZSnappy),
|
||||||
// V2 variants have higher preference then V1
|
// V2 variants have higher preference then V1
|
||||||
@ -227,7 +231,15 @@ impl<TSpec: EthSpec> UpgradeInfo for RPCProtocol<TSpec> {
|
|||||||
ProtocolId::new(Protocol::Ping, Version::V1, Encoding::SSZSnappy),
|
ProtocolId::new(Protocol::Ping, Version::V1, Encoding::SSZSnappy),
|
||||||
ProtocolId::new(Protocol::MetaData, Version::V2, Encoding::SSZSnappy),
|
ProtocolId::new(Protocol::MetaData, Version::V2, Encoding::SSZSnappy),
|
||||||
ProtocolId::new(Protocol::MetaData, Version::V1, Encoding::SSZSnappy),
|
ProtocolId::new(Protocol::MetaData, Version::V1, Encoding::SSZSnappy),
|
||||||
]
|
];
|
||||||
|
if self.enable_light_client_server {
|
||||||
|
supported_protocols.push(ProtocolId::new(
|
||||||
|
Protocol::LightClientBootstrap,
|
||||||
|
Version::V1,
|
||||||
|
Encoding::SSZSnappy,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
supported_protocols
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,6 +301,10 @@ impl ProtocolId {
|
|||||||
<Ping as Encode>::ssz_fixed_len(),
|
<Ping as Encode>::ssz_fixed_len(),
|
||||||
<Ping as Encode>::ssz_fixed_len(),
|
<Ping as Encode>::ssz_fixed_len(),
|
||||||
),
|
),
|
||||||
|
Protocol::LightClientBootstrap => RpcLimits::new(
|
||||||
|
<LightClientBootstrapRequest as Encode>::ssz_fixed_len(),
|
||||||
|
<LightClientBootstrapRequest as Encode>::ssz_fixed_len(),
|
||||||
|
),
|
||||||
Protocol::MetaData => RpcLimits::new(0, 0), // Metadata requests are empty
|
Protocol::MetaData => RpcLimits::new(0, 0), // Metadata requests are empty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -312,6 +328,10 @@ impl ProtocolId {
|
|||||||
<MetaDataV1<T> as Encode>::ssz_fixed_len(),
|
<MetaDataV1<T> as Encode>::ssz_fixed_len(),
|
||||||
<MetaDataV2<T> as Encode>::ssz_fixed_len(),
|
<MetaDataV2<T> as Encode>::ssz_fixed_len(),
|
||||||
),
|
),
|
||||||
|
Protocol::LightClientBootstrap => RpcLimits::new(
|
||||||
|
<LightClientBootstrapRequest as Encode>::ssz_fixed_len(),
|
||||||
|
<LightClientBootstrapRequest as Encode>::ssz_fixed_len(),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,57 +437,13 @@ pub enum InboundRequest<TSpec: EthSpec> {
|
|||||||
Goodbye(GoodbyeReason),
|
Goodbye(GoodbyeReason),
|
||||||
BlocksByRange(OldBlocksByRangeRequest),
|
BlocksByRange(OldBlocksByRangeRequest),
|
||||||
BlocksByRoot(BlocksByRootRequest),
|
BlocksByRoot(BlocksByRootRequest),
|
||||||
|
LightClientBootstrap(LightClientBootstrapRequest),
|
||||||
Ping(Ping),
|
Ping(Ping),
|
||||||
MetaData(PhantomData<TSpec>),
|
MetaData(PhantomData<TSpec>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<TSpec: EthSpec> UpgradeInfo for InboundRequest<TSpec> {
|
|
||||||
type Info = ProtocolId;
|
|
||||||
type InfoIter = Vec<Self::Info>;
|
|
||||||
|
|
||||||
// add further protocols as we support more encodings/versions
|
|
||||||
fn protocol_info(&self) -> Self::InfoIter {
|
|
||||||
self.supported_protocols()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements the encoding per supported protocol for `RPCRequest`.
|
/// Implements the encoding per supported protocol for `RPCRequest`.
|
||||||
impl<TSpec: EthSpec> InboundRequest<TSpec> {
|
impl<TSpec: EthSpec> InboundRequest<TSpec> {
|
||||||
pub fn supported_protocols(&self) -> Vec<ProtocolId> {
|
|
||||||
match self {
|
|
||||||
// add more protocols when versions/encodings are supported
|
|
||||||
InboundRequest::Status(_) => vec![ProtocolId::new(
|
|
||||||
Protocol::Status,
|
|
||||||
Version::V1,
|
|
||||||
Encoding::SSZSnappy,
|
|
||||||
)],
|
|
||||||
InboundRequest::Goodbye(_) => vec![ProtocolId::new(
|
|
||||||
Protocol::Goodbye,
|
|
||||||
Version::V1,
|
|
||||||
Encoding::SSZSnappy,
|
|
||||||
)],
|
|
||||||
InboundRequest::BlocksByRange(_) => vec![
|
|
||||||
// V2 has higher preference when negotiating a stream
|
|
||||||
ProtocolId::new(Protocol::BlocksByRange, Version::V2, Encoding::SSZSnappy),
|
|
||||||
ProtocolId::new(Protocol::BlocksByRange, Version::V1, Encoding::SSZSnappy),
|
|
||||||
],
|
|
||||||
InboundRequest::BlocksByRoot(_) => vec![
|
|
||||||
// V2 has higher preference when negotiating a stream
|
|
||||||
ProtocolId::new(Protocol::BlocksByRoot, Version::V2, Encoding::SSZSnappy),
|
|
||||||
ProtocolId::new(Protocol::BlocksByRoot, Version::V1, Encoding::SSZSnappy),
|
|
||||||
],
|
|
||||||
InboundRequest::Ping(_) => vec![ProtocolId::new(
|
|
||||||
Protocol::Ping,
|
|
||||||
Version::V1,
|
|
||||||
Encoding::SSZSnappy,
|
|
||||||
)],
|
|
||||||
InboundRequest::MetaData(_) => vec![
|
|
||||||
ProtocolId::new(Protocol::MetaData, Version::V2, Encoding::SSZSnappy),
|
|
||||||
ProtocolId::new(Protocol::MetaData, Version::V1, Encoding::SSZSnappy),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* These functions are used in the handler for stream management */
|
/* These functions are used in the handler for stream management */
|
||||||
|
|
||||||
/// Number of responses expected for this request.
|
/// Number of responses expected for this request.
|
||||||
@ -479,6 +455,7 @@ impl<TSpec: EthSpec> InboundRequest<TSpec> {
|
|||||||
InboundRequest::BlocksByRoot(req) => req.block_roots.len() as u64,
|
InboundRequest::BlocksByRoot(req) => req.block_roots.len() as u64,
|
||||||
InboundRequest::Ping(_) => 1,
|
InboundRequest::Ping(_) => 1,
|
||||||
InboundRequest::MetaData(_) => 1,
|
InboundRequest::MetaData(_) => 1,
|
||||||
|
InboundRequest::LightClientBootstrap(_) => 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,6 +468,7 @@ impl<TSpec: EthSpec> InboundRequest<TSpec> {
|
|||||||
InboundRequest::BlocksByRoot(_) => Protocol::BlocksByRoot,
|
InboundRequest::BlocksByRoot(_) => Protocol::BlocksByRoot,
|
||||||
InboundRequest::Ping(_) => Protocol::Ping,
|
InboundRequest::Ping(_) => Protocol::Ping,
|
||||||
InboundRequest::MetaData(_) => Protocol::MetaData,
|
InboundRequest::MetaData(_) => Protocol::MetaData,
|
||||||
|
InboundRequest::LightClientBootstrap(_) => Protocol::LightClientBootstrap,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,6 +484,7 @@ impl<TSpec: EthSpec> InboundRequest<TSpec> {
|
|||||||
InboundRequest::Goodbye(_) => unreachable!(),
|
InboundRequest::Goodbye(_) => unreachable!(),
|
||||||
InboundRequest::Ping(_) => unreachable!(),
|
InboundRequest::Ping(_) => unreachable!(),
|
||||||
InboundRequest::MetaData(_) => unreachable!(),
|
InboundRequest::MetaData(_) => unreachable!(),
|
||||||
|
InboundRequest::LightClientBootstrap(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -609,6 +588,9 @@ impl<TSpec: EthSpec> std::fmt::Display for InboundRequest<TSpec> {
|
|||||||
InboundRequest::BlocksByRoot(req) => write!(f, "Blocks by root: {:?}", req),
|
InboundRequest::BlocksByRoot(req) => write!(f, "Blocks by root: {:?}", req),
|
||||||
InboundRequest::Ping(ping) => write!(f, "Ping: {}", ping.data),
|
InboundRequest::Ping(ping) => write!(f, "Ping: {}", ping.data),
|
||||||
InboundRequest::MetaData(_) => write!(f, "MetaData request"),
|
InboundRequest::MetaData(_) => write!(f, "MetaData request"),
|
||||||
|
InboundRequest::LightClientBootstrap(bootstrap) => {
|
||||||
|
write!(f, "LightClientBootstrap: {}", bootstrap.root)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,8 @@ pub struct RPCRateLimiter {
|
|||||||
bbrange_rl: Limiter<PeerId>,
|
bbrange_rl: Limiter<PeerId>,
|
||||||
/// BlocksByRoot rate limiter.
|
/// BlocksByRoot rate limiter.
|
||||||
bbroots_rl: Limiter<PeerId>,
|
bbroots_rl: Limiter<PeerId>,
|
||||||
|
/// LightClientBootstrap rate limiter.
|
||||||
|
lcbootstrap_rl: Limiter<PeerId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error type for non conformant requests
|
/// Error type for non conformant requests
|
||||||
@ -98,6 +100,8 @@ pub struct RPCRateLimiterBuilder {
|
|||||||
bbrange_quota: Option<Quota>,
|
bbrange_quota: Option<Quota>,
|
||||||
/// Quota for the BlocksByRoot protocol.
|
/// Quota for the BlocksByRoot protocol.
|
||||||
bbroots_quota: Option<Quota>,
|
bbroots_quota: Option<Quota>,
|
||||||
|
/// Quota for the LightClientBootstrap protocol.
|
||||||
|
lcbootstrap_quota: Option<Quota>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RPCRateLimiterBuilder {
|
impl RPCRateLimiterBuilder {
|
||||||
@ -116,6 +120,7 @@ impl RPCRateLimiterBuilder {
|
|||||||
Protocol::Goodbye => self.goodbye_quota = q,
|
Protocol::Goodbye => self.goodbye_quota = q,
|
||||||
Protocol::BlocksByRange => self.bbrange_quota = q,
|
Protocol::BlocksByRange => self.bbrange_quota = q,
|
||||||
Protocol::BlocksByRoot => self.bbroots_quota = q,
|
Protocol::BlocksByRoot => self.bbroots_quota = q,
|
||||||
|
Protocol::LightClientBootstrap => self.lcbootstrap_quota = q,
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -155,6 +160,9 @@ impl RPCRateLimiterBuilder {
|
|||||||
let bbrange_quota = self
|
let bbrange_quota = self
|
||||||
.bbrange_quota
|
.bbrange_quota
|
||||||
.ok_or("BlocksByRange quota not specified")?;
|
.ok_or("BlocksByRange quota not specified")?;
|
||||||
|
let lcbootstrap_quote = self
|
||||||
|
.lcbootstrap_quota
|
||||||
|
.ok_or("LightClientBootstrap quota not specified")?;
|
||||||
|
|
||||||
// create the rate limiters
|
// create the rate limiters
|
||||||
let ping_rl = Limiter::from_quota(ping_quota)?;
|
let ping_rl = Limiter::from_quota(ping_quota)?;
|
||||||
@ -163,6 +171,7 @@ impl RPCRateLimiterBuilder {
|
|||||||
let goodbye_rl = Limiter::from_quota(goodbye_quota)?;
|
let goodbye_rl = Limiter::from_quota(goodbye_quota)?;
|
||||||
let bbroots_rl = Limiter::from_quota(bbroots_quota)?;
|
let bbroots_rl = Limiter::from_quota(bbroots_quota)?;
|
||||||
let bbrange_rl = Limiter::from_quota(bbrange_quota)?;
|
let bbrange_rl = Limiter::from_quota(bbrange_quota)?;
|
||||||
|
let lcbootstrap_rl = Limiter::from_quota(lcbootstrap_quote)?;
|
||||||
|
|
||||||
// check for peers to prune every 30 seconds, starting in 30 seconds
|
// check for peers to prune every 30 seconds, starting in 30 seconds
|
||||||
let prune_every = tokio::time::Duration::from_secs(30);
|
let prune_every = tokio::time::Duration::from_secs(30);
|
||||||
@ -176,6 +185,7 @@ impl RPCRateLimiterBuilder {
|
|||||||
goodbye_rl,
|
goodbye_rl,
|
||||||
bbroots_rl,
|
bbroots_rl,
|
||||||
bbrange_rl,
|
bbrange_rl,
|
||||||
|
lcbootstrap_rl,
|
||||||
init_time: Instant::now(),
|
init_time: Instant::now(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -199,6 +209,7 @@ impl RPCRateLimiter {
|
|||||||
Protocol::Goodbye => &mut self.goodbye_rl,
|
Protocol::Goodbye => &mut self.goodbye_rl,
|
||||||
Protocol::BlocksByRange => &mut self.bbrange_rl,
|
Protocol::BlocksByRange => &mut self.bbrange_rl,
|
||||||
Protocol::BlocksByRoot => &mut self.bbroots_rl,
|
Protocol::BlocksByRoot => &mut self.bbroots_rl,
|
||||||
|
Protocol::LightClientBootstrap => &mut self.lcbootstrap_rl,
|
||||||
};
|
};
|
||||||
check(limiter)
|
check(limiter)
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use libp2p::core::connection::ConnectionId;
|
use libp2p::core::connection::ConnectionId;
|
||||||
use types::{EthSpec, SignedBeaconBlock};
|
use types::{light_client_bootstrap::LightClientBootstrap, EthSpec, SignedBeaconBlock};
|
||||||
|
|
||||||
use crate::rpc::{
|
use crate::rpc::{
|
||||||
methods::{
|
methods::{
|
||||||
BlocksByRangeRequest, BlocksByRootRequest, OldBlocksByRangeRequest, RPCCodedResponse,
|
BlocksByRangeRequest, BlocksByRootRequest, LightClientBootstrapRequest,
|
||||||
RPCResponse, ResponseTermination, StatusMessage,
|
OldBlocksByRangeRequest, RPCCodedResponse, RPCResponse, ResponseTermination, StatusMessage,
|
||||||
},
|
},
|
||||||
OutboundRequest, SubstreamId,
|
OutboundRequest, SubstreamId,
|
||||||
};
|
};
|
||||||
@ -34,6 +34,8 @@ pub enum Request {
|
|||||||
BlocksByRange(BlocksByRangeRequest),
|
BlocksByRange(BlocksByRangeRequest),
|
||||||
/// A request blocks root request.
|
/// A request blocks root request.
|
||||||
BlocksByRoot(BlocksByRootRequest),
|
BlocksByRoot(BlocksByRootRequest),
|
||||||
|
// light client bootstrap request
|
||||||
|
LightClientBootstrap(LightClientBootstrapRequest),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<TSpec: EthSpec> std::convert::From<Request> for OutboundRequest<TSpec> {
|
impl<TSpec: EthSpec> std::convert::From<Request> for OutboundRequest<TSpec> {
|
||||||
@ -47,6 +49,7 @@ impl<TSpec: EthSpec> std::convert::From<Request> for OutboundRequest<TSpec> {
|
|||||||
step: 1,
|
step: 1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Request::LightClientBootstrap(b) => OutboundRequest::LightClientBootstrap(b),
|
||||||
Request::Status(s) => OutboundRequest::Status(s),
|
Request::Status(s) => OutboundRequest::Status(s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,6 +69,8 @@ pub enum Response<TSpec: EthSpec> {
|
|||||||
BlocksByRange(Option<Arc<SignedBeaconBlock<TSpec>>>),
|
BlocksByRange(Option<Arc<SignedBeaconBlock<TSpec>>>),
|
||||||
/// A response to a get BLOCKS_BY_ROOT request.
|
/// A response to a get BLOCKS_BY_ROOT request.
|
||||||
BlocksByRoot(Option<Arc<SignedBeaconBlock<TSpec>>>),
|
BlocksByRoot(Option<Arc<SignedBeaconBlock<TSpec>>>),
|
||||||
|
/// A response to a LightClientUpdate request.
|
||||||
|
LightClientBootstrap(LightClientBootstrap<TSpec>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<TSpec: EthSpec> std::convert::From<Response<TSpec>> for RPCCodedResponse<TSpec> {
|
impl<TSpec: EthSpec> std::convert::From<Response<TSpec>> for RPCCodedResponse<TSpec> {
|
||||||
@ -80,6 +85,9 @@ impl<TSpec: EthSpec> std::convert::From<Response<TSpec>> for RPCCodedResponse<TS
|
|||||||
None => RPCCodedResponse::StreamTermination(ResponseTermination::BlocksByRange),
|
None => RPCCodedResponse::StreamTermination(ResponseTermination::BlocksByRange),
|
||||||
},
|
},
|
||||||
Response::Status(s) => RPCCodedResponse::Success(RPCResponse::Status(s)),
|
Response::Status(s) => RPCCodedResponse::Success(RPCResponse::Status(s)),
|
||||||
|
Response::LightClientBootstrap(b) => {
|
||||||
|
RPCCodedResponse::Success(RPCResponse::LightClientBootstrap(b))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,7 +259,11 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
|||||||
(gossipsub, update_gossipsub_scores)
|
(gossipsub, update_gossipsub_scores)
|
||||||
};
|
};
|
||||||
|
|
||||||
let eth2_rpc = RPC::new(ctx.fork_context.clone(), log.clone());
|
let eth2_rpc = RPC::new(
|
||||||
|
ctx.fork_context.clone(),
|
||||||
|
config.enable_light_client_server,
|
||||||
|
log.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
let discovery = {
|
let discovery = {
|
||||||
// Build and start the discovery sub-behaviour
|
// Build and start the discovery sub-behaviour
|
||||||
@ -978,6 +982,9 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
|||||||
Request::Status(_) => {
|
Request::Status(_) => {
|
||||||
metrics::inc_counter_vec(&metrics::TOTAL_RPC_REQUESTS, &["status"])
|
metrics::inc_counter_vec(&metrics::TOTAL_RPC_REQUESTS, &["status"])
|
||||||
}
|
}
|
||||||
|
Request::LightClientBootstrap(_) => {
|
||||||
|
metrics::inc_counter_vec(&metrics::TOTAL_RPC_REQUESTS, &["light_client_bootstrap"])
|
||||||
|
}
|
||||||
Request::BlocksByRange { .. } => {
|
Request::BlocksByRange { .. } => {
|
||||||
metrics::inc_counter_vec(&metrics::TOTAL_RPC_REQUESTS, &["blocks_by_range"])
|
metrics::inc_counter_vec(&metrics::TOTAL_RPC_REQUESTS, &["blocks_by_range"])
|
||||||
}
|
}
|
||||||
@ -1247,6 +1254,14 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
|||||||
);
|
);
|
||||||
Some(event)
|
Some(event)
|
||||||
}
|
}
|
||||||
|
InboundRequest::LightClientBootstrap(req) => {
|
||||||
|
let event = self.build_request(
|
||||||
|
peer_request_id,
|
||||||
|
peer_id,
|
||||||
|
Request::LightClientBootstrap(req),
|
||||||
|
);
|
||||||
|
Some(event)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(RPCReceived::Response(id, resp)) => {
|
Ok(RPCReceived::Response(id, resp)) => {
|
||||||
@ -1274,6 +1289,10 @@ impl<AppReqId: ReqId, TSpec: EthSpec> Network<AppReqId, TSpec> {
|
|||||||
RPCResponse::BlocksByRoot(resp) => {
|
RPCResponse::BlocksByRoot(resp) => {
|
||||||
self.build_response(id, peer_id, Response::BlocksByRoot(Some(resp)))
|
self.build_response(id, peer_id, Response::BlocksByRoot(Some(resp)))
|
||||||
}
|
}
|
||||||
|
// Should never be reached
|
||||||
|
RPCResponse::LightClientBootstrap(bootstrap) => {
|
||||||
|
self.build_response(id, peer_id, Response::LightClientBootstrap(bootstrap))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(RPCReceived::EndOfStream(id, termination)) => {
|
Ok(RPCReceived::EndOfStream(id, termination)) => {
|
||||||
|
@ -45,6 +45,7 @@ use beacon_chain::{BeaconChain, BeaconChainTypes, GossipVerifiedBlock};
|
|||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
use futures::stream::{Stream, StreamExt};
|
use futures::stream::{Stream, StreamExt};
|
||||||
use futures::task::Poll;
|
use futures::task::Poll;
|
||||||
|
use lighthouse_network::rpc::LightClientBootstrapRequest;
|
||||||
use lighthouse_network::{
|
use lighthouse_network::{
|
||||||
rpc::{BlocksByRangeRequest, BlocksByRootRequest, StatusMessage},
|
rpc::{BlocksByRangeRequest, BlocksByRootRequest, StatusMessage},
|
||||||
Client, MessageId, NetworkGlobals, PeerId, PeerRequestId,
|
Client, MessageId, NetworkGlobals, PeerId, PeerRequestId,
|
||||||
@ -156,6 +157,10 @@ const MAX_BLOCKS_BY_RANGE_QUEUE_LEN: usize = 1_024;
|
|||||||
/// will be stored before we start dropping them.
|
/// will be stored before we start dropping them.
|
||||||
const MAX_BLOCKS_BY_ROOTS_QUEUE_LEN: usize = 1_024;
|
const MAX_BLOCKS_BY_ROOTS_QUEUE_LEN: usize = 1_024;
|
||||||
|
|
||||||
|
/// The maximum number of queued `LightClientBootstrapRequest` objects received from the network RPC that
|
||||||
|
/// will be stored before we start dropping them.
|
||||||
|
const MAX_LIGHT_CLIENT_BOOTSTRAP_QUEUE_LEN: usize = 1_024;
|
||||||
|
|
||||||
/// The name of the manager tokio task.
|
/// The name of the manager tokio task.
|
||||||
const MANAGER_TASK_NAME: &str = "beacon_processor_manager";
|
const MANAGER_TASK_NAME: &str = "beacon_processor_manager";
|
||||||
|
|
||||||
@ -195,6 +200,7 @@ pub const CHAIN_SEGMENT: &str = "chain_segment";
|
|||||||
pub const STATUS_PROCESSING: &str = "status_processing";
|
pub const STATUS_PROCESSING: &str = "status_processing";
|
||||||
pub const BLOCKS_BY_RANGE_REQUEST: &str = "blocks_by_range_request";
|
pub const BLOCKS_BY_RANGE_REQUEST: &str = "blocks_by_range_request";
|
||||||
pub const BLOCKS_BY_ROOTS_REQUEST: &str = "blocks_by_roots_request";
|
pub const BLOCKS_BY_ROOTS_REQUEST: &str = "blocks_by_roots_request";
|
||||||
|
pub const LIGHT_CLIENT_BOOTSTRAP_REQUEST: &str = "light_client_bootstrap";
|
||||||
pub const UNKNOWN_BLOCK_ATTESTATION: &str = "unknown_block_attestation";
|
pub const UNKNOWN_BLOCK_ATTESTATION: &str = "unknown_block_attestation";
|
||||||
pub const UNKNOWN_BLOCK_AGGREGATE: &str = "unknown_block_aggregate";
|
pub const UNKNOWN_BLOCK_AGGREGATE: &str = "unknown_block_aggregate";
|
||||||
|
|
||||||
@ -557,6 +563,22 @@ impl<T: BeaconChainTypes> WorkEvent<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new work event to process `LightClientBootstrap`s from the RPC network.
|
||||||
|
pub fn lightclient_bootstrap_request(
|
||||||
|
peer_id: PeerId,
|
||||||
|
request_id: PeerRequestId,
|
||||||
|
request: LightClientBootstrapRequest,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
drop_during_sync: true,
|
||||||
|
work: Work::LightClientBootstrapRequest {
|
||||||
|
peer_id,
|
||||||
|
request_id,
|
||||||
|
request,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a `str` representation of the type of work this `WorkEvent` contains.
|
/// Get a `str` representation of the type of work this `WorkEvent` contains.
|
||||||
pub fn work_type(&self) -> &'static str {
|
pub fn work_type(&self) -> &'static str {
|
||||||
self.work.str_id()
|
self.work.str_id()
|
||||||
@ -733,6 +755,11 @@ pub enum Work<T: BeaconChainTypes> {
|
|||||||
request_id: PeerRequestId,
|
request_id: PeerRequestId,
|
||||||
request: BlocksByRootRequest,
|
request: BlocksByRootRequest,
|
||||||
},
|
},
|
||||||
|
LightClientBootstrapRequest {
|
||||||
|
peer_id: PeerId,
|
||||||
|
request_id: PeerRequestId,
|
||||||
|
request: LightClientBootstrapRequest,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: BeaconChainTypes> Work<T> {
|
impl<T: BeaconChainTypes> Work<T> {
|
||||||
@ -755,6 +782,7 @@ impl<T: BeaconChainTypes> Work<T> {
|
|||||||
Work::Status { .. } => STATUS_PROCESSING,
|
Work::Status { .. } => STATUS_PROCESSING,
|
||||||
Work::BlocksByRangeRequest { .. } => BLOCKS_BY_RANGE_REQUEST,
|
Work::BlocksByRangeRequest { .. } => BLOCKS_BY_RANGE_REQUEST,
|
||||||
Work::BlocksByRootsRequest { .. } => BLOCKS_BY_ROOTS_REQUEST,
|
Work::BlocksByRootsRequest { .. } => BLOCKS_BY_ROOTS_REQUEST,
|
||||||
|
Work::LightClientBootstrapRequest { .. } => LIGHT_CLIENT_BOOTSTRAP_REQUEST,
|
||||||
Work::UnknownBlockAttestation { .. } => UNKNOWN_BLOCK_ATTESTATION,
|
Work::UnknownBlockAttestation { .. } => UNKNOWN_BLOCK_ATTESTATION,
|
||||||
Work::UnknownBlockAggregate { .. } => UNKNOWN_BLOCK_AGGREGATE,
|
Work::UnknownBlockAggregate { .. } => UNKNOWN_BLOCK_AGGREGATE,
|
||||||
}
|
}
|
||||||
@ -898,7 +926,7 @@ impl<T: BeaconChainTypes> BeaconProcessor<T> {
|
|||||||
let mut status_queue = FifoQueue::new(MAX_STATUS_QUEUE_LEN);
|
let mut status_queue = FifoQueue::new(MAX_STATUS_QUEUE_LEN);
|
||||||
let mut bbrange_queue = FifoQueue::new(MAX_BLOCKS_BY_RANGE_QUEUE_LEN);
|
let mut bbrange_queue = FifoQueue::new(MAX_BLOCKS_BY_RANGE_QUEUE_LEN);
|
||||||
let mut bbroots_queue = FifoQueue::new(MAX_BLOCKS_BY_ROOTS_QUEUE_LEN);
|
let mut bbroots_queue = FifoQueue::new(MAX_BLOCKS_BY_ROOTS_QUEUE_LEN);
|
||||||
|
let mut lcbootstrap_queue = FifoQueue::new(MAX_LIGHT_CLIENT_BOOTSTRAP_QUEUE_LEN);
|
||||||
// Channels for sending work to the re-process scheduler (`work_reprocessing_tx`) and to
|
// Channels for sending work to the re-process scheduler (`work_reprocessing_tx`) and to
|
||||||
// receive them back once they are ready (`ready_work_rx`).
|
// receive them back once they are ready (`ready_work_rx`).
|
||||||
let (ready_work_tx, ready_work_rx) = mpsc::channel(MAX_SCHEDULED_WORK_QUEUE_LEN);
|
let (ready_work_tx, ready_work_rx) = mpsc::channel(MAX_SCHEDULED_WORK_QUEUE_LEN);
|
||||||
@ -1137,6 +1165,8 @@ impl<T: BeaconChainTypes> BeaconProcessor<T> {
|
|||||||
} else if let Some(item) = backfill_chain_segment.pop() {
|
} else if let Some(item) = backfill_chain_segment.pop() {
|
||||||
self.spawn_worker(item, toolbox);
|
self.spawn_worker(item, toolbox);
|
||||||
// This statement should always be the final else statement.
|
// This statement should always be the final else statement.
|
||||||
|
} else if let Some(item) = lcbootstrap_queue.pop() {
|
||||||
|
self.spawn_worker(item, toolbox);
|
||||||
} else {
|
} else {
|
||||||
// Let the journal know that a worker is freed and there's nothing else
|
// Let the journal know that a worker is freed and there's nothing else
|
||||||
// for it to do.
|
// for it to do.
|
||||||
@ -1237,6 +1267,9 @@ impl<T: BeaconChainTypes> BeaconProcessor<T> {
|
|||||||
Work::BlocksByRootsRequest { .. } => {
|
Work::BlocksByRootsRequest { .. } => {
|
||||||
bbroots_queue.push(work, work_id, &self.log)
|
bbroots_queue.push(work, work_id, &self.log)
|
||||||
}
|
}
|
||||||
|
Work::LightClientBootstrapRequest { .. } => {
|
||||||
|
lcbootstrap_queue.push(work, work_id, &self.log)
|
||||||
|
}
|
||||||
Work::UnknownBlockAttestation { .. } => {
|
Work::UnknownBlockAttestation { .. } => {
|
||||||
unknown_block_attestation_queue.push(work)
|
unknown_block_attestation_queue.push(work)
|
||||||
}
|
}
|
||||||
@ -1594,6 +1627,16 @@ impl<T: BeaconChainTypes> BeaconProcessor<T> {
|
|||||||
request,
|
request,
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
/*
|
||||||
|
* Processing of lightclient bootstrap requests from other peers.
|
||||||
|
*/
|
||||||
|
Work::LightClientBootstrapRequest {
|
||||||
|
peer_id,
|
||||||
|
request_id,
|
||||||
|
request,
|
||||||
|
} => task_spawner.spawn_blocking(move || {
|
||||||
|
worker.handle_light_client_bootstrap(peer_id, request_id, request)
|
||||||
|
}),
|
||||||
Work::UnknownBlockAttestation {
|
Work::UnknownBlockAttestation {
|
||||||
message_id,
|
message_id,
|
||||||
peer_id,
|
peer_id,
|
||||||
|
@ -11,7 +11,7 @@ use slog::{debug, error};
|
|||||||
use slot_clock::SlotClock;
|
use slot_clock::SlotClock;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use task_executor::TaskExecutor;
|
use task_executor::TaskExecutor;
|
||||||
use types::{Epoch, EthSpec, Hash256, Slot};
|
use types::{light_client_bootstrap::LightClientBootstrap, Epoch, EthSpec, Hash256, Slot};
|
||||||
|
|
||||||
use super::Worker;
|
use super::Worker;
|
||||||
|
|
||||||
@ -204,6 +204,79 @@ impl<T: BeaconChainTypes> Worker<T> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handle a `BlocksByRoot` request from the peer.
|
||||||
|
pub fn handle_light_client_bootstrap(
|
||||||
|
self,
|
||||||
|
peer_id: PeerId,
|
||||||
|
request_id: PeerRequestId,
|
||||||
|
request: LightClientBootstrapRequest,
|
||||||
|
) {
|
||||||
|
let block_root = request.root;
|
||||||
|
let state_root = match self.chain.get_blinded_block(&block_root) {
|
||||||
|
Ok(signed_block) => match signed_block {
|
||||||
|
Some(signed_block) => signed_block.state_root(),
|
||||||
|
None => {
|
||||||
|
self.send_error_response(
|
||||||
|
peer_id,
|
||||||
|
RPCResponseErrorCode::ResourceUnavailable,
|
||||||
|
"Bootstrap not avaiable".into(),
|
||||||
|
request_id,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
self.send_error_response(
|
||||||
|
peer_id,
|
||||||
|
RPCResponseErrorCode::ResourceUnavailable,
|
||||||
|
"Bootstrap not avaiable".into(),
|
||||||
|
request_id,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut beacon_state = match self.chain.get_state(&state_root, None) {
|
||||||
|
Ok(beacon_state) => match beacon_state {
|
||||||
|
Some(state) => state,
|
||||||
|
None => {
|
||||||
|
self.send_error_response(
|
||||||
|
peer_id,
|
||||||
|
RPCResponseErrorCode::ResourceUnavailable,
|
||||||
|
"Bootstrap not avaiable".into(),
|
||||||
|
request_id,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
self.send_error_response(
|
||||||
|
peer_id,
|
||||||
|
RPCResponseErrorCode::ResourceUnavailable,
|
||||||
|
"Bootstrap not avaiable".into(),
|
||||||
|
request_id,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let bootstrap = match LightClientBootstrap::from_beacon_state(&mut beacon_state) {
|
||||||
|
Ok(bootstrap) => bootstrap,
|
||||||
|
Err(_) => {
|
||||||
|
self.send_error_response(
|
||||||
|
peer_id,
|
||||||
|
RPCResponseErrorCode::ResourceUnavailable,
|
||||||
|
"Bootstrap not avaiable".into(),
|
||||||
|
request_id,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.send_response(
|
||||||
|
peer_id,
|
||||||
|
Response::LightClientBootstrap(bootstrap),
|
||||||
|
request_id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle a `BlocksByRange` request from the peer.
|
/// Handle a `BlocksByRange` request from the peer.
|
||||||
pub fn handle_blocks_by_range_request(
|
pub fn handle_blocks_by_range_request(
|
||||||
self,
|
self,
|
||||||
|
@ -168,6 +168,9 @@ impl<T: BeaconChainTypes> Router<T> {
|
|||||||
Request::BlocksByRoot(request) => self
|
Request::BlocksByRoot(request) => self
|
||||||
.processor
|
.processor
|
||||||
.on_blocks_by_root_request(peer_id, id, request),
|
.on_blocks_by_root_request(peer_id, id, request),
|
||||||
|
Request::LightClientBootstrap(request) => self
|
||||||
|
.processor
|
||||||
|
.on_lightclient_bootstrap(peer_id, id, request),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,6 +195,7 @@ impl<T: BeaconChainTypes> Router<T> {
|
|||||||
self.processor
|
self.processor
|
||||||
.on_blocks_by_root_response(peer_id, request_id, beacon_block);
|
.on_blocks_by_root_response(peer_id, request_id, beacon_block);
|
||||||
}
|
}
|
||||||
|
Response::LightClientBootstrap(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,6 +160,18 @@ impl<T: BeaconChainTypes> Processor<T> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handle a `LightClientBootstrap` request from the peer.
|
||||||
|
pub fn on_lightclient_bootstrap(
|
||||||
|
&mut self,
|
||||||
|
peer_id: PeerId,
|
||||||
|
request_id: PeerRequestId,
|
||||||
|
request: LightClientBootstrapRequest,
|
||||||
|
) {
|
||||||
|
self.send_beacon_processor_work(BeaconWorkEvent::lightclient_bootstrap_request(
|
||||||
|
peer_id, request_id, request,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle a `BlocksByRange` request from the peer.
|
/// Handle a `BlocksByRange` request from the peer.
|
||||||
pub fn on_blocks_by_range_request(
|
pub fn on_blocks_by_range_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -708,9 +708,6 @@ pub fn get_config<E: EthSpec>(
|
|||||||
client_config.chain.builder_fallback_disable_checks =
|
client_config.chain.builder_fallback_disable_checks =
|
||||||
cli_args.is_present("builder-fallback-disable-checks");
|
cli_args.is_present("builder-fallback-disable-checks");
|
||||||
|
|
||||||
// Light client server config.
|
|
||||||
client_config.chain.enable_light_client_server = cli_args.is_present("light-client-server");
|
|
||||||
|
|
||||||
Ok(client_config)
|
Ok(client_config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -922,6 +919,9 @@ pub fn set_network_config(
|
|||||||
config.discv5_config.table_filter = |_| true;
|
config.discv5_config.table_filter = |_| true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Light client server config.
|
||||||
|
config.enable_light_client_server = cli_args.is_present("light-client-server");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1587,7 +1587,7 @@ fn sync_eth1_chain_disable_deposit_contract_sync_flag() {
|
|||||||
fn light_client_server_default() {
|
fn light_client_server_default() {
|
||||||
CommandLineTest::new()
|
CommandLineTest::new()
|
||||||
.run_with_zero_port()
|
.run_with_zero_port()
|
||||||
.with_config(|config| assert_eq!(config.chain.enable_light_client_server, false));
|
.with_config(|config| assert_eq!(config.network.enable_light_client_server, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1595,5 +1595,5 @@ fn light_client_server_enabled() {
|
|||||||
CommandLineTest::new()
|
CommandLineTest::new()
|
||||||
.flag("light-client-server", None)
|
.flag("light-client-server", None)
|
||||||
.run_with_zero_port()
|
.run_with_zero_port()
|
||||||
.with_config(|config| assert_eq!(config.chain.enable_light_client_server, true));
|
.with_config(|config| assert_eq!(config.network.enable_light_client_server, true));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user