kona_protocol/batch/
core.rs1use crate::{
4 BatchDecodingError, BatchEncodingError, BatchType, RawSpanBatch, SingleBatch, SpanBatch,
5};
6use alloy_primitives::bytes;
7use alloy_rlp::{Buf, Decodable, Encodable};
8use kona_genesis::RollupConfig;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
12#[allow(clippy::large_enum_variant)]
13pub enum Batch {
14 Single(SingleBatch),
16 Span(SpanBatch),
18}
19
20impl core::fmt::Display for Batch {
21 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
22 match self {
23 Self::Single(_) => write!(f, "single"),
24 Self::Span(_) => write!(f, "span"),
25 }
26 }
27}
28
29impl Batch {
30 pub fn timestamp(&self) -> u64 {
32 match self {
33 Self::Single(sb) => sb.timestamp,
34 Self::Span(sb) => sb.starting_timestamp(),
35 }
36 }
37
38 pub fn decode(r: &mut &[u8], cfg: &RollupConfig) -> Result<Self, BatchDecodingError> {
40 if r.is_empty() {
41 return Err(BatchDecodingError::EmptyBuffer);
42 }
43
44 let batch_type = BatchType::from(r[0]);
46 r.advance(1);
47
48 match batch_type {
49 BatchType::Single => {
50 let single_batch =
51 SingleBatch::decode(r).map_err(BatchDecodingError::AlloyRlpError)?;
52 Ok(Self::Single(single_batch))
53 }
54 BatchType::Span => {
55 let mut raw_span_batch = RawSpanBatch::decode(r)?;
56 let span_batch = raw_span_batch
57 .derive(cfg.block_time, cfg.genesis.l2_time, cfg.l2_chain_id.id())
58 .map_err(BatchDecodingError::SpanBatchError)?;
59 Ok(Self::Span(span_batch))
60 }
61 }
62 }
63
64 pub fn encode(&self, out: &mut dyn bytes::BufMut) -> Result<(), BatchEncodingError> {
66 match self {
67 Self::Single(sb) => {
68 out.put_u8(BatchType::Single as u8);
69 sb.encode(out);
70 }
71 Self::Span(sb) => {
72 out.put_u8(BatchType::Span as u8);
73 let raw_span_batch =
74 sb.to_raw_span_batch().map_err(BatchEncodingError::SpanBatchError)?;
75 raw_span_batch.encode(out).map_err(BatchEncodingError::SpanBatchError)?;
76 }
77 }
78 Ok(())
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 use crate::{SpanBatchElement, SpanBatchError, SpanBatchTransactions};
86 use alloc::{vec, vec::Vec};
87 use alloy_consensus::{Signed, TxEip2930, TxEnvelope};
88 use alloy_primitives::{Bytes, Signature, TxKind, address, hex};
89
90 #[test]
91 fn test_single_batch_encode_decode() {
92 let mut out = Vec::new();
93 let batch = Batch::Single(SingleBatch::default());
94 batch.encode(&mut out).unwrap();
95 let decoded = Batch::decode(&mut out.as_slice(), &RollupConfig::default()).unwrap();
96 assert_eq!(batch, decoded);
97 }
98
99 #[test]
100 fn test_span_batch_encode_decode() {
101 let sig = Signature::test_signature();
102 let to = address!("0123456789012345678901234567890123456789");
103 let tx = TxEnvelope::Eip2930(Signed::new_unchecked(
104 TxEip2930 { to: TxKind::Call(to), chain_id: 1, ..Default::default() },
105 sig,
106 Default::default(),
107 ));
108 let mut span_batch_txs = SpanBatchTransactions::default();
109 let mut buf = vec![];
110 tx.encode(&mut buf);
111 let txs = vec![Bytes::from(buf)];
112 let chain_id = 1;
113 span_batch_txs.add_txs(txs, chain_id).unwrap();
114
115 let mut out = Vec::new();
116 let batch = Batch::Span(SpanBatch {
117 block_tx_counts: vec![1],
118 batches: vec![SpanBatchElement::default()],
119 txs: span_batch_txs,
120 ..Default::default()
121 });
122 batch.encode(&mut out).unwrap();
123 let decoded = Batch::decode(&mut out.as_slice(), &RollupConfig::default()).unwrap();
124 assert_eq!(Batch::Span(SpanBatch {
125 batches: vec![SpanBatchElement {
126 transactions: vec![hex!("01f85f808080809401234567890123456789012345678901234567898080c080a0840cfc572845f5786e702984c2a582528cad4b49b2a10b9db1be7fca90058565a025e7109ceb98168d95b09b18bbf6b685130e0562f233877d492b94eee0c5b6d1").into()],
127 ..Default::default()
128 }],
129 txs: SpanBatchTransactions::default(),
130 ..Default::default()
131 }), decoded);
132 }
133
134 #[test]
135 fn test_empty_span_batch() {
136 let mut out = Vec::new();
137 let batch = Batch::Span(SpanBatch::default());
138 let err = batch.encode(&mut out).unwrap_err();
140 assert_eq!(BatchEncodingError::SpanBatchError(SpanBatchError::EmptySpanBatch), err);
141 }
142}