Skip to main content

eth_valkyoth_protocol/transaction/access_list/
error.rs

1use core::fmt;
2
3use eth_valkyoth_codec::{DecodeError, DecodeErrorCategory};
4
5use super::AccessListTransactionField;
6use crate::transaction::{TransactionEnvelopeError, TransactionEnvelopeErrorCategory};
7
8/// EIP-2930 access-list transaction decode failure.
9#[non_exhaustive]
10#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11pub enum AccessListTransactionDecodeError {
12    /// Envelope classification failed before access-list fields could decode.
13    Envelope(TransactionEnvelopeError),
14    /// A non-EIP-2930 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 eleven 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: AccessListTransactionField,
30        /// Underlying decode error.
31        source: DecodeError,
32    },
33    /// The `to` field was neither empty nor 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}
59
60impl AccessListTransactionDecodeError {
61    /// Stable machine-readable error code.
62    #[must_use]
63    pub const fn code(self) -> &'static str {
64        match self {
65            Self::Envelope(error) => error.code(),
66            Self::WrongTransactionType { .. } => "ETH_ACCESS_LIST_TX_WRONG_TYPE",
67            Self::WrongFieldCount { .. } => "ETH_ACCESS_LIST_TX_WRONG_FIELD_COUNT",
68            Self::FieldDecode { source, .. } => source.code(),
69            Self::InvalidToLength { .. } => "ETH_ACCESS_LIST_TX_INVALID_TO_LENGTH",
70            Self::InvalidYParity { .. } => "ETH_ACCESS_LIST_TX_INVALID_Y_PARITY",
71            Self::InvalidAccessListEntryFieldCount { .. } => {
72                "ETH_ACCESS_LIST_TX_INVALID_ENTRY_FIELD_COUNT"
73            }
74            Self::InvalidAccessListAddressLength { .. } => {
75                "ETH_ACCESS_LIST_TX_INVALID_ADDRESS_LENGTH"
76            }
77            Self::InvalidStorageKeyLength { .. } => "ETH_ACCESS_LIST_TX_INVALID_STORAGE_KEY_LENGTH",
78        }
79    }
80
81    /// Stable human-readable error message.
82    #[must_use]
83    pub const fn message(self) -> &'static str {
84        match self {
85            Self::Envelope(error) => error.message(),
86            Self::WrongTransactionType { .. } => {
87                "access-list transaction decoder received a different envelope type"
88            }
89            Self::WrongFieldCount { .. } => {
90                "access-list transaction must contain exactly eleven RLP fields"
91            }
92            Self::FieldDecode { .. } => "access-list transaction field failed bounded decoding",
93            Self::InvalidToLength { .. } => {
94                "access-list transaction to field must be empty or a 20-byte address"
95            }
96            Self::InvalidYParity { .. } => "access-list transaction y parity must be 0 or 1",
97            Self::InvalidAccessListEntryFieldCount { .. } => {
98                "access-list entry must contain exactly address and storage-key list"
99            }
100            Self::InvalidAccessListAddressLength { .. } => {
101                "access-list address must be a 20-byte scalar"
102            }
103            Self::InvalidStorageKeyLength { .. } => {
104                "access-list storage key must be a 32-byte scalar"
105            }
106        }
107    }
108
109    /// Stable high-level category for policy decisions.
110    #[must_use]
111    pub const fn category(self) -> AccessListTransactionDecodeErrorCategory {
112        match self {
113            Self::Envelope(error) => match error.category() {
114                TransactionEnvelopeErrorCategory::ResourceExhaustion => {
115                    AccessListTransactionDecodeErrorCategory::ResourceExhaustion
116                }
117                TransactionEnvelopeErrorCategory::Unsupported => {
118                    AccessListTransactionDecodeErrorCategory::WrongType
119                }
120                _ => AccessListTransactionDecodeErrorCategory::MalformedInput,
121            },
122            Self::WrongTransactionType { .. } => {
123                AccessListTransactionDecodeErrorCategory::WrongType
124            }
125            Self::FieldDecode { source, .. } => match source.category() {
126                DecodeErrorCategory::ResourceExhaustion => {
127                    AccessListTransactionDecodeErrorCategory::ResourceExhaustion
128                }
129                _ => AccessListTransactionDecodeErrorCategory::MalformedInput,
130            },
131            Self::WrongFieldCount { .. }
132            | Self::InvalidToLength { .. }
133            | Self::InvalidYParity { .. }
134            | Self::InvalidAccessListEntryFieldCount { .. }
135            | Self::InvalidAccessListAddressLength { .. }
136            | Self::InvalidStorageKeyLength { .. } => {
137                AccessListTransactionDecodeErrorCategory::MalformedInput
138            }
139        }
140    }
141}
142
143impl fmt::Display for AccessListTransactionDecodeError {
144    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
145        formatter.write_str(self.message())
146    }
147}
148
149#[cfg(feature = "std")]
150impl std::error::Error for AccessListTransactionDecodeError {}
151
152/// Stable high-level access-list transaction decode error categories.
153#[non_exhaustive]
154#[derive(Clone, Copy, Debug, Eq, PartialEq)]
155pub enum AccessListTransactionDecodeErrorCategory {
156    /// Input is malformed for an EIP-2930 transaction.
157    MalformedInput,
158    /// A non-EIP-2930 transaction envelope was supplied.
159    WrongType,
160    /// The active decode policy rejected the input as too large or too deep.
161    ResourceExhaustion,
162}