@@ -2,9 +2,11 @@ package relayer
22
33import (
44 "fmt"
5+ "math/big"
56
67 "github.com/scroll-tech/da-codec/encoding"
78 "github.com/scroll-tech/go-ethereum/common"
9+ "github.com/scroll-tech/go-ethereum/core/types"
810 "github.com/scroll-tech/go-ethereum/crypto/kzg4844"
911
1012 "scroll-tech/rollup/internal/orm"
@@ -28,22 +30,14 @@ func (r *Layer2Relayer) sanityChecksCommitBatchCodecV7CalldataAndBlobs(calldata
2830 return fmt .Errorf ("failed to get batches from database: %w" , err )
2931 }
3032
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 )
3735 }
3836
3937 if err := r .validateDatabaseConsistency (batchesToValidate ); err != nil {
4038 return fmt .Errorf ("database consistency validation failed: %w" , err )
4139 }
4240
43- if err := r .validateBlobsAgainstDatabase (blobs , batchesToValidate ); err != nil {
44- return fmt .Errorf ("blob validation failed: %w" , err )
45- }
46-
4741 return nil
4842}
4943
@@ -138,26 +132,6 @@ func (r *Layer2Relayer) getBatchesFromCalldata(info *CalldataInfo) ([]*dbBatchWi
138132 return batchesToValidate , firstBatch , lastBatch , nil
139133}
140134
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-
161135// validateDatabaseConsistency performs comprehensive validation of database records
162136func (r * Layer2Relayer ) validateDatabaseConsistency (batchesToValidate []* dbBatchWithChunks ) error {
163137 if len (batchesToValidate ) == 0 {
@@ -328,10 +302,29 @@ func (r *Layer2Relayer) validateSingleChunkConsistency(chunk *orm.Chunk, prevChu
328302 return nil
329303}
330304
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+
333327 // Get codec for blob decoding
334- firstBatch := batchesToValidate [0 ].Batch
335328 codec , err := encoding .CodecFromVersion (encoding .CodecVersion (firstBatch .CodecVersion ))
336329 if err != nil {
337330 return fmt .Errorf ("failed to get codec: %w" , err )
@@ -340,9 +333,7 @@ func (r *Layer2Relayer) validateBlobsAgainstDatabase(blobs []*kzg4844.Blob, batc
340333 // Validate each blob against its corresponding batch
341334 for i , blob := range blobs {
342335 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 {
346337 return fmt .Errorf ("blob validation failed for batch %d: %w" , dbBatch .Index , err )
347338 }
348339 }
@@ -351,53 +342,21 @@ func (r *Layer2Relayer) validateBlobsAgainstDatabase(blobs []*kzg4844.Blob, batc
351342}
352343
353344// 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 {
376346 // Decode blob payload
377347 payload , err := codec .DecodeBlob (blob )
378348 if err != nil {
379349 return fmt .Errorf ("failed to decode blob: %w" , err )
380350 }
381351
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 )
389356 }
390357
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 )
401360 }
402361
403362 return nil
@@ -436,3 +395,51 @@ func (r *Layer2Relayer) validateMessageQueueConsistency(batchIndex uint64, chunk
436395
437396 return nil
438397}
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