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 pub fn encoded(&self) -> Bytes {
38 alloy_rlp::encode(self).into()
39 }
40}
41
42impl Encodable for RawCapabilityMessage {
43 fn encode(&self, out: &mut dyn BufMut) {
45 self.id.encode(out);
46 out.put_slice(&self.payload);
47 }
48
49 fn length(&self) -> usize {
51 self.id.length() + self.payload.len()
52 }
53}
54
55impl Decodable for RawCapabilityMessage {
56 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
58 let id = usize::decode(buf)?;
59 let payload = Bytes::copy_from_slice(buf);
60 *buf = &buf[buf.len()..];
61
62 Ok(Self { id, payload })
63 }
64}
65
66#[add_arbitrary_tests(rlp)]
68#[derive(Clone, Debug, PartialEq, Eq, RlpEncodable, RlpDecodable, Default, Hash)]
69#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
70pub struct Capability {
71 pub name: Cow<'static, str>,
73 pub version: usize,
75}
76
77impl Capability {
78 pub const fn new(name: String, version: usize) -> Self {
80 Self { name: Cow::Owned(name), version }
81 }
82
83 pub const fn new_static(name: &'static str, version: usize) -> Self {
85 Self { name: Cow::Borrowed(name), version }
86 }
87
88 pub const fn eth(version: EthVersion) -> Self {
90 Self::new_static("eth", version as usize)
91 }
92
93 pub const fn snap(version: SnapVersion) -> Self {
95 Self::new_static("snap", version as usize)
96 }
97
98 pub const fn eth_66() -> Self {
100 Self::eth(EthVersion::Eth66)
101 }
102
103 pub const fn eth_67() -> Self {
105 Self::eth(EthVersion::Eth67)
106 }
107
108 pub const fn eth_68() -> Self {
110 Self::eth(EthVersion::Eth68)
111 }
112
113 pub const fn eth_69() -> Self {
115 Self::eth(EthVersion::Eth69)
116 }
117
118 pub const fn eth_70() -> Self {
120 Self::eth(EthVersion::Eth70)
121 }
122
123 pub const fn eth_71() -> Self {
125 Self::eth(EthVersion::Eth71)
126 }
127
128 pub const fn eth_72() -> Self {
130 Self::eth(EthVersion::Eth72)
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))
213 }
214}
215
216#[derive(Debug, Clone, Eq, PartialEq)]
218pub struct Capabilities {
219 inner: Vec<Capability>,
221 eth_66: bool,
222 eth_67: bool,
223 eth_68: bool,
224 eth_69: bool,
225 eth_70: bool,
226 eth_71: bool,
227 eth_72: bool,
228}
229
230impl Capabilities {
231 pub fn new(value: Vec<Capability>) -> Self {
233 Self {
234 eth_66: value.iter().any(Capability::is_eth_v66),
235 eth_67: value.iter().any(Capability::is_eth_v67),
236 eth_68: value.iter().any(Capability::is_eth_v68),
237 eth_69: value.iter().any(Capability::is_eth_v69),
238 eth_70: value.iter().any(Capability::is_eth_v70),
239 eth_71: value.iter().any(Capability::is_eth_v71),
240 eth_72: value.iter().any(Capability::is_eth_v72),
241 inner: value,
242 }
243 }
244
245 pub const fn supports_eth_at_least(&self, version: &EthVersion) -> bool {
255 match version {
256 EthVersion::Eth66 => {
257 self.eth_66 ||
258 self.eth_67 ||
259 self.eth_68 ||
260 self.eth_69 ||
261 self.eth_70 ||
262 self.eth_71 ||
263 self.eth_72
264 }
265 EthVersion::Eth67 => {
266 self.eth_67 ||
267 self.eth_68 ||
268 self.eth_69 ||
269 self.eth_70 ||
270 self.eth_71 ||
271 self.eth_72
272 }
273 EthVersion::Eth68 => {
274 self.eth_68 || self.eth_69 || self.eth_70 || self.eth_71 || self.eth_72
275 }
276 EthVersion::Eth69 => self.eth_69 || self.eth_70 || self.eth_71 || self.eth_72,
277 EthVersion::Eth70 => self.eth_70 || self.eth_71 || self.eth_72,
278 EthVersion::Eth71 => self.eth_71 || self.eth_72,
279 EthVersion::Eth72 => self.eth_72,
280 }
281 }
282
283 #[inline]
285 pub fn capabilities(&self) -> &[Capability] {
286 &self.inner
287 }
288
289 #[inline]
291 pub fn into_inner(self) -> Vec<Capability> {
292 self.inner
293 }
294
295 #[inline]
297 pub const fn supports_eth(&self) -> bool {
298 self.eth_72 ||
299 self.eth_71 ||
300 self.eth_70 ||
301 self.eth_69 ||
302 self.eth_68 ||
303 self.eth_67 ||
304 self.eth_66
305 }
306
307 #[inline]
309 pub const fn supports_eth_v66(&self) -> bool {
310 self.eth_66
311 }
312
313 #[inline]
315 pub const fn supports_eth_v67(&self) -> bool {
316 self.eth_67
317 }
318
319 #[inline]
321 pub const fn supports_eth_v68(&self) -> bool {
322 self.eth_68
323 }
324
325 #[inline]
327 pub const fn supports_eth_v69(&self) -> bool {
328 self.eth_69
329 }
330
331 #[inline]
333 pub const fn supports_eth_v70(&self) -> bool {
334 self.eth_70
335 }
336
337 #[inline]
339 pub const fn supports_eth_v71(&self) -> bool {
340 self.eth_71
341 }
342}
343
344impl From<Vec<Capability>> for Capabilities {
345 fn from(value: Vec<Capability>) -> Self {
346 Self::new(value)
347 }
348}
349
350impl Encodable for Capabilities {
351 fn encode(&self, out: &mut dyn BufMut) {
352 self.inner.encode(out)
353 }
354}
355
356impl Decodable for Capabilities {
357 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
358 let inner = Vec::<Capability>::decode(buf)?;
359
360 Ok(Self {
361 eth_66: inner.iter().any(Capability::is_eth_v66),
362 eth_67: inner.iter().any(Capability::is_eth_v67),
363 eth_68: inner.iter().any(Capability::is_eth_v68),
364 eth_69: inner.iter().any(Capability::is_eth_v69),
365 eth_70: inner.iter().any(Capability::is_eth_v70),
366 eth_71: inner.iter().any(Capability::is_eth_v71),
367 eth_72: inner.iter().any(Capability::is_eth_v72),
368 inner,
369 })
370 }
371}