From 0d481407f4a3d4fcc2ec8e8c32935221ba87132a Mon Sep 17 00:00:00 2001 From: clabby Date: Tue, 2 Apr 2024 20:19:59 -0400 Subject: [PATCH] chore(derive): Clean up RLP encoding + use `TxType` rather than ints --- crates/derive/src/types/batch/single_batch.rs | 56 ++----------------- .../derive/src/types/batch/span_batch/raw.rs | 5 +- .../src/types/batch/span_batch/signature.rs | 9 ++- .../types/batch/span_batch/transactions.rs | 17 +++--- .../types/batch/span_batch/tx_data/eip1559.rs | 56 +------------------ .../types/batch/span_batch/tx_data/eip2930.rs | 54 ++---------------- .../types/batch/span_batch/tx_data/legacy.rs | 46 +-------------- .../types/batch/span_batch/tx_data/wrapper.rs | 23 ++++---- .../src/types/batch/span_batch/utils.rs | 19 ++++--- crates/derive/src/types/mod.rs | 5 +- 10 files changed, 61 insertions(+), 229 deletions(-) diff --git a/crates/derive/src/types/batch/single_batch.rs b/crates/derive/src/types/batch/single_batch.rs index fd7e7b787..23e891df2 100644 --- a/crates/derive/src/types/batch/single_batch.rs +++ b/crates/derive/src/types/batch/single_batch.rs @@ -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, @@ -20,52 +20,6 @@ pub struct SingleBatch { pub transactions: Vec, } -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 { - 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 { @@ -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] @@ -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(); @@ -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()); diff --git a/crates/derive/src/types/batch/span_batch/raw.rs b/crates/derive/src/types/batch/span_batch/raw.rs index 90b4c7f61..961f8f8c2 100644 --- a/crates/derive/src/types/batch/span_batch/raw.rs +++ b/crates/derive/src/types/batch/span_batch/raw.rs @@ -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 }); diff --git a/crates/derive/src/types/batch/span_batch/signature.rs b/crates/derive/src/types/batch/span_batch/signature.rs index c154d10c8..61a20d289 100644 --- a/crates/derive/src/types/batch/span_batch/signature.rs +++ b/crates/derive/src/types/batch/span_batch/signature.rs @@ -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. @@ -26,7 +27,11 @@ impl TryFrom for Signature { type Error = SpanBatchError; fn try_from(value: SpanBatchSignature) -> Result { - 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)) } } diff --git a/crates/derive/src/types/batch/span_batch/transactions.rs b/crates/derive/src/types/batch/span_batch/transactions.rs index 01170715a..d4590887f 100644 --- a/crates/derive/src/types/batch/span_batch/transactions.rs +++ b/crates/derive/src/types/batch/span_batch/transactions.rs @@ -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, + pub tx_types: Vec, /// Total legacy transaction count in the span batch. pub legacy_tx_count: u64, } @@ -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; } } @@ -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 @@ -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, )), @@ -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); @@ -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(()) diff --git a/crates/derive/src/types/batch/span_batch/tx_data/eip1559.rs b/crates/derive/src/types/batch/span_batch/tx_data/eip1559.rs index 7cc5afbb3..5e514d2f8 100644 --- a/crates/derive/src/types/batch/span_batch/tx_data/eip1559.rs +++ b/crates/derive/src/types/batch/span_batch/tx_data/eip1559.rs @@ -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, @@ -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 { - 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() { diff --git a/crates/derive/src/types/batch/span_batch/tx_data/eip2930.rs b/crates/derive/src/types/batch/span_batch/tx_data/eip2930.rs index 79203bd54..1d29e75da 100644 --- a/crates/derive/src/types/batch/span_batch/tx_data/eip2930.rs +++ b/crates/derive/src/types/batch/span_batch/tx_data/eip2930.rs @@ -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, @@ -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, @@ -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 { - 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() { diff --git a/crates/derive/src/types/batch/span_batch/tx_data/legacy.rs b/crates/derive/src/types/batch/span_batch/tx_data/legacy.rs index d8f600929..bc64924db 100644 --- a/crates/derive/src/types/batch/span_batch/tx_data/legacy.rs +++ b/crates/derive/src/types/batch/span_batch/tx_data/legacy.rs @@ -4,10 +4,10 @@ use crate::types::{ network::Signed, SpanBatchError, SpanDecodingError, Transaction, TxEnvelope, TxKind, TxLegacy, }; use alloy_primitives::{Address, Signature, U256}; -use alloy_rlp::{Bytes, Decodable, Encodable, Header}; +use alloy_rlp::{Bytes, RlpDecodable, RlpEncodable}; /// The transaction data for a legacy transaction within a span batch. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct SpanBatchLegacyTransactionData { /// The ETH value of the transaction. pub value: U256, @@ -52,52 +52,12 @@ impl SpanBatchLegacyTransactionData { } } -impl Encodable for SpanBatchLegacyTransactionData { - fn encode(&self, out: &mut dyn alloy_rlp::BufMut) { - let payload_length = self.value.length() + self.gas_price.length() + self.data.length(); - let header = Header { - list: true, - payload_length, - }; - - header.encode(out); - self.value.encode(out); - self.gas_price.encode(out); - self.data.encode(out); - } -} - -impl Decodable for SpanBatchLegacyTransactionData { - fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { - let header = Header::decode(buf)?; - if !header.list { - return Err(alloy_rlp::Error::Custom( - "Expected list data for Legacy transaction", - )); - } - let buf_len_start = buf.len(); - - let value = U256::decode(buf)?; - let gas_price = U256::decode(buf)?; - let data = Bytes::decode(buf)?; - - if buf.len() != buf_len_start - header.payload_length { - return Err(alloy_rlp::Error::Custom("Invalid Legacy transaction RLP")); - } - - Ok(Self { - value, - gas_price, - data, - }) - } -} - #[cfg(test)] mod test { use super::*; use crate::types::SpanBatchTransactionData; use alloc::vec::Vec; + use alloy_rlp::{Decodable, Encodable as _}; // use alloy_primitives::B256; // #[test] diff --git a/crates/derive/src/types/batch/span_batch/tx_data/wrapper.rs b/crates/derive/src/types/batch/span_batch/tx_data/wrapper.rs index 7ec45954d..fa7ef9228 100644 --- a/crates/derive/src/types/batch/span_batch/tx_data/wrapper.rs +++ b/crates/derive/src/types/batch/span_batch/tx_data/wrapper.rs @@ -4,7 +4,7 @@ use super::{ SpanBatchEip1559TransactionData, SpanBatchEip2930TransactionData, SpanBatchLegacyTransactionData, }; -use crate::types::{SpanBatchError, SpanDecodingError, Transaction, TxEnvelope}; +use crate::types::{SpanBatchError, SpanDecodingError, Transaction, TxEnvelope, TxType}; use alloy_primitives::{Address, Signature, U256}; use alloy_rlp::{Bytes, Decodable, Encodable}; @@ -26,11 +26,11 @@ impl Encodable for SpanBatchTransactionData { data.encode(out); } Self::Eip2930(data) => { - out.put_u8(1); + out.put_u8(TxType::Eip2930 as u8); data.encode(out); } Self::Eip1559(data) => { - out.put_u8(2); + out.put_u8(TxType::Eip1559 as u8); data.encode(out); } } @@ -88,11 +88,11 @@ impl TryFrom<&TxEnvelope> for SpanBatchTransactionData { impl SpanBatchTransactionData { /// Returns the transaction type of the [SpanBatchTransactionData]. - pub fn tx_type(&self) -> u8 { + pub fn tx_type(&self) -> TxType { match self { - Self::Legacy(_) => 0, - Self::Eip2930(_) => 1, - Self::Eip1559(_) => 2, + Self::Legacy(_) => TxType::Legacy, + Self::Eip2930(_) => TxType::Eip2930, + Self::Eip1559(_) => TxType::Eip1559, } } @@ -102,11 +102,14 @@ impl SpanBatchTransactionData { return Err(alloy_rlp::Error::Custom("Invalid transaction data")); } - match b[0] { - 1 => Ok(SpanBatchTransactionData::Eip2930( + match b[0] + .try_into() + .map_err(|_| alloy_rlp::Error::Custom("Invalid tx type"))? + { + TxType::Eip2930 => Ok(SpanBatchTransactionData::Eip2930( SpanBatchEip2930TransactionData::decode(&mut &b[1..])?, )), - 2 => Ok(SpanBatchTransactionData::Eip1559( + TxType::Eip1559 => Ok(SpanBatchTransactionData::Eip1559( SpanBatchEip1559TransactionData::decode(&mut &b[1..])?, )), _ => Err(alloy_rlp::Error::Custom("Invalid transaction type")), diff --git a/crates/derive/src/types/batch/span_batch/utils.rs b/crates/derive/src/types/batch/span_batch/utils.rs index a5e735cde..dc227d608 100644 --- a/crates/derive/src/types/batch/span_batch/utils.rs +++ b/crates/derive/src/types/batch/span_batch/utils.rs @@ -1,12 +1,12 @@ //! Utilities for Span Batch Encoding and Decoding. +use super::{SpanBatchError, SpanDecodingError}; +use crate::types::TxType; use alloc::vec::Vec; use alloy_rlp::{Buf, Header}; -use super::{SpanBatchError, SpanDecodingError}; - /// Reads transaction data from a reader. -pub(crate) fn read_tx_data(r: &mut &[u8]) -> Result<(Vec, u8), SpanBatchError> { +pub(crate) fn read_tx_data(r: &mut &[u8]) -> Result<(Vec, TxType), SpanBatchError> { let mut tx_data = Vec::new(); let first_byte = *r.first().ok_or(SpanBatchError::Decoding( SpanDecodingError::InvalidTransactionData, @@ -39,13 +39,18 @@ pub(crate) fn read_tx_data(r: &mut &[u8]) -> Result<(Vec, u8), SpanBatchErro }?; tx_data.extend_from_slice(&tx_payload); - Ok((tx_data, tx_type)) + Ok(( + tx_data, + tx_type + .try_into() + .map_err(|_| SpanBatchError::Decoding(SpanDecodingError::InvalidTransactionType))?, + )) } /// Converts a `v` value to a y parity bit, from the transaaction type. -pub(crate) fn convert_v_to_y_parity(v: u64, tx_type: u64) -> Result { +pub(crate) fn convert_v_to_y_parity(v: u64, tx_type: TxType) -> Result { match tx_type { - 0 => { + TxType::Legacy => { if v != 27 && v != 28 { // EIP-155: v = 2 * chain_id + 35 + yParity Ok((v - 35) & 1 == 1) @@ -54,7 +59,7 @@ pub(crate) fn convert_v_to_y_parity(v: u64, tx_type: u64) -> Result Ok(v == 1), + TxType::Eip2930 | TxType::Eip1559 => Ok(v == 1), _ => Err(SpanBatchError::Decoding( SpanDecodingError::InvalidTransactionType, )), diff --git a/crates/derive/src/types/mod.rs b/crates/derive/src/types/mod.rs index a0d2f858a..ad8f5b8f9 100644 --- a/crates/derive/src/types/mod.rs +++ b/crates/derive/src/types/mod.rs @@ -1,6 +1,7 @@ //! This module contains all of the types used within the derivation pipeline. use alloc::vec::Vec; +use alloy_primitives::Bytes; use alloy_rlp::{Decodable, Encodable}; mod batch; @@ -62,7 +63,7 @@ pub use errors::{DecodeError, StageError, StageResult}; /// A raw transaction #[derive(Debug, Clone, PartialEq, Eq)] -pub struct RawTransaction(pub Vec); +pub struct RawTransaction(pub Bytes); impl Encodable for RawTransaction { fn encode(&self, out: &mut dyn alloy_rlp::BufMut) { @@ -73,7 +74,7 @@ impl Encodable for RawTransaction { impl Decodable for RawTransaction { /// Decodes RLP encoded bytes into [RawTransaction] bytes fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { - let tx_bytes: Vec = Decodable::decode(buf)?; + let tx_bytes = Bytes::decode(buf)?; Ok(Self(tx_bytes)) } }