Skip to main content

eth_valkyoth_protocol/transaction/set_code/
error.rs

1use core::fmt;
2
3use eth_valkyoth_codec::{DecodeError, DecodeErrorCategory};
4
5use super::SetCodeTransactionField;
6use crate::transaction::{TransactionEnvelopeError, TransactionEnvelopeErrorCategory};
7
8/// EIP-7702 authorization tuple sub-field identifier.
9#[non_exhaustive]
10#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11pub enum SetCodeAuthorizationField {
12    /// Authorization chain ID.
13    ChainId,
14    /// Authorized account address.
15    Address,
16    /// Authorized account nonce.
17    Nonce,
18    /// Authorization signature y parity.
19    YParity,
20    /// Authorization signature `r`.
21    R,
22    /// Authorization signature `s`.
23    S,
24}
25
26/// EIP-7702 set-code transaction decode failure.
27#[non_exhaustive]
28#[derive(Clone, Copy, Debug, Eq, PartialEq)]
29pub enum SetCodeTransactionDecodeError {
30    /// Envelope classification failed before set-code fields could decode.
31    Envelope(TransactionEnvelopeError),
32    /// A non-EIP-7702 envelope was supplied to this decoder.
33    WrongTransactionType {
34        /// Observed transaction type, or legacy zero.
35        type_byte: u8,
36    },
37    /// Transaction payload did not contain exactly thirteen fields.
38    WrongFieldCount {
39        /// Expected field count.
40        expected: usize,
41        /// Actual field count.
42        found: usize,
43    },
44    /// A field failed RLP or primitive-domain decoding.
45    FieldDecode {
46        /// Field being decoded.
47        field: SetCodeTransactionField,
48        /// Underlying decode error.
49        source: DecodeError,
50    },
51    /// An authorization tuple sub-field failed RLP or primitive-domain decoding.
52    AuthorizationFieldDecode {
53        /// Authorization tuple sub-field being decoded.
54        field: SetCodeAuthorizationField,
55        /// Underlying decode error.
56        source: DecodeError,
57    },
58    /// The `destination` field was not a 20-byte address.
59    InvalidToLength {
60        /// Actual decoded scalar byte length.
61        found: usize,
62    },
63    /// Signature y parity was not `0` or `1`.
64    InvalidYParity {
65        /// Observed y-parity integer.
66        value: u64,
67    },
68    /// Access-list entry was not `[address, storageKeys]`.
69    InvalidAccessListEntryFieldCount {
70        /// Actual entry field count.
71        found: usize,
72    },
73    /// Access-list address was not a 20-byte scalar.
74    InvalidAccessListAddressLength {
75        /// Actual decoded scalar byte length.
76        found: usize,
77    },
78    /// Access-list storage key was not a 32-byte scalar.
79    InvalidStorageKeyLength {
80        /// Actual decoded scalar byte length.
81        found: usize,
82    },
83    /// Authorization tuple did not contain exactly six fields.
84    InvalidAuthorizationFieldCount {
85        /// Actual tuple field count.
86        found: usize,
87    },
88    /// Authorization address was not a 20-byte scalar.
89    InvalidAuthorizationAddressLength {
90        /// Actual decoded scalar byte length.
91        found: usize,
92    },
93    /// Authorization y parity was not `0` or `1`.
94    InvalidAuthorizationYParity {
95        /// Observed y-parity integer.
96        value: u64,
97    },
98}
99
100impl SetCodeTransactionDecodeError {
101    /// Stable machine-readable error code.
102    #[must_use]
103    pub const fn code(self) -> &'static str {
104        match self {
105            Self::Envelope(error) => error.code(),
106            Self::WrongTransactionType { .. } => "ETH_SET_CODE_TX_WRONG_TYPE",
107            Self::WrongFieldCount { .. } => "ETH_SET_CODE_TX_WRONG_FIELD_COUNT",
108            Self::FieldDecode { source, .. } => source.code(),
109            Self::AuthorizationFieldDecode { source, .. } => source.code(),
110            Self::InvalidToLength { .. } => "ETH_SET_CODE_TX_INVALID_TO_LENGTH",
111            Self::InvalidYParity { .. } => "ETH_SET_CODE_TX_INVALID_Y_PARITY",
112            Self::InvalidAccessListEntryFieldCount { .. } => {
113                "ETH_SET_CODE_TX_INVALID_ENTRY_FIELD_COUNT"
114            }
115            Self::InvalidAccessListAddressLength { .. } => {
116                "ETH_SET_CODE_TX_INVALID_ACCESS_ADDRESS_LENGTH"
117            }
118            Self::InvalidStorageKeyLength { .. } => "ETH_SET_CODE_TX_INVALID_STORAGE_KEY_LENGTH",
119            Self::InvalidAuthorizationFieldCount { .. } => {
120                "ETH_SET_CODE_TX_INVALID_AUTH_FIELD_COUNT"
121            }
122            Self::InvalidAuthorizationAddressLength { .. } => {
123                "ETH_SET_CODE_TX_INVALID_AUTH_ADDRESS_LENGTH"
124            }
125            Self::InvalidAuthorizationYParity { .. } => "ETH_SET_CODE_TX_INVALID_AUTH_Y_PARITY",
126        }
127    }
128
129    /// Stable human-readable error message.
130    #[must_use]
131    pub const fn message(self) -> &'static str {
132        match self {
133            Self::Envelope(error) => error.message(),
134            Self::WrongTransactionType { .. } => {
135                "set-code transaction decoder received a different envelope type"
136            }
137            Self::WrongFieldCount { .. } => {
138                "set-code transaction must contain exactly thirteen RLP fields"
139            }
140            Self::FieldDecode { .. } => "set-code transaction field failed bounded decoding",
141            Self::AuthorizationFieldDecode { .. } => {
142                "set-code authorization tuple field failed bounded decoding"
143            }
144            Self::InvalidToLength { .. } => {
145                "set-code transaction destination field must be a 20-byte address"
146            }
147            Self::InvalidYParity { .. } => "set-code transaction y parity must be 0 or 1",
148            Self::InvalidAccessListEntryFieldCount { .. } => {
149                "set-code transaction access-list entry must contain exactly address and storage-key list"
150            }
151            Self::InvalidAccessListAddressLength { .. } => {
152                "set-code transaction access-list address must be a 20-byte scalar"
153            }
154            Self::InvalidStorageKeyLength { .. } => {
155                "set-code transaction access-list storage key must be a 32-byte scalar"
156            }
157            Self::InvalidAuthorizationFieldCount { .. } => {
158                "set-code authorization tuple must contain exactly chain id, address, nonce, y parity, r, and s"
159            }
160            Self::InvalidAuthorizationAddressLength { .. } => {
161                "set-code authorization address must be a 20-byte scalar"
162            }
163            Self::InvalidAuthorizationYParity { .. } => {
164                "set-code authorization y parity must be 0 or 1"
165            }
166        }
167    }
168
169    /// Stable high-level category for policy decisions.
170    #[must_use]
171    pub const fn category(self) -> SetCodeTransactionDecodeErrorCategory {
172        match self {
173            Self::Envelope(error) => match error.category() {
174                TransactionEnvelopeErrorCategory::ResourceExhaustion => {
175                    SetCodeTransactionDecodeErrorCategory::ResourceExhaustion
176                }
177                TransactionEnvelopeErrorCategory::Unsupported => {
178                    SetCodeTransactionDecodeErrorCategory::WrongType
179                }
180                _ => SetCodeTransactionDecodeErrorCategory::MalformedInput,
181            },
182            Self::WrongTransactionType { .. } => SetCodeTransactionDecodeErrorCategory::WrongType,
183            Self::FieldDecode { source, .. } | Self::AuthorizationFieldDecode { source, .. } => {
184                match source.category() {
185                    DecodeErrorCategory::ResourceExhaustion => {
186                        SetCodeTransactionDecodeErrorCategory::ResourceExhaustion
187                    }
188                    _ => SetCodeTransactionDecodeErrorCategory::MalformedInput,
189                }
190            }
191            Self::WrongFieldCount { .. }
192            | Self::InvalidToLength { .. }
193            | Self::InvalidYParity { .. }
194            | Self::InvalidAccessListEntryFieldCount { .. }
195            | Self::InvalidAccessListAddressLength { .. }
196            | Self::InvalidStorageKeyLength { .. }
197            | Self::InvalidAuthorizationFieldCount { .. }
198            | Self::InvalidAuthorizationAddressLength { .. }
199            | Self::InvalidAuthorizationYParity { .. } => {
200                SetCodeTransactionDecodeErrorCategory::MalformedInput
201            }
202        }
203    }
204}
205
206impl fmt::Display for SetCodeTransactionDecodeError {
207    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
208        formatter.write_str(self.message())
209    }
210}
211
212#[cfg(feature = "std")]
213impl std::error::Error for SetCodeTransactionDecodeError {}
214
215/// Stable high-level set-code transaction decode error categories.
216#[non_exhaustive]
217#[derive(Clone, Copy, Debug, Eq, PartialEq)]
218pub enum SetCodeTransactionDecodeErrorCategory {
219    /// Input is malformed for an EIP-7702 transaction.
220    MalformedInput,
221    /// A non-EIP-7702 transaction envelope was supplied.
222    WrongType,
223    /// The active decode policy rejected the input as too large or too deep.
224    ResourceExhaustion,
225}