Skip to content

Commit

Permalink
chore(derive): Test and Clean Batch Types (#670)
Browse files Browse the repository at this point in the history
* chore(derive): test and clean batch types

* chore(derive): test span batch transactions

* chore(derive): test span batch utils
  • Loading branch information
refcell authored Oct 9, 2024
1 parent 5955408 commit c2eb864
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 21 deletions.
33 changes: 33 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ spin.workspace = true
anyhow.workspace = true
alloy-rpc-client.workspace = true
alloy-transport-http.workspace = true
alloy-primitives = { workspace = true, features = ["rlp", "k256", "map", "arbitrary"] }
tokio.workspace = true
proptest.workspace = true
tracing-subscriber.workspace = true
Expand Down
37 changes: 16 additions & 21 deletions crates/derive/src/batch/span_batch/bits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,22 @@ use core::cmp::Ordering;
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct SpanBatchBits(pub Vec<u8>);

impl AsRef<Vec<u8>> for SpanBatchBits {
fn as_ref(&self) -> &Vec<u8> {
&self.0
}
}

impl AsRef<[u8]> for SpanBatchBits {
fn as_ref(&self) -> &[u8] {
&self.0
}
}

impl From<SpanBatchBits> for Vec<u8> {
fn from(bits: SpanBatchBits) -> Self {
bits.0
impl SpanBatchBits {
/// Returns the max amount of bytes that can be stored in the bitlist.
pub const fn max_bytes(is_fjord_active: bool) -> usize {
if is_fjord_active {
FJORD_MAX_SPAN_BATCH_BYTES as usize
} else {
MAX_SPAN_BATCH_BYTES as usize
}
}
}

impl SpanBatchBits {
/// Decodes a standard span-batch bitlist from a reader.
/// The bitlist is encoded as big-endian integer, left-padded with zeroes to a multiple of 8
/// bits. The encoded bitlist cannot be longer than [MAX_SPAN_BATCH_BYTES].
Expand All @@ -37,11 +34,7 @@ impl SpanBatchBits {
is_fjord_active: bool,
) -> Result<Self, SpanBatchError> {
let buffer_len = bit_length / 8 + if bit_length % 8 != 0 { 1 } else { 0 };
let max_bytes = if is_fjord_active {
FJORD_MAX_SPAN_BATCH_BYTES as usize
} else {
MAX_SPAN_BATCH_BYTES as usize
};
let max_bytes = Self::max_bytes(is_fjord_active);
if buffer_len > max_bytes {
return Err(SpanBatchError::TooBigSpanBatchSize);
}
Expand Down Expand Up @@ -82,11 +75,7 @@ impl SpanBatchBits {
// Round up, ensure enough bytes when number of bits is not a multiple of 8.
// Alternative of (L+7)/8 is not overflow-safe.
let buf_len = bit_length / 8 + if bit_length % 8 != 0 { 1 } else { 0 };
let max_bytes = if is_fjord_active {
FJORD_MAX_SPAN_BATCH_BYTES as usize
} else {
MAX_SPAN_BATCH_BYTES as usize
};
let max_bytes = Self::max_bytes(is_fjord_active);
if buf_len > max_bytes {
return Err(SpanBatchError::TooBigSpanBatchSize);
}
Expand Down Expand Up @@ -185,6 +174,12 @@ mod test {
use super::*;
use proptest::{collection::vec, prelude::any, proptest};

#[test]
fn test_bitlist_max_bytes() {
assert_eq!(SpanBatchBits::max_bytes(false), MAX_SPAN_BATCH_BYTES as usize);
assert_eq!(SpanBatchBits::max_bytes(true), FJORD_MAX_SPAN_BATCH_BYTES as usize);
}

proptest! {
#[test]
fn test_encode_decode_roundtrip_span_bitlist(vec in vec(any::<u8>(), 0..5096)) {
Expand Down
24 changes: 24 additions & 0 deletions crates/derive/src/batch/span_batch/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,27 @@ impl From<SingleBatch> for SpanBatchElement {
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use proptest::{collection::vec, prelude::any, proptest};

proptest! {
#[test]
fn test_span_batch_element_from_single_batch(epoch_num in 0u64..u64::MAX, timestamp in 0u64..u64::MAX, transactions in vec(any::<Bytes>(), 0..100)) {
let single_batch = SingleBatch {
epoch_num,
timestamp,
transactions: transactions.clone(),
..Default::default()
};

let span_batch_element: SpanBatchElement = single_batch.into();

assert_eq!(span_batch_element.epoch_num, epoch_num);
assert_eq!(span_batch_element.timestamp, timestamp);
assert_eq!(span_batch_element.transactions, transactions);
}
}
}
91 changes: 91 additions & 0 deletions crates/derive/src/batch/span_batch/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,3 +403,94 @@ impl SpanBatchTransactions {
Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;
use alloy_consensus::{Signed, TxEip1559, TxEip2930, TxLegacy};
use alloy_primitives::{address, Signature};

#[test]
fn test_span_batch_transactions_add_empty_txs() {
let mut span_batch_txs = SpanBatchTransactions::default();
let txs = vec![];
let chain_id = 1;
let result = span_batch_txs.add_txs(txs, chain_id);
assert!(result.is_ok());
assert_eq!(span_batch_txs.total_block_tx_count, 0);
}

#[test]
fn test_span_batch_transactions_add_invalid_legacy_parity_decoding() {
let sig = Signature::test_signature();
let to = address!("0123456789012345678901234567890123456789");
let tx = TxEnvelope::Legacy(Signed::new_unchecked(
TxLegacy { to: TxKind::Call(to), ..Default::default() },
sig,
Default::default(),
));
let mut span_batch_txs = SpanBatchTransactions::default();
let mut buf = vec![];
tx.encode(&mut buf);
let txs = vec![Bytes::from(buf)];
let chain_id = 1;
let err = span_batch_txs.add_txs(txs, chain_id).unwrap_err();
assert_eq!(err, SpanBatchError::Decoding(SpanDecodingError::InvalidTransactionData));
}

#[test]
fn test_span_batch_transactions_add_eip2930_tx_wrong_chain_id() {
let sig = Signature::test_signature();
let to = address!("0123456789012345678901234567890123456789");
let tx = TxEnvelope::Eip2930(Signed::new_unchecked(
TxEip2930 { to: TxKind::Call(to), ..Default::default() },
sig,
Default::default(),
));
let mut span_batch_txs = SpanBatchTransactions::default();
let mut buf = vec![];
tx.encode(&mut buf);
let txs = vec![Bytes::from(buf)];
let chain_id = 1;
let err = span_batch_txs.add_txs(txs, chain_id).unwrap_err();
assert_eq!(err, SpanBatchError::Decoding(SpanDecodingError::InvalidTransactionData));
}

#[test]
fn test_span_batch_transactions_add_eip2930_tx() {
let sig = Signature::test_signature();
let to = address!("0123456789012345678901234567890123456789");
let tx = TxEnvelope::Eip2930(Signed::new_unchecked(
TxEip2930 { to: TxKind::Call(to), chain_id: 1, ..Default::default() },
sig,
Default::default(),
));
let mut span_batch_txs = SpanBatchTransactions::default();
let mut buf = vec![];
tx.encode(&mut buf);
let txs = vec![Bytes::from(buf)];
let chain_id = 1;
let result = span_batch_txs.add_txs(txs, chain_id);
assert_eq!(result, Ok(()));
assert_eq!(span_batch_txs.total_block_tx_count, 1);
}

#[test]
fn test_span_batch_transactions_add_eip1559_tx() {
let sig = Signature::test_signature();
let to = address!("0123456789012345678901234567890123456789");
let tx = TxEnvelope::Eip1559(Signed::new_unchecked(
TxEip1559 { to: TxKind::Call(to), chain_id: 1, ..Default::default() },
sig,
Default::default(),
));
let mut span_batch_txs = SpanBatchTransactions::default();
let mut buf = vec![];
tx.encode(&mut buf);
let txs = vec![Bytes::from(buf)];
let chain_id = 1;
let result = span_batch_txs.add_txs(txs, chain_id);
assert_eq!(result, Ok(()));
assert_eq!(span_batch_txs.total_block_tx_count, 1);
}
}
66 changes: 66 additions & 0 deletions crates/derive/src/batch/span_batch/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,69 @@ pub(crate) const fn is_protected_v(tx: &TxEnvelope) -> bool {
_ => true,
}
}

#[cfg(test)]
mod tests {
use super::*;
use alloy_consensus::{
Signed, TxEip1559, TxEip2930, TxEip4844, TxEip4844Variant, TxEip7702, TxLegacy,
};
use alloy_primitives::{b256, Signature};

#[test]
fn test_convert_v_to_y_parity() {
assert_eq!(convert_v_to_y_parity(27, TxType::Legacy), Ok(false));
assert_eq!(convert_v_to_y_parity(28, TxType::Legacy), Ok(true));
assert_eq!(convert_v_to_y_parity(36, TxType::Legacy), Ok(true));
assert_eq!(convert_v_to_y_parity(37, TxType::Legacy), Ok(false));
assert_eq!(convert_v_to_y_parity(1, TxType::Eip2930), Ok(true));
assert_eq!(convert_v_to_y_parity(1, TxType::Eip1559), Ok(true));
assert_eq!(
convert_v_to_y_parity(1, TxType::Eip4844),
Err(SpanBatchError::Decoding(SpanDecodingError::InvalidTransactionType))
);
assert_eq!(
convert_v_to_y_parity(0, TxType::Eip7702),
Err(SpanBatchError::Decoding(SpanDecodingError::InvalidTransactionType))
);
}

#[test]
fn test_is_protected_v() {
let sig = Signature::test_signature();
assert!(!is_protected_v(&TxEnvelope::Legacy(Signed::new_unchecked(
TxLegacy::default(),
sig,
Default::default(),
))));
let r = b256!("840cfc572845f5786e702984c2a582528cad4b49b2a10b9db1be7fca90058565");
let s = b256!("25e7109ceb98168d95b09b18bbf6b685130e0562f233877d492b94eee0c5b6d1");
let v = 27;
let valid_sig = Signature::from_scalars_and_parity(r, s, v).unwrap();
assert!(!is_protected_v(&TxEnvelope::Legacy(Signed::new_unchecked(
TxLegacy::default(),
valid_sig,
Default::default(),
))));
assert!(is_protected_v(&TxEnvelope::Eip2930(Signed::new_unchecked(
TxEip2930::default(),
sig,
Default::default(),
))));
assert!(is_protected_v(&TxEnvelope::Eip1559(Signed::new_unchecked(
TxEip1559::default(),
sig,
Default::default(),
))));
assert!(is_protected_v(&TxEnvelope::Eip4844(Signed::new_unchecked(
TxEip4844Variant::TxEip4844(TxEip4844::default()),
sig,
Default::default(),
))));
assert!(is_protected_v(&TxEnvelope::Eip7702(Signed::new_unchecked(
TxEip7702::default(),
sig,
Default::default(),
))));
}
}

0 comments on commit c2eb864

Please sign in to comment.