Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions rust/kona/crates/protocol/protocol/src/batch/prefix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ impl SpanBatchPrefix {

/// Decodes the parent check from a reader.
pub fn decode_parent_check(&mut self, r: &mut &[u8]) -> Result<(), SpanBatchError> {
if r.len() < 20 {
return Err(SpanBatchError::Decoding(SpanDecodingError::ParentCheck));
}
let (parent_check, remaining) = r.split_at(20);
let parent_check = FixedBytes::<20>::from_slice(parent_check);
*r = remaining;
Expand All @@ -56,6 +59,9 @@ impl SpanBatchPrefix {

/// Decodes the L1 origin check from a reader.
pub fn decode_l1_origin_check(&mut self, r: &mut &[u8]) -> Result<(), SpanBatchError> {
if r.len() < 20 {
return Err(SpanBatchError::Decoding(SpanDecodingError::L1OriginCheck));
}
let (l1_origin_check, remaining) = r.split_at(20);
let l1_origin_check = FixedBytes::<20>::from_slice(l1_origin_check);
*r = remaining;
Expand All @@ -79,6 +85,29 @@ mod test {
use alloc::vec::Vec;
use alloy_primitives::address;

#[test]
fn test_decode_parent_check_truncated() {
let mut prefix = SpanBatchPrefix::default();
let buf = [0u8; 19]; // one byte short
let result = prefix.decode_parent_check(&mut buf.as_slice());
assert_eq!(result, Err(SpanBatchError::Decoding(SpanDecodingError::ParentCheck)));
}

#[test]
fn test_decode_l1_origin_check_truncated() {
let mut prefix = SpanBatchPrefix::default();
let buf = [0u8; 19]; // one byte short
let result = prefix.decode_l1_origin_check(&mut buf.as_slice());
assert_eq!(result, Err(SpanBatchError::Decoding(SpanDecodingError::L1OriginCheck)));
}

#[test]
fn test_decode_parent_check_empty() {
let mut prefix = SpanBatchPrefix::default();
let result = prefix.decode_parent_check(&mut [].as_slice());
assert_eq!(result, Err(SpanBatchError::Decoding(SpanDecodingError::ParentCheck)));
}

#[test]
fn test_span_batch_prefix_encoding_roundtrip() {
let expected = SpanBatchPrefix {
Expand Down
50 changes: 50 additions & 0 deletions rust/kona/crates/protocol/protocol/src/batch/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ impl SpanBatchTransactions {
let mut sigs = Vec::with_capacity(self.total_block_tx_count as usize);
for i in 0..self.total_block_tx_count {
let y_parity = y_parity_bits.get_bit(i as usize).expect("same length");
if r.len() < 64 {
return Err(SpanBatchError::Decoding(
SpanDecodingError::InvalidTransactionSignature,
));
}
let r_val = U256::from_be_slice(&r[..32]);
let s_val = U256::from_be_slice(&r[32..64]);
sigs.push(Signature::new(r_val, s_val, y_parity == 1));
Expand Down Expand Up @@ -193,6 +198,9 @@ impl SpanBatchTransactions {
let mut tos = Vec::with_capacity(self.total_block_tx_count as usize);
let contract_creation_count = self.contract_creation_count();
for _ in 0..(self.total_block_tx_count - contract_creation_count) {
if r.len() < 20 {
return Err(SpanBatchError::Decoding(SpanDecodingError::InvalidTransactionData));
}
let to = Address::from_slice(&r[..20]);
tos.push(to);
r.advance(20);
Expand Down Expand Up @@ -356,6 +364,48 @@ mod tests {
use alloy_consensus::{Signed, TxEip1559, TxEip2930, TxEip7702};
use alloy_primitives::{Signature, TxKind, address};

#[test]
fn test_decode_tx_sigs_truncated() {
let mut txs = SpanBatchTransactions { total_block_tx_count: 1, ..Default::default() };
// Provide a valid y_parity bitfield (1 bit = 1 byte) but truncated signature data
// SpanBatchBits::decode for 1 bit needs 1 byte for the bitfield
let buf = vec![0u8]; // y_parity byte, but no r/s signature bytes
let result = txs.decode_tx_sigs(&mut buf.as_slice());
assert_eq!(
result,
Err(SpanBatchError::Decoding(SpanDecodingError::InvalidTransactionSignature))
);
}

#[test]
fn test_decode_tx_tos_truncated() {
let mut txs = SpanBatchTransactions {
total_block_tx_count: 1,
contract_creation_bits: SpanBatchBits::default(),
..Default::default()
};
let buf = [0u8; 19]; // one byte short of a 20-byte address
let result = txs.decode_tx_tos(&mut buf.as_slice());
assert_eq!(
result,
Err(SpanBatchError::Decoding(SpanDecodingError::InvalidTransactionData))
);
}

#[test]
fn test_decode_tx_tos_empty() {
let mut txs = SpanBatchTransactions {
total_block_tx_count: 1,
contract_creation_bits: SpanBatchBits::default(),
..Default::default()
};
let result = txs.decode_tx_tos(&mut [].as_slice());
assert_eq!(
result,
Err(SpanBatchError::Decoding(SpanDecodingError::InvalidTransactionData))
);
}

#[test]
fn test_span_batch_transactions_add_empty_txs() {
let mut span_batch_txs = SpanBatchTransactions::default();
Expand Down