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" ) ) ]
812extern crate alloc as std;
913
1014use std:: vec:: Vec ;
1115
16+ use crate :: { data_source:: CodecDataSource , error:: DerivationPipelineError } ;
17+ use alloy_eips:: eip4844:: Blob ;
1218use alloy_primitives:: B256 ;
1319use alloy_rpc_types_engine:: PayloadAttributes ;
1420use reth_scroll_chainspec:: SCROLL_FEE_VAULT_ADDRESS ;
21+ use rollup_node_primitives:: BatchCommitData ;
1522use scroll_alloy_consensus:: TxL1Message ;
1623use 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.
2129pub 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) ]
63101mod 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