alloy_consensus/transaction/
rlp.rs1use crate::Signed;
2use alloc::vec::Vec;
3use alloy_eips::{
4    eip2718::{Eip2718Error, Eip2718Result},
5    Typed2718,
6};
7use alloy_primitives::{keccak256, Signature, TxHash};
8use alloy_rlp::{Buf, BufMut, Decodable, Encodable, Header};
9
10#[doc(hidden)]
12#[doc(alias = "RlpEncodableTx", alias = "RlpTxEncoding")]
13#[auto_impl::auto_impl(&, Arc)]
14pub trait RlpEcdsaEncodableTx: Sized + Typed2718 {
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.ty(), 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.ty(), 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.ty())
113    }
114}
115
116#[doc(hidden)]
118#[doc(alias = "RlpDecodableTx", alias = "RlpTxDecoding")]
119pub trait RlpEcdsaDecodableTx: RlpEcdsaEncodableTx {
120    const DEFAULT_TX_TYPE: u8;
122
123    fn rlp_decode_fields(buf: &mut &[u8]) -> alloy_rlp::Result<Self>;
127
128    fn rlp_decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
130        let header = Header::decode(buf)?;
131        if !header.list {
132            return Err(alloy_rlp::Error::UnexpectedString);
133        }
134        let remaining = buf.len();
135
136        if header.payload_length > remaining {
137            return Err(alloy_rlp::Error::InputTooShort);
138        }
139
140        let this = Self::rlp_decode_fields(buf)?;
141
142        if buf.len() + header.payload_length != remaining {
143            return Err(alloy_rlp::Error::UnexpectedLength);
144        }
145
146        Ok(this)
147    }
148
149    fn rlp_decode_with_signature(buf: &mut &[u8]) -> alloy_rlp::Result<(Self, Signature)> {
151        let header = Header::decode(buf)?;
152        if !header.list {
153            return Err(alloy_rlp::Error::UnexpectedString);
154        }
155
156        let remaining = buf.len();
157        let tx = Self::rlp_decode_fields(buf)?;
158        let signature = Signature::decode_rlp_vrs(buf, bool::decode)?;
159
160        if buf.len() + header.payload_length != remaining {
161            return Err(alloy_rlp::Error::ListLengthMismatch {
162                expected: header.payload_length,
163                got: remaining - buf.len(),
164            });
165        }
166
167        Ok((tx, signature))
168    }
169
170    fn rlp_decode_signed(buf: &mut &[u8]) -> alloy_rlp::Result<Signed<Self>> {
173        Self::rlp_decode_with_signature(buf)
174            .map(|(tx, signature)| Signed::new_unhashed(tx, signature))
175    }
176
177    fn eip2718_decode_with_type(buf: &mut &[u8], ty: u8) -> Eip2718Result<Signed<Self>> {
180        let original_buf = *buf;
181
182        if buf.remaining() < 1 {
183            return Err(alloy_rlp::Error::InputTooShort.into());
184        }
185        let actual = buf.get_u8();
186        if actual != ty {
187            return Err(Eip2718Error::UnexpectedType(actual));
188        }
189
190        let (tx, signature) = Self::rlp_decode_with_signature(buf)?;
193        let total_len = tx.eip2718_encoded_length(&signature);
194        let hash = keccak256(&original_buf[..total_len]);
195
196        Ok(Signed::new_unchecked(tx, signature, hash))
197    }
198
199    fn eip2718_decode(buf: &mut &[u8]) -> Eip2718Result<Signed<Self>> {
202        Self::eip2718_decode_with_type(buf, Self::DEFAULT_TX_TYPE)
203    }
204
205    fn network_decode_with_type(buf: &mut &[u8], ty: u8) -> Eip2718Result<Signed<Self>> {
207        let header = Header::decode(buf)?;
208        if header.list {
209            return Err(alloy_rlp::Error::UnexpectedList.into());
210        }
211
212        let remaining = buf.len();
213        let res = Self::eip2718_decode_with_type(buf, ty)?;
214
215        if buf.len() + header.payload_length != remaining {
216            return Err(alloy_rlp::Error::UnexpectedLength.into());
217        }
218
219        Ok(res)
220    }
221
222    fn network_decode(buf: &mut &[u8]) -> Eip2718Result<Signed<Self>> {
225        Self::network_decode_with_type(buf, Self::DEFAULT_TX_TYPE)
226    }
227}
228
229#[doc(hidden)]
232pub trait RlpEcdsaTx: RlpEcdsaEncodableTx + RlpEcdsaDecodableTx {}
233
234impl<T> RlpEcdsaTx for T where T: RlpEcdsaEncodableTx + RlpEcdsaDecodableTx {}