1#![no_std]
2#![forbid(unsafe_code)]
3#[cfg(feature = "std")]
6extern crate std;
7
8use core::fmt;
9
10mod fork;
11mod state;
12mod transaction;
13
14pub use fork::{ChainSpec, ForkActivation, ForkError, ForkSpec, Hardfork, ValidationContext};
15pub use state::{
16 Canonical, CanonicalValidationProof, Decoded, ForkValidated, ForkValidationProof,
17 SenderRecovered, SenderRecoveryProof, StateTransitionError, Transaction,
18};
19pub use transaction::{
20 ACCESS_LIST_TRANSACTION_FIELD_COUNT, ACCESS_LIST_TRANSACTION_TYPE, AccessList,
21 AccessListEntries, AccessListEntry, AccessListStorageKeyItems, AccessListStorageKeys,
22 AccessListTransactionDecodeError, AccessListTransactionDecodeErrorCategory,
23 AccessListTransactionField, AccessListTransactionTo, BLOB_TRANSACTION_FIELD_COUNT,
24 BLOB_TRANSACTION_TYPE, BlobTransactionDecodeError, BlobTransactionDecodeErrorCategory,
25 BlobTransactionField, BlobVersionedHashItems, BlobVersionedHashes,
26 DYNAMIC_FEE_TRANSACTION_FIELD_COUNT, DYNAMIC_FEE_TRANSACTION_TYPE,
27 DynamicFeeTransactionDecodeError, DynamicFeeTransactionDecodeErrorCategory,
28 DynamicFeeTransactionField, DynamicFeeTransactionTo, EIP_2718_MAX_TYPED_PREFIX,
29 EIP_2718_RESERVED_PREFIX, EIP_2718_SCALAR_PREFIX_START, EIP_2718_TYPED_ZERO_PREFIX,
30 InvalidSignatureYParity, LEGACY_TRANSACTION_FIELD_COUNT, LEGACY_TRANSACTION_PREFIX_START,
31 LegacyTransactionDecodeError, LegacyTransactionDecodeErrorCategory, LegacyTransactionField,
32 LegacyTransactionTo, SET_CODE_AUTHORIZATION_FIELD_COUNT, SET_CODE_TRANSACTION_FIELD_COUNT,
33 SET_CODE_TRANSACTION_TYPE, SetCodeAuthorization, SetCodeAuthorizationChainId,
34 SetCodeAuthorizationField, SetCodeAuthorizationItems, SetCodeAuthorizationList,
35 SetCodeTransactionDecodeError, SetCodeTransactionDecodeErrorCategory, SetCodeTransactionField,
36 SignatureYParity, TransactionEncodeError, TransactionEncodeErrorCategory, TransactionEnvelope,
37 TransactionEnvelopeError, TransactionEnvelopeErrorCategory, TypedTransactionEnvelope,
38 UnvalidatedAccessListTransaction, UnvalidatedBlobTransaction, UnvalidatedDynamicFeeTransaction,
39 UnvalidatedLegacyTransaction, UnvalidatedSetCodeTransaction, UnvalidatedTransaction,
40 decode_access_list_transaction, decode_blob_transaction, decode_dynamic_fee_transaction,
41 decode_legacy_transaction, decode_set_code_transaction, decode_transaction_envelope,
42 encode_access_list_signing_preimage, encode_access_list_transaction,
43 encode_blob_signing_preimage, encode_blob_transaction, encode_dynamic_fee_signing_preimage,
44 encode_dynamic_fee_transaction, encode_legacy_eip155_signing_preimage,
45 encode_legacy_transaction, encode_set_code_transaction, encode_transaction,
46 encoded_access_list_signing_preimage_len, encoded_access_list_transaction_len,
47 encoded_blob_signing_preimage_len, encoded_blob_transaction_len,
48 encoded_dynamic_fee_signing_preimage_len, encoded_dynamic_fee_transaction_len,
49 encoded_legacy_eip155_signing_preimage_len, encoded_legacy_transaction_len,
50 encoded_set_code_transaction_len, encoded_transaction_len,
51};
52
53#[non_exhaustive]
55#[derive(Clone, Copy, Debug, Eq, PartialEq)]
56pub enum ProtocolError {
57 Feature(FeatureError),
59 Fork(ForkError),
61 InvalidStateTransition,
63}
64
65impl ProtocolError {
66 #[must_use]
68 pub const fn code(self) -> &'static str {
69 match self {
70 Self::Feature(error) => error.code(),
71 Self::Fork(error) => error.code(),
72 Self::InvalidStateTransition => "ETH_PROTOCOL_INVALID_STATE_TRANSITION",
73 }
74 }
75
76 #[must_use]
78 pub const fn message(self) -> &'static str {
79 match self {
80 Self::Feature(error) => error.message(),
81 Self::Fork(error) => error.message(),
82 Self::InvalidStateTransition => {
83 "validation state transition is not allowed from the current state"
84 }
85 }
86 }
87
88 #[must_use]
90 pub const fn category(self) -> ProtocolErrorCategory {
91 match self {
92 Self::Feature(_) => ProtocolErrorCategory::Feature,
93 Self::Fork(_) => ProtocolErrorCategory::Fork,
94 Self::InvalidStateTransition => ProtocolErrorCategory::State,
95 }
96 }
97}
98
99impl fmt::Display for ProtocolError {
100 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
101 formatter.write_str(self.message())
102 }
103}
104
105#[cfg(feature = "std")]
106impl std::error::Error for ProtocolError {}
107
108#[non_exhaustive]
110#[derive(Clone, Copy, Debug, Eq, PartialEq)]
111pub enum ProtocolErrorCategory {
112 Feature,
114 Fork,
116 State,
118}
119
120#[non_exhaustive]
122#[derive(Clone, Copy, Debug, Eq, PartialEq)]
123pub enum FeatureError {
124 Disabled,
126 Unsupported,
128}
129
130impl FeatureError {
131 #[must_use]
133 pub const fn code(self) -> &'static str {
134 match self {
135 Self::Disabled => "ETH_FEATURE_DISABLED",
136 Self::Unsupported => "ETH_FEATURE_UNSUPPORTED",
137 }
138 }
139
140 #[must_use]
142 pub const fn message(self) -> &'static str {
143 match self {
144 Self::Disabled => "feature is disabled for this operation",
145 Self::Unsupported => "feature is not supported by this crate version",
146 }
147 }
148}
149
150impl fmt::Display for FeatureError {
151 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
152 formatter.write_str(self.message())
153 }
154}
155
156#[cfg(feature = "std")]
157impl std::error::Error for FeatureError {}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162 extern crate std;
163 use std::string::ToString;
164
165 #[test]
166 fn protocol_errors_have_stable_codes_and_categories() {
167 let error = ProtocolError::Fork(ForkError::Inactive);
168
169 assert_eq!(error.code(), "ETH_FORK_INACTIVE");
170 assert_eq!(
171 error.message(),
172 "fork is not active for the validation context"
173 );
174 assert_eq!(error.category(), ProtocolErrorCategory::Fork);
175 assert_eq!(
176 error.to_string(),
177 "fork is not active for the validation context"
178 );
179 }
180
181 #[test]
182 fn feature_errors_format_without_payloads() {
183 let error = ProtocolError::Feature(FeatureError::Unsupported);
184
185 assert_eq!(error.code(), "ETH_FEATURE_UNSUPPORTED");
186 assert_eq!(
187 FeatureError::Unsupported.to_string(),
188 "feature is not supported by this crate version"
189 );
190 }
191}