Skip to content

Commit

Permalink
refactor: swap ProtocolId with Subnetwork type (ethereum#1478)
Browse files Browse the repository at this point in the history
* refactor: swap ProtocolId with Subnetwork type
  • Loading branch information
njgheorghita authored Sep 24, 2024
1 parent 08293cd commit 3152246
Show file tree
Hide file tree
Showing 32 changed files with 296 additions and 363 deletions.
8 changes: 7 additions & 1 deletion ethportal-api/src/types/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,13 +339,19 @@ pub fn network_parser(network_string: &str) -> Result<Arc<NetworkSpec>, String>
pub fn subnetwork_parser(subnetwork_string: &str) -> Result<Arc<Vec<Subnetwork>>, String> {
let subnetworks = subnetwork_string
.split(',')
.map(Subnetwork::from_str)
.map(Subnetwork::from_cli_arg)
.collect::<Result<Vec<Subnetwork>, String>>()?;

if subnetworks.is_empty() {
return Err("At least one subnetwork must be enabled".to_owned());
}

for subnetwork in &subnetworks {
if !subnetwork.is_active() {
return Err("{subnetwork} subnetwork has not yet been activated".to_owned());
}
}

Ok(Arc::new(subnetworks))
}

Expand Down
6 changes: 3 additions & 3 deletions ethportal-api/src/types/content_value/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub enum ContentValueError {
decode_error: ssz::DecodeError,
input: String,
},
#[error("could not determine content type of {bytes} from {subnetwork} subnetwork")]
#[error("could not determine content type of {bytes} from {subnetwork:?} subnetwork")]
UnknownContent {
bytes: String,
subnetwork: Subnetwork,
Expand All @@ -25,12 +25,12 @@ pub enum ContentValueError {
/// This error implies that handling of the "content absent" response was skipped.
#[error("attempted to decode the '0x' absent content message")]
DecodeAbsentContent,
#[error("could not determine fork digest of {bytes} from {subnetwork} subnetwork")]
#[error("could not determine fork digest of {bytes} from {subnetwork:?} subnetwork")]
UnknownForkDigest {
bytes: String,
subnetwork: Subnetwork,
},
#[error("could not determine fork name of {bytes} from {subnetwork} subnetwork")]
#[error("could not determine fork name of {bytes} from {subnetwork:?} subnetwork")]
UnknownForkName {
bytes: String,
subnetwork: Subnetwork,
Expand Down
2 changes: 1 addition & 1 deletion ethportal-api/src/types/content_value/history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ mod test {
// Test the error Display representation.
assert_eq!(
error.to_string(),
"could not determine content type of 0x010203040506070809 from history subnetwork"
"could not determine content type of 0x010203040506070809 from History subnetwork"
);
}
}
53 changes: 45 additions & 8 deletions ethportal-api/src/types/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,32 +29,69 @@ impl std::str::FromStr for Network {
}

/// Enum for various different portal subnetworks in a "core" network.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Subnetwork {
Beacon,
History,
State,
CanonicalIndices,
VerkleState,
TransactionGossip,
Utp,
}

// Pretty printed version of the subnetwork enum, used in metrics labels.
impl fmt::Display for Subnetwork {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Subnetwork::Beacon => write!(f, "beacon"),
Subnetwork::History => write!(f, "history"),
Subnetwork::State => write!(f, "state"),
Subnetwork::Beacon => write!(f, "Beacon"),
Subnetwork::History => write!(f, "History"),
Subnetwork::State => write!(f, "State"),
Subnetwork::CanonicalIndices => write!(f, "Canonical Indices"),
Subnetwork::VerkleState => write!(f, "Verkle State"),
Subnetwork::TransactionGossip => write!(f, "Transaction Gossip"),
Subnetwork::Utp => write!(f, "uTP"),
}
}
}

impl std::str::FromStr for Subnetwork {
type Err = String;

fn from_str(s: &str) -> Result<Self, Self::Err> {
// Convert camel_case cli args to/from the Subnetwork enum.
impl Subnetwork {
pub fn from_cli_arg(s: &str) -> Result<Self, String> {
match s {
"beacon" => Ok(Subnetwork::Beacon),
"history" => Ok(Subnetwork::History),
"state" => Ok(Subnetwork::State),
"canonical_indices" => Ok(Subnetwork::CanonicalIndices),
"verkle_state" => Ok(Subnetwork::VerkleState),
"transaction_gossip" => Ok(Subnetwork::TransactionGossip),
"utp" => Ok(Subnetwork::Utp),
_ => Err(format!("Unknown subnetwork: {s}")),
}
}

pub fn to_cli_arg(&self) -> String {
match self {
Subnetwork::Beacon => "beacon".to_string(),
Subnetwork::History => "history".to_string(),
Subnetwork::State => "state".to_string(),
Subnetwork::CanonicalIndices => "canonical_indices".to_string(),
Subnetwork::VerkleState => "verkle_state".to_string(),
Subnetwork::TransactionGossip => "transaction_gossip".to_string(),
Subnetwork::Utp => "utp".to_string(),
}
}

/// Returns true if the subnetwork has been "fully" activated.
pub fn is_active(&self) -> bool {
match self {
Subnetwork::Beacon => true,
Subnetwork::History => true,
Subnetwork::State => true,
Subnetwork::CanonicalIndices => false,
Subnetwork::VerkleState => false,
Subnetwork::TransactionGossip => false,
Subnetwork::Utp => false,
}
}
}
156 changes: 43 additions & 113 deletions ethportal-api/src/types/portal_wire.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::{
};

use alloy_primitives::U256;
use anyhow::anyhow;
use bimap::BiHashMap;
use once_cell::sync::Lazy;
use rlp::Encodable;
Expand All @@ -22,9 +23,9 @@ use crate::{
bytes::ByteList2048,
distance::Distance,
enr::{Enr, SszEnr},
network::Network,
network::{Network, Subnetwork},
},
utils::bytes::{hex_decode, hex_encode, ByteUtilsError},
utils::bytes::{hex_decode, hex_encode},
RawContentKey,
};

Expand Down Expand Up @@ -157,117 +158,70 @@ pub enum DiscoveryRequestError {
InvalidMessage,
}

#[derive(Error, Debug)]
pub enum ProtocolIdError {
#[error("Unable to decode protocol id to bytes")]
Decode(ByteUtilsError),

#[error("invalid protocol id")]
Invalid,
}

/// Protocol identifiers
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum ProtocolId {
State,
VerkleState,
History,
TransactionGossip,
CanonicalIndices,
Beacon,
Utp,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct NetworkSpec {
network: Network,
portal_networks: BiHashMap<ProtocolId, String>,
// mapping of subnetworks to protocol id hex strings
portal_subnetworks: BiHashMap<Subnetwork, String>,
}

impl NetworkSpec {
pub fn network(&self) -> Network {
self.network
}

pub fn get_protocol_id_from_hex(&self, hex: &str) -> Result<ProtocolId, ProtocolIdError> {
self.portal_networks
pub fn get_subnetwork_from_protocol_identifier(&self, hex: &str) -> anyhow::Result<Subnetwork> {
self.portal_subnetworks
.get_by_right(hex)
.copied()
.ok_or(ProtocolIdError::Invalid)
.ok_or(anyhow!("Invalid subnetwork identifier: {hex}"))
}

pub fn get_protocol_hex_from_id(
pub fn get_protocol_identifier_from_subnetwork(
&self,
protocol_id: &ProtocolId,
) -> Result<String, ProtocolIdError> {
self.portal_networks
.get_by_left(protocol_id)
subnetwork: &Subnetwork,
) -> anyhow::Result<String> {
self.portal_subnetworks
.get_by_left(subnetwork)
.cloned()
.ok_or(ProtocolIdError::Invalid)
.ok_or(anyhow!(
"Cannot find protocol identifier for subnetwork: {subnetwork}"
))
}
}

pub static MAINNET: Lazy<Arc<NetworkSpec>> = Lazy::new(|| {
let mut portal_networks = BiHashMap::new();
portal_networks.insert(ProtocolId::State, "0x500A".to_string());
portal_networks.insert(ProtocolId::History, "0x500B".to_string());
portal_networks.insert(ProtocolId::Beacon, "0x500C".to_string());
portal_networks.insert(ProtocolId::CanonicalIndices, "0x500D".to_string());
portal_networks.insert(ProtocolId::VerkleState, "0x500E".to_string());
portal_networks.insert(ProtocolId::TransactionGossip, "0x500F".to_string());
portal_networks.insert(ProtocolId::Utp, "0x757470".to_string());
let mut portal_subnetworks = BiHashMap::new();
portal_subnetworks.insert(Subnetwork::State, "0x500A".to_string());
portal_subnetworks.insert(Subnetwork::History, "0x500B".to_string());
portal_subnetworks.insert(Subnetwork::Beacon, "0x500C".to_string());
portal_subnetworks.insert(Subnetwork::CanonicalIndices, "0x500D".to_string());
portal_subnetworks.insert(Subnetwork::VerkleState, "0x500E".to_string());
portal_subnetworks.insert(Subnetwork::TransactionGossip, "0x500F".to_string());
portal_subnetworks.insert(Subnetwork::Utp, "0x757470".to_string());
NetworkSpec {
portal_networks,
portal_subnetworks,
network: Network::Mainnet,
}
.into()
});

pub static ANGELFOOD: Lazy<Arc<NetworkSpec>> = Lazy::new(|| {
let mut portal_networks = BiHashMap::new();
portal_networks.insert(ProtocolId::State, "0x504A".to_string());
portal_networks.insert(ProtocolId::History, "0x504B".to_string());
portal_networks.insert(ProtocolId::Beacon, "0x504C".to_string());
portal_networks.insert(ProtocolId::CanonicalIndices, "0x504D".to_string());
portal_networks.insert(ProtocolId::VerkleState, "0x504E".to_string());
portal_networks.insert(ProtocolId::TransactionGossip, "0x504F".to_string());
portal_networks.insert(ProtocolId::Utp, "0x757470".to_string());
let mut portal_subnetworks = BiHashMap::new();
portal_subnetworks.insert(Subnetwork::State, "0x504A".to_string());
portal_subnetworks.insert(Subnetwork::History, "0x504B".to_string());
portal_subnetworks.insert(Subnetwork::Beacon, "0x504C".to_string());
portal_subnetworks.insert(Subnetwork::CanonicalIndices, "0x504D".to_string());
portal_subnetworks.insert(Subnetwork::VerkleState, "0x504E".to_string());
portal_subnetworks.insert(Subnetwork::TransactionGossip, "0x504F".to_string());
portal_subnetworks.insert(Subnetwork::Utp, "0x757470".to_string());
NetworkSpec {
portal_networks,
portal_subnetworks,
network: Network::Angelfood,
}
.into()
});

impl fmt::Display for ProtocolId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let protocol = match self {
ProtocolId::State => "State",
ProtocolId::VerkleState => "Verkle State",
ProtocolId::History => "History",
ProtocolId::TransactionGossip => "Transaction Gossip",
ProtocolId::CanonicalIndices => "Canonical Indices",
ProtocolId::Beacon => "Beacon",
ProtocolId::Utp => "uTP",
};
write!(f, "{protocol}")
}
}

impl From<ProtocolId> for u8 {
fn from(protocol_id: ProtocolId) -> Self {
match protocol_id {
ProtocolId::State => 2,
ProtocolId::VerkleState => 5,
ProtocolId::History => 0,
ProtocolId::TransactionGossip => 3,
ProtocolId::CanonicalIndices => 4,
ProtocolId::Beacon => 1,
ProtocolId::Utp => 99,
}
}
}

/// A Portal protocol message.
#[derive(Debug, PartialEq, Clone, Encode, Decode)]
#[ssz(enum_behaviour = "union")]
Expand Down Expand Up @@ -628,49 +582,25 @@ mod test {
use test_log::test;

#[test]
fn protocol_id_invalid() {
fn subnetwork_invalid() {
let hex = "0x504F";
assert!(!MAINNET.portal_networks.contains_right(hex));
assert!(!MAINNET.portal_subnetworks.contains_right(hex));
}

#[test]
fn protocol_id_encoding() {
fn subnetwork_encoding() {
let hex = "0x500A";
let protocol_id = MAINNET.get_protocol_id_from_hex(hex).unwrap();
let expected_hex = MAINNET.get_protocol_hex_from_id(&protocol_id).unwrap();
let protocol_id = MAINNET
.get_subnetwork_from_protocol_identifier(hex)
.unwrap();
let expected_hex = MAINNET
.get_protocol_identifier_from_subnetwork(&protocol_id)
.unwrap();
assert_eq!(hex, expected_hex);
}

#[test]
fn prtocol_id_to_u8() {
let protocol_id = ProtocolId::History;
let expected_u8 = 0;
assert_eq!(expected_u8, u8::from(protocol_id));

let protocol_id = ProtocolId::Beacon;
let expected_u8 = 1;
assert_eq!(expected_u8, u8::from(protocol_id));

let protocol_id = ProtocolId::State;
let expected_u8 = 2;
assert_eq!(expected_u8, u8::from(protocol_id));

let protocol_id = ProtocolId::TransactionGossip;
let expected_u8 = 3;
assert_eq!(expected_u8, u8::from(protocol_id));

let protocol_id = ProtocolId::CanonicalIndices;
let expected_u8 = 4;
assert_eq!(expected_u8, u8::from(protocol_id));

let protocol_id = ProtocolId::Utp;
let expected_u8 = 99;
assert_eq!(expected_u8, u8::from(protocol_id));
}

// Wire message test vectors available in Ethereum Portal Network specs repo:
// github.com/ethereum/portal-network-specs

#[test]
fn message_encoding_ping() {
let data_radius: U256 = U256::MAX - U256::from(1u8);
Expand Down
2 changes: 1 addition & 1 deletion ethportal-peertest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ fn generate_trin_config(
let private_key = hex_encode(private_key);
let subnetworks = subnetworks
.iter()
.map(|sn| sn.to_string())
.map(|sn| sn.to_cli_arg())
.collect::<Vec<String>>()
.join(",");
let network = network.to_string();
Expand Down
Loading

0 comments on commit 3152246

Please sign in to comment.