@@ -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"
@@ -28,22 +30,14 @@ func (r *Layer2Relayer) sanityChecksCommitBatchCodecV7CalldataAndBlobs(calldata
28
30
return fmt .Errorf ("failed to get batches from database: %w" , err )
29
31
}
30
32
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 )
33
+ if err := r .validateCalldataAndBlobsAgainstDatabase (calldataInfo , blobs , batchesToValidate , firstBatch , lastBatch ); err != nil {
34
+ return fmt .Errorf ("calldata and blobs validation failed: %w" , err )
37
35
}
38
36
39
37
if err := r .validateDatabaseConsistency (batchesToValidate ); err != nil {
40
38
return fmt .Errorf ("database consistency validation failed: %w" , err )
41
39
}
42
40
43
- if err := r .validateBlobsAgainstDatabase (blobs , batchesToValidate ); err != nil {
44
- return fmt .Errorf ("blob validation failed: %w" , err )
45
- }
46
-
47
41
return nil
48
42
}
49
43
@@ -138,26 +132,6 @@ func (r *Layer2Relayer) getBatchesFromCalldata(info *CalldataInfo) ([]*dbBatchWi
138
132
return batchesToValidate , firstBatch , lastBatch , nil
139
133
}
140
134
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
159
- }
160
-
161
135
// validateDatabaseConsistency performs comprehensive validation of database records
162
136
func (r * Layer2Relayer ) validateDatabaseConsistency (batchesToValidate []* dbBatchWithChunks ) error {
163
137
if len (batchesToValidate ) == 0 {
@@ -328,10 +302,29 @@ func (r *Layer2Relayer) validateSingleChunkConsistency(chunk *orm.Chunk, prevChu
328
302
return nil
329
303
}
330
304
331
- // validateBlobsAgainstDatabase validates blobs against database records
332
- func (r * Layer2Relayer ) validateBlobsAgainstDatabase (blobs []* kzg4844.Blob , batchesToValidate []* dbBatchWithChunks ) error {
305
+ // validateCalldataAndBlobsAgainstDatabase validates calldata and blobs against database records
306
+ func (r * Layer2Relayer ) validateCalldataAndBlobsAgainstDatabase (calldataInfo * CalldataInfo , blobs []* kzg4844.Blob , batchesToValidate []* dbBatchWithChunks , firstBatch , lastBatch * orm.Batch ) error {
307
+ // Validate blob count
308
+ if len (blobs ) != len (batchesToValidate ) {
309
+ return fmt .Errorf ("blob count mismatch: got %d blobs, expected %d batches" , len (blobs ), len (batchesToValidate ))
310
+ }
311
+
312
+ // Validate codec version
313
+ if calldataInfo .Version != uint8 (firstBatch .CodecVersion ) {
314
+ return fmt .Errorf ("version mismatch: calldata=%d, db=%d" , calldataInfo .Version , firstBatch .CodecVersion )
315
+ }
316
+
317
+ // Validate parent batch hash
318
+ if calldataInfo .ParentBatchHash != common .HexToHash (firstBatch .ParentBatchHash ) {
319
+ return fmt .Errorf ("parentBatchHash mismatch: calldata=%s, db=%s" , calldataInfo .ParentBatchHash .Hex (), firstBatch .ParentBatchHash )
320
+ }
321
+
322
+ // Validate last batch hash
323
+ if calldataInfo .LastBatchHash != common .HexToHash (lastBatch .Hash ) {
324
+ return fmt .Errorf ("lastBatchHash mismatch: calldata=%s, db=%s" , calldataInfo .LastBatchHash .Hex (), lastBatch .Hash )
325
+ }
326
+
333
327
// Get codec for blob decoding
334
- firstBatch := batchesToValidate [0 ].Batch
335
328
codec , err := encoding .CodecFromVersion (encoding .CodecVersion (firstBatch .CodecVersion ))
336
329
if err != nil {
337
330
return fmt .Errorf ("failed to get codec: %w" , err )
@@ -340,9 +333,7 @@ func (r *Layer2Relayer) validateBlobsAgainstDatabase(blobs []*kzg4844.Blob, batc
340
333
// Validate each blob against its corresponding batch
341
334
for i , blob := range blobs {
342
335
dbBatch := batchesToValidate [i ].Batch
343
- dbChunks := batchesToValidate [i ].Chunks
344
-
345
- if err := r .validateSingleBlobAgainstBatch (blob , dbBatch , dbChunks , codec ); err != nil {
336
+ if err := r .validateSingleBlobAgainstBatch (calldataInfo , blob , dbBatch , codec ); err != nil {
346
337
return fmt .Errorf ("blob validation failed for batch %d: %w" , dbBatch .Index , err )
347
338
}
348
339
}
@@ -351,53 +342,21 @@ func (r *Layer2Relayer) validateBlobsAgainstDatabase(blobs []*kzg4844.Blob, batc
351
342
}
352
343
353
344
// 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
-
345
+ func (r * Layer2Relayer ) validateSingleBlobAgainstBatch (calldataInfo * CalldataInfo , blob * kzg4844.Blob , dbBatch * orm.Batch , codec encoding.Codec ) error {
376
346
// Decode blob payload
377
347
payload , err := codec .DecodeBlob (blob )
378
348
if err != nil {
379
349
return fmt .Errorf ("failed to decode blob: %w" , err )
380
350
}
381
351
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 )
352
+ // Validate batch hash
353
+ daBatch , err := assembleDABatchFromPayload (calldataInfo , payload , dbBatch , codec )
354
+ if err != nil {
355
+ return fmt .Errorf ("failed to assemble batch from payload: %w" , err )
389
356
}
390
357
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 ))
395
- }
396
-
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
- }
358
+ if daBatch .Hash () != common .HexToHash (dbBatch .Hash ) {
359
+ return fmt .Errorf ("batch hash mismatch: decoded from blob=%s, db=%s" , daBatch .Hash ().Hex (), dbBatch .Hash )
401
360
}
402
361
403
362
return nil
@@ -436,3 +395,51 @@ func (r *Layer2Relayer) validateMessageQueueConsistency(batchIndex uint64, chunk
436
395
437
396
return nil
438
397
}
398
+
399
+ func assembleDABatchFromPayload (calldataInfo * CalldataInfo , payload encoding.DABlobPayload , dbBatch * orm.Batch , codec encoding.Codec ) (encoding.DABatch , error ) {
400
+ blocks , err := assembleBlocksFromPayload (payload )
401
+ if err != nil {
402
+ 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 )
403
+ }
404
+ parentBatchHash := calldataInfo .ParentBatchHash
405
+ batch := & encoding.Batch {
406
+ Index : dbBatch .Index , // The database provides only batch index, other fields are derived from blob payload
407
+ ParentBatchHash : parentBatchHash ,
408
+ PrevL1MessageQueueHash : payload .PrevL1MessageQueueHash (),
409
+ PostL1MessageQueueHash : payload .PostL1MessageQueueHash (),
410
+ Blocks : blocks ,
411
+ Chunks : []* encoding.Chunk { // One chunk for this batch to pass sanity checks when building DABatch
412
+ {
413
+ Blocks : blocks ,
414
+ PrevL1MessageQueueHash : payload .PrevL1MessageQueueHash (),
415
+ PostL1MessageQueueHash : payload .PostL1MessageQueueHash (),
416
+ },
417
+ },
418
+ }
419
+ daBatch , err := codec .NewDABatch (batch )
420
+ if err != nil {
421
+ 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 )
422
+ }
423
+ return daBatch , nil
424
+ }
425
+
426
+ func assembleBlocksFromPayload (payload encoding.DABlobPayload ) ([]* encoding.Block , error ) {
427
+ daBlocks := payload .Blocks ()
428
+ txss := payload .Transactions ()
429
+ if len (daBlocks ) != len (txss ) {
430
+ return nil , fmt .Errorf ("mismatched number of blocks and transactions: %d blocks, %d transactions" , len (daBlocks ), len (txss ))
431
+ }
432
+ blocks := make ([]* encoding.Block , len (daBlocks ))
433
+ for i := range daBlocks {
434
+ blocks [i ] = & encoding.Block {
435
+ Header : & types.Header {
436
+ Number : new (big.Int ).SetUint64 (daBlocks [i ].Number ()),
437
+ Time : daBlocks [i ].Timestamp (),
438
+ BaseFee : daBlocks [i ].BaseFee (),
439
+ GasLimit : daBlocks [i ].GasLimit (),
440
+ },
441
+ Transactions : encoding .TxsToTxsData (txss [i ]),
442
+ }
443
+ }
444
+ return blocks , nil
445
+ }
0 commit comments