1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//! 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<ProtocolVersion>),

    /// 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<DisconnectReason> {
        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,
}