1//! Error handling for (`EthStream`)[`crate::EthStream`]
23use crate::{
4errors::P2PStreamError, message::MessageError, version::ParseVersionError, DisconnectReason,
5};
6use alloy_chains::Chain;
7use alloy_primitives::B256;
8use reth_eth_wire_types::EthVersion;
9use reth_ethereum_forks::ValidationError;
10use reth_primitives_traits::{GotExpected, GotExpectedBoxed};
11use std::io;
1213/// Errors when sending/receiving messages
14#[derive(thiserror::Error, Debug)]
15pub enum EthStreamError {
16#[error(transparent)]
17/// Error of the underlying P2P connection.
18P2PStreamError(#[from] P2PStreamError),
19#[error(transparent)]
20/// Failed to parse peer's version.
21ParseVersionError(#[from] ParseVersionError),
22#[error(transparent)]
23/// Failed Ethereum handshake.
24EthHandshakeError(#[from] EthHandshakeError),
25/// Thrown when decoding a message failed.
26#[error(transparent)]
27InvalidMessage(#[from] MessageError),
28#[error("message size ({0}) exceeds max length (10MB)")]
29/// Received a message whose size exceeds the standard limit.
30MessageTooBig(usize),
31#[error(
32"TransactionHashes invalid len of fields: hashes_len={hashes_len} types_len={types_len} sizes_len={sizes_len}"
33)]
34/// Received malformed transaction hashes message with discrepancies in field lengths.
35TransactionHashesInvalidLenOfFields {
36/// The number of transaction hashes.
37hashes_len: usize,
38/// The number of transaction types.
39types_len: usize,
40/// The number of transaction sizes.
41sizes_len: usize,
42 },
43/// Error when data is not received from peer for a prolonged period.
44#[error("never received data from remote peer")]
45StreamTimeout,
46/// Error triggered when an unknown or unsupported Ethereum message ID is received.
47#[error("Received unknown ETH message ID: 0x{message_id:X}")]
48UnsupportedMessage {
49/// The identifier of the unknown Ethereum message.
50message_id: u8,
51 },
52}
5354// === impl EthStreamError ===
5556impl EthStreamError {
57/// Returns the [`DisconnectReason`] if the error is a disconnect message
58pub const fn as_disconnected(&self) -> Option<DisconnectReason> {
59if let Self::P2PStreamError(err) = self{
60err.as_disconnected()
61 } else {
62None63 }
64 }
6566/// Returns the [`io::Error`] if it was caused by IO
67pub const fn as_io(&self) -> Option<&io::Error> {
68if let Self::P2PStreamError(P2PStreamError::Io(io)) = self{
69return Some(io)
70 }
71None72 }
73}
7475impl From<io::Error> for EthStreamError {
76fn from(err: io::Error) -> Self {
77P2PStreamError::from(err).into()
78 }
79}
8081/// Error that can occur during the `eth` sub-protocol handshake.
82#[derive(thiserror::Error, Debug)]
83pub enum EthHandshakeError {
84/// Status message received or sent outside of the handshake process.
85#[error("status message can only be recv/sent in handshake")]
86StatusNotInHandshake,
87/// Receiving a non-status message during the handshake phase.
88#[error("received non-status message when trying to handshake")]
89NonStatusMessageInHandshake,
90#[error("no response received when sending out handshake")]
91/// No response received during the handshake process.
92NoResponse,
93#[error(transparent)]
94/// Invalid fork data.
95InvalidFork(#[from] ValidationError),
96#[error("mismatched genesis in status message: {0}")]
97/// Mismatch in the genesis block during status exchange.
98MismatchedGenesis(GotExpectedBoxed<B256>),
99#[error("mismatched protocol version in status message: {0}")]
100/// Mismatched protocol versions in status messages.
101MismatchedProtocolVersion(GotExpected<EthVersion>),
102#[error("mismatched chain in status message: {0}")]
103/// Mismatch in chain details in status messages.
104MismatchedChain(GotExpected<Chain>),
105#[error("total difficulty bitlen is too large: got {got}, maximum {maximum}")]
106/// Excessively large total difficulty bit lengths.
107TotalDifficultyBitLenTooLarge {
108/// The actual bit length of the total difficulty.
109got: usize,
110/// The maximum allowed bit length for the total difficulty.
111maximum: usize,
112 },
113}