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