Merge branch 'unstable' into max-blobs-preset

This commit is contained in:
Pawan Dhananjay
2024-10-21 14:46:00 -07:00
287 changed files with 10187 additions and 9415 deletions

View File

@@ -1,5 +1,5 @@
use super::methods::*;
use crate::rpc::codec::{base::BaseInboundCodec, ssz_snappy::SSZSnappyInboundCodec, InboundCodec};
use crate::rpc::codec::SSZSnappyInboundCodec;
use futures::future::BoxFuture;
use futures::prelude::{AsyncRead, AsyncWrite};
use futures::{FutureExt, StreamExt};
@@ -21,7 +21,8 @@ use types::{
BlobSidecar, ChainSpec, DataColumnSidecar, EmptyBlock, EthSpec, ForkContext, ForkName,
LightClientBootstrap, LightClientBootstrapAltair, LightClientFinalityUpdate,
LightClientFinalityUpdateAltair, LightClientOptimisticUpdate,
LightClientOptimisticUpdateAltair, MainnetEthSpec, Signature, SignedBeaconBlock,
LightClientOptimisticUpdateAltair, LightClientUpdate, MainnetEthSpec, Signature,
SignedBeaconBlock,
};
// Note: Hardcoding the `EthSpec` type for `SignedBeaconBlock` as min/max values is
@@ -143,6 +144,13 @@ pub static LIGHT_CLIENT_BOOTSTRAP_ELECTRA_MAX: LazyLock<usize> = LazyLock::new(|
LightClientBootstrap::<MainnetEthSpec>::ssz_max_len_for_fork(ForkName::Electra)
});
pub static LIGHT_CLIENT_UPDATES_BY_RANGE_CAPELLA_MAX: LazyLock<usize> =
LazyLock::new(|| LightClientUpdate::<MainnetEthSpec>::ssz_max_len_for_fork(ForkName::Capella));
pub static LIGHT_CLIENT_UPDATES_BY_RANGE_DENEB_MAX: LazyLock<usize> =
LazyLock::new(|| LightClientUpdate::<MainnetEthSpec>::ssz_max_len_for_fork(ForkName::Deneb));
pub static LIGHT_CLIENT_UPDATES_BY_RANGE_ELECTRA_MAX: LazyLock<usize> =
LazyLock::new(|| LightClientUpdate::<MainnetEthSpec>::ssz_max_len_for_fork(ForkName::Electra));
/// The protocol prefix the RPC protocol id.
const PROTOCOL_PREFIX: &str = "/eth2/beacon_chain/req";
/// The number of seconds to wait for the first bytes of a request once a protocol has been
@@ -151,12 +159,10 @@ const REQUEST_TIMEOUT: u64 = 15;
/// Returns the maximum bytes that can be sent across the RPC.
pub fn max_rpc_size(fork_context: &ForkContext, max_chunk_size: usize) -> usize {
match fork_context.current_fork() {
ForkName::Altair | ForkName::Base => max_chunk_size / 10,
ForkName::Bellatrix => max_chunk_size,
ForkName::Capella => max_chunk_size,
ForkName::Deneb => max_chunk_size,
ForkName::Electra => max_chunk_size,
if fork_context.current_fork().bellatrix_enabled() {
max_chunk_size
} else {
max_chunk_size / 10
}
}
@@ -192,6 +198,26 @@ pub fn rpc_block_limits_by_fork(current_fork: ForkName) -> RpcLimits {
}
}
fn rpc_light_client_updates_by_range_limits_by_fork(current_fork: ForkName) -> RpcLimits {
let altair_fixed_len = LightClientFinalityUpdateAltair::<MainnetEthSpec>::ssz_fixed_len();
match &current_fork {
ForkName::Base => RpcLimits::new(0, 0),
ForkName::Altair | ForkName::Bellatrix => {
RpcLimits::new(altair_fixed_len, altair_fixed_len)
}
ForkName::Capella => {
RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_UPDATES_BY_RANGE_CAPELLA_MAX)
}
ForkName::Deneb => {
RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_UPDATES_BY_RANGE_DENEB_MAX)
}
ForkName::Electra => {
RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_UPDATES_BY_RANGE_ELECTRA_MAX)
}
}
}
fn rpc_light_client_finality_update_limits_by_fork(current_fork: ForkName) -> RpcLimits {
let altair_fixed_len = LightClientFinalityUpdateAltair::<MainnetEthSpec>::ssz_fixed_len();
@@ -288,6 +314,9 @@ pub enum Protocol {
/// The `LightClientFinalityUpdate` protocol name.
#[strum(serialize = "light_client_finality_update")]
LightClientFinalityUpdate,
/// The `LightClientUpdatesByRange` protocol name
#[strum(serialize = "light_client_updates_by_range")]
LightClientUpdatesByRange,
}
impl Protocol {
@@ -306,6 +335,7 @@ impl Protocol {
Protocol::LightClientBootstrap => None,
Protocol::LightClientOptimisticUpdate => None,
Protocol::LightClientFinalityUpdate => None,
Protocol::LightClientUpdatesByRange => None,
}
}
}
@@ -336,6 +366,7 @@ pub enum SupportedProtocol {
LightClientBootstrapV1,
LightClientOptimisticUpdateV1,
LightClientFinalityUpdateV1,
LightClientUpdatesByRangeV1,
}
impl SupportedProtocol {
@@ -358,6 +389,7 @@ impl SupportedProtocol {
SupportedProtocol::LightClientBootstrapV1 => "1",
SupportedProtocol::LightClientOptimisticUpdateV1 => "1",
SupportedProtocol::LightClientFinalityUpdateV1 => "1",
SupportedProtocol::LightClientUpdatesByRangeV1 => "1",
}
}
@@ -382,6 +414,7 @@ impl SupportedProtocol {
Protocol::LightClientOptimisticUpdate
}
SupportedProtocol::LightClientFinalityUpdateV1 => Protocol::LightClientFinalityUpdate,
SupportedProtocol::LightClientUpdatesByRangeV1 => Protocol::LightClientUpdatesByRange,
}
}
@@ -544,6 +577,10 @@ impl ProtocolId {
),
Protocol::LightClientOptimisticUpdate => RpcLimits::new(0, 0),
Protocol::LightClientFinalityUpdate => RpcLimits::new(0, 0),
Protocol::LightClientUpdatesByRange => RpcLimits::new(
LightClientUpdatesByRangeRequest::ssz_min_len(),
LightClientUpdatesByRangeRequest::ssz_max_len(),
),
Protocol::MetaData => RpcLimits::new(0, 0), // Metadata requests are empty
}
}
@@ -579,6 +616,9 @@ impl ProtocolId {
Protocol::LightClientFinalityUpdate => {
rpc_light_client_finality_update_limits_by_fork(fork_context.current_fork())
}
Protocol::LightClientUpdatesByRange => {
rpc_light_client_updates_by_range_limits_by_fork(fork_context.current_fork())
}
}
}
@@ -594,7 +634,8 @@ impl ProtocolId {
| SupportedProtocol::DataColumnsByRangeV1
| SupportedProtocol::LightClientBootstrapV1
| SupportedProtocol::LightClientOptimisticUpdateV1
| SupportedProtocol::LightClientFinalityUpdateV1 => true,
| SupportedProtocol::LightClientFinalityUpdateV1
| SupportedProtocol::LightClientUpdatesByRangeV1 => true,
SupportedProtocol::StatusV1
| SupportedProtocol::BlocksByRootV1
| SupportedProtocol::BlocksByRangeV1
@@ -645,9 +686,9 @@ pub fn rpc_data_column_limits<E: EthSpec>() -> RpcLimits {
// The inbound protocol reads the request, decodes it and returns the stream to the protocol
// handler to respond to once ready.
pub type InboundOutput<TSocket, E> = (InboundRequest<E>, InboundFramed<TSocket, E>);
pub type InboundOutput<TSocket, E> = (RequestType<E>, InboundFramed<TSocket, E>);
pub type InboundFramed<TSocket, E> =
Framed<std::pin::Pin<Box<TimeoutStream<Compat<TSocket>>>>, InboundCodec<E>>;
Framed<std::pin::Pin<Box<TimeoutStream<Compat<TSocket>>>>, SSZSnappyInboundCodec<E>>;
impl<TSocket, E> InboundUpgrade<TSocket> for RPCProtocol<E>
where
@@ -664,15 +705,13 @@ where
// convert the socket to tokio compatible socket
let socket = socket.compat();
let codec = match protocol.encoding {
Encoding::SSZSnappy => {
let ssz_snappy_codec = BaseInboundCodec::new(SSZSnappyInboundCodec::new(
protocol,
self.max_rpc_size,
self.fork_context.clone(),
));
InboundCodec::SSZSnappy(ssz_snappy_codec)
}
Encoding::SSZSnappy => SSZSnappyInboundCodec::new(
protocol,
self.max_rpc_size,
self.fork_context.clone(),
),
};
let mut timed_socket = TimeoutStream::new(socket);
timed_socket.set_read_timeout(Some(self.ttfb_timeout));
@@ -681,19 +720,19 @@ where
// MetaData requests should be empty, return the stream
match versioned_protocol {
SupportedProtocol::MetaDataV1 => {
Ok((InboundRequest::MetaData(MetadataRequest::new_v1()), socket))
Ok((RequestType::MetaData(MetadataRequest::new_v1()), socket))
}
SupportedProtocol::MetaDataV2 => {
Ok((InboundRequest::MetaData(MetadataRequest::new_v2()), socket))
Ok((RequestType::MetaData(MetadataRequest::new_v2()), socket))
}
SupportedProtocol::MetaDataV3 => {
Ok((InboundRequest::MetaData(MetadataRequest::new_v3()), socket))
Ok((RequestType::MetaData(MetadataRequest::new_v3()), socket))
}
SupportedProtocol::LightClientOptimisticUpdateV1 => {
Ok((InboundRequest::LightClientOptimisticUpdate, socket))
Ok((RequestType::LightClientOptimisticUpdate, socket))
}
SupportedProtocol::LightClientFinalityUpdateV1 => {
Ok((InboundRequest::LightClientFinalityUpdate, socket))
Ok((RequestType::LightClientFinalityUpdate, socket))
}
_ => {
match tokio::time::timeout(
@@ -715,7 +754,7 @@ where
}
#[derive(Debug, Clone, PartialEq)]
pub enum InboundRequest<E: EthSpec> {
pub enum RequestType<E: EthSpec> {
Status(StatusMessage),
Goodbye(GoodbyeReason),
BlocksByRange(OldBlocksByRangeRequest),
@@ -727,63 +766,68 @@ pub enum InboundRequest<E: EthSpec> {
LightClientBootstrap(LightClientBootstrapRequest),
LightClientOptimisticUpdate,
LightClientFinalityUpdate,
LightClientUpdatesByRange(LightClientUpdatesByRangeRequest),
Ping(Ping),
MetaData(MetadataRequest<E>),
}
/// Implements the encoding per supported protocol for `RPCRequest`.
impl<E: EthSpec> InboundRequest<E> {
impl<E: EthSpec> RequestType<E> {
/* These functions are used in the handler for stream management */
/// Maximum number of responses expected for this request.
pub fn max_responses(&self) -> u64 {
match self {
InboundRequest::Status(_) => 1,
InboundRequest::Goodbye(_) => 0,
InboundRequest::BlocksByRange(req) => *req.count(),
InboundRequest::BlocksByRoot(req) => req.block_roots().len() as u64,
InboundRequest::BlobsByRange(req) => req.max_blobs_requested::<E>(),
InboundRequest::BlobsByRoot(req) => req.blob_ids.len() as u64,
InboundRequest::DataColumnsByRoot(req) => req.data_column_ids.len() as u64,
InboundRequest::DataColumnsByRange(req) => req.max_requested::<E>(),
InboundRequest::Ping(_) => 1,
InboundRequest::MetaData(_) => 1,
InboundRequest::LightClientBootstrap(_) => 1,
InboundRequest::LightClientOptimisticUpdate => 1,
InboundRequest::LightClientFinalityUpdate => 1,
RequestType::Status(_) => 1,
RequestType::Goodbye(_) => 0,
RequestType::BlocksByRange(req) => *req.count(),
RequestType::BlocksByRoot(req) => req.block_roots().len() as u64,
RequestType::BlobsByRange(req) => req.max_blobs_requested::<E>(),
RequestType::BlobsByRoot(req) => req.blob_ids.len() as u64,
RequestType::DataColumnsByRoot(req) => req.data_column_ids.len() as u64,
RequestType::DataColumnsByRange(req) => req.max_requested::<E>(),
RequestType::Ping(_) => 1,
RequestType::MetaData(_) => 1,
RequestType::LightClientBootstrap(_) => 1,
RequestType::LightClientOptimisticUpdate => 1,
RequestType::LightClientFinalityUpdate => 1,
RequestType::LightClientUpdatesByRange(req) => req.max_requested(),
}
}
/// Gives the corresponding `SupportedProtocol` to this request.
pub fn versioned_protocol(&self) -> SupportedProtocol {
match self {
InboundRequest::Status(_) => SupportedProtocol::StatusV1,
InboundRequest::Goodbye(_) => SupportedProtocol::GoodbyeV1,
InboundRequest::BlocksByRange(req) => match req {
RequestType::Status(_) => SupportedProtocol::StatusV1,
RequestType::Goodbye(_) => SupportedProtocol::GoodbyeV1,
RequestType::BlocksByRange(req) => match req {
OldBlocksByRangeRequest::V1(_) => SupportedProtocol::BlocksByRangeV1,
OldBlocksByRangeRequest::V2(_) => SupportedProtocol::BlocksByRangeV2,
},
InboundRequest::BlocksByRoot(req) => match req {
RequestType::BlocksByRoot(req) => match req {
BlocksByRootRequest::V1(_) => SupportedProtocol::BlocksByRootV1,
BlocksByRootRequest::V2(_) => SupportedProtocol::BlocksByRootV2,
},
InboundRequest::BlobsByRange(_) => SupportedProtocol::BlobsByRangeV1,
InboundRequest::BlobsByRoot(_) => SupportedProtocol::BlobsByRootV1,
InboundRequest::DataColumnsByRoot(_) => SupportedProtocol::DataColumnsByRootV1,
InboundRequest::DataColumnsByRange(_) => SupportedProtocol::DataColumnsByRangeV1,
InboundRequest::Ping(_) => SupportedProtocol::PingV1,
InboundRequest::MetaData(req) => match req {
RequestType::BlobsByRange(_) => SupportedProtocol::BlobsByRangeV1,
RequestType::BlobsByRoot(_) => SupportedProtocol::BlobsByRootV1,
RequestType::DataColumnsByRoot(_) => SupportedProtocol::DataColumnsByRootV1,
RequestType::DataColumnsByRange(_) => SupportedProtocol::DataColumnsByRangeV1,
RequestType::Ping(_) => SupportedProtocol::PingV1,
RequestType::MetaData(req) => match req {
MetadataRequest::V1(_) => SupportedProtocol::MetaDataV1,
MetadataRequest::V2(_) => SupportedProtocol::MetaDataV2,
MetadataRequest::V3(_) => SupportedProtocol::MetaDataV3,
},
InboundRequest::LightClientBootstrap(_) => SupportedProtocol::LightClientBootstrapV1,
InboundRequest::LightClientOptimisticUpdate => {
RequestType::LightClientBootstrap(_) => SupportedProtocol::LightClientBootstrapV1,
RequestType::LightClientOptimisticUpdate => {
SupportedProtocol::LightClientOptimisticUpdateV1
}
InboundRequest::LightClientFinalityUpdate => {
RequestType::LightClientFinalityUpdate => {
SupportedProtocol::LightClientFinalityUpdateV1
}
RequestType::LightClientUpdatesByRange(_) => {
SupportedProtocol::LightClientUpdatesByRangeV1
}
}
}
@@ -793,19 +837,102 @@ impl<E: EthSpec> InboundRequest<E> {
match self {
// this only gets called after `multiple_responses()` returns true. Therefore, only
// variants that have `multiple_responses()` can have values.
InboundRequest::BlocksByRange(_) => ResponseTermination::BlocksByRange,
InboundRequest::BlocksByRoot(_) => ResponseTermination::BlocksByRoot,
InboundRequest::BlobsByRange(_) => ResponseTermination::BlobsByRange,
InboundRequest::BlobsByRoot(_) => ResponseTermination::BlobsByRoot,
InboundRequest::DataColumnsByRoot(_) => ResponseTermination::DataColumnsByRoot,
InboundRequest::DataColumnsByRange(_) => ResponseTermination::DataColumnsByRange,
InboundRequest::Status(_) => unreachable!(),
InboundRequest::Goodbye(_) => unreachable!(),
InboundRequest::Ping(_) => unreachable!(),
InboundRequest::MetaData(_) => unreachable!(),
InboundRequest::LightClientBootstrap(_) => unreachable!(),
InboundRequest::LightClientFinalityUpdate => unreachable!(),
InboundRequest::LightClientOptimisticUpdate => unreachable!(),
RequestType::BlocksByRange(_) => ResponseTermination::BlocksByRange,
RequestType::BlocksByRoot(_) => ResponseTermination::BlocksByRoot,
RequestType::BlobsByRange(_) => ResponseTermination::BlobsByRange,
RequestType::BlobsByRoot(_) => ResponseTermination::BlobsByRoot,
RequestType::DataColumnsByRoot(_) => ResponseTermination::DataColumnsByRoot,
RequestType::DataColumnsByRange(_) => ResponseTermination::DataColumnsByRange,
RequestType::Status(_) => unreachable!(),
RequestType::Goodbye(_) => unreachable!(),
RequestType::Ping(_) => unreachable!(),
RequestType::MetaData(_) => unreachable!(),
RequestType::LightClientBootstrap(_) => unreachable!(),
RequestType::LightClientFinalityUpdate => unreachable!(),
RequestType::LightClientOptimisticUpdate => unreachable!(),
RequestType::LightClientUpdatesByRange(_) => unreachable!(),
}
}
pub fn supported_protocols(&self) -> Vec<ProtocolId> {
match self {
// add more protocols when versions/encodings are supported
RequestType::Status(_) => vec![ProtocolId::new(
SupportedProtocol::StatusV1,
Encoding::SSZSnappy,
)],
RequestType::Goodbye(_) => vec![ProtocolId::new(
SupportedProtocol::GoodbyeV1,
Encoding::SSZSnappy,
)],
RequestType::BlocksByRange(_) => vec![
ProtocolId::new(SupportedProtocol::BlocksByRangeV2, Encoding::SSZSnappy),
ProtocolId::new(SupportedProtocol::BlocksByRangeV1, Encoding::SSZSnappy),
],
RequestType::BlocksByRoot(_) => vec![
ProtocolId::new(SupportedProtocol::BlocksByRootV2, Encoding::SSZSnappy),
ProtocolId::new(SupportedProtocol::BlocksByRootV1, Encoding::SSZSnappy),
],
RequestType::BlobsByRange(_) => vec![ProtocolId::new(
SupportedProtocol::BlobsByRangeV1,
Encoding::SSZSnappy,
)],
RequestType::BlobsByRoot(_) => vec![ProtocolId::new(
SupportedProtocol::BlobsByRootV1,
Encoding::SSZSnappy,
)],
RequestType::DataColumnsByRoot(_) => vec![ProtocolId::new(
SupportedProtocol::DataColumnsByRootV1,
Encoding::SSZSnappy,
)],
RequestType::DataColumnsByRange(_) => vec![ProtocolId::new(
SupportedProtocol::DataColumnsByRangeV1,
Encoding::SSZSnappy,
)],
RequestType::Ping(_) => vec![ProtocolId::new(
SupportedProtocol::PingV1,
Encoding::SSZSnappy,
)],
RequestType::MetaData(_) => vec![
ProtocolId::new(SupportedProtocol::MetaDataV3, Encoding::SSZSnappy),
ProtocolId::new(SupportedProtocol::MetaDataV2, Encoding::SSZSnappy),
ProtocolId::new(SupportedProtocol::MetaDataV1, Encoding::SSZSnappy),
],
RequestType::LightClientBootstrap(_) => vec![ProtocolId::new(
SupportedProtocol::LightClientBootstrapV1,
Encoding::SSZSnappy,
)],
RequestType::LightClientOptimisticUpdate => vec![ProtocolId::new(
SupportedProtocol::LightClientOptimisticUpdateV1,
Encoding::SSZSnappy,
)],
RequestType::LightClientFinalityUpdate => vec![ProtocolId::new(
SupportedProtocol::LightClientFinalityUpdateV1,
Encoding::SSZSnappy,
)],
RequestType::LightClientUpdatesByRange(_) => vec![ProtocolId::new(
SupportedProtocol::LightClientUpdatesByRangeV1,
Encoding::SSZSnappy,
)],
}
}
pub fn expect_exactly_one_response(&self) -> bool {
match self {
RequestType::Status(_) => true,
RequestType::Goodbye(_) => false,
RequestType::BlocksByRange(_) => false,
RequestType::BlocksByRoot(_) => false,
RequestType::BlobsByRange(_) => false,
RequestType::BlobsByRoot(_) => false,
RequestType::DataColumnsByRoot(_) => false,
RequestType::DataColumnsByRange(_) => false,
RequestType::Ping(_) => true,
RequestType::MetaData(_) => true,
RequestType::LightClientBootstrap(_) => true,
RequestType::LightClientOptimisticUpdate => true,
RequestType::LightClientFinalityUpdate => true,
RequestType::LightClientUpdatesByRange(_) => true,
}
}
}
@@ -821,7 +948,7 @@ pub enum RPCError {
/// IO Error.
IoError(String),
/// The peer returned a valid response but the response indicated an error.
ErrorResponse(RPCResponseErrorCode, String),
ErrorResponse(RpcErrorResponse, String),
/// Timed out waiting for a response.
StreamTimeout,
/// Peer does not support the protocol.
@@ -900,30 +1027,33 @@ impl std::error::Error for RPCError {
}
}
impl<E: EthSpec> std::fmt::Display for InboundRequest<E> {
impl<E: EthSpec> std::fmt::Display for RequestType<E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
InboundRequest::Status(status) => write!(f, "Status Message: {}", status),
InboundRequest::Goodbye(reason) => write!(f, "Goodbye: {}", reason),
InboundRequest::BlocksByRange(req) => write!(f, "Blocks by range: {}", req),
InboundRequest::BlocksByRoot(req) => write!(f, "Blocks by root: {:?}", req),
InboundRequest::BlobsByRange(req) => write!(f, "Blobs by range: {:?}", req),
InboundRequest::BlobsByRoot(req) => write!(f, "Blobs by root: {:?}", req),
InboundRequest::DataColumnsByRoot(req) => write!(f, "Data columns by root: {:?}", req),
InboundRequest::DataColumnsByRange(req) => {
RequestType::Status(status) => write!(f, "Status Message: {}", status),
RequestType::Goodbye(reason) => write!(f, "Goodbye: {}", reason),
RequestType::BlocksByRange(req) => write!(f, "Blocks by range: {}", req),
RequestType::BlocksByRoot(req) => write!(f, "Blocks by root: {:?}", req),
RequestType::BlobsByRange(req) => write!(f, "Blobs by range: {:?}", req),
RequestType::BlobsByRoot(req) => write!(f, "Blobs by root: {:?}", req),
RequestType::DataColumnsByRoot(req) => write!(f, "Data columns by root: {:?}", req),
RequestType::DataColumnsByRange(req) => {
write!(f, "Data columns by range: {:?}", req)
}
InboundRequest::Ping(ping) => write!(f, "Ping: {}", ping.data),
InboundRequest::MetaData(_) => write!(f, "MetaData request"),
InboundRequest::LightClientBootstrap(bootstrap) => {
RequestType::Ping(ping) => write!(f, "Ping: {}", ping.data),
RequestType::MetaData(_) => write!(f, "MetaData request"),
RequestType::LightClientBootstrap(bootstrap) => {
write!(f, "Light client boostrap: {}", bootstrap.root)
}
InboundRequest::LightClientOptimisticUpdate => {
RequestType::LightClientOptimisticUpdate => {
write!(f, "Light client optimistic update request")
}
InboundRequest::LightClientFinalityUpdate => {
RequestType::LightClientFinalityUpdate => {
write!(f, "Light client finality update request")
}
RequestType::LightClientUpdatesByRange(_) => {
write!(f, "Light client updates by range request")
}
}
}
}