Skip to content

Commit 4c04f84

Browse files
committed
feat: modify derivation pipeline to fetch blob
1 parent 1054a38 commit 4c04f84

File tree

5 files changed

+114
-19
lines changed

5 files changed

+114
-19
lines changed

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/derivation-pipeline/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ workspace = true
1111

1212
[dependencies]
1313
# alloy
14+
alloy-eips.workspace = true
1415
alloy-primitives = { workspace = true, default-features = false }
1516
alloy-rpc-types-engine = { workspace = true, default-features = false }
1617

@@ -20,8 +21,12 @@ scroll-alloy-consensus = { workspace = true, default-features = false }
2021
scroll-alloy-rpc-types-engine.workspace = true
2122

2223
# rollup node
24+
rollup-node-primitives.workspace = true
2325
scroll-codec.workspace = true
2426

27+
# misc
28+
thiserror.workspace = true
29+
2530
[dev-dependencies]
2631
eyre.workspace = true
2732
scroll-codec = { workspace = true, features = ["test-utils"] }
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use alloy_eips::eip4844::Blob;
2+
use alloy_primitives::Bytes;
3+
use scroll_codec::CommitDataSource;
4+
5+
/// Holds the data for the codec.
6+
pub(crate) struct CodecDataSource<'a> {
7+
pub(crate) calldata: &'a Bytes,
8+
pub(crate) blob: Option<&'a Blob>,
9+
}
10+
11+
impl<'a> CommitDataSource for CodecDataSource<'a> {
12+
fn calldata(&self) -> &Bytes {
13+
self.calldata
14+
}
15+
16+
fn blob(&self) -> Option<&Blob> {
17+
self.blob
18+
}
19+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use scroll_codec::CodecError;
2+
3+
/// An error occurred during the derivation process.
4+
#[derive(Debug, thiserror::Error)]
5+
pub enum DerivationPipelineError {
6+
/// An error in the codec.
7+
#[error(transparent)]
8+
Codec(#[from] CodecError),
9+
/// Missing L1 messages cursor.
10+
#[error("missing l1 message queue cursor")]
11+
MissingL1MessageQueueCursor,
12+
}

crates/derivation-pipeline/src/lib.rs

Lines changed: 75 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,35 +4,71 @@
44
//! into payload attributes for block building.
55
66
#![cfg_attr(not(feature = "std"), no_std)]
7+
8+
mod data_source;
9+
mod error;
10+
711
#[cfg(not(feature = "std"))]
812
extern crate alloc as std;
913

1014
use std::vec::Vec;
1115

16+
use crate::{data_source::CodecDataSource, error::DerivationPipelineError};
17+
use alloy_eips::eip4844::Blob;
1218
use alloy_primitives::B256;
1319
use alloy_rpc_types_engine::PayloadAttributes;
1420
use reth_scroll_chainspec::SCROLL_FEE_VAULT_ADDRESS;
21+
use rollup_node_primitives::BatchCommitData;
1522
use scroll_alloy_consensus::TxL1Message;
1623
use scroll_alloy_rpc_types_engine::ScrollPayloadAttributes;
17-
use scroll_codec::decoding::batch::Batch;
24+
use scroll_codec::Codec;
1825

19-
/// An instance of the trait can be used to provide the next L1 message to be used in the derivation
20-
/// pipeline.
26+
/// An instance of the trait can provide L1 messages using a cursor approach. Set the cursor for the
27+
/// provider using the queue index or hash and then call [`L1MessageProvider::next_l1_message`] to
28+
/// iterate the queue.
2129
pub trait L1MessageProvider {
22-
/// Returns the next L1 message.
30+
/// Returns the L1 message at the current cursor and advances the cursor.
2331
fn next_l1_message(&self) -> TxL1Message;
32+
/// Set the index cursor for the provider.
33+
fn set_index_cursor(&mut self, index: u64);
34+
/// Set the hash cursor for the provider.
35+
fn set_hash_cursor(&mut self, hash: B256);
36+
}
37+
38+
/// An instance of the trait can be used to provide L1 data.
39+
pub trait L1Provider: L1MessageProvider {
40+
/// Returns corresponding blob data for the provided hash.
41+
fn blob(&self, hash: B256) -> Option<Blob>;
2442
}
2543

26-
/// Returns an iterator over [`ScrollPayloadAttributes`] from the [`Batch`] and a
27-
/// [`L1MessageProvider`].
28-
pub fn derive<P: L1MessageProvider>(
29-
batch: Batch,
30-
l1_message_provider: &P,
31-
) -> impl Iterator<Item = ScrollPayloadAttributes> + use<'_, P> {
32-
batch.data.into_l2_blocks().into_iter().map(|mut block| {
44+
/// Returns an iterator over [`ScrollPayloadAttributes`] from the [`BatchCommitData`] and a
45+
/// [`L1Provider`].
46+
pub fn derive<P: L1Provider>(
47+
batch: BatchCommitData,
48+
l1_provider: &mut P,
49+
) -> Result<impl Iterator<Item = ScrollPayloadAttributes> + use<'_, P>, DerivationPipelineError> {
50+
// fetch the blob then decode the input batch.
51+
let blob = batch.blob_versioned_hash.and_then(|hash| l1_provider.blob(hash));
52+
let data = CodecDataSource { calldata: batch.calldata.as_ref(), blob: blob.as_ref() };
53+
let decoded = Codec::decode(&data)?;
54+
55+
// set the cursor for the l1 provider.
56+
let data = &decoded.data;
57+
if let Some(index) = data.queue_index_start() {
58+
l1_provider.set_index_cursor(index)
59+
} else if let Some(hash) = data.prev_l1_message_queue_hash() {
60+
l1_provider.set_hash_cursor(*hash);
61+
// we skip the first l1 message, as we are interested in the one starting after
62+
// prev_l1_message_queue_hash.
63+
let _ = l1_provider.next_l1_message();
64+
} else {
65+
return Err(DerivationPipelineError::MissingL1MessageQueueCursor)
66+
}
67+
68+
let iter = decoded.data.into_l2_blocks().into_iter().map(|mut block| {
3369
// query the appropriate amount of l1 messages.
3470
let mut txs = (0..block.context.num_l1_messages)
35-
.map(|_| l1_message_provider.next_l1_message())
71+
.map(|_| l1_provider.next_l1_message())
3672
.map(|tx| {
3773
let mut bytes = Vec::new();
3874
tx.eip2718_encode(&mut bytes);
@@ -56,31 +92,51 @@ pub fn derive<P: L1MessageProvider>(
5692
transactions: Some(txs),
5793
no_tx_pool: true,
5894
}
59-
})
95+
});
96+
97+
Ok(iter)
6098
}
6199

62100
#[cfg(test)]
63101
mod tests {
64102
use super::*;
65-
use alloy_primitives::{address, bytes, U256};
66-
use scroll_codec::decoding::{test_utils::read_to_bytes, v0::decode_v0};
67-
use std::cell::RefCell;
103+
use core::cell::RefCell;
104+
use std::sync::Arc;
105+
106+
use alloy_primitives::{address, b256, bytes, U256};
107+
use scroll_codec::decoding::test_utils::read_to_bytes;
68108

69109
struct TestL1MessageProvider {
70110
messages: RefCell<Vec<TxL1Message>>,
71111
}
72112

113+
impl L1Provider for TestL1MessageProvider {
114+
fn blob(&self, _hash: B256) -> Option<Blob> {
115+
None
116+
}
117+
}
118+
73119
impl L1MessageProvider for TestL1MessageProvider {
74120
fn next_l1_message(&self) -> TxL1Message {
75121
self.messages.borrow_mut().remove(0)
76122
}
123+
124+
fn set_index_cursor(&mut self, _index: u64) {}
125+
126+
fn set_hash_cursor(&mut self, _hash: B256) {}
77127
}
78128

79129
#[test]
80130
fn test_should_derive_batch() -> eyre::Result<()> {
81131
// https://etherscan.io/tx/0x8f4f0fcab656aa81589db5b53255094606c4624bfd99702b56b2debaf6211f48
82132
let raw_calldata = read_to_bytes("./testdata/calldata_v0.bin")?;
83-
let batch = decode_v0(&raw_calldata)?;
133+
let batch_data = BatchCommitData {
134+
hash: b256!("7f26edf8e3decbc1620b4d2ba5f010a6bdd10d6bb16430c4f458134e36ab3961"),
135+
index: 12,
136+
block_number: 18319648,
137+
calldata: Arc::new(raw_calldata),
138+
blob_versioned_hash: None,
139+
};
84140

85141
let l1_messages = vec![TxL1Message {
86142
queue_index: 33,
@@ -97,9 +153,9 @@ mod tests {
97153
sender: address!("7885BcBd5CeCEf1336b5300fb5186A12DDD8c478"),
98154
input: bytes!("8ef1332e0000000000000000000000007f2b8c31f88b6006c382775eea88297ec1e3e9050000000000000000000000006ea73e05adc79974b931123675ea8f78ffdacdf000000000000000000000000000000000000000000000000000470de4df820000000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000a4232e8748000000000000000000000000982fe4a7cbd74bb3422ebe46333c3e8046c12c7f000000000000000000000000982fe4a7cbd74bb3422ebe46333c3e8046c12c7f00000000000000000000000000000000000000000000000000470de4df8200000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
99155
}];
100-
let provider = TestL1MessageProvider { messages: RefCell::new(l1_messages) };
156+
let mut provider = TestL1MessageProvider { messages: RefCell::new(l1_messages) };
101157

102-
let mut attributes = derive(batch, &provider);
158+
let mut attributes = derive(batch_data, &mut provider)?;
103159
let attribute = attributes.find(|a| a.payload_attributes.timestamp == 1696935384).unwrap();
104160

105161
let expected = ScrollPayloadAttributes{

0 commit comments

Comments
 (0)