reth_eth_wire_types/
capability.rs1use crate::{EthMessageID, EthVersion, SnapVersion};
4use alloc::{borrow::Cow, string::String, vec::Vec};
5use alloy_primitives::bytes::Bytes;
6use alloy_rlp::{Decodable, Encodable, RlpDecodable, RlpEncodable};
7use bytes::BufMut;
8use core::fmt;
9use reth_codecs_derive::add_arbitrary_tests;
10
11#[derive(Debug, Clone, Eq, PartialEq)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct RawCapabilityMessage {
15 pub id: usize,
17 pub payload: Bytes,
19}
20
21impl RawCapabilityMessage {
22 pub const fn new(id: usize, payload: Bytes) -> Self {
24 Self { id, payload }
25 }
26
27 pub const fn eth(id: EthMessageID, payload: Bytes) -> Self {
33 Self::new(id.to_u8() as usize, payload)
34 }
35}
36
37impl Encodable for RawCapabilityMessage {
38 fn encode(&self, out: &mut dyn BufMut) {
40 self.id.encode(out);
41 out.put_slice(&self.payload);
42 }
43
44 fn length(&self) -> usize {
46 self.id.length() + self.payload.len()
47 }
48}
49
50impl Decodable for RawCapabilityMessage {
51 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
53 let id = usize::decode(buf)?;
54 let payload = Bytes::copy_from_slice(buf);
55 *buf = &buf[buf.len()..];
56
57 Ok(Self { id, payload })
58 }
59}
60
61#[add_arbitrary_tests(rlp)]
63#[derive(Clone, Debug, PartialEq, Eq, RlpEncodable, RlpDecodable, Default, Hash)]
64#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
65pub struct Capability {
66 pub name: Cow<'static, str>,
68 pub version: usize,
70}
71
72impl Capability {
73 pub const fn new(name: String, version: usize) -> Self {
75 Self { name: Cow::Owned(name), version }
76 }
77
78 pub const fn new_static(name: &'static str, version: usize) -> Self {
80 Self { name: Cow::Borrowed(name), version }
81 }
82
83 pub const fn eth(version: EthVersion) -> Self {
85 Self::new_static("eth", version as usize)
86 }
87
88 pub const fn snap(version: SnapVersion) -> Self {
90 Self::new_static("snap", version as usize)
91 }
92
93 pub const fn eth_66() -> Self {
95 Self::eth(EthVersion::Eth66)
96 }
97
98 pub const fn eth_67() -> Self {
100 Self::eth(EthVersion::Eth67)
101 }
102
103 pub const fn eth_68() -> Self {
105 Self::eth(EthVersion::Eth68)
106 }
107
108 pub const fn eth_69() -> Self {
110 Self::eth(EthVersion::Eth69)
111 }
112
113 pub const fn eth_70() -> Self {
115 Self::eth(EthVersion::Eth70)
116 }
117
118 pub const fn eth_71() -> Self {
120 Self::eth(EthVersion::Eth71)
121 }
122
123 pub const fn eth_72() -> Self {
125 Self::eth(EthVersion::Eth72)
126 }
127
128 pub const fn snap_1() -> Self {
130 Self::snap(SnapVersion::V1)
131 }
132
133 pub const fn snap_2() -> Self {
135 Self::snap(SnapVersion::V2)
136 }
137
138 #[inline]
140 pub fn is_eth_v66(&self) -> bool {
141 self.name == "eth" && self.version == 66
142 }
143
144 #[inline]
146 pub fn is_eth_v67(&self) -> bool {
147 self.name == "eth" && self.version == 67
148 }
149
150 #[inline]
152 pub fn is_eth_v68(&self) -> bool {
153 self.name == "eth" && self.version == 68
154 }
155
156 #[inline]
158 pub fn is_eth_v69(&self) -> bool {
159 self.name == "eth" && self.version == 69
160 }
161
162 #[inline]
164 pub fn is_eth_v70(&self) -> bool {
165 self.name == "eth" && self.version == 70
166 }
167
168 #[inline]
170 pub fn is_eth_v71(&self) -> bool {
171 self.name == "eth" && self.version == 71
172 }
173
174 #[inline]
176 pub fn is_eth_v72(&self) -> bool {
177 self.name == "eth" && self.version == 72
178 }
179
180 #[inline]
182 pub fn is_eth(&self) -> bool {
183 self.is_eth_v66() ||
184 self.is_eth_v67() ||
185 self.is_eth_v68() ||
186 self.is_eth_v69() ||
187 self.is_eth_v70() ||
188 self.is_eth_v71() ||
189 self.is_eth_v72()
190 }
191}
192
193impl fmt::Display for Capability {
194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195 write!(f, "{}/{}", self.name, self.version)
196 }
197}
198
199impl From<EthVersion> for Capability {
200 #[inline]
201 fn from(value: EthVersion) -> Self {
202 Self::eth(value)
203 }
204}
205
206#[cfg(any(test, feature = "arbitrary"))]
207impl<'a> arbitrary::Arbitrary<'a> for Capability {
208 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
209 let version = u.int_in_range(66..=71)?; Ok(Self::new_static("eth", version))
212 }
213}
214
215#[derive(Debug, Clone, Eq, PartialEq)]
217pub struct Capabilities {
218 inner: Vec<Capability>,
220 eth_66: bool,
221 eth_67: bool,
222 eth_68: bool,
223 eth_69: bool,
224 eth_70: bool,
225 eth_71: bool,
226 eth_72: bool,
227}
228
229impl Capabilities {
230 pub fn new(value: Vec<Capability>) -> Self {
232 Self {
233 eth_66: value.iter().any(Capability::is_eth_v66),
234 eth_67: value.iter().any(Capability::is_eth_v67),
235 eth_68: value.iter().any(Capability::is_eth_v68),
236 eth_69: value.iter().any(Capability::is_eth_v69),
237 eth_70: value.iter().any(Capability::is_eth_v70),
238 eth_71: value.iter().any(Capability::is_eth_v71),
239 eth_72: value.iter().any(Capability::is_eth_v72),
240 inner: value,
241 }
242 }
243
244 pub const fn supports_eth_at_least(&self, version: &EthVersion) -> bool {
254 match version {
255 EthVersion::Eth66 => {
256 self.eth_66 ||
257 self.eth_67 ||
258 self.eth_68 ||
259 self.eth_69 ||
260 self.eth_70 ||
261 self.eth_71 ||
262 self.eth_72
263 }
264 EthVersion::Eth67 => {
265 self.eth_67 ||
266 self.eth_68 ||
267 self.eth_69 ||
268 self.eth_70 ||
269 self.eth_71 ||
270 self.eth_72
271 }
272 EthVersion::Eth68 => {
273 self.eth_68 || self.eth_69 || self.eth_70 || self.eth_71 || self.eth_72
274 }
275 EthVersion::Eth69 => self.eth_69 || self.eth_70 || self.eth_71 || self.eth_72,
276 EthVersion::Eth70 => self.eth_70 || self.eth_71 || self.eth_72,
277 EthVersion::Eth71 => self.eth_71 || self.eth_72,
278 EthVersion::Eth72 => self.eth_72,
279 }
280 }
281
282 #[inline]
284 pub fn capabilities(&self) -> &[Capability] {
285 &self.inner
286 }
287
288 #[inline]
290 pub fn into_inner(self) -> Vec<Capability> {
291 self.inner
292 }
293
294 #[inline]
296 pub const fn supports_eth(&self) -> bool {
297 self.eth_71 || self.eth_70 || self.eth_69 || self.eth_68 || self.eth_67 || self.eth_66
298 }
299
300 #[inline]
302 pub const fn supports_eth_v66(&self) -> bool {
303 self.eth_66
304 }
305
306 #[inline]
308 pub const fn supports_eth_v67(&self) -> bool {
309 self.eth_67
310 }
311
312 #[inline]
314 pub const fn supports_eth_v68(&self) -> bool {
315 self.eth_68
316 }
317
318 #[inline]
320 pub const fn supports_eth_v69(&self) -> bool {
321 self.eth_69
322 }
323
324 #[inline]
326 pub const fn supports_eth_v70(&self) -> bool {
327 self.eth_70
328 }
329
330 #[inline]
332 pub const fn supports_eth_v71(&self) -> bool {
333 self.eth_71
334 }
335}
336
337impl From<Vec<Capability>> for Capabilities {
338 fn from(value: Vec<Capability>) -> Self {
339 Self::new(value)
340 }
341}
342
343impl Encodable for Capabilities {
344 fn encode(&self, out: &mut dyn BufMut) {
345 self.inner.encode(out)
346 }
347}
348
349impl Decodable for Capabilities {
350 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
351 let inner = Vec::<Capability>::decode(buf)?;
352
353 Ok(Self {
354 eth_66: inner.iter().any(Capability::is_eth_v66),
355 eth_67: inner.iter().any(Capability::is_eth_v67),
356 eth_68: inner.iter().any(Capability::is_eth_v68),
357 eth_69: inner.iter().any(Capability::is_eth_v69),
358 eth_70: inner.iter().any(Capability::is_eth_v70),
359 eth_71: inner.iter().any(Capability::is_eth_v71),
360 eth_72: inner.iter().any(Capability::is_eth_v72),
361 inner,
362 })
363 }
364}