reth_codecs/alloy/transaction/
ethereum.rs
1use crate::{Compact, Vec};
2use alloy_consensus::{
3 transaction::RlpEcdsaEncodableTx, EthereumTxEnvelope, Signed, Transaction, TxEip1559,
4 TxEip2930, TxEip7702, TxLegacy, TxType,
5};
6use alloy_primitives::PrimitiveSignature;
7use bytes::{Buf, BufMut};
8
9pub(super) trait ToTxCompact {
18 fn to_tx_compact(&self, buf: &mut (impl BufMut + AsMut<[u8]>));
23}
24
25pub(super) trait FromTxCompact {
34 type TxType;
35
36 fn from_tx_compact(
43 buf: &[u8],
44 tx_type: Self::TxType,
45 signature: PrimitiveSignature,
46 ) -> (Self, &[u8])
47 where
48 Self: Sized;
49}
50
51impl<Eip4844: Compact + Transaction> ToTxCompact for EthereumTxEnvelope<Eip4844> {
52 fn to_tx_compact(&self, buf: &mut (impl BufMut + AsMut<[u8]>)) {
53 match self {
54 Self::Legacy(tx) => tx.tx().to_compact(buf),
55 Self::Eip2930(tx) => tx.tx().to_compact(buf),
56 Self::Eip1559(tx) => tx.tx().to_compact(buf),
57 Self::Eip4844(tx) => tx.tx().to_compact(buf),
58 Self::Eip7702(tx) => tx.tx().to_compact(buf),
59 };
60 }
61}
62
63impl<Eip4844: Compact + Transaction> FromTxCompact for EthereumTxEnvelope<Eip4844> {
64 type TxType = TxType;
65
66 fn from_tx_compact(
67 buf: &[u8],
68 tx_type: TxType,
69 signature: PrimitiveSignature,
70 ) -> (Self, &[u8]) {
71 match tx_type {
72 TxType::Legacy => {
73 let (tx, buf) = TxLegacy::from_compact(buf, buf.len());
74 let tx = Signed::new_unhashed(tx, signature);
75 (Self::Legacy(tx), buf)
76 }
77 TxType::Eip2930 => {
78 let (tx, buf) = TxEip2930::from_compact(buf, buf.len());
79 let tx = Signed::new_unhashed(tx, signature);
80 (Self::Eip2930(tx), buf)
81 }
82 TxType::Eip1559 => {
83 let (tx, buf) = TxEip1559::from_compact(buf, buf.len());
84 let tx = Signed::new_unhashed(tx, signature);
85 (Self::Eip1559(tx), buf)
86 }
87 TxType::Eip4844 => {
88 let (tx, buf) = Eip4844::from_compact(buf, buf.len());
89 let tx = Signed::new_unhashed(tx, signature);
90 (Self::Eip4844(tx), buf)
91 }
92 TxType::Eip7702 => {
93 let (tx, buf) = TxEip7702::from_compact(buf, buf.len());
94 let tx = Signed::new_unhashed(tx, signature);
95 (Self::Eip7702(tx), buf)
96 }
97 }
98 }
99}
100
101pub(super) trait Envelope: FromTxCompact<TxType: Compact> {
102 fn signature(&self) -> &PrimitiveSignature;
103 fn tx_type(&self) -> Self::TxType;
104}
105
106impl<Eip4844: Compact + Transaction + RlpEcdsaEncodableTx> Envelope
107 for EthereumTxEnvelope<Eip4844>
108{
109 fn signature(&self) -> &PrimitiveSignature {
110 Self::signature(self)
111 }
112
113 fn tx_type(&self) -> Self::TxType {
114 Self::tx_type(self)
115 }
116}
117
118pub(super) trait CompactEnvelope: Sized {
119 fn to_compact<B>(&self, buf: &mut B) -> usize
121 where
122 B: BufMut + AsMut<[u8]>;
123
124 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]);
131}
132
133impl<T: Envelope + ToTxCompact + Transaction + Send + Sync> CompactEnvelope for T {
134 fn to_compact<B>(&self, buf: &mut B) -> usize
135 where
136 B: BufMut + AsMut<[u8]>,
137 {
138 let start = buf.as_mut().len();
139
140 buf.put_u8(0);
143
144 let sig_bit = self.signature().to_compact(buf) as u8;
145 let zstd_bit = self.input().len() >= 32;
146 let tx_bits = self.tx_type().to_compact(buf) as u8;
147 let flags = sig_bit | (tx_bits << 1) | ((zstd_bit as u8) << 3);
148
149 buf.as_mut()[start] = flags;
150
151 if zstd_bit {
152 let mut tx_buf = Vec::with_capacity(256);
153
154 self.to_tx_compact(&mut tx_buf);
155
156 buf.put_slice(
157 &{
158 #[cfg(feature = "std")]
159 {
160 reth_zstd_compressors::TRANSACTION_COMPRESSOR.with(|compressor| {
161 let mut compressor = compressor.borrow_mut();
162 compressor.compress(&tx_buf)
163 })
164 }
165 #[cfg(not(feature = "std"))]
166 {
167 let mut compressor = reth_zstd_compressors::create_tx_compressor();
168 compressor.compress(&tx_buf)
169 }
170 }
171 .expect("Failed to compress"),
172 );
173 } else {
174 self.to_tx_compact(buf);
175 };
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) = PrimitiveSignature::from_compact(buf, sig_bit);
188 let (tx_type, buf) = T::TxType::from_compact(buf, tx_bits);
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
196 let (tx, _) =
197 Self::from_tx_compact(decompressor.decompress(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
206 let (tx, _) =
207 Self::from_tx_compact(decompressor.decompress(buf), tx_type, signature);
208
209 (tx, buf)
210 }
211 } else {
212 Self::from_tx_compact(buf, tx_type, signature)
213 };
214
215 (transaction, buf)
216 }
217}
218
219impl<Eip4844: Compact + RlpEcdsaEncodableTx + Transaction + Send + Sync> Compact
220 for EthereumTxEnvelope<Eip4844>
221{
222 fn to_compact<B>(&self, buf: &mut B) -> usize
223 where
224 B: BufMut + AsMut<[u8]>,
225 {
226 <Self as CompactEnvelope>::to_compact(self, buf)
227 }
228
229 fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
230 <Self as CompactEnvelope>::from_compact(buf, len)
231 }
232}