alloy_consensus/transaction/
rlp.rs1use crate::Signed;
2use alloc::vec::Vec;
3use alloy_eips::eip2718::{Eip2718Error, Eip2718Result};
4use alloy_primitives::{keccak256, PrimitiveSignature as Signature, TxHash};
5use alloy_rlp::{Buf, BufMut, Decodable, Encodable, Header};
6
7#[doc(hidden)]
9#[doc(alias = "RlpEncodableTx", alias = "RlpTxEncoding")]
10#[auto_impl::auto_impl(&, Arc)]
11pub trait RlpEcdsaEncodableTx: Sized {
12 const DEFAULT_TX_TYPE: u8;
14
15 fn rlp_encoded_fields_length(&self) -> usize;
18
19 fn rlp_encode_fields(&self, out: &mut dyn alloy_rlp::BufMut);
22
23 fn rlp_header(&self) -> Header {
25 Header { list: true, payload_length: self.rlp_encoded_fields_length() }
26 }
27
28 fn rlp_encoded_length(&self) -> usize {
30 self.rlp_header().length_with_payload()
31 }
32
33 fn rlp_encode(&self, out: &mut dyn BufMut) {
35 self.rlp_header().encode(out);
36 self.rlp_encode_fields(out);
37 }
38
39 fn rlp_header_signed(&self, signature: &Signature) -> Header {
41 let payload_length =
42 self.rlp_encoded_fields_length() + signature.rlp_rs_len() + signature.v().length();
43 Header { list: true, payload_length }
44 }
45
46 fn rlp_encoded_length_with_signature(&self, signature: &Signature) -> usize {
49 self.rlp_header_signed(signature).length_with_payload()
50 }
51
52 fn rlp_encode_signed(&self, signature: &Signature, out: &mut dyn BufMut) {
54 self.rlp_header_signed(signature).encode(out);
55 self.rlp_encode_fields(out);
56 signature.write_rlp_vrs(out, signature.v());
57 }
58
59 fn eip2718_encoded_length(&self, signature: &Signature) -> usize {
62 self.rlp_encoded_length_with_signature(signature) + 1
63 }
64
65 fn eip2718_encode_with_type(&self, signature: &Signature, ty: u8, out: &mut dyn BufMut) {
67 out.put_u8(ty);
68 self.rlp_encode_signed(signature, out);
69 }
70
71 fn eip2718_encode(&self, signature: &Signature, out: &mut dyn BufMut) {
74 self.eip2718_encode_with_type(signature, Self::DEFAULT_TX_TYPE, out);
75 }
76
77 fn network_header(&self, signature: &Signature) -> Header {
81 let payload_length = self.eip2718_encoded_length(signature);
82 Header { list: false, payload_length }
83 }
84
85 fn network_encoded_length(&self, signature: &Signature) -> usize {
88 self.network_header(signature).length_with_payload()
89 }
90
91 fn network_encode_with_type(&self, signature: &Signature, ty: u8, out: &mut dyn BufMut) {
93 self.network_header(signature).encode(out);
94 self.eip2718_encode_with_type(signature, ty, out);
95 }
96
97 fn network_encode(&self, signature: &Signature, out: &mut dyn BufMut) {
100 self.network_encode_with_type(signature, Self::DEFAULT_TX_TYPE, out);
101 }
102
103 fn tx_hash_with_type(&self, signature: &Signature, ty: u8) -> TxHash {
105 let mut buf = Vec::with_capacity(self.eip2718_encoded_length(signature));
106 self.eip2718_encode_with_type(signature, ty, &mut buf);
107 keccak256(&buf)
108 }
109
110 fn tx_hash(&self, signature: &Signature) -> TxHash {
112 self.tx_hash_with_type(signature, Self::DEFAULT_TX_TYPE)
113 }
114}
115
116#[doc(hidden)]
118#[doc(alias = "RlpDecodableTx", alias = "RlpTxDecoding")]
119pub trait RlpEcdsaDecodableTx: RlpEcdsaEncodableTx {
120 fn rlp_decode_fields(buf: &mut &[u8]) -> alloy_rlp::Result<Self>;
124
125 fn rlp_decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
127 let header = Header::decode(buf)?;
128 if !header.list {
129 return Err(alloy_rlp::Error::UnexpectedString);
130 }
131 let remaining = buf.len();
132
133 if header.payload_length > remaining {
134 return Err(alloy_rlp::Error::InputTooShort);
135 }
136
137 let this = Self::rlp_decode_fields(buf)?;
138
139 if buf.len() + header.payload_length != remaining {
140 return Err(alloy_rlp::Error::UnexpectedLength);
141 }
142
143 Ok(this)
144 }
145
146 fn rlp_decode_with_signature(buf: &mut &[u8]) -> alloy_rlp::Result<(Self, Signature)> {
148 let header = Header::decode(buf)?;
149 if !header.list {
150 return Err(alloy_rlp::Error::UnexpectedString);
151 }
152
153 let remaining = buf.len();
154 let tx = Self::rlp_decode_fields(buf)?;
155 let signature = Signature::decode_rlp_vrs(buf, bool::decode)?;
156
157 if buf.len() + header.payload_length != remaining {
158 return Err(alloy_rlp::Error::ListLengthMismatch {
159 expected: header.payload_length,
160 got: remaining - buf.len(),
161 });
162 }
163
164 Ok((tx, signature))
165 }
166
167 fn rlp_decode_signed(buf: &mut &[u8]) -> alloy_rlp::Result<Signed<Self>> {
170 Self::rlp_decode_with_signature(buf)
171 .map(|(tx, signature)| Signed::new_unhashed(tx, signature))
172 }
173
174 fn eip2718_decode_with_type(buf: &mut &[u8], ty: u8) -> Eip2718Result<Signed<Self>> {
177 let original_buf = *buf;
178
179 if buf.remaining() < 1 {
180 return Err(alloy_rlp::Error::InputTooShort.into());
181 }
182 let actual = buf.get_u8();
183 if actual != ty {
184 return Err(Eip2718Error::UnexpectedType(actual));
185 }
186
187 let (tx, signature) = Self::rlp_decode_with_signature(buf)?;
190 let total_len = tx.eip2718_encoded_length(&signature);
191 let hash = keccak256(&original_buf[..total_len]);
192
193 Ok(Signed::new_unchecked(tx, signature, hash))
194 }
195
196 fn eip2718_decode(buf: &mut &[u8]) -> Eip2718Result<Signed<Self>> {
199 Self::eip2718_decode_with_type(buf, Self::DEFAULT_TX_TYPE)
200 }
201
202 fn network_decode_with_type(buf: &mut &[u8], ty: u8) -> Eip2718Result<Signed<Self>> {
204 let header = Header::decode(buf)?;
205 if header.list {
206 return Err(alloy_rlp::Error::UnexpectedList.into());
207 }
208
209 let remaining = buf.len();
210 let res = Self::eip2718_decode_with_type(buf, ty)?;
211
212 if buf.len() + header.payload_length != remaining {
213 return Err(alloy_rlp::Error::UnexpectedLength.into());
214 }
215
216 Ok(res)
217 }
218
219 fn network_decode(buf: &mut &[u8]) -> Eip2718Result<Signed<Self>> {
222 Self::network_decode_with_type(buf, Self::DEFAULT_TX_TYPE)
223 }
224}
225
226#[doc(hidden)]
229pub trait RlpEcdsaTx: RlpEcdsaEncodableTx + RlpEcdsaDecodableTx {}
230
231impl<T> RlpEcdsaTx for T where T: RlpEcdsaEncodableTx + RlpEcdsaDecodableTx {}