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