@@ -2,9 +2,11 @@ package relayer
2
2
3
3
import (
4
4
"fmt"
5
+ "math/big"
5
6
6
7
"github.com/scroll-tech/da-codec/encoding"
7
8
"github.com/scroll-tech/go-ethereum/common"
9
+ "github.com/scroll-tech/go-ethereum/core/types"
8
10
"github.com/scroll-tech/go-ethereum/crypto/kzg4844"
9
11
10
12
"scroll-tech/rollup/internal/orm"
@@ -14,36 +16,24 @@ import (
14
16
// transaction data (calldata and blobs) by parsing them and comparing against database records.
15
17
// This ensures the constructed transaction data is correct and consistent with the database state.
16
18
func (r * Layer2Relayer ) sanityChecksCommitBatchCodecV7CalldataAndBlobs (calldata []byte , blobs []* kzg4844.Blob ) error {
17
- if len (blobs ) == 0 {
18
- return fmt .Errorf ("no blobs provided" )
19
- }
20
-
21
19
calldataInfo , err := r .parseCommitBatchesCalldata (calldata )
22
20
if err != nil {
23
21
return fmt .Errorf ("failed to parse calldata: %w" , err )
24
22
}
25
23
26
- batchesToValidate , firstBatch , lastBatch , err := r .getBatchesFromCalldata (calldataInfo )
24
+ batchesToValidate , err := r .getBatchesFromCalldata (calldataInfo )
27
25
if err != nil {
28
26
return fmt .Errorf ("failed to get batches from database: %w" , err )
29
27
}
30
28
31
- if len (blobs ) != len (batchesToValidate ) {
32
- return fmt .Errorf ("blob count mismatch: got %d blobs, expected %d batches" , len (blobs ), len (batchesToValidate ))
33
- }
34
-
35
- if err := r .validateCalldataAgainstDatabase (calldataInfo , firstBatch , lastBatch ); err != nil {
36
- return fmt .Errorf ("calldata validation failed: %w" , err )
29
+ if err := r .validateCalldataAndBlobsAgainstDatabase (calldataInfo , blobs , batchesToValidate ); err != nil {
30
+ return fmt .Errorf ("calldata and blobs validation failed: %w" , err )
37
31
}
38
32
39
33
if err := r .validateDatabaseConsistency (batchesToValidate ); err != nil {
40
34
return fmt .Errorf ("database consistency validation failed: %w" , err )
41
35
}
42
36
43
- if err := r .validateBlobsAgainstDatabase (blobs , batchesToValidate ); err != nil {
44
- return fmt .Errorf ("blob validation failed: %w" , err )
45
- }
46
-
47
37
return nil
48
38
}
49
39
@@ -91,17 +81,17 @@ func (r *Layer2Relayer) parseCommitBatchesCalldata(calldata []byte) (*CalldataIn
91
81
}
92
82
93
83
// getBatchesFromCalldata retrieves the relevant batches from database based on calldata information
94
- func (r * Layer2Relayer ) getBatchesFromCalldata (info * CalldataInfo ) ([]* dbBatchWithChunks , * orm. Batch , * orm. Batch , error ) {
84
+ func (r * Layer2Relayer ) getBatchesFromCalldata (info * CalldataInfo ) ([]* dbBatchWithChunks , error ) {
95
85
// Get the parent batch to determine the starting point
96
86
parentBatch , err := r .batchOrm .GetBatchByHash (r .ctx , info .ParentBatchHash .Hex ())
97
87
if err != nil {
98
- return nil , nil , nil , fmt .Errorf ("failed to get parent batch by hash %s: %w" , info .ParentBatchHash .Hex (), err )
88
+ return nil , fmt .Errorf ("failed to get parent batch by hash %s: %w" , info .ParentBatchHash .Hex (), err )
99
89
}
100
90
101
91
// Get the last batch to determine the ending point
102
92
lastBatch , err := r .batchOrm .GetBatchByHash (r .ctx , info .LastBatchHash .Hex ())
103
93
if err != nil {
104
- return nil , nil , nil , fmt .Errorf ("failed to get last batch by hash %s: %w" , info .LastBatchHash .Hex (), err )
94
+ return nil , fmt .Errorf ("failed to get last batch by hash %s: %w" , info .LastBatchHash .Hex (), err )
105
95
}
106
96
107
97
// Get all batches in the range (parent+1 to last)
@@ -110,20 +100,20 @@ func (r *Layer2Relayer) getBatchesFromCalldata(info *CalldataInfo) ([]*dbBatchWi
110
100
111
101
// Check if the range is valid
112
102
if firstBatchIndex > lastBatchIndex {
113
- return nil , nil , nil , fmt .Errorf ("no batches found in range: first index %d, last index %d" , firstBatchIndex , lastBatchIndex )
103
+ return nil , fmt .Errorf ("no batches found in range: first index %d, last index %d" , firstBatchIndex , lastBatchIndex )
114
104
}
115
105
116
106
var batchesToValidate []* dbBatchWithChunks
117
107
for batchIndex := firstBatchIndex ; batchIndex <= lastBatchIndex ; batchIndex ++ {
118
108
dbBatch , err := r .batchOrm .GetBatchByIndex (r .ctx , batchIndex )
119
109
if err != nil {
120
- return nil , nil , nil , fmt .Errorf ("failed to get batch by index %d: %w" , batchIndex , err )
110
+ return nil , fmt .Errorf ("failed to get batch by index %d: %w" , batchIndex , err )
121
111
}
122
112
123
113
// Get chunks for this batch
124
114
dbChunks , err := r .chunkOrm .GetChunksInRange (r .ctx , dbBatch .StartChunkIndex , dbBatch .EndChunkIndex )
125
115
if err != nil {
126
- return nil , nil , nil , fmt .Errorf ("failed to get chunks for batch %d: %w" , batchIndex , err )
116
+ return nil , fmt .Errorf ("failed to get chunks for batch %d: %w" , batchIndex , err )
127
117
}
128
118
129
119
batchesToValidate = append (batchesToValidate , & dbBatchWithChunks {
@@ -132,30 +122,7 @@ func (r *Layer2Relayer) getBatchesFromCalldata(info *CalldataInfo) ([]*dbBatchWi
132
122
})
133
123
}
134
124
135
- // Get first batch for return
136
- firstBatch := batchesToValidate [0 ].Batch
137
-
138
- return batchesToValidate , firstBatch , lastBatch , nil
139
- }
140
-
141
- // validateCalldataAgainstDatabase validates calldata parameters against database records
142
- func (r * Layer2Relayer ) validateCalldataAgainstDatabase (info * CalldataInfo , firstBatch , lastBatch * orm.Batch ) error {
143
- // Validate codec version
144
- if info .Version != uint8 (firstBatch .CodecVersion ) {
145
- return fmt .Errorf ("version mismatch: calldata=%d, db=%d" , info .Version , firstBatch .CodecVersion )
146
- }
147
-
148
- // Validate parent batch hash
149
- if info .ParentBatchHash != common .HexToHash (firstBatch .ParentBatchHash ) {
150
- return fmt .Errorf ("parentBatchHash mismatch: calldata=%s, db=%s" , info .ParentBatchHash .Hex (), firstBatch .ParentBatchHash )
151
- }
152
-
153
- // Validate last batch hash
154
- if info .LastBatchHash != common .HexToHash (lastBatch .Hash ) {
155
- return fmt .Errorf ("lastBatchHash mismatch: calldata=%s, db=%s" , info .LastBatchHash .Hex (), lastBatch .Hash )
156
- }
157
-
158
- return nil
125
+ return batchesToValidate , nil
159
126
}
160
127
161
128
// validateDatabaseConsistency performs comprehensive validation of database records
@@ -328,10 +295,38 @@ func (r *Layer2Relayer) validateSingleChunkConsistency(chunk *orm.Chunk, prevChu
328
295
return nil
329
296
}
330
297
331
- // validateBlobsAgainstDatabase validates blobs against database records
332
- func (r * Layer2Relayer ) validateBlobsAgainstDatabase (blobs []* kzg4844.Blob , batchesToValidate []* dbBatchWithChunks ) error {
333
- // Get codec for blob decoding
298
+ // validateCalldataAndBlobsAgainstDatabase validates calldata and blobs against database records
299
+ func (r * Layer2Relayer ) validateCalldataAndBlobsAgainstDatabase (calldataInfo * CalldataInfo , blobs []* kzg4844.Blob , batchesToValidate []* dbBatchWithChunks ) error {
300
+ // Validate blobs
301
+ if len (blobs ) == 0 {
302
+ return fmt .Errorf ("no blobs provided" )
303
+ }
304
+
305
+ // Validate blob count
306
+ if len (blobs ) != len (batchesToValidate ) {
307
+ return fmt .Errorf ("blob count mismatch: got %d blobs, expected %d batches" , len (blobs ), len (batchesToValidate ))
308
+ }
309
+
310
+ // Get first and last batches for validation, length check is already done above
334
311
firstBatch := batchesToValidate [0 ].Batch
312
+ lastBatch := batchesToValidate [len (batchesToValidate )- 1 ].Batch
313
+
314
+ // Validate codec version
315
+ if calldataInfo .Version != uint8 (firstBatch .CodecVersion ) {
316
+ return fmt .Errorf ("version mismatch: calldata=%d, db=%d" , calldataInfo .Version , firstBatch .CodecVersion )
317
+ }
318
+
319
+ // Validate parent batch hash
320
+ if calldataInfo .ParentBatchHash != common .HexToHash (firstBatch .ParentBatchHash ) {
321
+ return fmt .Errorf ("parentBatchHash mismatch: calldata=%s, db=%s" , calldataInfo .ParentBatchHash .Hex (), firstBatch .ParentBatchHash )
322
+ }
323
+
324
+ // Validate last batch hash
325
+ if calldataInfo .LastBatchHash != common .HexToHash (lastBatch .Hash ) {
326
+ return fmt .Errorf ("lastBatchHash mismatch: calldata=%s, db=%s" , calldataInfo .LastBatchHash .Hex (), lastBatch .Hash )
327
+ }
328
+
329
+ // Get codec for blob decoding
335
330
codec , err := encoding .CodecFromVersion (encoding .CodecVersion (firstBatch .CodecVersion ))
336
331
if err != nil {
337
332
return fmt .Errorf ("failed to get codec: %w" , err )
@@ -340,9 +335,7 @@ func (r *Layer2Relayer) validateBlobsAgainstDatabase(blobs []*kzg4844.Blob, batc
340
335
// Validate each blob against its corresponding batch
341
336
for i , blob := range blobs {
342
337
dbBatch := batchesToValidate [i ].Batch
343
- dbChunks := batchesToValidate [i ].Chunks
344
-
345
- if err := r .validateSingleBlobAgainstBatch (blob , dbBatch , dbChunks , codec ); err != nil {
338
+ if err := r .validateSingleBlobAgainstBatch (calldataInfo , blob , dbBatch , codec ); err != nil {
346
339
return fmt .Errorf ("blob validation failed for batch %d: %w" , dbBatch .Index , err )
347
340
}
348
341
}
@@ -351,53 +344,21 @@ func (r *Layer2Relayer) validateBlobsAgainstDatabase(blobs []*kzg4844.Blob, batc
351
344
}
352
345
353
346
// validateSingleBlobAgainstBatch validates a single blob against its batch data
354
- func (r * Layer2Relayer ) validateSingleBlobAgainstBatch (blob * kzg4844.Blob , dbBatch * orm.Batch , dbChunks []* orm.Chunk , codec encoding.Codec ) error {
355
- // Collect all blocks for the batch
356
- var batchBlocks []* encoding.Block
357
- for _ , c := range dbChunks {
358
- blocks , err := r .l2BlockOrm .GetL2BlocksInRange (r .ctx , c .StartBlockNumber , c .EndBlockNumber )
359
- if err != nil {
360
- return fmt .Errorf ("failed to get blocks for chunk %d: %w" , c .Index , err )
361
- }
362
-
363
- if len (blocks ) == 0 {
364
- return fmt .Errorf ("chunk %d has no blocks in range [%d, %d]" , c .Index , c .StartBlockNumber , c .EndBlockNumber )
365
- }
366
-
367
- // Verify block count matches expected range
368
- expectedBlockCount := c .EndBlockNumber - c .StartBlockNumber + 1
369
- if len (blocks ) != int (expectedBlockCount ) {
370
- return fmt .Errorf ("chunk %d expected %d blocks but got %d" , c .Index , expectedBlockCount , len (blocks ))
371
- }
372
-
373
- batchBlocks = append (batchBlocks , blocks ... )
374
- }
375
-
347
+ func (r * Layer2Relayer ) validateSingleBlobAgainstBatch (calldataInfo * CalldataInfo , blob * kzg4844.Blob , dbBatch * orm.Batch , codec encoding.Codec ) error {
376
348
// Decode blob payload
377
349
payload , err := codec .DecodeBlob (blob )
378
350
if err != nil {
379
351
return fmt .Errorf ("failed to decode blob: %w" , err )
380
352
}
381
353
382
- // Validate L1 message queue hashes
383
- if payload .PrevL1MessageQueueHash () != common .HexToHash (dbBatch .PrevL1MessageQueueHash ) {
384
- return fmt .Errorf ("prevL1MessageQueueHash mismatch: decoded=%s, db=%s" , payload .PrevL1MessageQueueHash ().Hex (), dbBatch .PrevL1MessageQueueHash )
385
- }
386
-
387
- if payload .PostL1MessageQueueHash () != common .HexToHash (dbBatch .PostL1MessageQueueHash ) {
388
- return fmt .Errorf ("postL1MessageQueueHash mismatch: decoded=%s, db=%s" , payload .PostL1MessageQueueHash ().Hex (), dbBatch .PostL1MessageQueueHash )
389
- }
390
-
391
- // Validate block data
392
- decodedBlocks := payload .Blocks ()
393
- if len (decodedBlocks ) != len (batchBlocks ) {
394
- return fmt .Errorf ("block count mismatch: decoded=%d, db=%d" , len (decodedBlocks ), len (batchBlocks ))
354
+ // Validate batch hash
355
+ daBatch , err := assembleDABatchFromPayload (calldataInfo , payload , dbBatch , codec )
356
+ if err != nil {
357
+ return fmt .Errorf ("failed to assemble batch from payload: %w" , err )
395
358
}
396
359
397
- for j , dbBlock := range batchBlocks {
398
- if decodedBlocks [j ].Number () != dbBlock .Header .Number .Uint64 () {
399
- return fmt .Errorf ("block number mismatch at index %d: decoded=%d, db=%d" , j , decodedBlocks [j ].Number (), dbBlock .Header .Number .Uint64 ())
400
- }
360
+ if daBatch .Hash () != common .HexToHash (dbBatch .Hash ) {
361
+ return fmt .Errorf ("batch hash mismatch: decoded from blob=%s, db=%s" , daBatch .Hash ().Hex (), dbBatch .Hash )
401
362
}
402
363
403
364
return nil
@@ -436,3 +397,51 @@ func (r *Layer2Relayer) validateMessageQueueConsistency(batchIndex uint64, chunk
436
397
437
398
return nil
438
399
}
400
+
401
+ func assembleDABatchFromPayload (calldataInfo * CalldataInfo , payload encoding.DABlobPayload , dbBatch * orm.Batch , codec encoding.Codec ) (encoding.DABatch , error ) {
402
+ blocks , err := assembleBlocksFromPayload (payload )
403
+ if err != nil {
404
+ return nil , fmt .Errorf ("failed to assemble blocks from payload batch_index=%d codec_version=%d parent_batch_hash=%s: %w" , dbBatch .Index , dbBatch .CodecVersion , calldataInfo .ParentBatchHash .Hex (), err )
405
+ }
406
+ parentBatchHash := calldataInfo .ParentBatchHash
407
+ batch := & encoding.Batch {
408
+ Index : dbBatch .Index , // The database provides only batch index, other fields are derived from blob payload
409
+ ParentBatchHash : parentBatchHash ,
410
+ PrevL1MessageQueueHash : payload .PrevL1MessageQueueHash (),
411
+ PostL1MessageQueueHash : payload .PostL1MessageQueueHash (),
412
+ Blocks : blocks ,
413
+ Chunks : []* encoding.Chunk { // One chunk for this batch to pass sanity checks when building DABatch
414
+ {
415
+ Blocks : blocks ,
416
+ PrevL1MessageQueueHash : payload .PrevL1MessageQueueHash (),
417
+ PostL1MessageQueueHash : payload .PostL1MessageQueueHash (),
418
+ },
419
+ },
420
+ }
421
+ daBatch , err := codec .NewDABatch (batch )
422
+ if err != nil {
423
+ return nil , fmt .Errorf ("failed to build DABatch batch_index=%d codec_version=%d parent_batch_hash=%s: %w" , dbBatch .Index , dbBatch .CodecVersion , calldataInfo .ParentBatchHash .Hex (), err )
424
+ }
425
+ return daBatch , nil
426
+ }
427
+
428
+ func assembleBlocksFromPayload (payload encoding.DABlobPayload ) ([]* encoding.Block , error ) {
429
+ daBlocks := payload .Blocks ()
430
+ txss := payload .Transactions ()
431
+ if len (daBlocks ) != len (txss ) {
432
+ return nil , fmt .Errorf ("mismatched number of blocks and transactions: %d blocks, %d transactions" , len (daBlocks ), len (txss ))
433
+ }
434
+ blocks := make ([]* encoding.Block , len (daBlocks ))
435
+ for i := range daBlocks {
436
+ blocks [i ] = & encoding.Block {
437
+ Header : & types.Header {
438
+ Number : new (big.Int ).SetUint64 (daBlocks [i ].Number ()),
439
+ Time : daBlocks [i ].Timestamp (),
440
+ BaseFee : daBlocks [i ].BaseFee (),
441
+ GasLimit : daBlocks [i ].GasLimit (),
442
+ },
443
+ Transactions : encoding .TxsToTxsData (txss [i ]),
444
+ }
445
+ }
446
+ return blocks , nil
447
+ }
0 commit comments