alloy_consensus/transaction/
rlp.rsuse crate::{SignableTransaction, Signed};
use alloc::vec::Vec;
use alloy_eips::eip2718::{Eip2718Error, Eip2718Result};
use alloy_primitives::{keccak256, PrimitiveSignature as Signature, TxHash};
use alloy_rlp::{Buf, BufMut, Decodable, Encodable, Header};
#[doc(hidden)]
pub trait RlpEcdsaTx: SignableTransaction<Signature> + Sized {
const DEFAULT_TX_TYPE: u8;
fn rlp_encoded_fields_length(&self) -> usize;
fn rlp_encode_fields(&self, out: &mut dyn alloy_rlp::BufMut);
fn rlp_header(&self) -> Header {
Header { list: true, payload_length: self.rlp_encoded_fields_length() }
}
fn rlp_encoded_length(&self) -> usize {
self.rlp_header().length_with_payload()
}
fn rlp_encode(&self, out: &mut dyn BufMut) {
self.rlp_header().encode(out);
self.rlp_encode_fields(out);
}
fn rlp_header_signed(&self, signature: &Signature) -> Header {
let payload_length =
self.rlp_encoded_fields_length() + signature.rlp_rs_len() + signature.v().length();
Header { list: true, payload_length }
}
fn rlp_encoded_length_with_signature(&self, signature: &Signature) -> usize {
self.rlp_header_signed(signature).length_with_payload()
}
fn rlp_encode_signed(&self, signature: &Signature, out: &mut dyn BufMut) {
self.rlp_header_signed(signature).encode(out);
self.rlp_encode_fields(out);
signature.write_rlp_vrs(out, signature.v());
}
fn eip2718_encoded_length(&self, signature: &Signature) -> usize {
self.rlp_encoded_length_with_signature(signature) + 1
}
fn eip2718_encode_with_type(&self, signature: &Signature, ty: u8, out: &mut dyn BufMut) {
out.put_u8(ty);
self.rlp_encode_signed(signature, out);
}
fn eip2718_encode(&self, signature: &Signature, out: &mut dyn BufMut) {
self.eip2718_encode_with_type(signature, Self::DEFAULT_TX_TYPE, out);
}
fn network_header(&self, signature: &Signature) -> Header {
let payload_length = self.eip2718_encoded_length(signature);
Header { list: false, payload_length }
}
fn network_encoded_length(&self, signature: &Signature) -> usize {
self.network_header(signature).length_with_payload()
}
fn network_encode_with_type(&self, signature: &Signature, ty: u8, out: &mut dyn BufMut) {
self.network_header(signature).encode(out);
self.eip2718_encode_with_type(signature, ty, out);
}
fn network_encode(&self, signature: &Signature, out: &mut dyn BufMut) {
self.network_encode_with_type(signature, Self::DEFAULT_TX_TYPE, out);
}
fn rlp_decode_fields(buf: &mut &[u8]) -> alloy_rlp::Result<Self>;
fn rlp_decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
let header = Header::decode(buf)?;
if !header.list {
return Err(alloy_rlp::Error::UnexpectedString);
}
let remaining = buf.len();
if header.payload_length > remaining {
return Err(alloy_rlp::Error::InputTooShort);
}
let this = Self::rlp_decode_fields(buf)?;
if buf.len() + header.payload_length != remaining {
return Err(alloy_rlp::Error::UnexpectedLength);
}
Ok(this)
}
fn rlp_decode_with_signature(buf: &mut &[u8]) -> alloy_rlp::Result<(Self, Signature)> {
let header = Header::decode(buf)?;
if !header.list {
return Err(alloy_rlp::Error::UnexpectedString);
}
let remaining = buf.len();
let tx = Self::rlp_decode_fields(buf)?;
let signature = Signature::decode_rlp_vrs(buf, bool::decode)?;
if buf.len() + header.payload_length != remaining {
return Err(alloy_rlp::Error::ListLengthMismatch {
expected: header.payload_length,
got: remaining - buf.len(),
});
}
Ok((tx, signature))
}
fn rlp_decode_signed(buf: &mut &[u8]) -> alloy_rlp::Result<Signed<Self>> {
Self::rlp_decode_with_signature(buf).map(|(tx, signature)| tx.into_signed(signature))
}
fn eip2718_decode_with_type(buf: &mut &[u8], ty: u8) -> Eip2718Result<Signed<Self>> {
let original_buf = *buf;
if buf.remaining() < 1 {
return Err(alloy_rlp::Error::InputTooShort.into());
}
let actual = buf.get_u8();
if actual != ty {
return Err(Eip2718Error::UnexpectedType(actual));
}
let (tx, signature) = Self::rlp_decode_with_signature(buf)?;
let total_len = tx.eip2718_encoded_length(&signature);
let hash = keccak256(&original_buf[..total_len]);
Ok(Signed::new_unchecked(tx, signature, hash))
}
fn eip2718_decode(buf: &mut &[u8]) -> Eip2718Result<Signed<Self>> {
Self::eip2718_decode_with_type(buf, Self::DEFAULT_TX_TYPE)
}
fn network_decode_with_type(buf: &mut &[u8], ty: u8) -> Eip2718Result<Signed<Self>> {
let header = Header::decode(buf)?;
if header.list {
return Err(alloy_rlp::Error::UnexpectedList.into());
}
let remaining = buf.len();
let res = Self::eip2718_decode_with_type(buf, ty)?;
if buf.len() + header.payload_length != remaining {
return Err(alloy_rlp::Error::UnexpectedLength.into());
}
Ok(res)
}
fn network_decode(buf: &mut &[u8]) -> Eip2718Result<Signed<Self>> {
Self::network_decode_with_type(buf, Self::DEFAULT_TX_TYPE)
}
fn tx_hash_with_type(&self, signature: &Signature, ty: u8) -> TxHash {
let mut buf = Vec::with_capacity(self.eip2718_encoded_length(signature));
self.eip2718_encode_with_type(signature, ty, &mut buf);
keccak256(&buf)
}
fn tx_hash(&self, signature: &Signature) -> TxHash {
self.tx_hash_with_type(signature, Self::DEFAULT_TX_TYPE)
}
}