Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add rlp support for EthVersion #12221

Merged
merged 4 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading