Skip to main content

eth_valkyoth_protocol/header/
error.rs

1use core::fmt;
2
3use eth_valkyoth_codec::{DecodeError, DecodeErrorCategory};
4
5/// Header field identifier.
6#[non_exhaustive]
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8pub enum BlockHeaderField {
9    /// `parent_hash`.
10    ParentHash,
11    /// `ommers_hash`.
12    OmmersHash,
13    /// `beneficiary`.
14    Beneficiary,
15    /// `state_root`.
16    StateRoot,
17    /// `transactions_root`.
18    TransactionsRoot,
19    /// `receipts_root`.
20    ReceiptsRoot,
21    /// `logs_bloom`.
22    LogsBloom,
23    /// `difficulty`.
24    Difficulty,
25    /// `number`.
26    Number,
27    /// `gas_limit`.
28    GasLimit,
29    /// `gas_used`.
30    GasUsed,
31    /// `timestamp`.
32    Timestamp,
33    /// `extra_data`.
34    ExtraData,
35    /// `mix_hash` / `prev_randao`.
36    MixHash,
37    /// `nonce`.
38    Nonce,
39    /// `base_fee_per_gas`.
40    BaseFeePerGas,
41    /// `withdrawals_root`.
42    WithdrawalsRoot,
43    /// `blob_gas_used`.
44    BlobGasUsed,
45    /// `excess_blob_gas`.
46    ExcessBlobGas,
47    /// `parent_beacon_block_root`.
48    ParentBeaconBlockRoot,
49    /// `requests_hash`.
50    RequestsHash,
51}
52
53/// Execution header decode failure.
54#[non_exhaustive]
55#[derive(Clone, Copy, Debug, Eq, PartialEq)]
56pub enum BlockHeaderDecodeError {
57    /// Header RLP list decode failed.
58    Decode(DecodeError),
59    /// Header field count did not match the selected fork field set.
60    WrongFieldCount {
61        /// Expected field count.
62        expected: usize,
63        /// Actual field count.
64        found: usize,
65    },
66    /// A field failed RLP or primitive-domain decoding.
67    FieldDecode {
68        /// Field being decoded.
69        field: BlockHeaderField,
70        /// Underlying decode error.
71        source: DecodeError,
72    },
73    /// A fixed-width field had the wrong byte length.
74    InvalidFieldLength {
75        /// Field being decoded.
76        field: BlockHeaderField,
77        /// Expected byte length.
78        expected: usize,
79        /// Actual decoded scalar byte length.
80        found: usize,
81    },
82}
83
84impl BlockHeaderDecodeError {
85    /// Stable machine-readable error code.
86    #[must_use]
87    pub const fn code(self) -> &'static str {
88        match self {
89            Self::Decode(error) => error.code(),
90            Self::WrongFieldCount { .. } => "ETH_HEADER_WRONG_FIELD_COUNT",
91            Self::FieldDecode { source, .. } => source.code(),
92            Self::InvalidFieldLength { .. } => "ETH_HEADER_INVALID_FIELD_LENGTH",
93        }
94    }
95
96    /// Stable human-readable error message.
97    #[must_use]
98    pub const fn message(self) -> &'static str {
99        match self {
100            Self::Decode(error) => error.message(),
101            Self::WrongFieldCount { .. } => {
102                "block header field count does not match the selected field set"
103            }
104            Self::FieldDecode { .. } => "block header field failed bounded decoding",
105            Self::InvalidFieldLength { .. } => {
106                "block header fixed-width field has an invalid byte length"
107            }
108        }
109    }
110
111    /// Stable high-level category for policy decisions.
112    #[must_use]
113    pub const fn category(self) -> BlockHeaderDecodeErrorCategory {
114        match self {
115            Self::WrongFieldCount { .. } | Self::InvalidFieldLength { .. } => {
116                BlockHeaderDecodeErrorCategory::MalformedInput
117            }
118            Self::Decode(error) | Self::FieldDecode { source: error, .. } => {
119                match error.category() {
120                    DecodeErrorCategory::ResourceExhaustion => {
121                        BlockHeaderDecodeErrorCategory::ResourceExhaustion
122                    }
123                    _ => BlockHeaderDecodeErrorCategory::MalformedInput,
124                }
125            }
126        }
127    }
128}
129
130impl fmt::Display for BlockHeaderDecodeError {
131    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
132        formatter.write_str(self.message())
133    }
134}
135
136#[cfg(feature = "std")]
137impl std::error::Error for BlockHeaderDecodeError {}
138
139/// Stable high-level header decode error categories.
140#[non_exhaustive]
141#[derive(Clone, Copy, Debug, Eq, PartialEq)]
142pub enum BlockHeaderDecodeErrorCategory {
143    /// Input is malformed for the selected header field set.
144    MalformedInput,
145    /// The active decode policy rejected the input as too large or too deep.
146    ResourceExhaustion,
147}