reth_eth_wire_types/
disconnect_reason.rsuse alloy_primitives::bytes::{Buf, BufMut};
use alloy_rlp::{Decodable, Encodable, Header};
use derive_more::Display;
use reth_codecs_derive::add_arbitrary_tests;
use thiserror::Error;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Display)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
#[add_arbitrary_tests(rlp)]
pub enum DisconnectReason {
#[default]
#[display("disconnect requested")]
DisconnectRequested = 0x00,
#[display("TCP sub-system error")]
TcpSubsystemError = 0x01,
#[display("breach of protocol, e.g. a malformed message, bad RLP, etc.")]
ProtocolBreach = 0x02,
#[display("useless peer")]
UselessPeer = 0x03,
#[display("too many peers")]
TooManyPeers = 0x04,
#[display("already connected")]
AlreadyConnected = 0x05,
#[display("incompatible P2P protocol version")]
IncompatibleP2PProtocolVersion = 0x06,
#[display("null node identity received - this is automatically invalid")]
NullNodeIdentity = 0x07,
#[display("client quitting")]
ClientQuitting = 0x08,
#[display("unexpected identity in handshake")]
UnexpectedHandshakeIdentity = 0x09,
#[display("identity is the same as this node (i.e. connected to itself)")]
ConnectedToSelf = 0x0a,
#[display("ping timeout")]
PingTimeout = 0x0b,
#[display("some other reason specific to a subprotocol")]
SubprotocolSpecific = 0x10,
}
impl TryFrom<u8> for DisconnectReason {
type Error = UnknownDisconnectReason;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0x00 => Ok(Self::DisconnectRequested),
0x01 => Ok(Self::TcpSubsystemError),
0x02 => Ok(Self::ProtocolBreach),
0x03 => Ok(Self::UselessPeer),
0x04 => Ok(Self::TooManyPeers),
0x05 => Ok(Self::AlreadyConnected),
0x06 => Ok(Self::IncompatibleP2PProtocolVersion),
0x07 => Ok(Self::NullNodeIdentity),
0x08 => Ok(Self::ClientQuitting),
0x09 => Ok(Self::UnexpectedHandshakeIdentity),
0x0a => Ok(Self::ConnectedToSelf),
0x0b => Ok(Self::PingTimeout),
0x10 => Ok(Self::SubprotocolSpecific),
_ => Err(UnknownDisconnectReason(value)),
}
}
}
impl Encodable for DisconnectReason {
fn encode(&self, out: &mut dyn BufMut) {
vec![*self as u8].encode(out);
}
fn length(&self) -> usize {
vec![*self as u8].length()
}
}
impl Decodable for DisconnectReason {
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
if buf.is_empty() {
return Err(alloy_rlp::Error::InputTooShort)
} else if buf.len() > 2 {
return Err(alloy_rlp::Error::Overflow)
}
if buf.len() > 1 {
let header = Header::decode(buf)?;
if !header.list {
return Err(alloy_rlp::Error::UnexpectedString)
}
if header.payload_length != 1 {
return Err(alloy_rlp::Error::ListLengthMismatch {
expected: 1,
got: header.payload_length,
})
}
}
if buf[0] == 0x00 {
buf.advance(1);
Ok(Self::DisconnectRequested)
} else {
Self::try_from(u8::decode(buf)?)
.map_err(|_| alloy_rlp::Error::Custom("unknown disconnect reason"))
}
}
}
#[derive(Debug, Clone, Error)]
#[error("unknown disconnect reason: {0}")]
pub struct UnknownDisconnectReason(u8);