Introduce StatusEth69 for eth/69 status messages (#14292)

This commit is contained in:
Yohann Kazoula
2025-02-10 22:46:48 +02:00
committed by GitHub
parent d9e660bd56
commit ecabf7575e
2 changed files with 167 additions and 2 deletions

View File

@ -12,7 +12,7 @@
extern crate alloc;
mod status;
pub use status::{Status, StatusBuilder};
pub use status::{Status, StatusBuilder, StatusEth69};
pub mod version;
pub use version::{EthVersion, ProtocolVersion};

View File

@ -213,9 +213,97 @@ impl StatusBuilder {
}
}
/// Similar to [`Status`], but for `eth/69` version, which does not contain
/// the `total_difficulty` field.
#[derive(Copy, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
#[add_arbitrary_tests(rlp)]
pub struct StatusEth69 {
/// The current protocol version.
/// Here, version is `eth/69`.
pub version: EthVersion,
/// The chain id, as introduced in
/// [EIP155](https://eips.ethereum.org/EIPS/eip-155#list-of-chain-ids).
pub chain: Chain,
/// The highest difficulty block hash the peer has seen
pub blockhash: B256,
/// The genesis hash of the peer's chain.
pub genesis: B256,
/// The fork identifier, a [CRC32
/// checksum](https://en.wikipedia.org/wiki/Cyclic_redundancy_check#CRC-32_algorithm) for
/// identifying the peer's fork as defined by
/// [EIP-2124](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2124.md).
/// This was added in [`eth/64`](https://eips.ethereum.org/EIPS/eip-2364)
pub forkid: ForkId,
}
impl Display for StatusEth69 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let hexed_blockhash = hex::encode(self.blockhash);
let hexed_genesis = hex::encode(self.genesis);
write!(
f,
"Status {{ version: {}, chain: {}, blockhash: {}, genesis: {}, forkid: {:X?} }}",
self.version, self.chain, hexed_blockhash, hexed_genesis, self.forkid
)
}
}
impl Debug for StatusEth69 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let hexed_blockhash = hex::encode(self.blockhash);
let hexed_genesis = hex::encode(self.genesis);
if f.alternate() {
write!(
f,
"Status {{\n\tversion: {:?},\n\tchain: {:?},\n\tblockhash: {},\n\tgenesis: {},\n\tforkid: {:X?}\n}}",
self.version,
self.chain,
hexed_blockhash,
hexed_genesis,
self.forkid
)
} else {
write!(
f,
"Status {{ version: {:?}, chain: {:?}, blockhash: {}, genesis: {}, forkid: {:X?} }}",
self.version,
self.chain,
hexed_blockhash,
hexed_genesis,
self.forkid
)
}
}
}
// <https://etherscan.io/block/0>
impl Default for StatusEth69 {
fn default() -> Self {
Status::default().into()
}
}
impl From<Status> for StatusEth69 {
fn from(status: Status) -> Self {
Self {
version: EthVersion::Eth69,
chain: status.chain,
blockhash: status.blockhash,
genesis: status.genesis,
forkid: status.forkid,
}
}
}
#[cfg(test)]
mod tests {
use crate::{EthVersion, Status};
use crate::{EthVersion, Status, StatusEth69};
use alloy_consensus::constants::MAINNET_GENESIS_HASH;
use alloy_genesis::Genesis;
use alloy_primitives::{hex, B256, U256};
@ -263,6 +351,83 @@ mod tests {
assert_eq!(status, expected);
}
#[test]
fn test_status_to_statuseth69_conversion() {
let status = StatusEth69 {
version: EthVersion::Eth69,
chain: Chain::from_named(NamedChain::Mainnet),
blockhash: B256::from_str(
"feb27336ca7923f8fab3bd617fcb6e75841538f71c1bcfc267d7838489d9e13d",
)
.unwrap(),
genesis: MAINNET_GENESIS_HASH,
forkid: ForkId { hash: ForkHash([0xb7, 0x15, 0x07, 0x7d]), next: 0 },
};
let status_converted: StatusEth69 = Status {
version: EthVersion::Eth69,
chain: Chain::from_named(NamedChain::Mainnet),
total_difficulty: U256::from(36206751599115524359527u128),
blockhash: B256::from_str(
"feb27336ca7923f8fab3bd617fcb6e75841538f71c1bcfc267d7838489d9e13d",
)
.unwrap(),
genesis: MAINNET_GENESIS_HASH,
forkid: ForkId { hash: ForkHash([0xb7, 0x15, 0x07, 0x7d]), next: 0 },
}
.into();
assert_eq!(status, status_converted);
}
#[test]
fn encode_eth69_status_message() {
let expected = hex!("f84b4501a0feb27336ca7923f8fab3bd617fcb6e75841538f71c1bcfc267d7838489d9e13da0d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3c684b715077d80");
let status = StatusEth69 {
version: EthVersion::Eth69,
chain: Chain::from_named(NamedChain::Mainnet),
blockhash: B256::from_str(
"feb27336ca7923f8fab3bd617fcb6e75841538f71c1bcfc267d7838489d9e13d",
)
.unwrap(),
genesis: MAINNET_GENESIS_HASH,
forkid: ForkId { hash: ForkHash([0xb7, 0x15, 0x07, 0x7d]), next: 0 },
};
let mut rlp_status = vec![];
status.encode(&mut rlp_status);
assert_eq!(rlp_status, expected);
let status: StatusEth69 = Status::builder()
.chain(Chain::from_named(NamedChain::Mainnet))
.blockhash(
B256::from_str("feb27336ca7923f8fab3bd617fcb6e75841538f71c1bcfc267d7838489d9e13d")
.unwrap(),
)
.genesis(MAINNET_GENESIS_HASH)
.forkid(ForkId { hash: ForkHash([0xb7, 0x15, 0x07, 0x7d]), next: 0 })
.build()
.into();
let mut rlp_status = vec![];
status.encode(&mut rlp_status);
assert_eq!(rlp_status, expected);
}
#[test]
fn decode_eth69_status_message() {
let data = hex!("0xf84b4501a0feb27336ca7923f8fab3bd617fcb6e75841538f71c1bcfc267d7838489d9e13da0d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3c684b715077d80");
let expected = StatusEth69 {
version: EthVersion::Eth69,
chain: Chain::from_named(NamedChain::Mainnet),
blockhash: B256::from_str(
"feb27336ca7923f8fab3bd617fcb6e75841538f71c1bcfc267d7838489d9e13d",
)
.unwrap(),
genesis: MAINNET_GENESIS_HASH,
forkid: ForkId { hash: ForkHash([0xb7, 0x15, 0x07, 0x7d]), next: 0 },
};
let status = StatusEth69::decode(&mut &data[..]).unwrap();
assert_eq!(status, expected);
}
#[test]
fn encode_network_status_message() {
let expected = hex!("f850423884024190faa0f8514c4680ef27700751b08f37645309ce65a449616a3ea966bf39dd935bb27ba00d21840abff46b96c84b2ac9e10e4f5cdaeb5693cb665db62a2f3b02d2d57b5bc6845d43d2fd80");