Skip to content

Commit

Permalink
refactor: transaction rlp encoding (#1539)
Browse files Browse the repository at this point in the history
  • Loading branch information
morph-dev authored Oct 20, 2024
1 parent fa22eea commit 0866446
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 207 deletions.
131 changes: 70 additions & 61 deletions ethportal-api/src/types/execution/block_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ use std::vec;

use alloy::{
primitives::{keccak256, B256},
rlp::{Decodable, Encodable, Error as RlpError, Header as RlpHeader},
rlp::{self, Decodable, Encodable},
};
use anyhow::{anyhow, bail};
use bytes::Buf;
use serde::Deserialize;
use ssz::{Encode, SszDecoderBuilder, SszEncoder};
use ssz_derive::Encode;

use super::{header::Header, transaction::Transaction};
use super::{
header::Header,
transaction::{Transaction, TransactionWithRlpHeader},
};
use crate::{
types::execution::withdrawal::Withdrawal, utils::roots::calculate_merkle_patricia_root,
};
Expand Down Expand Up @@ -45,7 +49,7 @@ impl Decodable for BlockBody {
} else if let Ok(val) = BlockBodyShanghai::decode(buf) {
Ok(BlockBody::Shanghai(val))
} else {
Err(RlpError::Custom("Invalid block body rlp"))
Err(rlp::Error::Custom("Invalid block body rlp"))
}
}
}
Expand Down Expand Up @@ -121,19 +125,16 @@ impl BlockBody {
}

/// Returns reference to uncle headers.
///
/// Returns None post Merge fork.
pub fn uncles(&self) -> Option<&[Header]> {
pub fn uncles(&self) -> &[Header] {
match self {
BlockBody::Legacy(body) => Some(&body.uncles),
BlockBody::Merge(_) => None,
BlockBody::Shanghai(_) => None,
BlockBody::Legacy(body) => &body.uncles,
BlockBody::Merge(_) => &[],
BlockBody::Shanghai(_) => &[],
}
}

pub fn uncles_root(&self) -> B256 {
let uncles = self.uncles().unwrap_or_default().to_vec();
let encoded_uncles = alloy_rlp::encode(uncles);
let encoded_uncles = alloy_rlp::encode(self.uncles().to_vec());
keccak256(&encoded_uncles)
}

Expand All @@ -156,17 +157,17 @@ impl BlockBody {
}
}

fn rlp_encode_transaction_list(out: &mut dyn bytes::BufMut, txs: &[Transaction]) {
let mut transactions_list = Vec::<u8>::new();
for tx in txs {
tx.encode_with_envelope(&mut transactions_list, true);
}
let header = RlpHeader {
list: true,
payload_length: transactions_list.len(),
};
header.encode(out);
out.put_slice(transactions_list.as_slice());
fn rlp_encode_transaction_list_with_header(out: &mut dyn bytes::BufMut, txs: &[Transaction]) {
txs.iter()
.cloned()
.map(TransactionWithRlpHeader)
.collect::<Vec<_>>()
.encode(out);
}

fn rlp_decode_transaction_list_with_header(buf: &mut &[u8]) -> rlp::Result<Vec<Transaction>> {
let txs = Vec::<TransactionWithRlpHeader>::decode(buf)?;
Ok(txs.into_iter().map(|tx| tx.0).collect())
}

#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
Expand All @@ -178,9 +179,9 @@ pub struct BlockBodyLegacy {
impl Encodable for BlockBodyLegacy {
fn encode(&self, out: &mut dyn bytes::BufMut) {
let mut list = Vec::<u8>::new();
rlp_encode_transaction_list(&mut list, &self.txs);
rlp_encode_transaction_list_with_header(&mut list, &self.txs);
self.uncles.encode(&mut list);
let header = RlpHeader {
let header = rlp::Header {
list: true,
payload_length: list.len(),
};
Expand All @@ -191,17 +192,20 @@ impl Encodable for BlockBodyLegacy {

impl Decodable for BlockBodyLegacy {
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
let header = RlpHeader::decode(buf)?;
if !header.list {
return Err(RlpError::UnexpectedString);
}
let mut bytes = RlpHeader::decode_bytes(buf, true)?;
let mut txs: Vec<Transaction> = vec![];
let payload_view = &mut bytes;
while !payload_view.is_empty() {
txs.push(Transaction::decode_enveloped_transactions(payload_view)?);
let mut payload_view = rlp::Header::decode_bytes(buf, /* is_list= */ true)?;
let payload_length = payload_view.remaining();

let txs = rlp_decode_transaction_list_with_header(&mut payload_view)?;
let uncles = Vec::<Header>::decode(&mut payload_view)?;

if payload_view.has_remaining() {
let consumed = payload_length - payload_view.remaining();
return Err(rlp::Error::ListLengthMismatch {
expected: payload_length,
got: consumed,
});
}
let uncles: Vec<Header> = Decodable::decode(buf)?;

Ok(Self { txs, uncles })
}
}
Expand Down Expand Up @@ -264,8 +268,8 @@ pub struct BlockBodyMerge {
impl Encodable for BlockBodyMerge {
fn encode(&self, out: &mut dyn bytes::BufMut) {
let mut list = Vec::<u8>::new();
rlp_encode_transaction_list(&mut list, &self.txs);
let header = RlpHeader {
rlp_encode_transaction_list_with_header(&mut list, &self.txs);
let header = rlp::Header {
list: true,
payload_length: list.len(),
};
Expand All @@ -276,15 +280,17 @@ impl Encodable for BlockBodyMerge {

impl Decodable for BlockBodyMerge {
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
let header = RlpHeader::decode(buf)?;
if !header.list {
return Err(RlpError::UnexpectedString);
}
let mut bytes = RlpHeader::decode_bytes(buf, true)?;
let mut txs: Vec<Transaction> = vec![];
let payload_view = &mut bytes;
while !payload_view.is_empty() {
txs.push(Transaction::decode_enveloped_transactions(payload_view)?);
let mut payload_view = rlp::Header::decode_bytes(buf, /* is_list= */ true)?;
let payload_length = payload_view.remaining();

let txs = rlp_decode_transaction_list_with_header(&mut payload_view)?;

if payload_view.has_remaining() {
let consumed = payload_length - payload_view.remaining();
return Err(rlp::Error::ListLengthMismatch {
expected: payload_length,
got: consumed,
});
}

Ok(Self { txs })
Expand Down Expand Up @@ -357,9 +363,9 @@ pub struct BlockBodyShanghai {
impl Encodable for BlockBodyShanghai {
fn encode(&self, out: &mut dyn bytes::BufMut) {
let mut list = Vec::<u8>::new();
rlp_encode_transaction_list(&mut list, &self.txs);
rlp_encode_transaction_list_with_header(&mut list, &self.txs);
self.withdrawals.encode(&mut list);
let header = RlpHeader {
let header = rlp::Header {
list: true,
payload_length: list.len(),
};
Expand All @@ -370,17 +376,20 @@ impl Encodable for BlockBodyShanghai {

impl Decodable for BlockBodyShanghai {
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
let header = RlpHeader::decode(buf)?;
if !header.list {
return Err(RlpError::UnexpectedString);
}
let mut bytes = RlpHeader::decode_bytes(buf, true)?;
let mut txs: Vec<Transaction> = vec![];
let payload_view = &mut bytes;
while !payload_view.is_empty() {
txs.push(Transaction::decode_enveloped_transactions(payload_view)?);
let mut payload_view = rlp::Header::decode_bytes(buf, /* is_list= */ true)?;
let payload_length = payload_view.remaining();

let txs = rlp_decode_transaction_list_with_header(&mut payload_view)?;
let withdrawals = Vec::<Withdrawal>::decode(&mut payload_view)?;

if payload_view.has_remaining() {
let consumed = payload_length - payload_view.remaining();
return Err(rlp::Error::ListLengthMismatch {
expected: payload_length,
got: consumed,
});
}
let withdrawals: Vec<Withdrawal> = Decodable::decode(buf)?;

Ok(Self { txs, withdrawals })
}
}
Expand Down Expand Up @@ -483,7 +492,7 @@ mod tests {
#[case(TX6, 41942)]
fn encode_and_decode_txs(#[case] tx: &str, #[case] expected_nonce: u32) {
let tx_rlp = hex_decode(tx).unwrap();
let tx = Decodable::decode(&mut tx_rlp.as_slice()).expect("error decoding tx");
let tx = Transaction::decode(&mut tx_rlp.as_slice()).expect("error decoding tx");
let expected_nonce = U256::from(expected_nonce);
match &tx {
Transaction::Legacy(tx) => assert_eq!(tx.nonce, expected_nonce),
Expand Down Expand Up @@ -521,7 +530,7 @@ mod tests {
let invalid_txs = &block_body.transactions()[..1];
let invalid_block_body = BlockBody::Legacy(BlockBodyLegacy {
txs: invalid_txs.to_vec(),
uncles: block_body.uncles().unwrap().to_vec(),
uncles: block_body.uncles().to_vec(),
});

let expected_tx_root =
Expand All @@ -537,8 +546,8 @@ mod tests {
let block_body = get_14764013_block_body();
// invalid uncles
let invalid_uncles = vec![
block_body.uncles().unwrap()[0].clone(),
block_body.uncles().unwrap()[0].clone(),
block_body.uncles()[0].clone(),
block_body.uncles()[0].clone(),
];
let invalid_block_body = BlockBody::Legacy(BlockBodyLegacy {
txs: block_body.transactions().to_vec(),
Expand Down
Loading

0 comments on commit 0866446

Please sign in to comment.