reth_eth_wire_types/
disconnect_reason.rs1use alloc::vec;
4use alloy_primitives::bytes::{Buf, BufMut};
5use alloy_rlp::{Decodable, Encodable, Header};
6use derive_more::Display;
7use reth_codecs_derive::add_arbitrary_tests;
8use thiserror::Error;
9
10#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Display)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
14#[add_arbitrary_tests(rlp)]
15pub enum DisconnectReason {
16 #[default]
18 #[display("disconnect requested")]
19 DisconnectRequested = 0x00,
20 #[display("TCP sub-system error")]
22 TcpSubsystemError = 0x01,
23 #[display("breach of protocol, e.g. a malformed message, bad RLP, etc.")]
25 ProtocolBreach = 0x02,
26 #[display("useless peer")]
28 UselessPeer = 0x03,
29 #[display("too many peers")]
31 TooManyPeers = 0x04,
32 #[display("already connected")]
34 AlreadyConnected = 0x05,
35 #[display("incompatible P2P protocol version")]
37 IncompatibleP2PProtocolVersion = 0x06,
38 #[display("null node identity received - this is automatically invalid")]
40 NullNodeIdentity = 0x07,
41 #[display("client quitting")]
43 ClientQuitting = 0x08,
44 #[display("unexpected identity in handshake")]
46 UnexpectedHandshakeIdentity = 0x09,
47 #[display("identity is the same as this node (i.e. connected to itself)")]
49 ConnectedToSelf = 0x0a,
50 #[display("ping timeout")]
52 PingTimeout = 0x0b,
53 #[display("some other reason specific to a subprotocol")]
55 SubprotocolSpecific = 0x10,
56}
57
58impl TryFrom<u8> for DisconnectReason {
59 type Error = UnknownDisconnectReason;
62
63 fn try_from(value: u8) -> Result<Self, Self::Error> {
64 match value {
65 0x00 => Ok(Self::DisconnectRequested),
66 0x01 => Ok(Self::TcpSubsystemError),
67 0x02 => Ok(Self::ProtocolBreach),
68 0x03 => Ok(Self::UselessPeer),
69 0x04 => Ok(Self::TooManyPeers),
70 0x05 => Ok(Self::AlreadyConnected),
71 0x06 => Ok(Self::IncompatibleP2PProtocolVersion),
72 0x07 => Ok(Self::NullNodeIdentity),
73 0x08 => Ok(Self::ClientQuitting),
74 0x09 => Ok(Self::UnexpectedHandshakeIdentity),
75 0x0a => Ok(Self::ConnectedToSelf),
76 0x0b => Ok(Self::PingTimeout),
77 0x10 => Ok(Self::SubprotocolSpecific),
78 _ => Err(UnknownDisconnectReason(value)),
79 }
80 }
81}
82
83impl Encodable for DisconnectReason {
84 fn encode(&self, out: &mut dyn BufMut) {
87 vec![*self as u8].encode(out);
88 }
89 fn length(&self) -> usize {
90 vec![*self as u8].length()
91 }
92}
93
94impl Decodable for DisconnectReason {
95 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
98 if buf.is_empty() {
99 return Err(alloy_rlp::Error::InputTooShort)
100 } else if buf.len() > 2 {
101 return Err(alloy_rlp::Error::Overflow)
102 }
103
104 if buf.len() > 1 {
105 let header = Header::decode(buf)?;
108
109 if !header.list {
110 return Err(alloy_rlp::Error::UnexpectedString)
111 }
112
113 if header.payload_length != 1 {
114 return Err(alloy_rlp::Error::ListLengthMismatch {
115 expected: 1,
116 got: header.payload_length,
117 })
118 }
119 }
120
121 if buf[0] == 0x00 {
124 buf.advance(1);
125 Ok(Self::DisconnectRequested)
126 } else {
127 Self::try_from(u8::decode(buf)?)
128 .map_err(|_| alloy_rlp::Error::Custom("unknown disconnect reason"))
129 }
130 }
131}
132
133#[derive(Debug, Clone, Error)]
135#[error("unknown disconnect reason: {0}")]
136pub struct UnknownDisconnectReason(u8);