Skip to content

Commit

Permalink
chore(derive): Clean up RLP encoding + use TxType rather than ints
Browse files Browse the repository at this point in the history
  • Loading branch information
clabby committed Apr 3, 2024
1 parent 616c666 commit 0d48140
Show file tree
Hide file tree
Showing 10 changed files with 61 additions and 229 deletions.
56 changes: 5 additions & 51 deletions crates/derive/src/types/batch/single_batch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
use crate::types::RawTransaction;
use alloc::vec::Vec;
use alloy_primitives::BlockHash;
use alloy_rlp::{Decodable, Encodable, Header};
use alloy_rlp::{RlpDecodable, RlpEncodable};

/// Represents a single batch: a single encoded L2 block
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)]
pub struct SingleBatch {
/// Block hash of the previous L2 block
pub parent_hash: BlockHash,
Expand All @@ -20,52 +20,6 @@ pub struct SingleBatch {
pub transactions: Vec<RawTransaction>,
}

impl Encodable for SingleBatch {
fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
let payload_length = self.parent_hash.length()
+ self.epoch_num.length()
+ self.epoch_hash.length()
+ self.timestamp.length()
+ self.transactions.length();
let header = Header {
list: true,
payload_length,
};
header.encode(out);

self.parent_hash.encode(out);
self.epoch_num.encode(out);
self.epoch_hash.encode(out);
self.timestamp.encode(out);
self.transactions.encode(out);
}
}

impl Decodable for SingleBatch {
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
let header = Header::decode(buf)?;
let buf_len_start = buf.len();

let parent_hash = Decodable::decode(buf)?;
let epoch_num = Decodable::decode(buf)?;
let epoch_hash = Decodable::decode(buf)?;
let timestamp = Decodable::decode(buf)?;
let transactions = Decodable::decode(buf)?;

if buf.len() != buf_len_start - header.payload_length {
return Err(alloy_rlp::Error::Overflow);
}

Ok(SingleBatch {
parent_hash,
epoch_num,
epoch_hash,
timestamp,
transactions,
})
}
}

impl SingleBatch {
/// If any transactions are empty or deposited transaction types.
pub fn has_invalid_transactions(&self) -> bool {
Expand All @@ -80,7 +34,7 @@ mod test {
use super::SingleBatch;
use crate::types::RawTransaction;
use alloc::vec;
use alloy_primitives::B256;
use alloy_primitives::{hex, B256};
use alloy_rlp::{BytesMut, Decodable, Encodable};

#[test]
Expand All @@ -90,7 +44,7 @@ mod test {
epoch_num: 0xFF,
epoch_hash: B256::ZERO,
timestamp: 0xEE,
transactions: vec![RawTransaction(vec![0x00])],
transactions: vec![RawTransaction(hex!("00").into())],
};

let mut out_buf = BytesMut::default();
Expand All @@ -107,7 +61,7 @@ mod test {
epoch_num: 0xFF,
epoch_hash: B256::ZERO,
timestamp: 0xEE,
transactions: vec![RawTransaction(vec![0x7E])],
transactions: vec![RawTransaction(hex!("7E").into())],
};

assert!(single_batch.has_invalid_transactions());
Expand Down
5 changes: 4 additions & 1 deletion crates/derive/src/types/batch/span_batch/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ impl RawSpanBatch {
acc.push(SpanBatchElement {
epoch_num: block_origin_nums[i as usize],
timestamp: genesis_time + self.prefix.rel_timestamp + block_time * i,
transactions: transactions.into_iter().map(RawTransaction).collect(),
transactions: transactions
.into_iter()
.map(|v| RawTransaction(v.into()))
.collect(),
});
acc
});
Expand Down
9 changes: 7 additions & 2 deletions crates/derive/src/types/batch/span_batch/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//! transaction within a span batch.
use super::{convert_v_to_y_parity, SpanBatchError, SpanDecodingError};
use crate::types::TxType;
use alloy_primitives::{Signature, U256};

/// The ECDSA signature of a transaction within a span batch.
Expand All @@ -26,7 +27,11 @@ impl TryFrom<SpanBatchSignature> for Signature {
type Error = SpanBatchError;

fn try_from(value: SpanBatchSignature) -> Result<Self, Self::Error> {
Self::from_rs_and_parity(value.r, value.s, convert_v_to_y_parity(value.v, 0)?)
.map_err(|_| SpanBatchError::Decoding(SpanDecodingError::InvalidTransactionSignature))
Self::from_rs_and_parity(
value.r,
value.s,
convert_v_to_y_parity(value.v, TxType::Legacy)?,
)
.map_err(|_| SpanBatchError::Decoding(SpanDecodingError::InvalidTransactionSignature))
}
}
17 changes: 7 additions & 10 deletions crates/derive/src/types/batch/span_batch/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub struct SpanBatchTransactions {
/// The protected bits, standard span-batch bitlist.
pub protected_bits: SpanBatchBits,
/// The types of the transactions.
pub tx_types: Vec<u64>,
pub tx_types: Vec<TxType>,
/// Total legacy transaction count in the span batch.
pub legacy_tx_count: u64,
}
Expand Down Expand Up @@ -222,8 +222,8 @@ impl SpanBatchTransactions {
for _ in 0..self.total_block_tx_count {
let (tx_data, tx_type) = read_tx_data(r)?;
tx_datas.push(tx_data);
tx_types.push(tx_type as u64);
if tx_type == 0 {
tx_types.push(tx_type);
if matches!(tx_type, TxType::Legacy) {
self.legacy_tx_count += 1;
}
}
Expand Down Expand Up @@ -257,7 +257,7 @@ impl SpanBatchTransactions {
.get_bit(i)
.ok_or(SpanBatchError::BitfieldTooLong)?;
let v = match tx_type {
0 => {
TxType::Legacy => {
// Legacy transaction
let protected_bit = self
.protected_bits
Expand All @@ -271,10 +271,7 @@ impl SpanBatchTransactions {
Ok(chain_id * 2 + 35 + bit as u64)
}
}
1 | 2 => {
// EIP-2930 + EIP-1559
Ok(bit as u64)
}
TxType::Eip2930 | TxType::Eip1559 => Ok(bit as u64),
_ => Err(SpanBatchError::Decoding(
SpanDecodingError::InvalidTransactionType,
)),
Expand Down Expand Up @@ -363,7 +360,7 @@ impl SpanBatchTransactions {
}
};
let signature_v = signature.v().to_u64();
let y_parity_bit = convert_v_to_y_parity(signature_v, tx_type as u64)?;
let y_parity_bit = convert_v_to_y_parity(signature_v, tx_type)?;
let contract_creation_bit = match to {
TxKind::Call(address) => {
self.tx_tos.push(address);
Expand All @@ -382,7 +379,7 @@ impl SpanBatchTransactions {
self.tx_nonces.push(nonce);
self.tx_datas.push(tx_data_buf);
self.tx_gases.push(gas);
self.tx_types.push(tx_type as u64);
self.tx_types.push(tx_type);
}
self.total_block_tx_count += total_block_tx_count;
Ok(())
Expand Down
56 changes: 3 additions & 53 deletions crates/derive/src/types/batch/span_batch/tx_data/eip1559.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ use crate::types::{
network::Signed, SpanBatchError, SpanDecodingError, Transaction, TxEip1559, TxEnvelope, TxKind,
};
use alloy_primitives::{Address, Signature, U256};
use alloy_rlp::{Bytes, Decodable, Encodable, Header};
use alloy_rlp::{Bytes, RlpDecodable, RlpEncodable};

/// The transaction data for an EIP-1559 transaction within a span batch.
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)]
pub struct SpanBatchEip1559TransactionData {
/// The ETH value of the transaction.
pub value: U256,
Expand Down Expand Up @@ -65,62 +65,12 @@ impl SpanBatchEip1559TransactionData {
}
}

impl Encodable for SpanBatchEip1559TransactionData {
fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
let payload_length = self.value.length()
+ self.max_fee_per_gas.length()
+ self.max_priority_fee_per_gas.length()
+ self.data.length()
+ self.access_list.length();
let header = Header {
list: true,
payload_length,
};

header.encode(out);
self.value.encode(out);
self.max_fee_per_gas.encode(out);
self.max_priority_fee_per_gas.encode(out);
self.data.encode(out);
self.access_list.encode(out);
}
}

impl Decodable for SpanBatchEip1559TransactionData {
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
let header = Header::decode(buf)?;
if !header.list {
return Err(alloy_rlp::Error::Custom(
"Expected list data for EIP-1559 transaction",
));
}
let buf_len_start = buf.len();

let value = U256::decode(buf)?;
let max_fee_per_gas = U256::decode(buf)?;
let max_priority_fee_per_gas = U256::decode(buf)?;
let data = Bytes::decode(buf)?;
let access_list = AccessList::decode(buf)?;

if buf.len() != buf_len_start - header.payload_length {
return Err(alloy_rlp::Error::Custom("Invalid EIP-1559 transaction RLP"));
}

Ok(Self {
value,
max_fee_per_gas,
max_priority_fee_per_gas,
data,
access_list,
})
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::types::SpanBatchTransactionData;
use alloc::vec::Vec;
use alloy_rlp::{Decodable, Encodable};

#[test]
fn encode_eip1559_tx_data_roundtrip() {
Expand Down
54 changes: 4 additions & 50 deletions crates/derive/src/types/batch/span_batch/tx_data/eip2930.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ use crate::types::{
network::Signed, SpanBatchError, SpanDecodingError, Transaction, TxEip2930, TxEnvelope, TxKind,
};
use alloy_primitives::{Address, Signature, U256};
use alloy_rlp::{Bytes, Decodable, Encodable, Header};
use alloy_rlp::{Bytes, RlpDecodable, RlpEncodable};

/// The transaction data for an EIP-2930 transaction within a span batch.
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)]
pub struct SpanBatchEip2930TransactionData {
/// The ETH value of the transaction.
pub value: U256,
Expand All @@ -21,7 +21,7 @@ pub struct SpanBatchEip2930TransactionData {
}

impl SpanBatchEip2930TransactionData {
/// Converts [SpanBatchEip1559TransactionData] into a [TxEnvelope].
/// Converts [SpanBatchEip2930TransactionData] into a [TxEnvelope].
pub fn to_enveloped_tx(
&self,
nonce: u64,
Expand Down Expand Up @@ -57,58 +57,12 @@ impl SpanBatchEip2930TransactionData {
}
}

impl Encodable for SpanBatchEip2930TransactionData {
fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
let payload_length = self.value.length()
+ self.gas_price.length()
+ self.data.length()
+ self.access_list.length();
let header = Header {
list: true,
payload_length,
};

header.encode(out);
self.value.encode(out);
self.gas_price.encode(out);
self.data.encode(out);
self.access_list.encode(out);
}
}

impl Decodable for SpanBatchEip2930TransactionData {
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
let header = Header::decode(buf)?;
if !header.list {
return Err(alloy_rlp::Error::Custom(
"Expected list data for EIP-2930 transaction",
));
}
let buf_len_start = buf.len();

let value = U256::decode(buf)?;
let gas_price = U256::decode(buf)?;
let data = Bytes::decode(buf)?;
let access_list = AccessList::decode(buf)?;

if buf.len() != buf_len_start - header.payload_length {
return Err(alloy_rlp::Error::Custom("Invalid EIP-2930 transaction RLP"));
}

Ok(Self {
value,
gas_price,
data,
access_list,
})
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::types::SpanBatchTransactionData;
use alloc::vec::Vec;
use alloy_rlp::{Decodable, Encodable};

#[test]
fn encode_eip2930_tx_data_roundtrip() {
Expand Down
Loading

0 comments on commit 0d48140

Please sign in to comment.