Skip to main content

eth_valkyoth_protocol/
state.rs

1use core::marker::PhantomData;
2
3use crate::ProtocolError;
4
5/// Raw wire input was accepted by the codec.
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7pub struct Decoded;
8
9/// Canonical wire form and type-specific structure were checked.
10#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11pub struct Canonical;
12
13/// Fork-specific validity was checked.
14#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15pub struct ForkValidated;
16
17/// Sender recovery succeeded.
18#[derive(Clone, Copy, Debug, Eq, PartialEq)]
19pub struct SenderRecovered;
20
21/// Proof that canonical transaction structure was checked.
22///
23/// This proof is intentionally not publicly constructible yet. Public
24/// constructors must bind the proof to the transaction identity they attest to
25/// before validators can create this value.
26#[derive(Debug, Eq, PartialEq)]
27pub struct CanonicalValidationProof {
28    _private: (),
29}
30
31impl CanonicalValidationProof {
32    #[must_use]
33    #[cfg(test)]
34    pub(crate) const fn new() -> Self {
35        Self { _private: () }
36    }
37}
38
39/// Proof that fork-specific transaction validity was checked.
40///
41/// This proof is intentionally not publicly constructible yet. Public
42/// constructors must bind the proof to the transaction identity they attest to
43/// before validators can create this value.
44#[derive(Debug, Eq, PartialEq)]
45pub struct ForkValidationProof {
46    _private: (),
47}
48
49impl ForkValidationProof {
50    #[must_use]
51    #[cfg(test)]
52    pub(crate) const fn new() -> Self {
53        Self { _private: () }
54    }
55}
56
57/// Proof that sender recovery succeeded.
58///
59/// This proof is intentionally not publicly constructible yet. Public
60/// constructors must bind the proof to the transaction identity they attest to
61/// before validators can create this value.
62#[derive(Debug, Eq, PartialEq)]
63pub struct SenderRecoveryProof {
64    _private: (),
65}
66
67impl SenderRecoveryProof {
68    #[must_use]
69    #[cfg(test)]
70    pub(crate) const fn new() -> Self {
71        Self { _private: () }
72    }
73}
74
75/// Failed state transition that returns the original transaction token.
76#[derive(Debug, Eq, PartialEq)]
77pub struct StateTransitionError<State> {
78    transaction: Transaction<State>,
79    error: ProtocolError,
80}
81
82impl<State> StateTransitionError<State> {
83    const fn new(transaction: Transaction<State>, error: ProtocolError) -> Self {
84        Self { transaction, error }
85    }
86
87    /// Returns the validation error that prevented promotion.
88    #[must_use]
89    pub const fn error(&self) -> ProtocolError {
90        self.error
91    }
92
93    /// Splits this error into the original transaction token and error.
94    #[must_use]
95    pub fn into_parts(self) -> (Transaction<State>, ProtocolError) {
96        (self.transaction, self.error)
97    }
98}
99
100/// A transaction token whose validation state is tracked at compile time.
101#[derive(Debug, Eq, PartialEq)]
102pub struct Transaction<State> {
103    _state: PhantomData<State>,
104}
105
106impl<State> Transaction<State> {
107    const fn new() -> Self {
108        Self {
109            _state: PhantomData,
110        }
111    }
112}
113
114impl Transaction<Decoded> {
115    /// Creates a token for a decoded transaction in internal tests.
116    ///
117    /// A public decoded-transaction entry point will be added only together
118    /// with the real codec output that proves the decoded state.
119    #[must_use]
120    #[cfg(test)]
121    pub(crate) const fn decoded() -> Self {
122        Self::new()
123    }
124
125    /// Advances to canonical form after canonical checks pass.
126    pub fn try_into_canonical(
127        self,
128        proof: Result<CanonicalValidationProof, ProtocolError>,
129    ) -> Result<Transaction<Canonical>, StateTransitionError<Decoded>> {
130        if let Err(error) = proof {
131            return Err(StateTransitionError::new(self, error));
132        }
133        Ok(Transaction::new())
134    }
135}
136
137impl Transaction<Canonical> {
138    /// Advances after fork-specific validation passes.
139    pub fn try_into_fork_validated(
140        self,
141        proof: Result<ForkValidationProof, ProtocolError>,
142    ) -> Result<Transaction<ForkValidated>, StateTransitionError<Canonical>> {
143        if let Err(error) = proof {
144            return Err(StateTransitionError::new(self, error));
145        }
146        Ok(Transaction::new())
147    }
148}
149
150impl Transaction<ForkValidated> {
151    /// Advances after sender recovery succeeds.
152    pub fn try_into_sender_recovered(
153        self,
154        proof: Result<SenderRecoveryProof, ProtocolError>,
155    ) -> Result<Transaction<SenderRecovered>, StateTransitionError<ForkValidated>> {
156        if let Err(error) = proof {
157            return Err(StateTransitionError::new(self, error));
158        }
159        Ok(Transaction::new())
160    }
161}
162
163#[cfg(test)]
164#[path = "state_tests.rs"]
165mod tests;