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