kona_protocol/batch/
payload.rs

1//! Raw Span Batch Payload
2
3use super::MAX_SPAN_BATCH_ELEMENTS;
4use crate::{SpanBatchBits, SpanBatchError, SpanBatchTransactions, SpanDecodingError};
5use alloc::vec::Vec;
6use alloy_primitives::bytes;
7
8/// Span Batch Payload
9#[derive(Debug, Clone, Default, PartialEq, Eq)]
10pub struct SpanBatchPayload {
11    /// Number of L2 block in the span
12    pub block_count: u64,
13    /// Standard span-batch bitlist of blockCount bits. Each bit indicates if the L1 origin is
14    /// changed at the L2 block.
15    pub origin_bits: SpanBatchBits,
16    /// List of transaction counts for each L2 block
17    pub block_tx_counts: Vec<u64>,
18    /// Transactions encoded in SpanBatch specs
19    pub txs: SpanBatchTransactions,
20}
21
22impl SpanBatchPayload {
23    /// Decodes a [SpanBatchPayload] from a reader.
24    pub fn decode_payload(r: &mut &[u8]) -> Result<Self, SpanBatchError> {
25        let mut payload = Self::default();
26        payload.decode_block_count(r)?;
27        payload.decode_origin_bits(r)?;
28        payload.decode_block_tx_counts(r)?;
29        payload.decode_txs(r)?;
30        Ok(payload)
31    }
32
33    /// Encodes a [SpanBatchPayload] into a writer.
34    pub fn encode_payload(&self, w: &mut dyn bytes::BufMut) -> Result<(), SpanBatchError> {
35        self.encode_block_count(w);
36        self.encode_origin_bits(w)?;
37        self.encode_block_tx_counts(w);
38        self.encode_txs(w)
39    }
40
41    /// Decodes the origin bits from a reader.
42    pub fn decode_origin_bits(&mut self, r: &mut &[u8]) -> Result<(), SpanBatchError> {
43        if self.block_count > MAX_SPAN_BATCH_ELEMENTS {
44            return Err(SpanBatchError::TooBigSpanBatchSize);
45        }
46
47        self.origin_bits = SpanBatchBits::decode(r, self.block_count as usize)?;
48        Ok(())
49    }
50
51    /// Decode a block count from a reader.
52    pub fn decode_block_count(&mut self, r: &mut &[u8]) -> Result<(), SpanBatchError> {
53        let (block_count, remaining) = unsigned_varint::decode::u64(r)
54            .map_err(|_| SpanBatchError::Decoding(SpanDecodingError::BlockCount))?;
55        // The number of transactions in a single L2 block cannot be greater than
56        // [MAX_SPAN_BATCH_ELEMENTS].
57        if block_count > MAX_SPAN_BATCH_ELEMENTS {
58            return Err(SpanBatchError::TooBigSpanBatchSize);
59        }
60        if block_count == 0 {
61            return Err(SpanBatchError::EmptySpanBatch);
62        }
63        self.block_count = block_count;
64        *r = remaining;
65        Ok(())
66    }
67
68    /// Decode block transaction counts from a reader.
69    pub fn decode_block_tx_counts(&mut self, r: &mut &[u8]) -> Result<(), SpanBatchError> {
70        // Initially allocate the vec with the block count, to reduce re-allocations in the first
71        // few blocks.
72        let mut block_tx_counts = Vec::with_capacity(self.block_count as usize);
73
74        for _ in 0..self.block_count {
75            let (block_tx_count, remaining) = unsigned_varint::decode::u64(r)
76                .map_err(|_| SpanBatchError::Decoding(SpanDecodingError::BlockTxCounts))?;
77
78            // The number of transactions in a single L2 block cannot be greater than
79            // [MAX_SPAN_BATCH_ELEMENTS].
80            if block_tx_count > MAX_SPAN_BATCH_ELEMENTS {
81                return Err(SpanBatchError::TooBigSpanBatchSize);
82            }
83            block_tx_counts.push(block_tx_count);
84            *r = remaining;
85        }
86        self.block_tx_counts = block_tx_counts;
87        Ok(())
88    }
89
90    /// Decode transactions from a reader.
91    pub fn decode_txs(&mut self, r: &mut &[u8]) -> Result<(), SpanBatchError> {
92        if self.block_tx_counts.is_empty() {
93            return Err(SpanBatchError::EmptySpanBatch);
94        }
95
96        let total_block_tx_count =
97            self.block_tx_counts.iter().try_fold(0u64, |acc, block_tx_count| {
98                acc.checked_add(*block_tx_count).ok_or(SpanBatchError::TooBigSpanBatchSize)
99            })?;
100
101        // The total number of transactions in a span batch cannot be greater than
102        // [MAX_SPAN_BATCH_ELEMENTS].
103        if total_block_tx_count > MAX_SPAN_BATCH_ELEMENTS {
104            return Err(SpanBatchError::TooBigSpanBatchSize);
105        }
106        self.txs.total_block_tx_count = total_block_tx_count;
107        self.txs.decode(r)?;
108        Ok(())
109    }
110
111    /// Encode the origin bits into a writer.
112    pub fn encode_origin_bits(&self, w: &mut dyn bytes::BufMut) -> Result<(), SpanBatchError> {
113        SpanBatchBits::encode(w, self.block_count as usize, &self.origin_bits)
114    }
115
116    /// Encode the block count into a writer.
117    pub fn encode_block_count(&self, w: &mut dyn bytes::BufMut) {
118        let mut u64_varint_buf = [0u8; 10];
119        w.put_slice(unsigned_varint::encode::u64(self.block_count, &mut u64_varint_buf));
120    }
121
122    /// Encode the block transaction counts into a writer.
123    pub fn encode_block_tx_counts(&self, w: &mut dyn bytes::BufMut) {
124        let mut u64_varint_buf = [0u8; 10];
125        for block_tx_count in &self.block_tx_counts {
126            u64_varint_buf.fill(0);
127            w.put_slice(unsigned_varint::encode::u64(*block_tx_count, &mut u64_varint_buf));
128        }
129    }
130
131    /// Encode the transactions into a writer.
132    pub fn encode_txs(&self, w: &mut dyn bytes::BufMut) -> Result<(), SpanBatchError> {
133        self.txs.encode(w)
134    }
135}
136
137#[cfg(test)]
138mod tests {
139    use super::*;
140    use alloc::vec;
141
142    #[test]
143    fn test_decode_origin_bits() {
144        let block_count = 10;
145        let encoded = vec![2; block_count / 8 + 1];
146        let mut payload =
147            SpanBatchPayload { block_count: block_count as u64, ..Default::default() };
148        payload.decode_origin_bits(&mut encoded.as_slice()).unwrap();
149        assert_eq!(payload.origin_bits, SpanBatchBits::new(vec![2; block_count / 8 + 1]));
150    }
151
152    #[test]
153    fn test_zero_block_count() {
154        let mut u64_varint_buf = [0; 10];
155        let mut encoded = unsigned_varint::encode::u64(0, &mut u64_varint_buf);
156        let mut payload = SpanBatchPayload::default();
157        let err = payload.decode_block_count(&mut encoded).unwrap_err();
158        assert_eq!(err, SpanBatchError::EmptySpanBatch);
159    }
160
161    #[test]
162    fn test_decode_block_count() {
163        let block_count = MAX_SPAN_BATCH_ELEMENTS;
164        let mut u64_varint_buf = [0; 10];
165        let mut encoded = unsigned_varint::encode::u64(block_count, &mut u64_varint_buf);
166        let mut payload = SpanBatchPayload::default();
167        payload.decode_block_count(&mut encoded).unwrap();
168        assert_eq!(payload.block_count, block_count);
169    }
170
171    #[test]
172    fn test_decode_block_count_errors() {
173        let block_count = MAX_SPAN_BATCH_ELEMENTS + 1;
174        let mut u64_varint_buf = [0; 10];
175        let mut encoded = unsigned_varint::encode::u64(block_count, &mut u64_varint_buf);
176        let mut payload = SpanBatchPayload::default();
177        let err = payload.decode_block_count(&mut encoded).unwrap_err();
178        assert_eq!(err, SpanBatchError::TooBigSpanBatchSize);
179    }
180
181    #[test]
182    fn test_decode_block_tx_counts() {
183        let block_count = 2;
184        let mut u64_varint_buf = [0; 10];
185        let mut encoded = unsigned_varint::encode::u64(block_count, &mut u64_varint_buf);
186        let mut payload = SpanBatchPayload::default();
187        payload.decode_block_count(&mut encoded).unwrap();
188        let mut r: Vec<u8> = Vec::new();
189        for _ in 0..2 {
190            let mut buf = [0u8; 10];
191            let encoded = unsigned_varint::encode::u64(2, &mut buf);
192            r.append(&mut encoded.to_vec());
193        }
194        payload.decode_block_tx_counts(&mut r.as_slice()).unwrap();
195        assert_eq!(payload.block_tx_counts, vec![2, 2]);
196    }
197}