Skip to content

Commit 751c40c

Browse files
authored
Merge branch 'main' into docs/docker-operations
2 parents f3c7acb + b6cfa91 commit 751c40c

File tree

17 files changed

+2736
-1749
lines changed

17 files changed

+2736
-1749
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ reth-provider = { git = "https://github.com/scroll-tech/reth.git", tag = "scroll
169169
reth-rpc-api = { git = "https://github.com/scroll-tech/reth.git", tag = "scroll-v91", default-features = false }
170170
reth-rpc-eth-api = { git = "https://github.com/scroll-tech/reth.git", tag = "scroll-v91", default-features = false }
171171
reth-rpc-eth-types = { git = "https://github.com/scroll-tech/reth.git", tag = "scroll-v91", default-features = false }
172+
reth-rpc-layer = { git = "https://github.com/scroll-tech/reth.git", tag = "scroll-v91", default-features = false }
172173
reth-rpc-server-types = { git = "https://github.com/scroll-tech/reth.git", tag = "scroll-v91", default-features = false }
173174
reth-storage-api = { git = "https://github.com/scroll-tech/reth.git", tag = "scroll-v91", default-features = false }
174175
reth-tasks = { git = "https://github.com/scroll-tech/reth.git", tag = "scroll-v91", default-features = false }

crates/codec/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub enum Codec {
4141

4242
impl Codec {
4343
/// Decodes the input data and returns the decoded [`Batch`].
44-
pub fn decode<T: CommitDataSource>(input: &T) -> Result<Batch, CodecError> {
44+
pub fn decode<T: CommitDataSource>(input: T) -> Result<Batch, CodecError> {
4545
let calldata = input.calldata();
4646
let version = get_codec_version(calldata)?;
4747

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
1-
use alloy_eips::eip4844::Blob;
21
use alloy_primitives::Bytes;
32
use scroll_codec::CommitDataSource;
43

54
/// 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>,
5+
pub(crate) struct CodecDataSource<Calldata, Blob> {
6+
pub(crate) calldata: Calldata,
7+
pub(crate) blob: Option<Blob>,
98
}
109

11-
impl<'a> CommitDataSource for CodecDataSource<'a> {
10+
impl<Calldata: AsRef<Bytes>, Blob: AsRef<alloy_eips::eip4844::Blob>> CommitDataSource
11+
for CodecDataSource<Calldata, Blob>
12+
{
1213
fn calldata(&self) -> &Bytes {
13-
self.calldata
14+
self.calldata.as_ref()
1415
}
1516

16-
fn blob(&self) -> Option<&Blob> {
17-
self.blob
17+
fn blob(&self) -> Option<&alloy_eips::eip4844::Blob> {
18+
self.blob.as_ref().map(|b| b.as_ref())
1819
}
1920
}

crates/derivation-pipeline/src/lib.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use futures::{stream::FuturesOrdered, Stream, StreamExt};
1010
use rollup_node_primitives::{BatchCommitData, BatchInfo, BatchStatus, L1MessageEnvelope};
1111
use rollup_node_providers::L1Provider;
1212
use scroll_alloy_rpc_types_engine::{BlockDataHint, ScrollPayloadAttributes};
13-
use scroll_codec::{decoding::payload::PayloadData, Codec};
13+
use scroll_codec::{decoding::payload::PayloadData, Codec, CodecError, DecodingError};
1414
use scroll_db::{Database, DatabaseReadOperations, L1MessageKey};
1515
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
1616

@@ -299,8 +299,15 @@ pub async fn derive<L1P: L1Provider + Sync + Send, DB: DatabaseReadOperations>(
299299
} else {
300300
None
301301
};
302-
let data = CodecDataSource { calldata: batch.calldata.as_ref(), blob: blob.as_deref() };
303-
let decoded = Codec::decode(&data)?;
302+
303+
let data = CodecDataSource { calldata: batch.calldata.clone(), blob };
304+
305+
let decoded =
306+
tokio::task::spawn_blocking(move || Codec::decode(data)).await.map_err(|err| {
307+
DerivationPipelineError::Codec(CodecError::Decoding(DecodingError::Other(Box::new(
308+
err,
309+
))))
310+
})??;
304311

305312
// set the cursor for the l1 provider.
306313
let payload_data = &decoded.data;

crates/node/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,16 @@ aws-config = "1.8.0"
7676
aws-sdk-kms = "1.76.0"
7777

7878
# test-utils
79+
alloy-eips = { workspace = true, optional = true }
80+
alloy-rpc-types-eth = { workspace = true, optional = true }
7981
alloy-rpc-types-engine = { workspace = true, optional = true }
8082
reth-e2e-test-utils = { workspace = true, optional = true }
8183
reth-engine-local = { workspace = true, optional = true }
8284
reth-provider = { workspace = true, optional = true }
85+
reth-rpc-layer = { workspace = true, optional = true }
8386
reth-rpc-server-types = { workspace = true, optional = true }
87+
reth-storage-api = { workspace = true, optional = true }
88+
reth-tokio-util = { workspace = true, optional = true }
8489
scroll-alloy-rpc-types-engine = { workspace = true, optional = true }
8590
scroll-alloy-rpc-types.workspace = true
8691

@@ -108,6 +113,7 @@ reth-e2e-test-utils.workspace = true
108113
reth-node-core.workspace = true
109114
reth-provider.workspace = true
110115
reth-primitives-traits.workspace = true
116+
reth-rpc-layer.workspace = true
111117
reth-rpc-server-types.workspace = true
112118
reth-scroll-node = { workspace = true, features = ["test-utils"] }
113119
reth-storage-api.workspace = true
@@ -140,10 +146,15 @@ test-utils = [
140146
"rollup-node/test-utils",
141147
"reth-e2e-test-utils",
142148
"reth-rpc-server-types",
149+
"reth-rpc-layer",
150+
"reth-tokio-util",
143151
"scroll-alloy-rpc-types-engine",
144152
"alloy-rpc-types-engine",
145153
"reth-primitives-traits/test-utils",
146154
"reth-network-p2p/test-utils",
147155
"rollup-node-chain-orchestrator/test-utils",
148156
"scroll-network/test-utils",
157+
"alloy-eips",
158+
"reth-storage-api",
159+
"alloy-rpc-types-eth",
149160
]
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
//! Block building helpers for test fixtures.
2+
3+
use super::fixture::TestFixture;
4+
use crate::test_utils::EventAssertions;
5+
6+
use alloy_primitives::B256;
7+
use reth_primitives_traits::transaction::TxHashRef;
8+
use reth_scroll_primitives::ScrollBlock;
9+
use scroll_alloy_consensus::ScrollTransaction;
10+
11+
/// Builder for constructing and validating blocks in tests.
12+
#[derive(Debug)]
13+
pub struct BlockBuilder<'a> {
14+
fixture: &'a mut TestFixture,
15+
expected_tx_hashes: Vec<B256>,
16+
expected_tx_count: Option<usize>,
17+
expected_base_fee: Option<u64>,
18+
expected_block_number: Option<u64>,
19+
expected_l1_message: Option<L1MessagesAssertion>,
20+
}
21+
22+
/// The assertion on the L1 messages.
23+
#[derive(Debug)]
24+
pub enum L1MessagesAssertion {
25+
/// Expect at least a single L1 message.
26+
ExpectL1Message,
27+
/// Expect an exact number of L1 messages.
28+
ExpectL1MessageCount(usize),
29+
}
30+
31+
impl L1MessagesAssertion {
32+
/// Assert the L1 messages count is correct.
33+
pub fn assert(&self, got: usize) -> eyre::Result<()> {
34+
match self {
35+
Self::ExpectL1Message => {
36+
if got == 0 {
37+
return Err(eyre::eyre!("Expected at least one L1 message, but block has none"));
38+
}
39+
}
40+
Self::ExpectL1MessageCount(count) => {
41+
if got != *count {
42+
return Err(eyre::eyre!("Expected at {count} L1 messages, but block has {got}"));
43+
}
44+
}
45+
}
46+
Ok(())
47+
}
48+
}
49+
50+
impl<'a> BlockBuilder<'a> {
51+
/// Create a new block builder.
52+
pub(crate) fn new(fixture: &'a mut TestFixture) -> Self {
53+
Self {
54+
fixture,
55+
expected_tx_hashes: Vec::new(),
56+
expected_tx_count: None,
57+
expected_block_number: None,
58+
expected_base_fee: None,
59+
expected_l1_message: None,
60+
}
61+
}
62+
63+
/// Expect a specific transaction to be included in the block.
64+
pub fn expect_tx(mut self, tx_hash: B256) -> Self {
65+
self.expected_tx_hashes.push(tx_hash);
66+
self
67+
}
68+
69+
/// Expect a specific number of transactions in the block.
70+
pub const fn expect_tx_count(mut self, count: usize) -> Self {
71+
self.expected_tx_count = Some(count);
72+
self
73+
}
74+
75+
/// Expect a specific block number.
76+
pub const fn expect_block_number(mut self, number: u64) -> Self {
77+
self.expected_block_number = Some(number);
78+
self
79+
}
80+
81+
/// Expect at least one L1 message in the block.
82+
pub const fn expect_l1_message(mut self) -> Self {
83+
self.expected_l1_message = Some(L1MessagesAssertion::ExpectL1Message);
84+
self
85+
}
86+
87+
/// Expect a specific number of L1 messages in the block.
88+
pub const fn expect_l1_message_count(mut self, count: usize) -> Self {
89+
self.expected_l1_message = Some(L1MessagesAssertion::ExpectL1MessageCount(count));
90+
self
91+
}
92+
93+
/// Build the block and validate against expectations.
94+
pub async fn build_and_await_block(self) -> eyre::Result<ScrollBlock> {
95+
let sequencer_node = &self.fixture.nodes[0];
96+
97+
// Get the sequencer from the rollup manager handle
98+
let handle = &sequencer_node.rollup_manager_handle;
99+
100+
// Trigger block building
101+
handle.build_block();
102+
103+
// If extract the block number.
104+
let expect = self.fixture.expect_event();
105+
let block =
106+
if let Some(b) = self.expected_block_number {
107+
expect.block_sequenced(b).await?
108+
} else {
109+
expect.extract(|e| {
110+
if let rollup_node_chain_orchestrator::ChainOrchestratorEvent::BlockSequenced(
111+
block,
112+
) = e
113+
{
114+
Some(block.clone())
115+
} else {
116+
None
117+
}
118+
}).await?.first().expect("should have block sequenced").clone()
119+
};
120+
121+
// Finally validate the block.
122+
self.validate_block(&block)
123+
}
124+
125+
/// Validate the block against expectations.
126+
fn validate_block(self, block: &ScrollBlock) -> eyre::Result<ScrollBlock> {
127+
// Check transaction count
128+
if let Some(expected_count) = self.expected_tx_count {
129+
if block.body.transactions.len() != expected_count {
130+
return Err(eyre::eyre!(
131+
"Expected {} transactions, but block has {}",
132+
expected_count,
133+
block.body.transactions.len()
134+
));
135+
}
136+
}
137+
138+
// Check block number
139+
if let Some(expected_number) = self.expected_block_number {
140+
if block.header.number != expected_number {
141+
return Err(eyre::eyre!(
142+
"Expected {} number, but block has {}",
143+
expected_number,
144+
block.header.number
145+
));
146+
}
147+
}
148+
149+
// Check specific transaction hashes
150+
for expected_hash in &self.expected_tx_hashes {
151+
if !block.body.transactions.iter().any(|tx| tx.tx_hash() == expected_hash) {
152+
return Err(eyre::eyre!(
153+
"Expected transaction {:?} not found in block",
154+
expected_hash
155+
));
156+
}
157+
}
158+
159+
// Check base fee
160+
if let Some(expected_base_fee) = self.expected_base_fee {
161+
let actual_base_fee = block
162+
.header
163+
.base_fee_per_gas
164+
.ok_or_else(|| eyre::eyre!("Block has no base fee"))?;
165+
if actual_base_fee != expected_base_fee {
166+
return Err(eyre::eyre!(
167+
"Expected base fee {}, but block has {}",
168+
expected_base_fee,
169+
actual_base_fee
170+
));
171+
}
172+
}
173+
174+
// Check L1 messages
175+
if let Some(assertion) = self.expected_l1_message {
176+
let l1_message_count =
177+
block.body.transactions.iter().filter(|tx| tx.queue_index().is_some()).count();
178+
assertion.assert(l1_message_count)?;
179+
}
180+
181+
Ok(block.clone())
182+
}
183+
}

0 commit comments

Comments
 (0)