reth_codecs/alloy/transaction/
optimism.rs

1//! Compact implementation for [`AlloyTxDeposit`]
2
3use crate::{
4    alloy::transaction::ethereum::{CompactEnvelope, Envelope, FromTxCompact, ToTxCompact},
5    generate_tests,
6    txtype::{
7        COMPACT_EXTENDED_IDENTIFIER_FLAG, COMPACT_IDENTIFIER_EIP1559, COMPACT_IDENTIFIER_EIP2930,
8        COMPACT_IDENTIFIER_LEGACY,
9    },
10    Compact,
11};
12use alloy_consensus::{
13    constants::EIP7702_TX_TYPE_ID, Signed, TxEip1559, TxEip2930, TxEip7702, TxLegacy,
14};
15use alloy_primitives::{Address, Bytes, Sealed, Signature, TxKind, B256, U256};
16use bytes::BufMut;
17use op_alloy_consensus::{OpTxEnvelope, OpTxType, OpTypedTransaction, TxDeposit as AlloyTxDeposit};
18use reth_codecs_derive::add_arbitrary_tests;
19
20/// Deposit transactions, also known as deposits are initiated on L1, and executed on L2.
21///
22/// This is a helper type to use derive on it instead of manually managing `bitfield`.
23///
24/// By deriving `Compact` here, any future changes or enhancements to the `Compact` derive
25/// will automatically apply to this type.
26///
27/// Notice: Make sure this struct is 1:1 with [`op_alloy_consensus::TxDeposit`]
28#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Compact)]
29#[cfg_attr(
30    any(test, feature = "test-utils"),
31    derive(arbitrary::Arbitrary, serde::Serialize, serde::Deserialize)
32)]
33#[cfg_attr(feature = "test-utils", allow(unreachable_pub), visibility::make(pub))]
34#[reth_codecs(crate = "crate")]
35#[add_arbitrary_tests(crate, compact)]
36pub(crate) struct TxDeposit {
37    source_hash: B256,
38    from: Address,
39    to: TxKind,
40    mint: Option<u128>,
41    value: U256,
42    gas_limit: u64,
43    is_system_transaction: bool,
44    input: Bytes,
45}
46
47impl Compact for AlloyTxDeposit {
48    fn to_compact<B>(&self, buf: &mut B) -> usize
49    where
50        B: bytes::BufMut + AsMut<[u8]>,
51    {
52        let tx = TxDeposit {
53            source_hash: self.source_hash,
54            from: self.from,
55            to: self.to,
56            mint: match self.mint {
57                0 => None,
58                v => Some(v),
59            },
60            value: self.value,
61            gas_limit: self.gas_limit,
62            is_system_transaction: self.is_system_transaction,
63            input: self.input.clone(),
64        };
65        tx.to_compact(buf)
66    }
67
68    fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
69        // Return the remaining slice from the inner from_compact to advance the cursor correctly.
70        let (tx, remaining) = TxDeposit::from_compact(buf, len);
71        let alloy_tx = Self {
72            source_hash: tx.source_hash,
73            from: tx.from,
74            to: tx.to,
75            mint: tx.mint.unwrap_or_default(),
76            value: tx.value,
77            gas_limit: tx.gas_limit,
78            is_system_transaction: tx.is_system_transaction,
79            input: tx.input,
80        };
81        (alloy_tx, remaining)
82    }
83}
84
85impl crate::Compact for OpTxType {
86    fn to_compact<B>(&self, buf: &mut B) -> usize
87    where
88        B: bytes::BufMut + AsMut<[u8]>,
89    {
90        use crate::txtype::*;
91
92        match self {
93            Self::Legacy => COMPACT_IDENTIFIER_LEGACY,
94            Self::Eip2930 => COMPACT_IDENTIFIER_EIP2930,
95            Self::Eip1559 => COMPACT_IDENTIFIER_EIP1559,
96            Self::Eip7702 => {
97                buf.put_u8(EIP7702_TX_TYPE_ID);
98                COMPACT_EXTENDED_IDENTIFIER_FLAG
99            }
100            Self::Deposit => {
101                buf.put_u8(op_alloy_consensus::DEPOSIT_TX_TYPE_ID);
102                COMPACT_EXTENDED_IDENTIFIER_FLAG
103            }
104        }
105    }
106
107    // For backwards compatibility purposes only 2 bits of the type are encoded in the identifier
108    // parameter. In the case of a [`COMPACT_EXTENDED_IDENTIFIER_FLAG`], the full transaction type
109    // is read from the buffer as a single byte.
110    fn from_compact(mut buf: &[u8], identifier: usize) -> (Self, &[u8]) {
111        use bytes::Buf;
112        (
113            match identifier {
114                COMPACT_IDENTIFIER_LEGACY => Self::Legacy,
115                COMPACT_IDENTIFIER_EIP2930 => Self::Eip2930,
116                COMPACT_IDENTIFIER_EIP1559 => Self::Eip1559,
117                COMPACT_EXTENDED_IDENTIFIER_FLAG => {
118                    let extended_identifier = buf.get_u8();
119                    match extended_identifier {
120                        EIP7702_TX_TYPE_ID => Self::Eip7702,
121                        op_alloy_consensus::DEPOSIT_TX_TYPE_ID => Self::Deposit,
122                        _ => panic!("Unsupported OpTxType identifier: {extended_identifier}"),
123                    }
124                }
125                _ => panic!("Unknown identifier for TxType: {identifier}"),
126            },
127            buf,
128        )
129    }
130}
131
132impl Compact for OpTypedTransaction {
133    fn to_compact<B>(&self, out: &mut B) -> usize
134    where
135        B: bytes::BufMut + AsMut<[u8]>,
136    {
137        let identifier = self.tx_type().to_compact(out);
138        match self {
139            Self::Legacy(tx) => tx.to_compact(out),
140            Self::Eip2930(tx) => tx.to_compact(out),
141            Self::Eip1559(tx) => tx.to_compact(out),
142            Self::Eip7702(tx) => tx.to_compact(out),
143            Self::Deposit(tx) => tx.to_compact(out),
144        };
145        identifier
146    }
147
148    fn from_compact(buf: &[u8], identifier: usize) -> (Self, &[u8]) {
149        let (tx_type, buf) = OpTxType::from_compact(buf, identifier);
150        match tx_type {
151            OpTxType::Legacy => {
152                let (tx, buf) = Compact::from_compact(buf, buf.len());
153                (Self::Legacy(tx), buf)
154            }
155            OpTxType::Eip2930 => {
156                let (tx, buf) = Compact::from_compact(buf, buf.len());
157                (Self::Eip2930(tx), buf)
158            }
159            OpTxType::Eip1559 => {
160                let (tx, buf) = Compact::from_compact(buf, buf.len());
161                (Self::Eip1559(tx), buf)
162            }
163            OpTxType::Eip7702 => {
164                let (tx, buf) = Compact::from_compact(buf, buf.len());
165                (Self::Eip7702(tx), buf)
166            }
167            OpTxType::Deposit => {
168                let (tx, buf) = Compact::from_compact(buf, buf.len());
169                (Self::Deposit(tx), buf)
170            }
171        }
172    }
173}
174
175impl ToTxCompact for OpTxEnvelope {
176    fn to_tx_compact(&self, buf: &mut (impl BufMut + AsMut<[u8]>)) {
177        match self {
178            Self::Legacy(tx) => tx.tx().to_compact(buf),
179            Self::Eip2930(tx) => tx.tx().to_compact(buf),
180            Self::Eip1559(tx) => tx.tx().to_compact(buf),
181            Self::Eip7702(tx) => tx.tx().to_compact(buf),
182            Self::Deposit(tx) => tx.to_compact(buf),
183        };
184    }
185}
186
187impl FromTxCompact for OpTxEnvelope {
188    type TxType = OpTxType;
189
190    fn from_tx_compact(buf: &[u8], tx_type: OpTxType, signature: Signature) -> (Self, &[u8]) {
191        match tx_type {
192            OpTxType::Legacy => {
193                let (tx, buf) = TxLegacy::from_compact(buf, buf.len());
194                let tx = Signed::new_unhashed(tx, signature);
195                (Self::Legacy(tx), buf)
196            }
197            OpTxType::Eip2930 => {
198                let (tx, buf) = TxEip2930::from_compact(buf, buf.len());
199                let tx = Signed::new_unhashed(tx, signature);
200                (Self::Eip2930(tx), buf)
201            }
202            OpTxType::Eip1559 => {
203                let (tx, buf) = TxEip1559::from_compact(buf, buf.len());
204                let tx = Signed::new_unhashed(tx, signature);
205                (Self::Eip1559(tx), buf)
206            }
207            OpTxType::Eip7702 => {
208                let (tx, buf) = TxEip7702::from_compact(buf, buf.len());
209                let tx = Signed::new_unhashed(tx, signature);
210                (Self::Eip7702(tx), buf)
211            }
212            OpTxType::Deposit => {
213                let (tx, buf) = op_alloy_consensus::TxDeposit::from_compact(buf, buf.len());
214                let tx = Sealed::new(tx);
215                (Self::Deposit(tx), buf)
216            }
217        }
218    }
219}
220
221const DEPOSIT_SIGNATURE: Signature = Signature::new(U256::ZERO, U256::ZERO, false);
222
223impl Envelope for OpTxEnvelope {
224    fn signature(&self) -> &Signature {
225        match self {
226            Self::Legacy(tx) => tx.signature(),
227            Self::Eip2930(tx) => tx.signature(),
228            Self::Eip1559(tx) => tx.signature(),
229            Self::Eip7702(tx) => tx.signature(),
230            Self::Deposit(_) => &DEPOSIT_SIGNATURE,
231        }
232    }
233
234    fn tx_type(&self) -> Self::TxType {
235        Self::tx_type(self)
236    }
237}
238
239impl Compact for OpTxEnvelope {
240    fn to_compact<B>(&self, buf: &mut B) -> usize
241    where
242        B: BufMut + AsMut<[u8]>,
243    {
244        CompactEnvelope::to_compact(self, buf)
245    }
246
247    fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
248        CompactEnvelope::from_compact(buf, len)
249    }
250}
251
252generate_tests!(#[crate, compact] OpTypedTransaction, OpTypedTransactionTests);