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 &{
153 #[cfg(feature = "std")]
154 {
155 reth_zstd_compressors::TRANSACTION_COMPRESSOR.with(|compressor| {
156 let mut compressor = compressor.borrow_mut();
157 compressor.compress(&tx_buf)
158 })
159 }
160 #[cfg(not(feature = "std"))]
161 {
162 let mut compressor = reth_zstd_compressors::create_tx_compressor();
163 compressor.compress(&tx_buf)
164 }
165 }
166 .expect("Failed to compress"),
167 );
168 tx_bits
169 } else {
170 let tx_bits = self.tx_type().to_compact(buf) as u8;
171 self.to_tx_compact(buf);
172 tx_bits
173 };
174
175 let flags = sig_bit | (tx_bits << 1) | ((zstd_bit as u8) << 3);
176 buf.as_mut()[start] = flags;
177
178 buf.as_mut().len() - start
179 }
180
181 fn from_compact(mut buf: &[u8], _len: usize) -> (Self, &[u8]) {
182 let flags = buf.get_u8() as usize;
183
184 let sig_bit = flags & 1;
185 let tx_bits = (flags & 0b110) >> 1;
186 let zstd_bit = flags >> 3;
187
188 let (signature, buf) = Signature::from_compact(buf, sig_bit);
189
190 let (transaction, buf) = if zstd_bit != 0 {
191 #[cfg(feature = "std")]
192 {
193 reth_zstd_compressors::TRANSACTION_DECOMPRESSOR.with(|decompressor| {
194 let mut decompressor = decompressor.borrow_mut();
195 let decompressed = decompressor.decompress(buf);
196
197 let (tx_type, tx_buf) = T::TxType::from_compact(decompressed, tx_bits);
198 let (tx, _) = Self::from_tx_compact(tx_buf, tx_type, signature);
199
200 (tx, buf)
201 })
202 }
203 #[cfg(not(feature = "std"))]
204 {
205 let mut decompressor = reth_zstd_compressors::create_tx_decompressor();
206 let decompressed = decompressor.decompress(buf);
207 let (tx_type, tx_buf) = T::TxType::from_compact(decompressed, tx_bits);
208 let (tx, _) = Self::from_tx_compact(tx_buf, tx_type, signature);
209
210 (tx, buf)
211 }
212 } else {
213 let (tx_type, buf) = T::TxType::from_compact(buf, tx_bits);
214 Self::from_tx_compact(buf, tx_type, signature)
215 };
216
217 (transaction, buf)
218 }
219}
220
221impl<Eip4844: Compact + RlpEcdsaEncodableTx + Transaction + Send + Sync> Compact
222 for EthereumTxEnvelope<Eip4844>
223{
224 fn to_compact<B>(&self, buf: &mut B) -> usize
225 where
226 B: BufMut + AsMut<[u8]>,
227 {
228 <Self as CompactEnvelope>::to_compact(self, buf)
229 }
230
231 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
232 <Self as CompactEnvelope>::from_compact(buf, len)
233 }
234}