Skip to main content

reth_eth_wire/
protocol.rs

1//! A Protocol defines a P2P subprotocol in an `RLPx` connection
2
3use crate::{Capability, EthMessageID, EthVersion, SnapVersion};
4
5/// Type that represents a [Capability] and the number of messages it uses.
6///
7/// Only the [Capability] is shared with the remote peer, assuming both parties know the number of
8/// messages used by the protocol which is used for message ID multiplexing.
9#[derive(Clone, Debug, PartialEq, Eq, Hash)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct Protocol {
12    /// The name of the subprotocol
13    pub cap: Capability,
14    /// The number of messages used/reserved by this protocol
15    ///
16    /// This is used for message ID multiplexing
17    messages: u8,
18}
19
20impl Protocol {
21    /// Create a new protocol with the given name and number of messages
22    pub const fn new(cap: Capability, messages: u8) -> Self {
23        Self { cap, messages }
24    }
25
26    /// Returns the corresponding eth capability for the given version.
27    pub const fn eth(version: EthVersion) -> Self {
28        let cap = Capability::eth(version);
29        let messages = EthMessageID::message_count(version);
30        Self::new(cap, messages)
31    }
32
33    /// Returns the corresponding snap capability for the given version.
34    pub const fn snap(version: SnapVersion) -> Self {
35        let cap = Capability::snap(version);
36        let messages = version.message_count();
37        Self::new(cap, messages)
38    }
39
40    /// Returns the [`EthVersion::Eth66`] capability.
41    pub const fn eth_66() -> Self {
42        Self::eth(EthVersion::Eth66)
43    }
44
45    /// Returns the [`EthVersion::Eth67`] capability.
46    pub const fn eth_67() -> Self {
47        Self::eth(EthVersion::Eth67)
48    }
49
50    /// Returns the [`EthVersion::Eth68`] capability.
51    pub const fn eth_68() -> Self {
52        Self::eth(EthVersion::Eth68)
53    }
54
55    /// Returns the `snap/2` capability.
56    pub const fn snap_2() -> Self {
57        Self::snap(SnapVersion::V2)
58    }
59
60    /// Consumes the type and returns a tuple of the [Capability] and number of messages.
61    #[inline]
62    pub(crate) fn split(self) -> (Capability, u8) {
63        (self.cap, self.messages)
64    }
65
66    /// The number of values needed to represent all message IDs of capability.
67    pub const fn messages(&self) -> u8 {
68        self.messages
69    }
70}
71
72/// Local limits for inbound messages of an `RLPx` subprotocol.
73///
74/// These limits are not advertised to the remote peer and do not affect message ID negotiation.
75#[derive(Clone, Copy, Debug, PartialEq, Eq)]
76pub struct ProtocolIngressLimits {
77    max_frame_bytes: Option<usize>,
78    max_buffered_bytes: usize,
79    max_buffered_messages: usize,
80}
81
82impl ProtocolIngressLimits {
83    /// Default byte budget for messages waiting to be polled by a protocol connection.
84    pub const DEFAULT_MAX_BUFFERED_BYTES: usize = 32 * 1024 * 1024;
85
86    /// Default message budget for messages waiting to be polled by a protocol connection.
87    pub const DEFAULT_MAX_BUFFERED_MESSAGES: usize = 1024;
88
89    /// Creates limits with an explicit maximum inbound frame size.
90    ///
91    /// The frame size includes the capability-local message ID byte.
92    ///
93    /// # Panics
94    ///
95    /// Panics if `max_frame_bytes` is zero.
96    pub const fn new(max_frame_bytes: usize) -> Self {
97        assert!(max_frame_bytes > 0, "maximum frame size must be non-zero");
98        Self { max_frame_bytes: Some(max_frame_bytes), ..Self::default_values() }
99    }
100
101    /// Sets the maximum number of buffered frame bytes.
102    ///
103    /// # Panics
104    ///
105    /// Panics if `max_buffered_bytes` is zero.
106    pub const fn with_max_buffered_bytes(mut self, max_buffered_bytes: usize) -> Self {
107        assert!(max_buffered_bytes > 0, "maximum buffered bytes must be non-zero");
108        self.max_buffered_bytes = max_buffered_bytes;
109        self
110    }
111
112    /// Sets the maximum number of buffered messages.
113    ///
114    /// # Panics
115    ///
116    /// Panics if `max_buffered_messages` is zero.
117    pub const fn with_max_buffered_messages(mut self, max_buffered_messages: usize) -> Self {
118        assert!(max_buffered_messages > 0, "maximum buffered messages must be non-zero");
119        self.max_buffered_messages = max_buffered_messages;
120        self
121    }
122
123    /// Returns the explicit maximum inbound frame size, if configured.
124    pub const fn max_frame_bytes(&self) -> Option<usize> {
125        self.max_frame_bytes
126    }
127
128    /// Returns the maximum number of buffered frame bytes.
129    pub const fn max_buffered_bytes(&self) -> usize {
130        self.max_buffered_bytes
131    }
132
133    /// Returns the maximum number of buffered messages.
134    pub const fn max_buffered_messages(&self) -> usize {
135        self.max_buffered_messages
136    }
137
138    const fn default_values() -> Self {
139        Self {
140            max_frame_bytes: None,
141            max_buffered_bytes: Self::DEFAULT_MAX_BUFFERED_BYTES,
142            max_buffered_messages: Self::DEFAULT_MAX_BUFFERED_MESSAGES,
143        }
144    }
145}
146
147impl Default for ProtocolIngressLimits {
148    fn default() -> Self {
149        Self::default_values()
150    }
151}
152
153impl From<EthVersion> for Protocol {
154    fn from(version: EthVersion) -> Self {
155        Self::eth(version)
156    }
157}
158
159/// A helper type to keep track of the protocol version and number of messages used by the protocol.
160#[derive(Clone, Debug, PartialEq, Eq, Hash)]
161pub(crate) struct ProtoVersion {
162    /// Number of messages for a protocol
163    pub(crate) messages: u8,
164    /// Version of the protocol
165    pub(crate) version: usize,
166}
167
168#[cfg(test)]
169mod tests {
170    use super::*;
171
172    #[test]
173    fn test_protocol_eth_message_count() {
174        // Test that Protocol::eth() returns correct message counts for each version
175        // This ensures that EthMessageID::message_count() produces the expected results
176        assert_eq!(Protocol::eth(EthVersion::Eth66).messages(), 17);
177        assert_eq!(Protocol::eth(EthVersion::Eth67).messages(), 17);
178        assert_eq!(Protocol::eth(EthVersion::Eth68).messages(), 17);
179        assert_eq!(Protocol::eth(EthVersion::Eth69).messages(), 18);
180        assert_eq!(Protocol::eth(EthVersion::Eth70).messages(), 18);
181        assert_eq!(Protocol::eth(EthVersion::Eth71).messages(), 20);
182        assert_eq!(Protocol::snap(SnapVersion::V2).messages(), 10);
183    }
184}