reth_codecs/alloy/transaction/
ethereum.rs1use crate::{Compact, Vec};
2use alloy_consensus::{
3 transaction::RlpEcdsaEncodableTx, EthereumTxEnvelope, Signed, Transaction, TxEip1559,
4 TxEip2930, TxEip7702, TxLegacy, TxType,
5};
6use alloy_primitives::Signature;
7use bytes::{Buf, BufMut};
8
9pub trait ToTxCompact {
18 fn to_tx_compact(&self, buf: &mut (impl BufMut + AsMut<[u8]>));
23}
24
25pub trait FromTxCompact {
34 type TxType;
36
37 fn from_tx_compact(buf: &[u8], tx_type: Self::TxType, signature: Signature) -> (Self, &[u8])
44 where
45 Self: Sized;
46}
47
48impl<Eip4844: Compact + Transaction> ToTxCompact for EthereumTxEnvelope<Eip4844> {
49 fn to_tx_compact(&self, buf: &mut (impl BufMut + AsMut<[u8]>)) {
50 match self {
51 Self::Legacy(tx) => tx.tx().to_compact(buf),
52 Self::Eip2930(tx) => tx.tx().to_compact(buf),
53 Self::Eip1559(tx) => tx.tx().to_compact(buf),
54 Self::Eip4844(tx) => tx.tx().to_compact(buf),
55 Self::Eip7702(tx) => tx.tx().to_compact(buf),
56 };
57 }
58}
59
60impl<Eip4844: Compact + Transaction> FromTxCompact for EthereumTxEnvelope<Eip4844> {
61 type TxType = TxType;
62
63 fn from_tx_compact(buf: &[u8], tx_type: TxType, signature: Signature) -> (Self, &[u8]) {
64 match tx_type {
65 TxType::Legacy => {
66 let (tx, buf) = TxLegacy::from_compact(buf, buf.len());
67 let tx = Signed::new_unhashed(tx, signature);
68 (Self::Legacy(tx), buf)
69 }
70 TxType::Eip2930 => {
71 let (tx, buf) = TxEip2930::from_compact(buf, buf.len());
72 let tx = Signed::new_unhashed(tx, signature);
73 (Self::Eip2930(tx), buf)
74 }
75 TxType::Eip1559 => {
76 let (tx, buf) = TxEip1559::from_compact(buf, buf.len());
77 let tx = Signed::new_unhashed(tx, signature);
78 (Self::Eip1559(tx), buf)
79 }
80 TxType::Eip4844 => {
81 let (tx, buf) = Eip4844::from_compact(buf, buf.len());
82 let tx = Signed::new_unhashed(tx, signature);
83 (Self::Eip4844(tx), buf)
84 }
85 TxType::Eip7702 => {
86 let (tx, buf) = TxEip7702::from_compact(buf, buf.len());
87 let tx = Signed::new_unhashed(tx, signature);
88 (Self::Eip7702(tx), buf)
89 }
90 }
91 }
92}
93
94pub trait Envelope: FromTxCompact<TxType: Compact> {
96 fn signature(&self) -> &Signature;
98
99 fn tx_type(&self) -> Self::TxType;
101}
102
103impl<Eip4844: Compact + Transaction + RlpEcdsaEncodableTx> Envelope
104 for EthereumTxEnvelope<Eip4844>
105{
106 fn signature(&self) -> &Signature {
107 Self::signature(self)
108 }
109
110 fn tx_type(&self) -> Self::TxType {
111 Self::tx_type(self)
112 }
113}
114
115pub trait CompactEnvelope: Sized {
117 fn to_compact<B>(&self, buf: &mut B) -> usize
119 where
120 B: BufMut + AsMut<[u8]>;
121
122 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]);
129}
130
131impl<T: Envelope + ToTxCompact + Transaction + Send + Sync> CompactEnvelope for T {
132 fn to_compact<B>(&self, buf: &mut B) -> usize
133 where
134 B: BufMut + AsMut<[u8]>,
135 {
136 let start = buf.as_mut().len();
137
138 buf.put_u8(0);
141
142 let sig_bit = self.signature().to_compact(buf) as u8;
143 let zstd_bit = self.input().len() >= 32;
144
145 let tx_bits = if zstd_bit {
146 let mut tx_buf = Vec::with_capacity(256);
148 let tx_bits = self.tx_type().to_compact(&mut tx_buf) as u8;
149 self.to_tx_compact(&mut tx_buf);
150
151 buf.put_slice(
152 &reth_zstd_compressors::with_tx_compressor(|compressor| {
153 compressor.compress(&tx_buf)
154 })
155 .expect("Failed to compress"),
156 );
157 tx_bits
158 } else {
159 let tx_bits = self.tx_type().to_compact(buf) as u8;
160 self.to_tx_compact(buf);
161 tx_bits
162 };
163
164 let flags = sig_bit | (tx_bits << 1) | ((zstd_bit as u8) << 3);
165 buf.as_mut()[start] = flags;
166
167 buf.as_mut().len() - start
168 }
169
170 fn from_compact(mut buf: &[u8], _len: usize) -> (Self, &[u8]) {
171 let flags = buf.get_u8() as usize;
172
173 let sig_bit = flags & 1;
174 let tx_bits = (flags & 0b110) >> 1;
175 let zstd_bit = flags >> 3;
176
177 let (signature, buf) = Signature::from_compact(buf, sig_bit);
178
179 let (transaction, buf) = if zstd_bit != 0 {
180 reth_zstd_compressors::with_tx_decompressor(|decompressor| {
181 let decompressed = decompressor.decompress(buf);
182 let (tx_type, tx_buf) = T::TxType::from_compact(decompressed, tx_bits);
183 let (tx, _) = Self::from_tx_compact(tx_buf, tx_type, signature);
184 (tx, buf)
185 })
186 } else {
187 let (tx_type, buf) = T::TxType::from_compact(buf, tx_bits);
188 Self::from_tx_compact(buf, tx_type, signature)
189 };
190
191 (transaction, buf)
192 }
193}
194
195impl<Eip4844: Compact + RlpEcdsaEncodableTx + Transaction + Send + Sync> Compact
196 for EthereumTxEnvelope<Eip4844>
197{
198 fn to_compact<B>(&self, buf: &mut B) -> usize
199 where
200 B: BufMut + AsMut<[u8]>,
201 {
202 <Self as CompactEnvelope>::to_compact(self, buf)
203 }
204
205 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
206 <Self as CompactEnvelope>::from_compact(buf, len)
207 }
208}