mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: add rlp support for EthVersion (#12221)
This commit is contained in:
@ -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).
|
||||
@ -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.
|
||||
@ -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,
|
||||
@ -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))
|
||||
@ -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),
|
||||
@ -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
|
||||
}
|
||||
@ -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(
|
||||
@ -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(
|
||||
@ -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(
|
||||
@ -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(
|
||||
@ -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",
|
||||
|
||||
@ -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,
|
||||
@ -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
|
||||
@ -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() {
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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>),
|
||||
|
||||
@ -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) => {
|
||||
@ -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(),
|
||||
@ -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(),
|
||||
@ -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(),
|
||||
@ -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(),
|
||||
@ -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(),
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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:?}")
|
||||
@ -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:?}")
|
||||
|
||||
@ -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?)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user