//! Error handling for [`P2PStream`](crate::P2PStream). use std::io; use reth_eth_wire_types::{DisconnectReason, UnknownDisconnectReason}; use reth_primitives::GotExpected; use crate::{capability::SharedCapabilityError, ProtocolVersion}; /// Errors when sending/receiving p2p messages. These should result in kicking the peer. #[derive(thiserror::Error, Debug)] pub enum P2PStreamError { /// I/O error. #[error(transparent)] Io(#[from] io::Error), /// RLP encoding/decoding error. #[error(transparent)] Rlp(#[from] alloy_rlp::Error), /// Error in compression/decompression using Snappy. #[error(transparent)] Snap(#[from] snap::Error), /// Error during the P2P handshake. #[error(transparent)] HandshakeError(#[from] P2PHandshakeError), /// Message size exceeds maximum length error. #[error("message size ({message_size}) exceeds max length ({max_size})")] MessageTooBig { /// The actual size of the message received. message_size: usize, /// The maximum allowed size for the message. max_size: usize, }, /// Unknown reserved P2P message ID error. #[error("unknown reserved p2p message id: {0}")] UnknownReservedMessageId(u8), /// Empty protocol message received error. #[error("empty protocol message received")] EmptyProtocolMessage, /// Error related to the Pinger. #[error(transparent)] PingerError(#[from] PingerError), /// Ping timeout error. #[error("ping timed out with")] PingTimeout, /// Error parsing shared capabilities. #[error(transparent)] ParseSharedCapability(#[from] SharedCapabilityError), /// Capability not supported on the stream to this peer. #[error("capability not supported on stream to this peer")] CapabilityNotShared, /// Mismatched protocol version error. #[error("mismatched protocol version in Hello message: {0}")] MismatchedProtocolVersion(GotExpected), /// Ping started before the handshake completed. #[error("started ping task before the handshake completed")] PingBeforeHandshake, /// Too many messages buffered before sending. #[error("too many messages buffered before sending")] SendBufferFull, /// Disconnected error. #[error("disconnected")] Disconnected(DisconnectReason), /// Unknown disconnect reason error. #[error("unknown disconnect reason: {0}")] UnknownDisconnectReason(#[from] UnknownDisconnectReason), } // === impl P2PStreamError === impl P2PStreamError { /// Returns the [`DisconnectReason`] if it is the `Disconnected` variant. pub const fn as_disconnected(&self) -> Option { let reason = match self { Self::HandshakeError(P2PHandshakeError::Disconnected(reason)) | Self::Disconnected(reason) => reason, _ => return None, }; Some(*reason) } } /// Errors when conducting a p2p handshake. #[derive(thiserror::Error, Debug, Clone, Eq, PartialEq)] pub enum P2PHandshakeError { /// Hello message received/sent outside of handshake error. #[error("hello message can only be recv/sent in handshake")] HelloNotInHandshake, /// Received a non-hello message when trying to handshake. #[error("received non-hello message when trying to handshake")] NonHelloMessageInHandshake, /// No capabilities shared with the peer. #[error("no capabilities shared with peer")] NoSharedCapabilities, /// No response received when sending out handshake. #[error("no response received when sending out handshake")] NoResponse, /// Handshake timed out. #[error("handshake timed out")] Timeout, /// Disconnected by peer with a specific reason. #[error("disconnected by peer: {0}")] Disconnected(DisconnectReason), /// Error decoding a message during handshake. #[error("error decoding a message during handshake: {0}")] DecodeError(#[from] alloy_rlp::Error), } /// An error that can occur when interacting with a pinger. #[derive(Debug, thiserror::Error)] pub enum PingerError { /// An unexpected pong was received while the pinger was in the `Ready` state. #[error("pong received while ready")] UnexpectedPong, }