Skip to content

Commit

Permalink
feat: add rlp support for EthVersion (#12221)
Browse files Browse the repository at this point in the history
  • Loading branch information
lean-apple authored Oct 31, 2024
1 parent e5fc048 commit c19af29
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 22 deletions.
22 changes: 11 additions & 11 deletions crates/net/eth-wire-types/src/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use std::fmt::{Debug, Display};
pub struct Status {
/// The current protocol version. For example, peers running `eth/66` would have a version of
/// 66.
pub version: u8,
pub version: EthVersion,

/// The chain id, as introduced in
/// [EIP155](https://eips.ethereum.org/EIPS/eip-155#list-of-chain-ids).
Expand Down Expand Up @@ -50,7 +50,7 @@ impl Status {

/// Sets the [`EthVersion`] for the status.
pub fn set_eth_version(&mut self, version: EthVersion) {
self.version = version as u8;
self.version = version;
}

/// Create a [`StatusBuilder`] from the given [`EthChainSpec`] and head block.
Expand Down Expand Up @@ -122,7 +122,7 @@ impl Default for Status {
fn default() -> Self {
let mainnet_genesis = MAINNET.genesis_hash();
Self {
version: EthVersion::Eth68 as u8,
version: EthVersion::Eth68,
chain: Chain::from_named(NamedChain::Mainnet),
total_difficulty: U256::from(17_179_869_184u64),
blockhash: mainnet_genesis,
Expand All @@ -145,7 +145,7 @@ impl Default for Status {
///
/// // this is just an example status message!
/// let status = Status::builder()
/// .version(EthVersion::Eth66.into())
/// .version(EthVersion::Eth66)
/// .chain(Chain::mainnet())
/// .total_difficulty(U256::from(100))
/// .blockhash(B256::from(MAINNET_GENESIS_HASH))
Expand All @@ -156,7 +156,7 @@ impl Default for Status {
/// assert_eq!(
/// status,
/// Status {
/// version: EthVersion::Eth66.into(),
/// version: EthVersion::Eth66,
/// chain: Chain::mainnet(),
/// total_difficulty: U256::from(100),
/// blockhash: B256::from(MAINNET_GENESIS_HASH),
Expand All @@ -177,7 +177,7 @@ impl StatusBuilder {
}

/// Sets the protocol version.
pub const fn version(mut self, version: u8) -> Self {
pub const fn version(mut self, version: EthVersion) -> Self {
self.status.version = version;
self
}
Expand Down Expand Up @@ -229,7 +229,7 @@ mod tests {
fn encode_eth_status_message() {
let expected = hex!("f85643018a07aac59dabcdd74bc567a0feb27336ca7923f8fab3bd617fcb6e75841538f71c1bcfc267d7838489d9e13da0d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3c684b715077d80");
let status = Status {
version: EthVersion::Eth67 as u8,
version: EthVersion::Eth67,
chain: Chain::from_named(NamedChain::Mainnet),
total_difficulty: U256::from(36206751599115524359527u128),
blockhash: B256::from_str(
Expand All @@ -249,7 +249,7 @@ mod tests {
fn decode_eth_status_message() {
let data = hex!("f85643018a07aac59dabcdd74bc567a0feb27336ca7923f8fab3bd617fcb6e75841538f71c1bcfc267d7838489d9e13da0d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3c684b715077d80");
let expected = Status {
version: EthVersion::Eth67 as u8,
version: EthVersion::Eth67,
chain: Chain::from_named(NamedChain::Mainnet),
total_difficulty: U256::from(36206751599115524359527u128),
blockhash: B256::from_str(
Expand All @@ -267,7 +267,7 @@ mod tests {
fn encode_network_status_message() {
let expected = hex!("f850423884024190faa0f8514c4680ef27700751b08f37645309ce65a449616a3ea966bf39dd935bb27ba00d21840abff46b96c84b2ac9e10e4f5cdaeb5693cb665db62a2f3b02d2d57b5bc6845d43d2fd80");
let status = Status {
version: EthVersion::Eth66 as u8,
version: EthVersion::Eth66,
chain: Chain::from_named(NamedChain::BinanceSmartChain),
total_difficulty: U256::from(37851386u64),
blockhash: B256::from_str(
Expand All @@ -290,7 +290,7 @@ mod tests {
fn decode_network_status_message() {
let data = hex!("f850423884024190faa0f8514c4680ef27700751b08f37645309ce65a449616a3ea966bf39dd935bb27ba00d21840abff46b96c84b2ac9e10e4f5cdaeb5693cb665db62a2f3b02d2d57b5bc6845d43d2fd80");
let expected = Status {
version: EthVersion::Eth66 as u8,
version: EthVersion::Eth66,
chain: Chain::from_named(NamedChain::BinanceSmartChain),
total_difficulty: U256::from(37851386u64),
blockhash: B256::from_str(
Expand All @@ -311,7 +311,7 @@ mod tests {
fn decode_another_network_status_message() {
let data = hex!("f86142820834936d68fcffffffffffffffffffffffffdeab81b8a0523e8163a6d620a4cc152c547a05f28a03fec91a2a615194cb86df9731372c0ca06499dccdc7c7def3ebb1ce4c6ee27ec6bd02aee570625ca391919faf77ef27bdc6841a67ccd880");
let expected = Status {
version: EthVersion::Eth66 as u8,
version: EthVersion::Eth66,
chain: Chain::from_id(2100),
total_difficulty: U256::from_str(
"0x000000000000000000000000006d68fcffffffffffffffffffffffffdeab81b8",
Expand Down
65 changes: 65 additions & 0 deletions crates/net/eth-wire-types/src/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ pub struct ParseVersionError(String);
/// The `eth` protocol version.
#[repr(u8)]
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Display)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
pub enum EthVersion {
/// The `eth` protocol version 66.
Eth66 = 66,
Expand Down Expand Up @@ -64,6 +66,26 @@ impl EthVersion {
}
}

/// RLP encodes `EthVersion` as a single byte (66-69).
impl Encodable for EthVersion {
fn encode(&self, out: &mut dyn BufMut) {
(*self as u8).encode(out)
}

fn length(&self) -> usize {
(*self as u8).length()
}
}

/// RLP decodes a single byte into `EthVersion`.
/// Returns error if byte is not a valid version (66-69).
impl Decodable for EthVersion {
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
let version = u8::decode(buf)?;
Self::try_from(version).map_err(|_| RlpError::Custom("invalid eth version"))
}
}

/// Allow for converting from a `&str` to an `EthVersion`.
///
/// # Example
Expand Down Expand Up @@ -183,6 +205,8 @@ impl Decodable for ProtocolVersion {
#[cfg(test)]
mod tests {
use super::{EthVersion, ParseVersionError};
use alloy_rlp::{Decodable, Encodable, Error as RlpError};
use bytes::BytesMut;

#[test]
fn test_eth_version_try_from_str() {
Expand All @@ -201,4 +225,45 @@ mod tests {
assert_eq!(EthVersion::Eth69, "69".parse().unwrap());
assert_eq!(Err(ParseVersionError("70".to_string())), "70".parse::<EthVersion>());
}

#[test]
fn test_eth_version_rlp_encode() {
let versions = [EthVersion::Eth66, EthVersion::Eth67, EthVersion::Eth68, EthVersion::Eth69];

for version in versions {
let mut encoded = BytesMut::new();
version.encode(&mut encoded);

assert_eq!(encoded.len(), 1);
assert_eq!(encoded[0], version as u8);
}
}
#[test]
fn test_eth_version_rlp_decode() {
let test_cases = [
(66_u8, Ok(EthVersion::Eth66)),
(67_u8, Ok(EthVersion::Eth67)),
(68_u8, Ok(EthVersion::Eth68)),
(69_u8, Ok(EthVersion::Eth69)),
(70_u8, Err(RlpError::Custom("invalid eth version"))),
(65_u8, Err(RlpError::Custom("invalid eth version"))),
];

for (input, expected) in test_cases {
let mut encoded = BytesMut::new();
input.encode(&mut encoded);

let mut slice = encoded.as_ref();
let result = EthVersion::decode(&mut slice);
assert_eq!(result, expected);
}
}

#[test]
fn test_eth_version_total_messages() {
assert_eq!(EthVersion::Eth66.total_messages(), 15);
assert_eq!(EthVersion::Eth67.total_messages(), 13);
assert_eq!(EthVersion::Eth68.total_messages(), 13);
assert_eq!(EthVersion::Eth69.total_messages(), 11);
}
}
3 changes: 2 additions & 1 deletion crates/net/eth-wire/src/errors/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::{
};
use alloy_primitives::B256;
use reth_chainspec::Chain;
use reth_eth_wire_types::EthVersion;
use reth_primitives::{GotExpected, GotExpectedBoxed, ValidationError};
use std::io;

Expand Down Expand Up @@ -88,7 +89,7 @@ pub enum EthHandshakeError {
MismatchedGenesis(GotExpectedBoxed<B256>),
#[error("mismatched protocol version in status message: {0}")]
/// Mismatched protocol versions in status messages.
MismatchedProtocolVersion(GotExpected<u8>),
MismatchedProtocolVersion(GotExpected<EthVersion>),
#[error("mismatched chain in status message: {0}")]
/// Mismatch in chain details in status messages.
MismatchedChain(GotExpected<Chain>),
Expand Down
12 changes: 6 additions & 6 deletions crates/net/eth-wire/src/ethstream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ where
return Err(EthStreamError::MessageTooBig(their_msg.len()))
}

let version = EthVersion::try_from(status.version)?;
let version = status.version;
let msg = match ProtocolMessage::decode_message(version, &mut their_msg.as_ref()) {
Ok(m) => m,
Err(err) => {
Expand Down Expand Up @@ -368,7 +368,7 @@ mod tests {
let fork_filter = ForkFilter::new(Head::default(), genesis, 0, Vec::new());

let status = Status {
version: EthVersion::Eth67 as u8,
version: EthVersion::Eth67,
chain: NamedChain::Mainnet.into(),
total_difficulty: U256::ZERO,
blockhash: B256::random(),
Expand Down Expand Up @@ -415,7 +415,7 @@ mod tests {
let fork_filter = ForkFilter::new(Head::default(), genesis, 0, Vec::new());

let status = Status {
version: EthVersion::Eth67 as u8,
version: EthVersion::Eth67,
chain: NamedChain::Mainnet.into(),
total_difficulty: U256::from(2).pow(U256::from(100)) - U256::from(1),
blockhash: B256::random(),
Expand Down Expand Up @@ -462,7 +462,7 @@ mod tests {
let fork_filter = ForkFilter::new(Head::default(), genesis, 0, Vec::new());

let status = Status {
version: EthVersion::Eth67 as u8,
version: EthVersion::Eth67,
chain: NamedChain::Mainnet.into(),
total_difficulty: U256::from(2).pow(U256::from(100)),
blockhash: B256::random(),
Expand Down Expand Up @@ -603,7 +603,7 @@ mod tests {
let fork_filter = ForkFilter::new(Head::default(), genesis, 0, Vec::new());

let status = Status {
version: EthVersion::Eth67 as u8,
version: EthVersion::Eth67,
chain: NamedChain::Mainnet.into(),
total_difficulty: U256::ZERO,
blockhash: B256::random(),
Expand Down Expand Up @@ -674,7 +674,7 @@ mod tests {
let fork_filter = ForkFilter::new(Head::default(), genesis, 0, Vec::new());

let status = Status {
version: EthVersion::Eth67 as u8,
version: EthVersion::Eth67,
chain: NamedChain::Mainnet.into(),
total_difficulty: U256::ZERO,
blockhash: B256::random(),
Expand Down
2 changes: 1 addition & 1 deletion crates/net/eth-wire/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub fn eth_handshake() -> (Status, ForkFilter) {
let fork_filter = ForkFilter::new(Head::default(), genesis, 0, Vec::new());

let status = Status {
version: EthVersion::Eth67 as u8,
version: EthVersion::Eth67,
chain: Chain::mainnet(),
total_difficulty: U256::ZERO,
blockhash: B256::random(),
Expand Down
4 changes: 2 additions & 2 deletions crates/net/network/tests/it/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ async fn test_session_established_with_highest_version() {
}
NetworkEvent::SessionEstablished { peer_id, status, .. } => {
assert_eq!(handle1.peer_id(), &peer_id);
assert_eq!(status.version, EthVersion::Eth68 as u8);
assert_eq!(status.version, EthVersion::Eth68);
}
ev => {
panic!("unexpected event {ev:?}")
Expand Down Expand Up @@ -71,7 +71,7 @@ async fn test_session_established_with_different_capability() {
}
NetworkEvent::SessionEstablished { peer_id, status, .. } => {
assert_eq!(handle1.peer_id(), &peer_id);
assert_eq!(status.version, EthVersion::Eth66 as u8);
assert_eq!(status.version, EthVersion::Eth66);
}
ev => {
panic!("unexpected event: {ev:?}")
Expand Down
3 changes: 2 additions & 1 deletion examples/manual-p2p/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ async fn handshake_eth(p2p_stream: AuthedP2PStream) -> eyre::Result<(AuthedEthSt
.forkid(MAINNET.hardfork_fork_id(EthereumHardfork::Shanghai).unwrap())
.build();

let status = Status { version: p2p_stream.shared_capabilities().eth()?.version(), ..status };
let status =
Status { version: p2p_stream.shared_capabilities().eth()?.version().try_into()?, ..status };
let eth_unauthed = UnauthedEthStream::new(p2p_stream);
Ok(eth_unauthed.handshake(status, fork_filter).await?)
}
Expand Down

0 comments on commit c19af29

Please sign in to comment.