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