Skip to main content

eth_valkyoth_protocol/transaction/blob/
error.rs

1use core::fmt;
2
3use eth_valkyoth_codec::{DecodeError, DecodeErrorCategory};
4
5use super::BlobTransactionField;
6use crate::transaction::{TransactionEnvelopeError, TransactionEnvelopeErrorCategory};
7
8/// EIP-4844 blob transaction decode failure.
9#[non_exhaustive]
10#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11pub enum BlobTransactionDecodeError {
12    /// Envelope classification failed before blob fields could decode.
13    Envelope(TransactionEnvelopeError),
14    /// A non-EIP-4844 envelope was supplied to this decoder.
15    WrongTransactionType {
16        /// Observed transaction type, or legacy zero.
17        type_byte: u8,
18    },
19    /// Transaction payload did not contain exactly fourteen fields.
20    WrongFieldCount {
21        /// Expected field count.
22        expected: usize,
23        /// Actual field count.
24        found: usize,
25    },
26    /// A field failed RLP or primitive-domain decoding.
27    FieldDecode {
28        /// Field being decoded.
29        field: BlobTransactionField,
30        /// Underlying decode error.
31        source: DecodeError,
32    },
33    /// The `to` field was not a 20-byte address.
34    InvalidToLength {
35        /// Actual decoded scalar byte length.
36        found: usize,
37    },
38    /// Signature y parity was not `0` or `1`.
39    InvalidYParity {
40        /// Observed y-parity integer.
41        value: u64,
42    },
43    /// Access-list entry was not `[address, storageKeys]`.
44    InvalidAccessListEntryFieldCount {
45        /// Actual entry field count.
46        found: usize,
47    },
48    /// Access-list address was not a 20-byte scalar.
49    InvalidAccessListAddressLength {
50        /// Actual decoded scalar byte length.
51        found: usize,
52    },
53    /// Access-list storage key was not a 32-byte scalar.
54    InvalidStorageKeyLength {
55        /// Actual decoded scalar byte length.
56        found: usize,
57    },
58    /// Blob versioned hash was not a 32-byte scalar.
59    InvalidBlobVersionedHashLength {
60        /// Actual decoded scalar byte length.
61        found: usize,
62    },
63}
64
65impl BlobTransactionDecodeError {
66    /// Stable machine-readable error code.
67    #[must_use]
68    pub const fn code(self) -> &'static str {
69        match self {
70            Self::Envelope(error) => error.code(),
71            Self::WrongTransactionType { .. } => "ETH_BLOB_TX_WRONG_TYPE",
72            Self::WrongFieldCount { .. } => "ETH_BLOB_TX_WRONG_FIELD_COUNT",
73            Self::FieldDecode { source, .. } => source.code(),
74            Self::InvalidToLength { .. } => "ETH_BLOB_TX_INVALID_TO_LENGTH",
75            Self::InvalidYParity { .. } => "ETH_BLOB_TX_INVALID_Y_PARITY",
76            Self::InvalidAccessListEntryFieldCount { .. } => {
77                "ETH_BLOB_TX_INVALID_ENTRY_FIELD_COUNT"
78            }
79            Self::InvalidAccessListAddressLength { .. } => "ETH_BLOB_TX_INVALID_ADDRESS_LENGTH",
80            Self::InvalidStorageKeyLength { .. } => "ETH_BLOB_TX_INVALID_STORAGE_KEY_LENGTH",
81            Self::InvalidBlobVersionedHashLength { .. } => {
82                "ETH_BLOB_TX_INVALID_VERSIONED_HASH_LENGTH"
83            }
84        }
85    }
86
87    /// Stable human-readable error message.
88    #[must_use]
89    pub const fn message(self) -> &'static str {
90        match self {
91            Self::Envelope(error) => error.message(),
92            Self::WrongTransactionType { .. } => {
93                "blob transaction decoder received a different envelope type"
94            }
95            Self::WrongFieldCount { .. } => {
96                "blob transaction must contain exactly fourteen RLP fields"
97            }
98            Self::FieldDecode { .. } => "blob transaction field failed bounded decoding",
99            Self::InvalidToLength { .. } => "blob transaction to field must be a 20-byte address",
100            Self::InvalidYParity { .. } => "blob transaction y parity must be 0 or 1",
101            Self::InvalidAccessListEntryFieldCount { .. } => {
102                "blob transaction access-list entry must contain exactly address and storage-key list"
103            }
104            Self::InvalidAccessListAddressLength { .. } => {
105                "blob transaction access-list address must be a 20-byte scalar"
106            }
107            Self::InvalidStorageKeyLength { .. } => {
108                "blob transaction access-list storage key must be a 32-byte scalar"
109            }
110            Self::InvalidBlobVersionedHashLength { .. } => {
111                "blob transaction versioned hash must be a 32-byte scalar"
112            }
113        }
114    }
115
116    /// Stable high-level category for policy decisions.
117    #[must_use]
118    pub const fn category(self) -> BlobTransactionDecodeErrorCategory {
119        match self {
120            Self::Envelope(error) => match error.category() {
121                TransactionEnvelopeErrorCategory::ResourceExhaustion => {
122                    BlobTransactionDecodeErrorCategory::ResourceExhaustion
123                }
124                TransactionEnvelopeErrorCategory::Unsupported => {
125                    BlobTransactionDecodeErrorCategory::WrongType
126                }
127                _ => BlobTransactionDecodeErrorCategory::MalformedInput,
128            },
129            Self::WrongTransactionType { .. } => BlobTransactionDecodeErrorCategory::WrongType,
130            Self::FieldDecode { source, .. } => match source.category() {
131                DecodeErrorCategory::ResourceExhaustion => {
132                    BlobTransactionDecodeErrorCategory::ResourceExhaustion
133                }
134                _ => BlobTransactionDecodeErrorCategory::MalformedInput,
135            },
136            Self::WrongFieldCount { .. }
137            | Self::InvalidToLength { .. }
138            | Self::InvalidYParity { .. }
139            | Self::InvalidAccessListEntryFieldCount { .. }
140            | Self::InvalidAccessListAddressLength { .. }
141            | Self::InvalidStorageKeyLength { .. }
142            | Self::InvalidBlobVersionedHashLength { .. } => {
143                BlobTransactionDecodeErrorCategory::MalformedInput
144            }
145        }
146    }
147}
148
149impl fmt::Display for BlobTransactionDecodeError {
150    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
151        formatter.write_str(self.message())
152    }
153}
154
155#[cfg(feature = "std")]
156impl std::error::Error for BlobTransactionDecodeError {}
157
158/// Stable high-level blob transaction decode error categories.
159#[non_exhaustive]
160#[derive(Clone, Copy, Debug, Eq, PartialEq)]
161pub enum BlobTransactionDecodeErrorCategory {
162    /// Input is malformed for an EIP-4844 transaction.
163    MalformedInput,
164    /// A non-EIP-4844 transaction envelope was supplied.
165    WrongType,
166    /// The active decode policy rejected the input as too large or too deep.
167    ResourceExhaustion,
168}