Skip to main content

eth_valkyoth_protocol/
lib.rs

1#![no_std]
2#![forbid(unsafe_code)]
3//! Fork-aware Ethereum protocol validation state.
4
5#[cfg(feature = "std")]
6extern crate std;
7
8use core::fmt;
9
10mod fork;
11mod header;
12mod state;
13mod transaction;
14
15pub use fork::{ChainSpec, ForkActivation, ForkError, ForkSpec, Hardfork, ValidationContext};
16pub use header::{
17    BlockHash, BlockHeaderDecodeError, BlockHeaderDecodeErrorCategory, BlockHeaderField,
18    CANCUN_HEADER_FIELD_COUNT, HeaderFieldSet, LEGACY_HEADER_FIELD_COUNT,
19    LONDON_HEADER_FIELD_COUNT, LogsBloom, PRAGUE_HEADER_FIELD_COUNT, SHANGHAI_HEADER_FIELD_COUNT,
20    UnvalidatedBlockHeader, decode_block_header,
21};
22pub use state::{
23    Canonical, CanonicalValidationProof, Decoded, ForkValidated, ForkValidationProof,
24    SenderRecovered, SenderRecoveryProof, StateTransitionError, Transaction,
25};
26pub use transaction::{
27    ACCESS_LIST_TRANSACTION_FIELD_COUNT, ACCESS_LIST_TRANSACTION_TYPE, AccessList,
28    AccessListEntries, AccessListEntry, AccessListStorageKeyItems, AccessListStorageKeys,
29    AccessListTransactionDecodeError, AccessListTransactionDecodeErrorCategory,
30    AccessListTransactionField, AccessListTransactionTo, BLOB_TRANSACTION_FIELD_COUNT,
31    BLOB_TRANSACTION_TYPE, BlobTransactionDecodeError, BlobTransactionDecodeErrorCategory,
32    BlobTransactionField, BlobVersionedHashItems, BlobVersionedHashes,
33    DYNAMIC_FEE_TRANSACTION_FIELD_COUNT, DYNAMIC_FEE_TRANSACTION_TYPE,
34    DynamicFeeTransactionDecodeError, DynamicFeeTransactionDecodeErrorCategory,
35    DynamicFeeTransactionField, DynamicFeeTransactionTo, EIP_2718_MAX_TYPED_PREFIX,
36    EIP_2718_RESERVED_PREFIX, EIP_2718_SCALAR_PREFIX_START, EIP_2718_TYPED_ZERO_PREFIX,
37    EIP_7702_DELEGATION_INDICATOR_PREFIX, InvalidSignatureYParity, LEGACY_TRANSACTION_FIELD_COUNT,
38    LEGACY_TRANSACTION_PREFIX_START, LegacyTransactionDecodeError,
39    LegacyTransactionDecodeErrorCategory, LegacyTransactionField, LegacyTransactionTo,
40    SET_CODE_AUTHORIZATION_FIELD_COUNT, SET_CODE_AUTHORIZATION_MAGIC,
41    SET_CODE_TRANSACTION_FIELD_COUNT, SET_CODE_TRANSACTION_TYPE, SetCodeAuthorityAccount,
42    SetCodeAuthorityCode, SetCodeAuthorityStateView, SetCodeAuthorization,
43    SetCodeAuthorizationAuthority, SetCodeAuthorizationAuthorityView, SetCodeAuthorizationChainId,
44    SetCodeAuthorizationField, SetCodeAuthorizationItems, SetCodeAuthorizationList,
45    SetCodeTransactionDecodeError, SetCodeTransactionDecodeErrorCategory, SetCodeTransactionField,
46    SetCodeTransactionValidationContext, SetCodeTransactionValidityError,
47    SetCodeTransactionValidityErrorCategory, SignatureYParity, TransactionEncodeError,
48    TransactionEncodeErrorCategory, TransactionEnvelope, TransactionEnvelopeError,
49    TransactionEnvelopeErrorCategory, TypedTransactionEnvelope, UnvalidatedAccessListTransaction,
50    UnvalidatedBlobTransaction, UnvalidatedDynamicFeeTransaction, UnvalidatedLegacyTransaction,
51    UnvalidatedSetCodeTransaction, UnvalidatedTransaction, ValidSetCodeTransaction,
52    decode_access_list_transaction, decode_blob_transaction, decode_dynamic_fee_transaction,
53    decode_legacy_transaction, decode_set_code_transaction, decode_transaction_envelope,
54    encode_access_list_signing_preimage, encode_access_list_transaction,
55    encode_blob_signing_preimage, encode_blob_transaction, encode_dynamic_fee_signing_preimage,
56    encode_dynamic_fee_transaction, encode_legacy_eip155_signing_preimage,
57    encode_legacy_transaction, encode_set_code_authorization_signing_preimage,
58    encode_set_code_signing_preimage, encode_set_code_transaction, encode_transaction,
59    encoded_access_list_signing_preimage_len, encoded_access_list_transaction_len,
60    encoded_blob_signing_preimage_len, encoded_blob_transaction_len,
61    encoded_dynamic_fee_signing_preimage_len, encoded_dynamic_fee_transaction_len,
62    encoded_legacy_eip155_signing_preimage_len, encoded_legacy_transaction_len,
63    encoded_set_code_authorization_signing_preimage_len, encoded_set_code_signing_preimage_len,
64    encoded_set_code_transaction_len, encoded_transaction_len,
65    validate_set_code_transaction_context,
66};
67
68/// Protocol validation failure.
69#[non_exhaustive]
70#[derive(Clone, Copy, Debug, Eq, PartialEq)]
71pub enum ProtocolError {
72    /// A feature is disabled or unsupported for the selected operation.
73    Feature(FeatureError),
74    /// Fork context is missing, unsupported, or inactive.
75    Fork(ForkError),
76    /// A validation state transition was attempted out of order.
77    InvalidStateTransition,
78}
79
80impl ProtocolError {
81    /// Stable machine-readable error code.
82    #[must_use]
83    pub const fn code(self) -> &'static str {
84        match self {
85            Self::Feature(error) => error.code(),
86            Self::Fork(error) => error.code(),
87            Self::InvalidStateTransition => "ETH_PROTOCOL_INVALID_STATE_TRANSITION",
88        }
89    }
90
91    /// Stable human-readable error message.
92    #[must_use]
93    pub const fn message(self) -> &'static str {
94        match self {
95            Self::Feature(error) => error.message(),
96            Self::Fork(error) => error.message(),
97            Self::InvalidStateTransition => {
98                "validation state transition is not allowed from the current state"
99            }
100        }
101    }
102
103    /// Stable high-level category for policy decisions.
104    #[must_use]
105    pub const fn category(self) -> ProtocolErrorCategory {
106        match self {
107            Self::Feature(_) => ProtocolErrorCategory::Feature,
108            Self::Fork(_) => ProtocolErrorCategory::Fork,
109            Self::InvalidStateTransition => ProtocolErrorCategory::State,
110        }
111    }
112}
113
114impl fmt::Display for ProtocolError {
115    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
116        formatter.write_str(self.message())
117    }
118}
119
120#[cfg(feature = "std")]
121impl std::error::Error for ProtocolError {}
122
123/// Stable high-level protocol error categories.
124#[non_exhaustive]
125#[derive(Clone, Copy, Debug, Eq, PartialEq)]
126pub enum ProtocolErrorCategory {
127    /// Feature support or configuration failure.
128    Feature,
129    /// Fork selection or activation failure.
130    Fork,
131    /// Validation state failure.
132    State,
133}
134
135/// Feature availability failure.
136#[non_exhaustive]
137#[derive(Clone, Copy, Debug, Eq, PartialEq)]
138pub enum FeatureError {
139    /// The feature is intentionally not enabled for this build or context.
140    Disabled,
141    /// The feature is not implemented by this crate version.
142    Unsupported,
143}
144
145impl FeatureError {
146    /// Stable machine-readable error code.
147    #[must_use]
148    pub const fn code(self) -> &'static str {
149        match self {
150            Self::Disabled => "ETH_FEATURE_DISABLED",
151            Self::Unsupported => "ETH_FEATURE_UNSUPPORTED",
152        }
153    }
154
155    /// Stable human-readable error message.
156    #[must_use]
157    pub const fn message(self) -> &'static str {
158        match self {
159            Self::Disabled => "feature is disabled for this operation",
160            Self::Unsupported => "feature is not supported by this crate version",
161        }
162    }
163}
164
165impl fmt::Display for FeatureError {
166    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
167        formatter.write_str(self.message())
168    }
169}
170
171#[cfg(feature = "std")]
172impl std::error::Error for FeatureError {}
173
174#[cfg(test)]
175mod tests {
176    use super::*;
177    extern crate std;
178    use std::string::ToString;
179
180    #[test]
181    fn protocol_errors_have_stable_codes_and_categories() {
182        let error = ProtocolError::Fork(ForkError::Inactive);
183
184        assert_eq!(error.code(), "ETH_FORK_INACTIVE");
185        assert_eq!(
186            error.message(),
187            "fork is not active for the validation context"
188        );
189        assert_eq!(error.category(), ProtocolErrorCategory::Fork);
190        assert_eq!(
191            error.to_string(),
192            "fork is not active for the validation context"
193        );
194    }
195
196    #[test]
197    fn feature_errors_format_without_payloads() {
198        let error = ProtocolError::Feature(FeatureError::Unsupported);
199
200        assert_eq!(error.code(), "ETH_FEATURE_UNSUPPORTED");
201        assert_eq!(
202            FeatureError::Unsupported.to_string(),
203            "feature is not supported by this crate version"
204        );
205    }
206}