Add test for protocol registration completeness (#8920)

Co-Authored-By: Jimmy Chen <jchen.tc@gmail.com>
This commit is contained in:
Jimmy Chen
2026-04-04 03:35:08 +11:00
committed by GitHub
parent 65c2e01612
commit 27af0ed82c

View File

@@ -11,7 +11,7 @@ use std::io;
use std::marker::PhantomData;
use std::sync::{Arc, LazyLock};
use std::time::Duration;
use strum::{AsRefStr, Display, EnumString, IntoStaticStr};
use strum::{AsRefStr, Display, EnumIter, EnumString, IntoStaticStr};
use tokio_util::{
codec::Framed,
compat::{Compat, FuturesAsyncReadCompatExt},
@@ -329,7 +329,7 @@ pub enum Encoding {
}
/// All valid protocol name and version combinations.
#[derive(Debug, Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter)]
pub enum SupportedProtocol {
StatusV1,
StatusV2,
@@ -499,6 +499,10 @@ impl<E: EthSpec> UpgradeInfo for RPCProtocol<E> {
SupportedProtocol::LightClientFinalityUpdateV1,
Encoding::SSZSnappy,
));
supported_protocols.push(ProtocolId::new(
SupportedProtocol::LightClientUpdatesByRangeV1,
Encoding::SSZSnappy,
));
}
supported_protocols
}
@@ -1133,3 +1137,101 @@ impl RPCError {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use libp2p::core::UpgradeInfo;
use std::collections::HashSet;
use strum::IntoEnumIterator;
use types::{Hash256, Slot};
type E = MainnetEthSpec;
/// Whether this protocol should appear in `currently_supported()` for the given context.
///
/// Uses an exhaustive match so that adding a new `SupportedProtocol` variant
/// causes a compile error until this function is updated.
fn expected_in_currently_supported(
protocol: SupportedProtocol,
fork_context: &ForkContext,
) -> bool {
use SupportedProtocol::*;
match protocol {
StatusV1 | StatusV2 | GoodbyeV1 | PingV1 | BlocksByRangeV1 | BlocksByRangeV2
| BlocksByRootV1 | BlocksByRootV2 | MetaDataV1 | MetaDataV2 => true,
BlobsByRangeV1 | BlobsByRootV1 => fork_context.fork_exists(ForkName::Deneb),
DataColumnsByRootV1 | DataColumnsByRangeV1 | MetaDataV3 => {
fork_context.spec.is_peer_das_scheduled()
}
PayloadEnvelopesByRangeV1 | PayloadEnvelopesByRootV1 => {
fork_context.fork_exists(ForkName::Gloas)
}
// Light client protocols are not in currently_supported()
LightClientBootstrapV1
| LightClientOptimisticUpdateV1
| LightClientFinalityUpdateV1
| LightClientUpdatesByRangeV1 => false,
}
}
/// Whether this protocol should appear in `protocol_info()` when light client server is
/// enabled.
///
/// Uses an exhaustive match so that adding a new `SupportedProtocol` variant
/// causes a compile error until this function is updated.
fn expected_in_protocol_info(protocol: SupportedProtocol, fork_context: &ForkContext) -> bool {
use SupportedProtocol::*;
match protocol {
LightClientBootstrapV1
| LightClientOptimisticUpdateV1
| LightClientFinalityUpdateV1
| LightClientUpdatesByRangeV1 => true,
_ => expected_in_currently_supported(protocol, fork_context),
}
}
#[test]
fn all_protocols_registered() {
for fork in ForkName::list_all() {
let spec = fork.make_genesis_spec(E::default_spec());
let fork_context = Arc::new(ForkContext::new::<E>(Slot::new(0), Hash256::ZERO, &spec));
let currently_supported: HashSet<SupportedProtocol> =
SupportedProtocol::currently_supported(&fork_context)
.into_iter()
.map(|pid| pid.versioned_protocol)
.collect();
let rpc_protocol = RPCProtocol::<E> {
fork_context: fork_context.clone(),
max_rpc_size: spec.max_payload_size as usize,
enable_light_client_server: true,
phantom: PhantomData,
};
let protocol_info: HashSet<SupportedProtocol> = rpc_protocol
.protocol_info()
.into_iter()
.map(|pid| pid.versioned_protocol)
.collect();
for protocol in SupportedProtocol::iter() {
assert_eq!(
currently_supported.contains(&protocol),
expected_in_currently_supported(protocol, &fork_context),
"{protocol:?} registration mismatch in currently_supported() at {fork:?}"
);
assert_eq!(
protocol_info.contains(&protocol),
expected_in_protocol_info(protocol, &fork_context),
"{protocol:?} registration mismatch in protocol_info() at {fork:?}"
);
}
}
}
}