Implement data columns by network boilerplate (#6224)

* Implement data columns by network boilerplate

* Use correct quota values

* Address PR review

* Update currently_supported

* Merge remote-tracking branch 'sigp/unstable' into peerdas-network-boilerplate

* PR reviews

* Fix data column rpc request not being sent due to incorrect limits set. (#6000)
This commit is contained in:
Lion - dapplion
2024-08-13 08:16:14 +08:00
committed by GitHub
parent f2fdbe7fbe
commit ff15c78ced
15 changed files with 624 additions and 34 deletions

View File

@@ -16,10 +16,11 @@ use std::marker::PhantomData;
use std::sync::Arc;
use tokio_util::codec::{Decoder, Encoder};
use types::{
BlobSidecar, ChainSpec, EthSpec, ForkContext, ForkName, Hash256, LightClientBootstrap,
LightClientFinalityUpdate, LightClientOptimisticUpdate, RuntimeVariableList, SignedBeaconBlock,
SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix,
SignedBeaconBlockCapella, SignedBeaconBlockDeneb, SignedBeaconBlockElectra,
BlobSidecar, ChainSpec, DataColumnSidecar, EthSpec, ForkContext, ForkName, Hash256,
LightClientBootstrap, LightClientFinalityUpdate, LightClientOptimisticUpdate,
RuntimeVariableList, SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase,
SignedBeaconBlockBellatrix, SignedBeaconBlockCapella, SignedBeaconBlockDeneb,
SignedBeaconBlockElectra,
};
use unsigned_varint::codec::Uvi;
@@ -70,6 +71,8 @@ impl<E: EthSpec> Encoder<RPCCodedResponse<E>> for SSZSnappyInboundCodec<E> {
RPCResponse::BlocksByRoot(res) => res.as_ssz_bytes(),
RPCResponse::BlobsByRange(res) => res.as_ssz_bytes(),
RPCResponse::BlobsByRoot(res) => res.as_ssz_bytes(),
RPCResponse::DataColumnsByRoot(res) => res.as_ssz_bytes(),
RPCResponse::DataColumnsByRange(res) => res.as_ssz_bytes(),
RPCResponse::LightClientBootstrap(res) => res.as_ssz_bytes(),
RPCResponse::LightClientOptimisticUpdate(res) => res.as_ssz_bytes(),
RPCResponse::LightClientFinalityUpdate(res) => res.as_ssz_bytes(),
@@ -224,6 +227,8 @@ impl<E: EthSpec> Encoder<OutboundRequest<E>> for SSZSnappyOutboundCodec<E> {
},
OutboundRequest::BlobsByRange(req) => req.as_ssz_bytes(),
OutboundRequest::BlobsByRoot(req) => req.blob_ids.as_ssz_bytes(),
OutboundRequest::DataColumnsByRange(req) => req.as_ssz_bytes(),
OutboundRequest::DataColumnsByRoot(req) => req.data_column_ids.as_ssz_bytes(),
OutboundRequest::Ping(req) => req.as_ssz_bytes(),
OutboundRequest::MetaData(_) => return Ok(()), // no metadata to encode
};
@@ -414,7 +419,12 @@ fn context_bytes<E: EthSpec>(
}
};
}
RPCResponse::BlobsByRange(_) | RPCResponse::BlobsByRoot(_) => {
RPCResponse::BlobsByRange(_)
| RPCResponse::BlobsByRoot(_)
| RPCResponse::DataColumnsByRoot(_)
| RPCResponse::DataColumnsByRange(_) => {
// TODO(das): If DataColumnSidecar is defined as an Electra type, update the
// context bytes to point to ForkName::Electra
return fork_context.to_context_bytes(ForkName::Deneb);
}
RPCResponse::LightClientBootstrap(lc_bootstrap) => {
@@ -512,6 +522,17 @@ fn handle_rpc_request<E: EthSpec>(
)?,
})))
}
SupportedProtocol::DataColumnsByRootV1 => Ok(Some(InboundRequest::DataColumnsByRoot(
DataColumnsByRootRequest {
data_column_ids: RuntimeVariableList::from_ssz_bytes(
decoded_buffer,
spec.max_request_data_column_sidecars as usize,
)?,
},
))),
SupportedProtocol::DataColumnsByRangeV1 => Ok(Some(InboundRequest::DataColumnsByRange(
DataColumnsByRangeRequest::from_ssz_bytes(decoded_buffer)?,
))),
SupportedProtocol::PingV1 => Ok(Some(InboundRequest::Ping(Ping {
data: u64::from_ssz_bytes(decoded_buffer)?,
}))),
@@ -604,6 +625,51 @@ fn handle_rpc_response<E: EthSpec>(
),
)),
},
SupportedProtocol::DataColumnsByRootV1 => match fork_name {
Some(fork_name) => {
// TODO(das): PeerDAS is currently supported for both deneb and electra. This check
// does not advertise the topic on deneb, simply allows it to decode it. Advertise
// logic is in `SupportedTopic::currently_supported`.
if fork_name.deneb_enabled() {
Ok(Some(RPCResponse::DataColumnsByRoot(Arc::new(
DataColumnSidecar::from_ssz_bytes(decoded_buffer)?,
))))
} else {
Err(RPCError::ErrorResponse(
RPCResponseErrorCode::InvalidRequest,
"Invalid fork name for data columns by root".to_string(),
))
}
}
None => Err(RPCError::ErrorResponse(
RPCResponseErrorCode::InvalidRequest,
format!(
"No context bytes provided for {:?} response",
versioned_protocol
),
)),
},
SupportedProtocol::DataColumnsByRangeV1 => match fork_name {
Some(fork_name) => {
if fork_name.deneb_enabled() {
Ok(Some(RPCResponse::DataColumnsByRange(Arc::new(
DataColumnSidecar::from_ssz_bytes(decoded_buffer)?,
))))
} else {
Err(RPCError::ErrorResponse(
RPCResponseErrorCode::InvalidRequest,
"Invalid fork name for data columns by range".to_string(),
))
}
}
None => Err(RPCError::ErrorResponse(
RPCResponseErrorCode::InvalidRequest,
format!(
"No context bytes provided for {:?} response",
versioned_protocol
),
)),
},
SupportedProtocol::PingV1 => Ok(Some(RPCResponse::Pong(Ping {
data: u64::from_ssz_bytes(decoded_buffer)?,
}))),
@@ -747,7 +813,8 @@ mod tests {
use crate::types::{EnrAttestationBitfield, EnrSyncCommitteeBitfield};
use types::{
blob_sidecar::BlobIdentifier, BeaconBlock, BeaconBlockAltair, BeaconBlockBase,
BeaconBlockBellatrix, EmptyBlock, Epoch, FullPayload, Signature, Slot,
BeaconBlockBellatrix, DataColumnIdentifier, EmptyBlock, Epoch, FullPayload, Signature,
Slot,
};
type Spec = types::MainnetEthSpec;
@@ -794,6 +861,10 @@ mod tests {
Arc::new(BlobSidecar::empty())
}
fn empty_data_column_sidecar() -> Arc<DataColumnSidecar<Spec>> {
Arc::new(DataColumnSidecar::empty())
}
/// Bellatrix block with length < max_rpc_size.
fn bellatrix_block_small(
fork_context: &ForkContext,
@@ -855,6 +926,27 @@ mod tests {
}
}
fn dcbrange_request() -> DataColumnsByRangeRequest {
DataColumnsByRangeRequest {
start_slot: 0,
count: 10,
columns: vec![1, 2, 3],
}
}
fn dcbroot_request(spec: &ChainSpec) -> DataColumnsByRootRequest {
DataColumnsByRootRequest {
data_column_ids: RuntimeVariableList::new(
vec![DataColumnIdentifier {
block_root: Hash256::zero(),
index: 0,
}],
spec.max_request_data_column_sidecars as usize,
)
.unwrap(),
}
}
fn bbroot_request_v1(spec: &ChainSpec) -> BlocksByRootRequest {
BlocksByRootRequest::new_v1(vec![Hash256::zero()], spec)
}
@@ -1012,6 +1104,12 @@ mod tests {
OutboundRequest::BlobsByRoot(bbroot) => {
assert_eq!(decoded, InboundRequest::BlobsByRoot(bbroot))
}
OutboundRequest::DataColumnsByRoot(dcbroot) => {
assert_eq!(decoded, InboundRequest::DataColumnsByRoot(dcbroot))
}
OutboundRequest::DataColumnsByRange(dcbrange) => {
assert_eq!(decoded, InboundRequest::DataColumnsByRange(dcbrange))
}
OutboundRequest::Ping(ping) => {
assert_eq!(decoded, InboundRequest::Ping(ping))
}
@@ -1138,6 +1236,34 @@ mod tests {
),
Ok(Some(RPCResponse::BlobsByRoot(empty_blob_sidecar()))),
);
assert_eq!(
encode_then_decode_response(
SupportedProtocol::DataColumnsByRangeV1,
RPCCodedResponse::Success(RPCResponse::DataColumnsByRange(
empty_data_column_sidecar()
)),
ForkName::Deneb,
&chain_spec
),
Ok(Some(RPCResponse::DataColumnsByRange(
empty_data_column_sidecar()
))),
);
assert_eq!(
encode_then_decode_response(
SupportedProtocol::DataColumnsByRootV1,
RPCCodedResponse::Success(RPCResponse::DataColumnsByRoot(
empty_data_column_sidecar()
)),
ForkName::Deneb,
&chain_spec
),
Ok(Some(RPCResponse::DataColumnsByRoot(
empty_data_column_sidecar()
))),
);
}
// Test RPCResponse encoding/decoding for V1 messages
@@ -1491,6 +1617,8 @@ mod tests {
OutboundRequest::MetaData(MetadataRequest::new_v1()),
OutboundRequest::BlobsByRange(blbrange_request()),
OutboundRequest::BlobsByRoot(blbroot_request(&chain_spec)),
OutboundRequest::DataColumnsByRange(dcbrange_request()),
OutboundRequest::DataColumnsByRoot(dcbroot_request(&chain_spec)),
OutboundRequest::MetaData(MetadataRequest::new_v2()),
];

View File

@@ -91,6 +91,8 @@ pub struct RateLimiterConfig {
pub(super) blocks_by_root_quota: Quota,
pub(super) blobs_by_range_quota: Quota,
pub(super) blobs_by_root_quota: Quota,
pub(super) data_columns_by_root_quota: Quota,
pub(super) data_columns_by_range_quota: Quota,
pub(super) light_client_bootstrap_quota: Quota,
pub(super) light_client_optimistic_update_quota: Quota,
pub(super) light_client_finality_update_quota: Quota,
@@ -110,6 +112,12 @@ impl RateLimiterConfig {
// measured against the maximum request size.
pub const DEFAULT_BLOBS_BY_RANGE_QUOTA: Quota = Quota::n_every(6144, 10);
pub const DEFAULT_BLOBS_BY_ROOT_QUOTA: Quota = Quota::n_every(768, 10);
// 320 blocks worth of columns for regular node, or 40 blocks for supernode.
// Range sync load balances when requesting blocks, and each batch is 32 blocks.
pub const DEFAULT_DATA_COLUMNS_BY_RANGE_QUOTA: Quota = Quota::n_every(5120, 10);
// 512 columns per request from spec. This should be plenty as peers are unlikely to send all
// sampling requests to a single peer.
pub const DEFAULT_DATA_COLUMNS_BY_ROOT_QUOTA: Quota = Quota::n_every(512, 10);
pub const DEFAULT_LIGHT_CLIENT_BOOTSTRAP_QUOTA: Quota = Quota::one_every(10);
pub const DEFAULT_LIGHT_CLIENT_OPTIMISTIC_UPDATE_QUOTA: Quota = Quota::one_every(10);
pub const DEFAULT_LIGHT_CLIENT_FINALITY_UPDATE_QUOTA: Quota = Quota::one_every(10);
@@ -126,6 +134,8 @@ impl Default for RateLimiterConfig {
blocks_by_root_quota: Self::DEFAULT_BLOCKS_BY_ROOT_QUOTA,
blobs_by_range_quota: Self::DEFAULT_BLOBS_BY_RANGE_QUOTA,
blobs_by_root_quota: Self::DEFAULT_BLOBS_BY_ROOT_QUOTA,
data_columns_by_root_quota: Self::DEFAULT_DATA_COLUMNS_BY_ROOT_QUOTA,
data_columns_by_range_quota: Self::DEFAULT_DATA_COLUMNS_BY_RANGE_QUOTA,
light_client_bootstrap_quota: Self::DEFAULT_LIGHT_CLIENT_BOOTSTRAP_QUOTA,
light_client_optimistic_update_quota:
Self::DEFAULT_LIGHT_CLIENT_OPTIMISTIC_UPDATE_QUOTA,
@@ -175,6 +185,8 @@ impl FromStr for RateLimiterConfig {
let mut blocks_by_root_quota = None;
let mut blobs_by_range_quota = None;
let mut blobs_by_root_quota = None;
let mut data_columns_by_root_quota = None;
let mut data_columns_by_range_quota = None;
let mut light_client_bootstrap_quota = None;
let mut light_client_optimistic_update_quota = None;
let mut light_client_finality_update_quota = None;
@@ -189,6 +201,12 @@ impl FromStr for RateLimiterConfig {
Protocol::BlocksByRoot => blocks_by_root_quota = blocks_by_root_quota.or(quota),
Protocol::BlobsByRange => blobs_by_range_quota = blobs_by_range_quota.or(quota),
Protocol::BlobsByRoot => blobs_by_root_quota = blobs_by_root_quota.or(quota),
Protocol::DataColumnsByRoot => {
data_columns_by_root_quota = data_columns_by_root_quota.or(quota)
}
Protocol::DataColumnsByRange => {
data_columns_by_range_quota = data_columns_by_range_quota.or(quota)
}
Protocol::Ping => ping_quota = ping_quota.or(quota),
Protocol::MetaData => meta_data_quota = meta_data_quota.or(quota),
Protocol::LightClientBootstrap => {
@@ -216,6 +234,10 @@ impl FromStr for RateLimiterConfig {
blobs_by_range_quota: blobs_by_range_quota
.unwrap_or(Self::DEFAULT_BLOBS_BY_RANGE_QUOTA),
blobs_by_root_quota: blobs_by_root_quota.unwrap_or(Self::DEFAULT_BLOBS_BY_ROOT_QUOTA),
data_columns_by_root_quota: data_columns_by_root_quota
.unwrap_or(Self::DEFAULT_DATA_COLUMNS_BY_ROOT_QUOTA),
data_columns_by_range_quota: data_columns_by_range_quota
.unwrap_or(Self::DEFAULT_DATA_COLUMNS_BY_RANGE_QUOTA),
light_client_bootstrap_quota: light_client_bootstrap_quota
.unwrap_or(Self::DEFAULT_LIGHT_CLIENT_BOOTSTRAP_QUOTA),
light_client_optimistic_update_quota: light_client_optimistic_update_quota

View File

@@ -14,9 +14,9 @@ use strum::IntoStaticStr;
use superstruct::superstruct;
use types::blob_sidecar::BlobIdentifier;
use types::{
blob_sidecar::BlobSidecar, ChainSpec, Epoch, EthSpec, Hash256, LightClientBootstrap,
LightClientFinalityUpdate, LightClientOptimisticUpdate, RuntimeVariableList, SignedBeaconBlock,
Slot,
blob_sidecar::BlobSidecar, ChainSpec, ColumnIndex, DataColumnIdentifier, DataColumnSidecar,
Epoch, EthSpec, Hash256, LightClientBootstrap, LightClientFinalityUpdate,
LightClientOptimisticUpdate, RuntimeVariableList, SignedBeaconBlock, Slot,
};
/// Maximum length of error message.
@@ -293,6 +293,43 @@ impl BlobsByRangeRequest {
}
}
/// Request a number of beacon data columns from a peer.
#[derive(Encode, Decode, Clone, Debug, PartialEq)]
pub struct DataColumnsByRangeRequest {
/// The starting slot to request data columns.
pub start_slot: u64,
/// The number of slots from the start slot.
pub count: u64,
/// The list column indices being requested.
pub columns: Vec<ColumnIndex>,
}
impl DataColumnsByRangeRequest {
pub fn max_requested<E: EthSpec>(&self) -> u64 {
self.count.saturating_mul(self.columns.len() as u64)
}
pub fn ssz_min_len() -> usize {
DataColumnsByRangeRequest {
start_slot: 0,
count: 0,
columns: vec![0],
}
.as_ssz_bytes()
.len()
}
pub fn ssz_max_len(spec: &ChainSpec) -> usize {
DataColumnsByRangeRequest {
start_slot: 0,
count: 0,
columns: vec![0; spec.number_of_columns],
}
.as_ssz_bytes()
.len()
}
}
/// Request a number of beacon block roots from a peer.
#[superstruct(
variants(V1, V2),
@@ -370,6 +407,27 @@ impl BlobsByRootRequest {
}
}
/// Request a number of data columns from a peer.
#[derive(Clone, Debug, PartialEq)]
pub struct DataColumnsByRootRequest {
/// The list of beacon block roots and column indices being requested.
pub data_column_ids: RuntimeVariableList<DataColumnIdentifier>,
}
impl DataColumnsByRootRequest {
pub fn new(data_column_ids: Vec<DataColumnIdentifier>, spec: &ChainSpec) -> Self {
let data_column_ids = RuntimeVariableList::from_vec(
data_column_ids,
spec.max_request_data_column_sidecars as usize,
);
Self { data_column_ids }
}
pub fn new_single(block_root: Hash256, index: ColumnIndex, spec: &ChainSpec) -> Self {
Self::new(vec![DataColumnIdentifier { block_root, index }], spec)
}
}
/* RPC Handling and Grouping */
// Collection of enums and structs used by the Codecs to encode/decode RPC messages
@@ -400,6 +458,12 @@ pub enum RPCResponse<E: EthSpec> {
/// A response to a get BLOBS_BY_ROOT request.
BlobsByRoot(Arc<BlobSidecar<E>>),
/// A response to a get DATA_COLUMN_SIDECARS_BY_ROOT request.
DataColumnsByRoot(Arc<DataColumnSidecar<E>>),
/// A response to a get DATA_COLUMN_SIDECARS_BY_RANGE request.
DataColumnsByRange(Arc<DataColumnSidecar<E>>),
/// A PONG response to a PING request.
Pong(Ping),
@@ -421,6 +485,12 @@ pub enum ResponseTermination {
/// Blobs by root stream termination.
BlobsByRoot,
/// Data column sidecars by root stream termination.
DataColumnsByRoot,
/// Data column sidecars by range stream termination.
DataColumnsByRange,
}
/// The structured response containing a result/code indicating success or failure
@@ -511,6 +581,8 @@ impl<E: EthSpec> RPCResponse<E> {
RPCResponse::BlocksByRoot(_) => Protocol::BlocksByRoot,
RPCResponse::BlobsByRange(_) => Protocol::BlobsByRange,
RPCResponse::BlobsByRoot(_) => Protocol::BlobsByRoot,
RPCResponse::DataColumnsByRoot(_) => Protocol::DataColumnsByRoot,
RPCResponse::DataColumnsByRange(_) => Protocol::DataColumnsByRange,
RPCResponse::Pong(_) => Protocol::Ping,
RPCResponse::MetaData(_) => Protocol::MetaData,
RPCResponse::LightClientBootstrap(_) => Protocol::LightClientBootstrap,
@@ -556,6 +628,16 @@ impl<E: EthSpec> std::fmt::Display for RPCResponse<E> {
RPCResponse::BlobsByRoot(sidecar) => {
write!(f, "BlobsByRoot: Blob slot: {}", sidecar.slot())
}
RPCResponse::DataColumnsByRoot(sidecar) => {
write!(f, "DataColumnsByRoot: Data column slot: {}", sidecar.slot())
}
RPCResponse::DataColumnsByRange(sidecar) => {
write!(
f,
"DataColumnsByRange: Data column slot: {}",
sidecar.slot()
)
}
RPCResponse::Pong(ping) => write!(f, "Pong: {}", ping.data),
RPCResponse::MetaData(metadata) => write!(f, "Metadata: {}", metadata.seq_number()),
RPCResponse::LightClientBootstrap(bootstrap) => {

View File

@@ -471,6 +471,8 @@ where
ResponseTermination::BlocksByRoot => Protocol::BlocksByRoot,
ResponseTermination::BlobsByRange => Protocol::BlobsByRange,
ResponseTermination::BlobsByRoot => Protocol::BlobsByRoot,
ResponseTermination::DataColumnsByRoot => Protocol::DataColumnsByRoot,
ResponseTermination::DataColumnsByRange => Protocol::DataColumnsByRange,
},
),
};

View File

@@ -36,6 +36,8 @@ pub enum OutboundRequest<E: EthSpec> {
BlocksByRoot(BlocksByRootRequest),
BlobsByRange(BlobsByRangeRequest),
BlobsByRoot(BlobsByRootRequest),
DataColumnsByRoot(DataColumnsByRootRequest),
DataColumnsByRange(DataColumnsByRangeRequest),
Ping(Ping),
MetaData(MetadataRequest<E>),
}
@@ -79,6 +81,14 @@ impl<E: EthSpec> OutboundRequest<E> {
SupportedProtocol::BlobsByRootV1,
Encoding::SSZSnappy,
)],
OutboundRequest::DataColumnsByRoot(_) => vec![ProtocolId::new(
SupportedProtocol::DataColumnsByRootV1,
Encoding::SSZSnappy,
)],
OutboundRequest::DataColumnsByRange(_) => vec![ProtocolId::new(
SupportedProtocol::DataColumnsByRangeV1,
Encoding::SSZSnappy,
)],
OutboundRequest::Ping(_) => vec![ProtocolId::new(
SupportedProtocol::PingV1,
Encoding::SSZSnappy,
@@ -100,6 +110,8 @@ impl<E: EthSpec> OutboundRequest<E> {
OutboundRequest::BlocksByRoot(req) => req.block_roots().len() as u64,
OutboundRequest::BlobsByRange(req) => req.max_blobs_requested::<E>(),
OutboundRequest::BlobsByRoot(req) => req.blob_ids.len() as u64,
OutboundRequest::DataColumnsByRoot(req) => req.data_column_ids.len() as u64,
OutboundRequest::DataColumnsByRange(req) => req.max_requested::<E>(),
OutboundRequest::Ping(_) => 1,
OutboundRequest::MetaData(_) => 1,
}
@@ -113,6 +125,8 @@ impl<E: EthSpec> OutboundRequest<E> {
OutboundRequest::BlocksByRoot(_) => false,
OutboundRequest::BlobsByRange(_) => false,
OutboundRequest::BlobsByRoot(_) => false,
OutboundRequest::DataColumnsByRoot(_) => false,
OutboundRequest::DataColumnsByRange(_) => false,
OutboundRequest::Ping(_) => true,
OutboundRequest::MetaData(_) => true,
}
@@ -133,6 +147,8 @@ impl<E: EthSpec> OutboundRequest<E> {
},
OutboundRequest::BlobsByRange(_) => SupportedProtocol::BlobsByRangeV1,
OutboundRequest::BlobsByRoot(_) => SupportedProtocol::BlobsByRootV1,
OutboundRequest::DataColumnsByRoot(_) => SupportedProtocol::DataColumnsByRootV1,
OutboundRequest::DataColumnsByRange(_) => SupportedProtocol::DataColumnsByRangeV1,
OutboundRequest::Ping(_) => SupportedProtocol::PingV1,
OutboundRequest::MetaData(req) => match req {
MetadataRequest::V1(_) => SupportedProtocol::MetaDataV1,
@@ -151,6 +167,8 @@ impl<E: EthSpec> OutboundRequest<E> {
OutboundRequest::BlocksByRoot(_) => ResponseTermination::BlocksByRoot,
OutboundRequest::BlobsByRange(_) => ResponseTermination::BlobsByRange,
OutboundRequest::BlobsByRoot(_) => ResponseTermination::BlobsByRoot,
OutboundRequest::DataColumnsByRoot(_) => ResponseTermination::DataColumnsByRoot,
OutboundRequest::DataColumnsByRange(_) => ResponseTermination::DataColumnsByRange,
OutboundRequest::Status(_) => unreachable!(),
OutboundRequest::Goodbye(_) => unreachable!(),
OutboundRequest::Ping(_) => unreachable!(),
@@ -208,6 +226,10 @@ impl<E: EthSpec> std::fmt::Display for OutboundRequest<E> {
OutboundRequest::BlocksByRoot(req) => write!(f, "Blocks by root: {:?}", req),
OutboundRequest::BlobsByRange(req) => write!(f, "Blobs by range: {:?}", req),
OutboundRequest::BlobsByRoot(req) => write!(f, "Blobs by root: {:?}", req),
OutboundRequest::DataColumnsByRoot(req) => write!(f, "Data columns by root: {:?}", req),
OutboundRequest::DataColumnsByRange(req) => {
write!(f, "Data columns by range: {:?}", req)
}
OutboundRequest::Ping(ping) => write!(f, "Ping: {}", ping.data),
OutboundRequest::MetaData(_) => write!(f, "MetaData request"),
}

View File

@@ -18,10 +18,10 @@ use tokio_util::{
};
use types::{
BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockCapella, BeaconBlockElectra,
BlobSidecar, ChainSpec, EmptyBlock, EthSpec, ForkContext, ForkName, LightClientBootstrap,
LightClientBootstrapAltair, LightClientFinalityUpdate, LightClientFinalityUpdateAltair,
LightClientOptimisticUpdate, LightClientOptimisticUpdateAltair, MainnetEthSpec, Signature,
SignedBeaconBlock,
BlobSidecar, ChainSpec, DataColumnSidecar, EmptyBlock, EthSpec, ForkContext, ForkName,
LightClientBootstrap, LightClientBootstrapAltair, LightClientFinalityUpdate,
LightClientFinalityUpdateAltair, LightClientOptimisticUpdate,
LightClientOptimisticUpdateAltair, MainnetEthSpec, Signature, SignedBeaconBlock,
};
// Note: Hardcoding the `EthSpec` type for `SignedBeaconBlock` as min/max values is
@@ -268,6 +268,12 @@ pub enum Protocol {
/// The `BlobsByRoot` protocol name.
#[strum(serialize = "blob_sidecars_by_root")]
BlobsByRoot,
/// The `DataColumnSidecarsByRoot` protocol name.
#[strum(serialize = "data_column_sidecars_by_root")]
DataColumnsByRoot,
/// The `DataColumnSidecarsByRange` protocol name.
#[strum(serialize = "data_column_sidecars_by_range")]
DataColumnsByRange,
/// The `Ping` protocol name.
Ping,
/// The `MetaData` protocol name.
@@ -293,6 +299,8 @@ impl Protocol {
Protocol::BlocksByRoot => Some(ResponseTermination::BlocksByRoot),
Protocol::BlobsByRange => Some(ResponseTermination::BlobsByRange),
Protocol::BlobsByRoot => Some(ResponseTermination::BlobsByRoot),
Protocol::DataColumnsByRoot => Some(ResponseTermination::DataColumnsByRoot),
Protocol::DataColumnsByRange => Some(ResponseTermination::DataColumnsByRange),
Protocol::Ping => None,
Protocol::MetaData => None,
Protocol::LightClientBootstrap => None,
@@ -319,6 +327,8 @@ pub enum SupportedProtocol {
BlocksByRootV2,
BlobsByRangeV1,
BlobsByRootV1,
DataColumnsByRootV1,
DataColumnsByRangeV1,
PingV1,
MetaDataV1,
MetaDataV2,
@@ -338,6 +348,8 @@ impl SupportedProtocol {
SupportedProtocol::BlocksByRootV2 => "2",
SupportedProtocol::BlobsByRangeV1 => "1",
SupportedProtocol::BlobsByRootV1 => "1",
SupportedProtocol::DataColumnsByRootV1 => "1",
SupportedProtocol::DataColumnsByRangeV1 => "1",
SupportedProtocol::PingV1 => "1",
SupportedProtocol::MetaDataV1 => "1",
SupportedProtocol::MetaDataV2 => "2",
@@ -357,6 +369,8 @@ impl SupportedProtocol {
SupportedProtocol::BlocksByRootV2 => Protocol::BlocksByRoot,
SupportedProtocol::BlobsByRangeV1 => Protocol::BlobsByRange,
SupportedProtocol::BlobsByRootV1 => Protocol::BlobsByRoot,
SupportedProtocol::DataColumnsByRootV1 => Protocol::DataColumnsByRoot,
SupportedProtocol::DataColumnsByRangeV1 => Protocol::DataColumnsByRange,
SupportedProtocol::PingV1 => Protocol::Ping,
SupportedProtocol::MetaDataV1 => Protocol::MetaData,
SupportedProtocol::MetaDataV2 => Protocol::MetaData,
@@ -387,6 +401,12 @@ impl SupportedProtocol {
ProtocolId::new(SupportedProtocol::BlobsByRangeV1, Encoding::SSZSnappy),
]);
}
if fork_context.spec.is_peer_das_scheduled() {
supported.extend_from_slice(&[
ProtocolId::new(SupportedProtocol::DataColumnsByRootV1, Encoding::SSZSnappy),
ProtocolId::new(SupportedProtocol::DataColumnsByRangeV1, Encoding::SSZSnappy),
]);
}
supported
}
}
@@ -495,6 +515,11 @@ impl ProtocolId {
<BlobsByRangeRequest as Encode>::ssz_fixed_len(),
),
Protocol::BlobsByRoot => RpcLimits::new(0, spec.max_blobs_by_root_request),
Protocol::DataColumnsByRoot => RpcLimits::new(0, spec.max_data_columns_by_root_request),
Protocol::DataColumnsByRange => RpcLimits::new(
DataColumnsByRangeRequest::ssz_min_len(),
DataColumnsByRangeRequest::ssz_max_len(spec),
),
Protocol::Ping => RpcLimits::new(
<Ping as Encode>::ssz_fixed_len(),
<Ping as Encode>::ssz_fixed_len(),
@@ -521,6 +546,8 @@ impl ProtocolId {
Protocol::BlocksByRoot => rpc_block_limits_by_fork(fork_context.current_fork()),
Protocol::BlobsByRange => rpc_blob_limits::<E>(),
Protocol::BlobsByRoot => rpc_blob_limits::<E>(),
Protocol::DataColumnsByRoot => rpc_data_column_limits::<E>(),
Protocol::DataColumnsByRange => rpc_data_column_limits::<E>(),
Protocol::Ping => RpcLimits::new(
<Ping as Encode>::ssz_fixed_len(),
<Ping as Encode>::ssz_fixed_len(),
@@ -549,6 +576,8 @@ impl ProtocolId {
| SupportedProtocol::BlocksByRootV2
| SupportedProtocol::BlobsByRangeV1
| SupportedProtocol::BlobsByRootV1
| SupportedProtocol::DataColumnsByRootV1
| SupportedProtocol::DataColumnsByRangeV1
| SupportedProtocol::LightClientBootstrapV1
| SupportedProtocol::LightClientOptimisticUpdateV1
| SupportedProtocol::LightClientFinalityUpdateV1 => true,
@@ -589,6 +618,13 @@ pub fn rpc_blob_limits<E: EthSpec>() -> RpcLimits {
)
}
pub fn rpc_data_column_limits<E: EthSpec>() -> RpcLimits {
RpcLimits::new(
DataColumnSidecar::<E>::empty().as_ssz_bytes().len(),
DataColumnSidecar::<E>::max_size(),
)
}
/* Inbound upgrade */
// The inbound protocol reads the request, decodes it and returns the stream to the protocol
@@ -668,6 +704,8 @@ pub enum InboundRequest<E: EthSpec> {
BlocksByRoot(BlocksByRootRequest),
BlobsByRange(BlobsByRangeRequest),
BlobsByRoot(BlobsByRootRequest),
DataColumnsByRoot(DataColumnsByRootRequest),
DataColumnsByRange(DataColumnsByRangeRequest),
LightClientBootstrap(LightClientBootstrapRequest),
LightClientOptimisticUpdate,
LightClientFinalityUpdate,
@@ -688,6 +726,8 @@ impl<E: EthSpec> InboundRequest<E> {
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,
@@ -711,6 +751,8 @@ impl<E: EthSpec> InboundRequest<E> {
},
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 {
MetadataRequest::V1(_) => SupportedProtocol::MetaDataV1,
@@ -736,6 +778,8 @@ impl<E: EthSpec> InboundRequest<E> {
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!(),
@@ -846,6 +890,10 @@ impl<E: EthSpec> std::fmt::Display for InboundRequest<E> {
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) => {
write!(f, "Data columns by range: {:?}", req)
}
InboundRequest::Ping(ping) => write!(f, "Ping: {}", ping.data),
InboundRequest::MetaData(_) => write!(f, "MetaData request"),
InboundRequest::LightClientBootstrap(bootstrap) => {

View File

@@ -97,6 +97,10 @@ pub struct RPCRateLimiter {
blbrange_rl: Limiter<PeerId>,
/// BlobsByRoot rate limiter.
blbroot_rl: Limiter<PeerId>,
/// DataColumnssByRoot rate limiter.
dcbroot_rl: Limiter<PeerId>,
/// DataColumnsByRange rate limiter.
dcbrange_rl: Limiter<PeerId>,
/// LightClientBootstrap rate limiter.
lc_bootstrap_rl: Limiter<PeerId>,
/// LightClientOptimisticUpdate rate limiter.
@@ -133,6 +137,10 @@ pub struct RPCRateLimiterBuilder {
blbrange_quota: Option<Quota>,
/// Quota for the BlobsByRoot protocol.
blbroot_quota: Option<Quota>,
/// Quota for the DataColumnsByRoot protocol.
dcbroot_quota: Option<Quota>,
/// Quota for the DataColumnsByRange protocol.
dcbrange_quota: Option<Quota>,
/// Quota for the LightClientBootstrap protocol.
lcbootstrap_quota: Option<Quota>,
/// Quota for the LightClientOptimisticUpdate protocol.
@@ -154,6 +162,8 @@ impl RPCRateLimiterBuilder {
Protocol::BlocksByRoot => self.bbroots_quota = q,
Protocol::BlobsByRange => self.blbrange_quota = q,
Protocol::BlobsByRoot => self.blbroot_quota = q,
Protocol::DataColumnsByRoot => self.dcbroot_quota = q,
Protocol::DataColumnsByRange => self.dcbrange_quota = q,
Protocol::LightClientBootstrap => self.lcbootstrap_quota = q,
Protocol::LightClientOptimisticUpdate => self.lc_optimistic_update_quota = q,
Protocol::LightClientFinalityUpdate => self.lc_finality_update_quota = q,
@@ -191,6 +201,14 @@ impl RPCRateLimiterBuilder {
.blbroot_quota
.ok_or("BlobsByRoot quota not specified")?;
let dcbroot_quota = self
.dcbroot_quota
.ok_or("DataColumnsByRoot quota not specified")?;
let dcbrange_quota = self
.dcbrange_quota
.ok_or("DataColumnsByRange quota not specified")?;
// create the rate limiters
let ping_rl = Limiter::from_quota(ping_quota)?;
let metadata_rl = Limiter::from_quota(metadata_quota)?;
@@ -200,6 +218,8 @@ impl RPCRateLimiterBuilder {
let bbrange_rl = Limiter::from_quota(bbrange_quota)?;
let blbrange_rl = Limiter::from_quota(blbrange_quota)?;
let blbroot_rl = Limiter::from_quota(blbroots_quota)?;
let dcbroot_rl = Limiter::from_quota(dcbroot_quota)?;
let dcbrange_rl = Limiter::from_quota(dcbrange_quota)?;
let lc_bootstrap_rl = Limiter::from_quota(lc_bootstrap_quota)?;
let lc_optimistic_update_rl = Limiter::from_quota(lc_optimistic_update_quota)?;
let lc_finality_update_rl = Limiter::from_quota(lc_finality_update_quota)?;
@@ -218,6 +238,8 @@ impl RPCRateLimiterBuilder {
bbrange_rl,
blbrange_rl,
blbroot_rl,
dcbroot_rl,
dcbrange_rl,
lc_bootstrap_rl,
lc_optimistic_update_rl,
lc_finality_update_rl,
@@ -262,6 +284,8 @@ impl RPCRateLimiter {
blocks_by_root_quota,
blobs_by_range_quota,
blobs_by_root_quota,
data_columns_by_root_quota,
data_columns_by_range_quota,
light_client_bootstrap_quota,
light_client_optimistic_update_quota,
light_client_finality_update_quota,
@@ -276,6 +300,8 @@ impl RPCRateLimiter {
.set_quota(Protocol::BlocksByRoot, blocks_by_root_quota)
.set_quota(Protocol::BlobsByRange, blobs_by_range_quota)
.set_quota(Protocol::BlobsByRoot, blobs_by_root_quota)
.set_quota(Protocol::DataColumnsByRoot, data_columns_by_root_quota)
.set_quota(Protocol::DataColumnsByRange, data_columns_by_range_quota)
.set_quota(Protocol::LightClientBootstrap, light_client_bootstrap_quota)
.set_quota(
Protocol::LightClientOptimisticUpdate,
@@ -312,6 +338,8 @@ impl RPCRateLimiter {
Protocol::BlocksByRoot => &mut self.bbroots_rl,
Protocol::BlobsByRange => &mut self.blbrange_rl,
Protocol::BlobsByRoot => &mut self.blbroot_rl,
Protocol::DataColumnsByRoot => &mut self.dcbroot_rl,
Protocol::DataColumnsByRange => &mut self.dcbrange_rl,
Protocol::LightClientBootstrap => &mut self.lc_bootstrap_rl,
Protocol::LightClientOptimisticUpdate => &mut self.lc_optimistic_update_rl,
Protocol::LightClientFinalityUpdate => &mut self.lc_finality_update_rl,