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        let (tx, _) = TxDeposit::from_compact(buf, len);
70        let alloy_tx = Self {
71            source_hash: tx.source_hash,
72            from: tx.from,
73            to: tx.to,
74            mint: tx.mint.unwrap_or_default(),
75            value: tx.value,
76            gas_limit: tx.gas_limit,
77            is_system_transaction: tx.is_system_transaction,
78            input: tx.input,
79        };
80        (alloy_tx, buf)
81    }
82}
83
84impl crate::Compact for OpTxType {
85    fn to_compact<B>(&self, buf: &mut B) -> usize
86    where
87        B: bytes::BufMut + AsMut<[u8]>,
88    {
89        use crate::txtype::*;
90
91        match self {
92            Self::Legacy => COMPACT_IDENTIFIER_LEGACY,
93            Self::Eip2930 => COMPACT_IDENTIFIER_EIP2930,
94            Self::Eip1559 => COMPACT_IDENTIFIER_EIP1559,
95            Self::Eip7702 => {
96                buf.put_u8(EIP7702_TX_TYPE_ID);
97                COMPACT_EXTENDED_IDENTIFIER_FLAG
98            }
99            Self::Deposit => {
100                buf.put_u8(op_alloy_consensus::DEPOSIT_TX_TYPE_ID);
101                COMPACT_EXTENDED_IDENTIFIER_FLAG
102            }
103        }
104    }
105
106    // For backwards compatibility purposes only 2 bits of the type are encoded in the identifier
107    // parameter. In the case of a [`COMPACT_EXTENDED_IDENTIFIER_FLAG`], the full transaction type
108    // is read from the buffer as a single byte.
109    fn from_compact(mut buf: &[u8], identifier: usize) -> (Self, &[u8]) {
110        use bytes::Buf;
111        (
112            match identifier {
113                COMPACT_IDENTIFIER_LEGACY => Self::Legacy,
114                COMPACT_IDENTIFIER_EIP2930 => Self::Eip2930,
115                COMPACT_IDENTIFIER_EIP1559 => Self::Eip1559,
116                COMPACT_EXTENDED_IDENTIFIER_FLAG => {
117                    let extended_identifier = buf.get_u8();
118                    match extended_identifier {
119                        EIP7702_TX_TYPE_ID => Self::Eip7702,
120                        op_alloy_consensus::DEPOSIT_TX_TYPE_ID => Self::Deposit,
121                        _ => panic!("Unsupported OpTxType identifier: {extended_identifier}"),
122                    }
123                }
124                _ => panic!("Unknown identifier for TxType: {identifier}"),
125            },
126            buf,
127        )
128    }
129}
130
131impl Compact for OpTypedTransaction {
132    fn to_compact<B>(&self, out: &mut B) -> usize
133    where
134        B: bytes::BufMut + AsMut<[u8]>,
135    {
136        let identifier = self.tx_type().to_compact(out);
137        match self {
138            Self::Legacy(tx) => tx.to_compact(out),
139            Self::Eip2930(tx) => tx.to_compact(out),
140            Self::Eip1559(tx) => tx.to_compact(out),
141            Self::Eip7702(tx) => tx.to_compact(out),
142            Self::Deposit(tx) => tx.to_compact(out),
143        };
144        identifier
145    }
146
147    fn from_compact(buf: &[u8], identifier: usize) -> (Self, &[u8]) {
148        let (tx_type, buf) = OpTxType::from_compact(buf, identifier);
149        match tx_type {
150            OpTxType::Legacy => {
151                let (tx, buf) = Compact::from_compact(buf, buf.len());
152                (Self::Legacy(tx), buf)
153            }
154            OpTxType::Eip2930 => {
155                let (tx, buf) = Compact::from_compact(buf, buf.len());
156                (Self::Eip2930(tx), buf)
157            }
158            OpTxType::Eip1559 => {
159                let (tx, buf) = Compact::from_compact(buf, buf.len());
160                (Self::Eip1559(tx), buf)
161            }
162            OpTxType::Eip7702 => {
163                let (tx, buf) = Compact::from_compact(buf, buf.len());
164                (Self::Eip7702(tx), buf)
165            }
166            OpTxType::Deposit => {
167                let (tx, buf) = Compact::from_compact(buf, buf.len());
168                (Self::Deposit(tx), buf)
169            }
170        }
171    }
172}
173
174impl ToTxCompact for OpTxEnvelope {
175    fn to_tx_compact(&self, buf: &mut (impl BufMut + AsMut<[u8]>)) {
176        match self {
177            Self::Legacy(tx) => tx.tx().to_compact(buf),
178            Self::Eip2930(tx) => tx.tx().to_compact(buf),
179            Self::Eip1559(tx) => tx.tx().to_compact(buf),
180            Self::Eip7702(tx) => tx.tx().to_compact(buf),
181            Self::Deposit(tx) => tx.to_compact(buf),
182        };
183    }
184}
185
186impl FromTxCompact for OpTxEnvelope {
187    type TxType = OpTxType;
188
189    fn from_tx_compact(buf: &[u8], tx_type: OpTxType, signature: Signature) -> (Self, &[u8]) {
190        match tx_type {
191            OpTxType::Legacy => {
192                let (tx, buf) = TxLegacy::from_compact(buf, buf.len());
193                let tx = Signed::new_unhashed(tx, signature);
194                (Self::Legacy(tx), buf)
195            }
196            OpTxType::Eip2930 => {
197                let (tx, buf) = TxEip2930::from_compact(buf, buf.len());
198                let tx = Signed::new_unhashed(tx, signature);
199                (Self::Eip2930(tx), buf)
200            }
201            OpTxType::Eip1559 => {
202                let (tx, buf) = TxEip1559::from_compact(buf, buf.len());
203                let tx = Signed::new_unhashed(tx, signature);
204                (Self::Eip1559(tx), buf)
205            }
206            OpTxType::Eip7702 => {
207                let (tx, buf) = TxEip7702::from_compact(buf, buf.len());
208                let tx = Signed::new_unhashed(tx, signature);
209                (Self::Eip7702(tx), buf)
210            }
211            OpTxType::Deposit => {
212                let (tx, buf) = op_alloy_consensus::TxDeposit::from_compact(buf, buf.len());
213                let tx = Sealed::new(tx);
214                (Self::Deposit(tx), buf)
215            }
216        }
217    }
218}
219
220const DEPOSIT_SIGNATURE: Signature = Signature::new(U256::ZERO, U256::ZERO, false);
221
222impl Envelope for OpTxEnvelope {
223    fn signature(&self) -> &Signature {
224        match self {
225            Self::Legacy(tx) => tx.signature(),
226            Self::Eip2930(tx) => tx.signature(),
227            Self::Eip1559(tx) => tx.signature(),
228            Self::Eip7702(tx) => tx.signature(),
229            Self::Deposit(_) => &DEPOSIT_SIGNATURE,
230        }
231    }
232
233    fn tx_type(&self) -> Self::TxType {
234        Self::tx_type(self)
235    }
236}
237
238impl Compact for OpTxEnvelope {
239    fn to_compact<B>(&self, buf: &mut B) -> usize
240    where
241        B: BufMut + AsMut<[u8]>,
242    {
243        CompactEnvelope::to_compact(self, buf)
244    }
245
246    fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
247        CompactEnvelope::from_compact(buf, len)
248    }
249}
250
251generate_tests!(#[crate, compact] OpTypedTransaction, OpTypedTransactionTests);