Skip to content
Closed
Show file tree
Hide file tree
Changes from 6 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
56 changes: 56 additions & 0 deletions crates/net/eth-wire-types/src/block_range.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//! Block range related types introduced in eth/70 (EIP-7975).

use alloy_rlp::{RlpDecodable, RlpEncodable};
use reth_codecs_derive::add_arbitrary_tests;

/// The block range a peer can currently serve (inclusive bounds).
#[derive(Clone, Copy, Debug, 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 BlockRange {
/// Earliest block number the peer can serve.
pub start_block: u64,
/// Latest block number the peer can serve.
pub end_block: u64,
}

impl BlockRange {
/// Returns true if the start/end pair forms a valid range.
pub const fn is_valid(&self) -> bool {
self.start_block <= self.end_block
}
}

/// eth/70 request for the peer's current block range.
///
/// The payload is empty; the request id is carried by the [`crate::message::RequestPair`].
#[derive(Clone, Copy, Debug, Default, 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 RequestBlockRange;

/// eth/70 response to [`RequestBlockRange`].
#[derive(Clone, Copy, Debug, 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 SendBlockRange {
/// The earliest block which is available.
pub start_block: u64,
/// The latest block which is available.
pub end_block: u64,
}

impl SendBlockRange {
/// Returns the contained range.
pub const fn as_range(&self) -> BlockRange {
BlockRange { start_block: self.start_block, end_block: self.end_block }
}

/// Constructs from a [`BlockRange`].
pub const fn from_range(range: BlockRange) -> Self {
Self { start_block: range.start_block, end_block: range.end_block }
}
}
2 changes: 1 addition & 1 deletion crates/net/eth-wire-types/src/broadcast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ impl NewPooledTransactionHashes {
matches!(version, EthVersion::Eth67 | EthVersion::Eth66)
}
Self::Eth68(_) => {
matches!(version, EthVersion::Eth68 | EthVersion::Eth69)
matches!(version, EthVersion::Eth68 | EthVersion::Eth69 | EthVersion::Eth70)
}
}
}
Expand Down
50 changes: 47 additions & 3 deletions crates/net/eth-wire-types/src/capability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,16 @@ impl Capability {
Self::eth(EthVersion::Eth68)
}

/// Returns the [`EthVersion::Eth69`] capability.
pub const fn eth_69() -> Self {
Self::eth(EthVersion::Eth69)
}

/// Returns the [`EthVersion::Eth70`] capability.
pub const fn eth_70() -> Self {
Self::eth(EthVersion::Eth70)
}

/// Whether this is eth v66 protocol.
#[inline]
pub fn is_eth_v66(&self) -> bool {
Expand All @@ -118,10 +128,26 @@ impl Capability {
self.name == "eth" && self.version == 68
}

/// Whether this is eth v69.
#[inline]
pub fn is_eth_v69(&self) -> bool {
self.name == "eth" && self.version == 69
}

/// Whether this is eth v70.
#[inline]
pub fn is_eth_v70(&self) -> bool {
self.name == "eth" && self.version == 70
}

/// Whether this is any eth version.
#[inline]
pub fn is_eth(&self) -> bool {
self.is_eth_v66() || self.is_eth_v67() || self.is_eth_v68()
self.is_eth_v66() ||
self.is_eth_v67() ||
self.is_eth_v68() ||
self.is_eth_v69() ||
self.is_eth_v70()
}
}

Expand All @@ -141,7 +167,7 @@ impl From<EthVersion> for Capability {
#[cfg(any(test, feature = "arbitrary"))]
impl<'a> arbitrary::Arbitrary<'a> for Capability {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
let version = u.int_in_range(66..=69)?; // Valid eth protocol versions are 66-69
let version = u.int_in_range(66..=70)?; // Valid eth protocol versions are 66-70
// Only generate valid eth protocol name for now since it's the only supported protocol
Ok(Self::new_static("eth", version))
}
Expand All @@ -155,6 +181,8 @@ pub struct Capabilities {
eth_66: bool,
eth_67: bool,
eth_68: bool,
eth_69: bool,
eth_70: bool,
}

impl Capabilities {
Expand All @@ -164,6 +192,8 @@ impl Capabilities {
eth_66: value.iter().any(Capability::is_eth_v66),
eth_67: value.iter().any(Capability::is_eth_v67),
eth_68: value.iter().any(Capability::is_eth_v68),
eth_69: value.iter().any(Capability::is_eth_v69),
eth_70: value.iter().any(Capability::is_eth_v70),
inner: value,
}
}
Expand All @@ -182,7 +212,7 @@ impl Capabilities {
/// Whether the peer supports `eth` sub-protocol.
#[inline]
pub const fn supports_eth(&self) -> bool {
self.eth_68 || self.eth_67 || self.eth_66
self.eth_70 || self.eth_69 || self.eth_68 || self.eth_67 || self.eth_66
}

/// Whether this peer supports eth v66 protocol.
Expand All @@ -202,6 +232,18 @@ impl Capabilities {
pub const fn supports_eth_v68(&self) -> bool {
self.eth_68
}

/// Whether this peer supports eth v69 protocol.
#[inline]
pub const fn supports_eth_v69(&self) -> bool {
self.eth_69
}

/// Whether this peer supports eth v70 protocol.
#[inline]
pub const fn supports_eth_v70(&self) -> bool {
self.eth_70
}
}

impl From<Vec<Capability>> for Capabilities {
Expand All @@ -224,6 +266,8 @@ impl Decodable for Capabilities {
eth_66: inner.iter().any(Capability::is_eth_v66),
eth_67: inner.iter().any(Capability::is_eth_v67),
eth_68: inner.iter().any(Capability::is_eth_v68),
eth_69: inner.iter().any(Capability::is_eth_v69),
eth_70: inner.iter().any(Capability::is_eth_v70),
inner,
})
}
Expand Down
5 changes: 4 additions & 1 deletion crates/net/eth-wire-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
extern crate alloc;

mod status;
pub use status::{Status, StatusBuilder, StatusEth69, StatusMessage, UnifiedStatus};
pub use status::{Status, StatusBuilder, StatusEth69, StatusEth70, StatusMessage, UnifiedStatus};

mod block_range;
pub use block_range::{BlockRange, RequestBlockRange, SendBlockRange};

pub mod version;
pub use version::{EthVersion, ProtocolVersion};
Expand Down
60 changes: 48 additions & 12 deletions crates/net/eth-wire-types/src/message.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Implements Ethereum wire protocol for versions 66, 67, and 68.
//! Implements Ethereum wire protocol for versions 66 through 70.
//! Defines structs/enums for messages, request-response pairs, and broadcasts.
//! Handles compatibility with [`EthVersion`].
//!
Expand All @@ -9,8 +9,8 @@
use super::{
broadcast::NewBlockHashes, BlockBodies, BlockHeaders, GetBlockBodies, GetBlockHeaders,
GetNodeData, GetPooledTransactions, GetReceipts, NewPooledTransactionHashes66,
NewPooledTransactionHashes68, NodeData, PooledTransactions, Receipts, Status, StatusEth69,
Transactions,
NewPooledTransactionHashes68, NodeData, PooledTransactions, Receipts, RequestBlockRange,
SendBlockRange, Status, StatusEth69, StatusEth70, Transactions,
};
use crate::{
status::StatusMessage, BlockRangeUpdate, EthNetworkPrimitives, EthVersion, NetworkPrimitives,
Expand Down Expand Up @@ -66,10 +66,12 @@ impl<N: NetworkPrimitives> ProtocolMessage<N> {
// For EIP-7642 (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7642.md):
// pre-merge (legacy) status messages include total difficulty, whereas eth/69 omits it.
let message = match message_type {
EthMessageID::Status => EthMessage::Status(if version < EthVersion::Eth69 {
StatusMessage::Legacy(Status::decode(buf)?)
} else {
EthMessageID::Status => EthMessage::Status(if version >= EthVersion::Eth70 {
StatusMessage::Eth70(StatusEth70::decode(buf)?)
} else if version >= EthVersion::Eth69 {
StatusMessage::Eth69(StatusEth69::decode(buf)?)
} else {
StatusMessage::Legacy(Status::decode(buf)?)
}),
EthMessageID::NewBlockHashes => {
EthMessage::NewBlockHashes(NewBlockHashes::decode(buf)?)
Expand Down Expand Up @@ -99,6 +101,18 @@ impl<N: NetworkPrimitives> ProtocolMessage<N> {
EthMessageID::PooledTransactions => {
EthMessage::PooledTransactions(RequestPair::decode(buf)?)
}
EthMessageID::RequestBlockRange => {
if version < EthVersion::Eth70 {
return Err(MessageError::Invalid(version, EthMessageID::RequestBlockRange))
}
EthMessage::RequestBlockRange(RequestPair::decode(buf)?)
}
EthMessageID::SendBlockRange => {
if version < EthVersion::Eth70 {
return Err(MessageError::Invalid(version, EthMessageID::SendBlockRange))
}
EthMessage::SendBlockRange(RequestPair::decode(buf)?)
}
EthMessageID::GetNodeData => {
if version >= EthVersion::Eth67 {
return Err(MessageError::Invalid(version, EthMessageID::GetNodeData))
Expand Down Expand Up @@ -205,6 +219,9 @@ impl<N: NetworkPrimitives> From<EthBroadcastMessage<N>> for ProtocolBroadcastMes
///
/// The `eth/69` announces the historical block range served by the node. Removes total difficulty
/// information. And removes the Bloom field from receipts transferred over the protocol.
///
/// The `eth/70` (EIP-7975) extends `Status` with `blockRange` and adds `RequestBlockRange` /
/// `SendBlockRange` messages to query/announce the currently served block interval.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum EthMessage<N: NetworkPrimitives = EthNetworkPrimitives> {
Expand Down Expand Up @@ -253,6 +270,10 @@ pub enum EthMessage<N: NetworkPrimitives = EthNetworkPrimitives> {
serde(bound = "N::PooledTransaction: serde::Serialize + serde::de::DeserializeOwned")
)]
PooledTransactions(RequestPair<PooledTransactions<N::PooledTransaction>>),
/// Represents a `RequestBlockRange` request-response pair.
RequestBlockRange(RequestPair<RequestBlockRange>),
/// Represents a `SendBlockRange` request-response pair.
SendBlockRange(RequestPair<SendBlockRange>),
/// Represents a `GetNodeData` request-response pair.
GetNodeData(RequestPair<GetNodeData>),
/// Represents a `NodeData` request-response pair.
Expand Down Expand Up @@ -298,6 +319,8 @@ impl<N: NetworkPrimitives> EthMessage<N> {
Self::BlockBodies(_) => EthMessageID::BlockBodies,
Self::GetPooledTransactions(_) => EthMessageID::GetPooledTransactions,
Self::PooledTransactions(_) => EthMessageID::PooledTransactions,
Self::RequestBlockRange(_) => EthMessageID::RequestBlockRange,
Self::SendBlockRange(_) => EthMessageID::SendBlockRange,
Self::GetNodeData(_) => EthMessageID::GetNodeData,
Self::NodeData(_) => EthMessageID::NodeData,
Self::GetReceipts(_) => EthMessageID::GetReceipts,
Expand All @@ -315,7 +338,8 @@ impl<N: NetworkPrimitives> EthMessage<N> {
Self::GetBlockHeaders(_) |
Self::GetReceipts(_) |
Self::GetPooledTransactions(_) |
Self::GetNodeData(_)
Self::GetNodeData(_) |
Self::RequestBlockRange(_)
)
}

Expand All @@ -328,7 +352,8 @@ impl<N: NetworkPrimitives> EthMessage<N> {
Self::Receipts69(_) |
Self::BlockHeaders(_) |
Self::BlockBodies(_) |
Self::NodeData(_)
Self::NodeData(_) |
Self::SendBlockRange(_)
)
}
}
Expand All @@ -348,6 +373,8 @@ impl<N: NetworkPrimitives> Encodable for EthMessage<N> {
Self::BlockBodies(bodies) => bodies.encode(out),
Self::GetPooledTransactions(request) => request.encode(out),
Self::PooledTransactions(transactions) => transactions.encode(out),
Self::RequestBlockRange(request) => request.encode(out),
Self::SendBlockRange(range) => range.encode(out),
Self::GetNodeData(request) => request.encode(out),
Self::NodeData(data) => data.encode(out),
Self::GetReceipts(request) => request.encode(out),
Expand All @@ -371,6 +398,8 @@ impl<N: NetworkPrimitives> Encodable for EthMessage<N> {
Self::BlockBodies(bodies) => bodies.length(),
Self::GetPooledTransactions(request) => request.length(),
Self::PooledTransactions(transactions) => transactions.length(),
Self::RequestBlockRange(request) => request.length(),
Self::SendBlockRange(range) => range.length(),
Self::GetNodeData(request) => request.length(),
Self::NodeData(data) => data.length(),
Self::GetReceipts(request) => request.length(),
Expand Down Expand Up @@ -452,6 +481,10 @@ pub enum EthMessageID {
GetPooledTransactions = 0x09,
/// Represents pooled transactions.
PooledTransactions = 0x0a,
/// Requests block range (eth/70).
RequestBlockRange = 0x0b,
/// Responds with block range (eth/70).
SendBlockRange = 0x0c,
/// Requests node data.
GetNodeData = 0x0d,
/// Represents node data.
Expand Down Expand Up @@ -483,6 +516,8 @@ impl EthMessageID {
Self::NewPooledTransactionHashes => 0x08,
Self::GetPooledTransactions => 0x09,
Self::PooledTransactions => 0x0a,
Self::RequestBlockRange => 0x0b,
Self::SendBlockRange => 0x0c,
Self::GetNodeData => 0x0d,
Self::NodeData => 0x0e,
Self::GetReceipts => 0x0f,
Expand All @@ -494,10 +529,9 @@ impl EthMessageID {

/// Returns the max value for the given version.
pub const fn max(version: EthVersion) -> u8 {
if version.is_eth69() {
Self::BlockRangeUpdate.to_u8()
} else {
Self::Receipts.to_u8()
match version {
EthVersion::Eth70 | EthVersion::Eth69 => Self::BlockRangeUpdate.to_u8(),
_ => Self::Receipts.to_u8(),
}
}

Expand Down Expand Up @@ -562,6 +596,8 @@ impl TryFrom<usize> for EthMessageID {
0x08 => Ok(Self::NewPooledTransactionHashes),
0x09 => Ok(Self::GetPooledTransactions),
0x0a => Ok(Self::PooledTransactions),
0x0b => Ok(Self::RequestBlockRange),
0x0c => Ok(Self::SendBlockRange),
0x0d => Ok(Self::GetNodeData),
0x0e => Ok(Self::NodeData),
0x0f => Ok(Self::GetReceipts),
Expand Down
Loading
Loading