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 EIP_7702_DELEGATION_INDICATOR_PREFIX, InvalidSignatureYParity, LEGACY_TRANSACTION_FIELD_COUNT,
31 LEGACY_TRANSACTION_PREFIX_START, LegacyTransactionDecodeError,
32 LegacyTransactionDecodeErrorCategory, LegacyTransactionField, LegacyTransactionTo,
33 SET_CODE_AUTHORIZATION_FIELD_COUNT, SET_CODE_AUTHORIZATION_MAGIC,
34 SET_CODE_TRANSACTION_FIELD_COUNT, SET_CODE_TRANSACTION_TYPE, SetCodeAuthorityAccount,
35 SetCodeAuthorityCode, SetCodeAuthorityStateView, SetCodeAuthorization,
36 SetCodeAuthorizationAuthority, SetCodeAuthorizationAuthorityView, SetCodeAuthorizationChainId,
37 SetCodeAuthorizationField, SetCodeAuthorizationItems, SetCodeAuthorizationList,
38 SetCodeTransactionDecodeError, SetCodeTransactionDecodeErrorCategory, SetCodeTransactionField,
39 SetCodeTransactionValidationContext, SetCodeTransactionValidityError,
40 SetCodeTransactionValidityErrorCategory, SignatureYParity, TransactionEncodeError,
41 TransactionEncodeErrorCategory, TransactionEnvelope, TransactionEnvelopeError,
42 TransactionEnvelopeErrorCategory, TypedTransactionEnvelope, UnvalidatedAccessListTransaction,
43 UnvalidatedBlobTransaction, UnvalidatedDynamicFeeTransaction, UnvalidatedLegacyTransaction,
44 UnvalidatedSetCodeTransaction, UnvalidatedTransaction, ValidSetCodeTransaction,
45 decode_access_list_transaction, decode_blob_transaction, decode_dynamic_fee_transaction,
46 decode_legacy_transaction, decode_set_code_transaction, decode_transaction_envelope,
47 encode_access_list_signing_preimage, encode_access_list_transaction,
48 encode_blob_signing_preimage, encode_blob_transaction, encode_dynamic_fee_signing_preimage,
49 encode_dynamic_fee_transaction, encode_legacy_eip155_signing_preimage,
50 encode_legacy_transaction, encode_set_code_authorization_signing_preimage,
51 encode_set_code_signing_preimage, encode_set_code_transaction, encode_transaction,
52 encoded_access_list_signing_preimage_len, encoded_access_list_transaction_len,
53 encoded_blob_signing_preimage_len, encoded_blob_transaction_len,
54 encoded_dynamic_fee_signing_preimage_len, encoded_dynamic_fee_transaction_len,
55 encoded_legacy_eip155_signing_preimage_len, encoded_legacy_transaction_len,
56 encoded_set_code_authorization_signing_preimage_len, encoded_set_code_signing_preimage_len,
57 encoded_set_code_transaction_len, encoded_transaction_len,
58 validate_set_code_transaction_context,
59};
60
61#[non_exhaustive]
63#[derive(Clone, Copy, Debug, Eq, PartialEq)]
64pub enum ProtocolError {
65 Feature(FeatureError),
67 Fork(ForkError),
69 InvalidStateTransition,
71}
72
73impl ProtocolError {
74 #[must_use]
76 pub const fn code(self) -> &'static str {
77 match self {
78 Self::Feature(error) => error.code(),
79 Self::Fork(error) => error.code(),
80 Self::InvalidStateTransition => "ETH_PROTOCOL_INVALID_STATE_TRANSITION",
81 }
82 }
83
84 #[must_use]
86 pub const fn message(self) -> &'static str {
87 match self {
88 Self::Feature(error) => error.message(),
89 Self::Fork(error) => error.message(),
90 Self::InvalidStateTransition => {
91 "validation state transition is not allowed from the current state"
92 }
93 }
94 }
95
96 #[must_use]
98 pub const fn category(self) -> ProtocolErrorCategory {
99 match self {
100 Self::Feature(_) => ProtocolErrorCategory::Feature,
101 Self::Fork(_) => ProtocolErrorCategory::Fork,
102 Self::InvalidStateTransition => ProtocolErrorCategory::State,
103 }
104 }
105}
106
107impl fmt::Display for ProtocolError {
108 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
109 formatter.write_str(self.message())
110 }
111}
112
113#[cfg(feature = "std")]
114impl std::error::Error for ProtocolError {}
115
116#[non_exhaustive]
118#[derive(Clone, Copy, Debug, Eq, PartialEq)]
119pub enum ProtocolErrorCategory {
120 Feature,
122 Fork,
124 State,
126}
127
128#[non_exhaustive]
130#[derive(Clone, Copy, Debug, Eq, PartialEq)]
131pub enum FeatureError {
132 Disabled,
134 Unsupported,
136}
137
138impl FeatureError {
139 #[must_use]
141 pub const fn code(self) -> &'static str {
142 match self {
143 Self::Disabled => "ETH_FEATURE_DISABLED",
144 Self::Unsupported => "ETH_FEATURE_UNSUPPORTED",
145 }
146 }
147
148 #[must_use]
150 pub const fn message(self) -> &'static str {
151 match self {
152 Self::Disabled => "feature is disabled for this operation",
153 Self::Unsupported => "feature is not supported by this crate version",
154 }
155 }
156}
157
158impl fmt::Display for FeatureError {
159 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
160 formatter.write_str(self.message())
161 }
162}
163
164#[cfg(feature = "std")]
165impl std::error::Error for FeatureError {}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170 extern crate std;
171 use std::string::ToString;
172
173 #[test]
174 fn protocol_errors_have_stable_codes_and_categories() {
175 let error = ProtocolError::Fork(ForkError::Inactive);
176
177 assert_eq!(error.code(), "ETH_FORK_INACTIVE");
178 assert_eq!(
179 error.message(),
180 "fork is not active for the validation context"
181 );
182 assert_eq!(error.category(), ProtocolErrorCategory::Fork);
183 assert_eq!(
184 error.to_string(),
185 "fork is not active for the validation context"
186 );
187 }
188
189 #[test]
190 fn feature_errors_format_without_payloads() {
191 let error = ProtocolError::Feature(FeatureError::Unsupported);
192
193 assert_eq!(error.code(), "ETH_FEATURE_UNSUPPORTED");
194 assert_eq!(
195 FeatureError::Unsupported.to_string(),
196 "feature is not supported by this crate version"
197 );
198 }
199}