Skip to content

Commit cff3a0a

Browse files
authored
feat: correctly handle boundary codec headers (#284)
* feat: correctly handle boundary codec headers * test: add etherscan url
1 parent 1519161 commit cff3a0a

File tree

7 files changed

+95
-16
lines changed

7 files changed

+95
-16
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use crate::{
2+
decoding::{v0::BatchHeaderV0, v1::BatchHeaderV1, v3::BatchHeaderV3, v7::BatchHeaderV7},
3+
DecodingError,
4+
};
5+
6+
/// The batch header.
7+
pub enum BatchHeader {
8+
/// The batch header for V0.
9+
V0(BatchHeaderV0),
10+
/// The batch header for V1.
11+
V1(BatchHeaderV1),
12+
/// The batch header for V3.
13+
V3(BatchHeaderV3),
14+
/// The batch header for V7.
15+
V7(BatchHeaderV7),
16+
}
17+
18+
impl BatchHeader {
19+
/// Returns the total number of L1 messages popped after the batch, if the version supports it.
20+
pub fn total_l1_message_popped(&self) -> Option<u64> {
21+
match self {
22+
BatchHeader::V0(header) => Some(header.total_l1_message_popped),
23+
BatchHeader::V1(header) => Some(header.total_l1_message_popped),
24+
BatchHeader::V3(header) => Some(header.total_l1_message_popped),
25+
BatchHeader::V7(_) => None,
26+
}
27+
}
28+
29+
/// Tries to read from the input buffer into the appropriate batch header version.
30+
/// Returns [`DecodingError::Eof`] if the buffer is empty or does not contain enough bytes for
31+
/// the specific version.
32+
pub fn try_from_buf(buf: &mut &[u8]) -> Result<Self, DecodingError> {
33+
if buf.is_empty() {
34+
return Err(DecodingError::Eof);
35+
}
36+
let version = buf[0];
37+
38+
match version {
39+
0 => Ok(BatchHeader::V0(BatchHeaderV0::try_from_buf(buf)?)),
40+
1..=2 => Ok(BatchHeader::V1(BatchHeaderV1::try_from_buf(buf)?)),
41+
3.. => Ok(BatchHeader::V3(BatchHeaderV3::try_from_buf(buf)?)),
42+
}
43+
}
44+
}

crates/codec/src/decoding/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
/// Batch related structures.
44
pub mod batch;
55

6+
/// Batch header related structures.
7+
pub mod batch_header;
8+
69
/// Blob related helpers.
710
pub mod blob;
811

crates/codec/src/decoding/v0/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ pub(crate) use block_context::BlockContextV0;
77
mod block_context;
88

99
use crate::{
10-
decoding::{batch::Batch, payload::PayloadData, transaction::Transaction},
10+
decoding::{
11+
batch::Batch, batch_header::BatchHeader, payload::PayloadData, transaction::Transaction,
12+
},
1113
error::DecodingError,
1214
L2Block,
1315
};
@@ -58,8 +60,8 @@ pub fn decode_v0(calldata: &[u8]) -> Result<Batch, DecodingError> {
5860

5961
// decode the parent batch header.
6062
let raw_parent_header = call.parent_batch_header().ok_or(DecodingError::MissingParentHeader)?;
61-
let parent_header = BatchHeaderV0::try_from_buf(&mut (&*raw_parent_header))?;
62-
let l1_message_start_index = parent_header.total_l1_message_popped;
63+
let parent_header = BatchHeader::try_from_buf(&mut (&*raw_parent_header))?;
64+
let l1_message_start_index = parent_header.total_l1_message_popped().expect("exists for v0");
6365

6466
let payload = PayloadData {
6567
blocks: l2_blocks,

crates/codec/src/decoding/v1/mod.rs

Lines changed: 35 additions & 4 deletions
Large diffs are not rendered by default.

crates/codec/src/decoding/v2/mod.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ pub mod zstd;
33
use crate::{
44
check_buf_len,
55
decoding::{
6-
batch::Batch,
7-
blob::BlobSliceIter,
8-
v1::{decode_v1_chunk, BatchHeaderV1},
6+
batch::Batch, batch_header::BatchHeader, blob::BlobSliceIter, v1::decode_v1_chunk,
97
v2::zstd::decompress_blob_data,
108
},
119
error::DecodingError,
@@ -32,8 +30,8 @@ pub fn decode_v2(calldata: &[u8], blob: &[u8]) -> Result<Batch, DecodingError> {
3230

3331
// decode the parent batch header.
3432
let raw_parent_header = call.parent_batch_header().ok_or(DecodingError::MissingParentHeader)?;
35-
let parent_header = BatchHeaderV1::try_from_buf(&mut (&*raw_parent_header))?;
36-
let l1_message_start_index = parent_header.total_l1_message_popped;
33+
let parent_header = BatchHeader::try_from_buf(&mut (&*raw_parent_header))?;
34+
let l1_message_start_index = parent_header.total_l1_message_popped().expect("exists for v2");
3735

3836
// get blob iterator and collect, skipping unused bytes.
3937
let compressed_heap_blob = BlobSliceIter::from_blob_slice(blob).copied().collect::<Vec<_>>();

crates/codec/src/decoding/v4/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::{
22
check_buf_len,
33
decoding::{
4-
batch::Batch, blob::BlobSliceIter, v1::decode_v1_chunk, v2::zstd::decompress_blob_data,
5-
v3::BatchHeaderV3,
4+
batch::Batch, batch_header::BatchHeader, blob::BlobSliceIter, v1::decode_v1_chunk,
5+
v2::zstd::decompress_blob_data,
66
},
77
error::DecodingError,
88
from_be_bytes_slice_and_advance_buf,
@@ -20,8 +20,8 @@ pub fn decode_v4(calldata: &[u8], blob: &[u8]) -> Result<Batch, DecodingError> {
2020

2121
// decode the parent batch header.
2222
let raw_parent_header = call.parent_batch_header().ok_or(DecodingError::MissingParentHeader)?;
23-
let parent_header = BatchHeaderV3::try_from_buf(&mut (&*raw_parent_header))?;
24-
let l1_message_start_index = parent_header.total_l1_message_popped;
23+
let parent_header = BatchHeader::try_from_buf(&mut (&*raw_parent_header))?;
24+
let l1_message_start_index = parent_header.total_l1_message_popped().expect("exists for v4");
2525

2626
// get blob iterator and collect, skipping unused bytes.
2727
let mut heap_blob = BlobSliceIter::from_blob_slice(blob).copied().collect::<Vec<_>>();

crates/codec/testdata/blob_v0_v1_boundary.bin

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)