op_alloy_protocol/batch/
payload.rsuse super::MAX_SPAN_BATCH_ELEMENTS;
use crate::{SpanBatchBits, SpanBatchError, SpanBatchTransactions, SpanDecodingError};
use alloc::vec::Vec;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct SpanBatchPayload {
pub block_count: u64,
pub origin_bits: SpanBatchBits,
pub block_tx_counts: Vec<u64>,
pub txs: SpanBatchTransactions,
}
impl SpanBatchPayload {
pub fn decode_payload(r: &mut &[u8]) -> Result<Self, SpanBatchError> {
let mut payload = Self::default();
payload.decode_block_count(r)?;
payload.decode_origin_bits(r)?;
payload.decode_block_tx_counts(r)?;
payload.decode_txs(r)?;
Ok(payload)
}
pub fn encode_payload(&self, w: &mut Vec<u8>) -> Result<(), SpanBatchError> {
self.encode_block_count(w);
self.encode_origin_bits(w)?;
self.encode_block_tx_counts(w);
self.encode_txs(w)
}
pub fn decode_origin_bits(&mut self, r: &mut &[u8]) -> Result<(), SpanBatchError> {
if self.block_count > MAX_SPAN_BATCH_ELEMENTS {
return Err(SpanBatchError::TooBigSpanBatchSize);
}
self.origin_bits = SpanBatchBits::decode(r, self.block_count as usize)?;
Ok(())
}
pub fn decode_block_count(&mut self, r: &mut &[u8]) -> Result<(), SpanBatchError> {
let (block_count, remaining) = unsigned_varint::decode::u64(r)
.map_err(|_| SpanBatchError::Decoding(SpanDecodingError::BlockCount))?;
if block_count > MAX_SPAN_BATCH_ELEMENTS {
return Err(SpanBatchError::TooBigSpanBatchSize);
}
if block_count == 0 {
return Err(SpanBatchError::EmptySpanBatch);
}
self.block_count = block_count;
*r = remaining;
Ok(())
}
pub fn decode_block_tx_counts(&mut self, r: &mut &[u8]) -> Result<(), SpanBatchError> {
let mut block_tx_counts = Vec::with_capacity(self.block_count as usize);
for _ in 0..self.block_count {
let (block_tx_count, remaining) = unsigned_varint::decode::u64(r)
.map_err(|_| SpanBatchError::Decoding(SpanDecodingError::BlockTxCounts))?;
if block_tx_count > MAX_SPAN_BATCH_ELEMENTS {
return Err(SpanBatchError::TooBigSpanBatchSize);
}
block_tx_counts.push(block_tx_count);
*r = remaining;
}
self.block_tx_counts = block_tx_counts;
Ok(())
}
pub fn decode_txs(&mut self, r: &mut &[u8]) -> Result<(), SpanBatchError> {
if self.block_tx_counts.is_empty() {
return Err(SpanBatchError::EmptySpanBatch);
}
let total_block_tx_count =
self.block_tx_counts.iter().try_fold(0u64, |acc, block_tx_count| {
acc.checked_add(*block_tx_count).ok_or(SpanBatchError::TooBigSpanBatchSize)
})?;
if total_block_tx_count > MAX_SPAN_BATCH_ELEMENTS {
return Err(SpanBatchError::TooBigSpanBatchSize);
}
self.txs.total_block_tx_count = total_block_tx_count;
self.txs.decode(r)?;
Ok(())
}
pub fn encode_origin_bits(&self, w: &mut Vec<u8>) -> Result<(), SpanBatchError> {
SpanBatchBits::encode(w, self.block_count as usize, &self.origin_bits)
}
pub fn encode_block_count(&self, w: &mut Vec<u8>) {
let mut u64_varint_buf = [0u8; 10];
w.extend_from_slice(unsigned_varint::encode::u64(self.block_count, &mut u64_varint_buf));
}
pub fn encode_block_tx_counts(&self, w: &mut Vec<u8>) {
let mut u64_varint_buf = [0u8; 10];
for block_tx_count in &self.block_tx_counts {
u64_varint_buf.fill(0);
w.extend_from_slice(unsigned_varint::encode::u64(*block_tx_count, &mut u64_varint_buf));
}
}
pub fn encode_txs(&self, w: &mut Vec<u8>) -> Result<(), SpanBatchError> {
self.txs.encode(w)
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
#[test]
fn test_decode_origin_bits() {
let block_count = 10;
let encoded = vec![2; block_count / 8 + 1];
let mut payload =
SpanBatchPayload { block_count: block_count as u64, ..Default::default() };
payload.decode_origin_bits(&mut encoded.as_slice()).unwrap();
assert_eq!(payload.origin_bits, SpanBatchBits::new(vec![2; block_count / 8 + 1]));
}
#[test]
fn test_zero_block_count() {
let mut u64_varint_buf = [0; 10];
let mut encoded = unsigned_varint::encode::u64(0, &mut u64_varint_buf);
let mut payload = SpanBatchPayload::default();
let err = payload.decode_block_count(&mut encoded).unwrap_err();
assert_eq!(err, SpanBatchError::EmptySpanBatch);
}
#[test]
fn test_decode_block_count() {
let block_count = MAX_SPAN_BATCH_ELEMENTS;
let mut u64_varint_buf = [0; 10];
let mut encoded = unsigned_varint::encode::u64(block_count, &mut u64_varint_buf);
let mut payload = SpanBatchPayload::default();
payload.decode_block_count(&mut encoded).unwrap();
assert_eq!(payload.block_count, block_count);
}
#[test]
fn test_decode_block_count_errors() {
let block_count = MAX_SPAN_BATCH_ELEMENTS + 1;
let mut u64_varint_buf = [0; 10];
let mut encoded = unsigned_varint::encode::u64(block_count, &mut u64_varint_buf);
let mut payload = SpanBatchPayload::default();
let err = payload.decode_block_count(&mut encoded).unwrap_err();
assert_eq!(err, SpanBatchError::TooBigSpanBatchSize);
}
#[test]
fn test_decode_block_tx_counts() {
let block_count = 2;
let mut u64_varint_buf = [0; 10];
let mut encoded = unsigned_varint::encode::u64(block_count, &mut u64_varint_buf);
let mut payload = SpanBatchPayload::default();
payload.decode_block_count(&mut encoded).unwrap();
let mut r: Vec<u8> = Vec::new();
for _ in 0..2 {
let mut buf = [0u8; 10];
let encoded = unsigned_varint::encode::u64(2, &mut buf);
r.append(&mut encoded.to_vec());
}
payload.decode_block_tx_counts(&mut r.as_slice()).unwrap();
assert_eq!(payload.block_tx_counts, vec![2, 2]);
}
}