kona_protocol/batch/
raw.rs1use alloc::{vec, vec::Vec};
4use alloy_primitives::bytes;
5
6use crate::{
7 BatchType, SpanBatch, SpanBatchElement, SpanBatchError, SpanBatchPayload, SpanBatchPrefix,
8 SpanDecodingError,
9};
10
11#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct RawSpanBatch {
14 pub prefix: SpanBatchPrefix,
16 pub payload: SpanBatchPayload,
18}
19
20impl RawSpanBatch {
21 pub const fn get_batch_type(&self) -> BatchType {
23 BatchType::Span
24 }
25
26 pub fn encode(&self, w: &mut dyn bytes::BufMut) -> Result<(), SpanBatchError> {
28 self.prefix.encode_prefix(w);
29 self.payload.encode_payload(w)
30 }
31
32 pub fn decode(r: &mut &[u8]) -> Result<Self, SpanBatchError> {
34 let prefix = SpanBatchPrefix::decode_prefix(r)?;
35 let payload = SpanBatchPayload::decode_payload(r)?;
36 Ok(Self { prefix, payload })
37 }
38
39 pub fn derive(
43 &mut self,
44 block_time: u64,
45 genesis_time: u64,
46 chain_id: u64,
47 ) -> Result<SpanBatch, SpanBatchError> {
48 if self.payload.block_count == 0 {
49 return Err(SpanBatchError::EmptySpanBatch);
50 }
51
52 let mut block_origin_nums = vec![0u64; self.payload.block_count as usize];
53 let mut l1_origin_number = self.prefix.l1_origin_num;
54 for i in (0..self.payload.block_count).rev() {
55 block_origin_nums[i as usize] = l1_origin_number;
56 if self
57 .payload
58 .origin_bits
59 .get_bit(i as usize)
60 .ok_or(SpanBatchError::Decoding(SpanDecodingError::L1OriginCheck))? ==
61 1 &&
62 i > 0
63 {
64 l1_origin_number -= 1;
65 }
66 }
67
68 let enveloped_txs = self.payload.txs.full_txs(chain_id)?;
70
71 let mut tx_idx = 0;
72 let batches = (0..self.payload.block_count).fold(Vec::new(), |mut acc, i| {
73 let transactions =
74 (0..self.payload.block_tx_counts[i as usize]).fold(Vec::new(), |mut acc, _| {
75 acc.push(enveloped_txs[tx_idx].clone());
76 tx_idx += 1;
77 acc
78 });
79 acc.push(SpanBatchElement {
80 epoch_num: block_origin_nums[i as usize],
81 timestamp: genesis_time + self.prefix.rel_timestamp + block_time * i,
82 transactions: transactions.into_iter().map(|v| v.into()).collect(),
83 });
84 acc
85 });
86
87 Ok(SpanBatch {
88 parent_check: self.prefix.parent_check,
89 l1_origin_check: self.prefix.l1_origin_check,
90 batches,
91 ..Default::default()
92 })
93 }
94}
95
96#[cfg(test)]
97mod test {
98 use super::*;
99 use alloy_primitives::FixedBytes;
100
101 #[test]
102 fn test_try_from_span_batch_empty_batches_errors() {
103 let span_batch = SpanBatch::default();
104 let raw_span_batch = span_batch.to_raw_span_batch().unwrap_err();
105 assert_eq!(raw_span_batch, SpanBatchError::EmptySpanBatch);
106 }
107
108 #[test]
109 fn test_try_from_span_batch_succeeds() {
110 let parent_check = FixedBytes::from([2u8; 20]);
111 let l1_origin_check = FixedBytes::from([3u8; 20]);
112 let first = SpanBatchElement { epoch_num: 100, timestamp: 400, transactions: Vec::new() };
113 let last = SpanBatchElement { epoch_num: 200, timestamp: 500, transactions: Vec::new() };
114 let span_batch = SpanBatch {
115 batches: vec![first, last],
116 genesis_timestamp: 300,
117 parent_check,
118 l1_origin_check,
119 ..Default::default()
120 };
121 let expected_prefix = SpanBatchPrefix {
122 rel_timestamp: 100,
123 l1_origin_num: 200,
124 parent_check,
125 l1_origin_check,
126 };
127 let expected_payload = SpanBatchPayload { block_count: 2, ..Default::default() };
128 let raw_span_batch = span_batch.to_raw_span_batch().unwrap();
129 assert_eq!(raw_span_batch.prefix, expected_prefix);
130 assert_eq!(raw_span_batch.payload, expected_payload);
131 }
132
133 #[test]
134 fn test_decode_encode_raw_span_batch() {
135 let raw_span_batch_hex = include_bytes!("./testdata/raw_batch.hex");
137 let raw_span_batch = RawSpanBatch::decode(&mut raw_span_batch_hex.as_slice()).unwrap();
138
139 let mut encoding_buf = Vec::new();
140 raw_span_batch.encode(&mut encoding_buf).unwrap();
141 assert_eq!(encoding_buf, raw_span_batch_hex);
142 }
143}