@@ -2,13 +2,16 @@ package logic
22
33import (
44 "context"
5+ "fmt"
56 "math/big"
67
8+ "github.com/scroll-tech/da-codec/encoding"
79 "github.com/scroll-tech/go-ethereum/common"
810 "github.com/scroll-tech/go-ethereum/core/types"
911 "github.com/scroll-tech/go-ethereum/crypto"
1012 "github.com/scroll-tech/go-ethereum/ethclient"
1113 "github.com/scroll-tech/go-ethereum/log"
14+ "github.com/scroll-tech/go-ethereum/rollup/da_syncer/blob_client"
1215
1316 backendabi "scroll-tech/bridge-history-api/abi"
1417 "scroll-tech/bridge-history-api/internal/config"
@@ -19,15 +22,17 @@ import (
1922
2023// L1EventParser the l1 event parser
2124type L1EventParser struct {
22- cfg * config.FetcherConfig
23- client * ethclient.Client
25+ cfg * config.FetcherConfig
26+ client * ethclient.Client
27+ blobClient blob_client.BlobClient
2428}
2529
2630// NewL1EventParser creates l1 event parser
27- func NewL1EventParser (cfg * config.FetcherConfig , client * ethclient.Client ) * L1EventParser {
31+ func NewL1EventParser (cfg * config.FetcherConfig , client * ethclient.Client , blobClient blob_client. BlobClient ) * L1EventParser {
2832 return & L1EventParser {
29- cfg : cfg ,
30- client : client ,
33+ cfg : cfg ,
34+ client : client ,
35+ blobClient : blobClient ,
3136 }
3237}
3338
@@ -232,7 +237,21 @@ func (e *L1EventParser) ParseL1SingleCrossChainEventLogs(ctx context.Context, lo
232237}
233238
234239// ParseL1BatchEventLogs parses L1 watched batch events.
235- func (e * L1EventParser ) ParseL1BatchEventLogs (ctx context.Context , logs []types.Log , client * ethclient.Client ) ([]* orm.BatchEvent , error ) {
240+ func (e * L1EventParser ) ParseL1BatchEventLogs (ctx context.Context , logs []types.Log , client * ethclient.Client , blockTimestampsMap map [uint64 ]uint64 ) ([]* orm.BatchEvent , error ) {
241+ // Since multiple CommitBatch events per transaction is introduced >= CodecV7,
242+ // with one transaction carrying multiple blobs,
243+ // each CommitBatch event corresponds to a blob containing block range data.
244+ // To correctly process these events, we need to:
245+ // 1. Parsing the associated blob data to extract the block range for each event
246+ // 2. Tracking the parent batch hash for each processed CommitBatch event, to:
247+ // - Validate the batch hash, since parent batch hash is needed to calculate the batch hash
248+ // - Derive the index of the current batch by the number of parent batch hashes tracked
249+ // In commitBatches and commitAndFinalizeBatch, the parent batch hash is passed in calldata,
250+ // so that we can use it to get the first batch's parent batch hash, and derive the rest.
251+ // The index map serves this purpose with:
252+ // Key: commit transaction hash
253+ // Value: parent batch hashes (in order) for each processed CommitBatch event in the transaction
254+ txBlobIndexMap := make (map [common.Hash ][]common.Hash )
236255 var l1BatchEvents []* orm.BatchEvent
237256 for _ , vlog := range logs {
238257 switch vlog .Topics [0 ] {
@@ -247,11 +266,59 @@ func (e *L1EventParser) ParseL1BatchEventLogs(ctx context.Context, logs []types.
247266 log .Error ("Failed to get commit batch tx or the tx is still pending" , "err" , err , "isPending" , isPending )
248267 return nil , err
249268 }
250- startBlock , endBlock , err := utils .GetBatchRangeFromCalldata (commitTx .Data ())
269+ version , startBlock , endBlock , err := utils .GetBatchVersionAndBlockRangeFromCalldata (commitTx .Data ())
251270 if err != nil {
252271 log .Error ("Failed to get batch range from calldata" , "hash" , commitTx .Hash ().String (), "height" , vlog .BlockNumber )
253272 return nil , err
254273 }
274+ if version >= 7 { // It's a batch with version >= 7.
275+ codec , err := encoding .CodecFromVersion (encoding .CodecVersion (version ))
276+ if err != nil {
277+ return nil , fmt .Errorf ("unsupported codec version: %v, err: %w" , version , err )
278+ }
279+
280+ // we append the batch hash to the slice for the current commit transaction after processing the batch.
281+ // that means the current index of the batch within the transaction is len(txBlobIndexMap[vlog.TxHash]).
282+ currentIndex := len (txBlobIndexMap [vlog .TxHash ])
283+ if currentIndex >= len (commitTx .BlobHashes ()) {
284+ return nil , fmt .Errorf ("commit transaction %s has %d blobs, but trying to access index %d (batch index %d)" ,
285+ vlog .TxHash .String (), len (commitTx .BlobHashes ()), currentIndex , event .BatchIndex .Uint64 ())
286+ }
287+ blobVersionedHash := commitTx .BlobHashes ()[currentIndex ]
288+
289+ // validate the batch hash
290+ var parentBatchHash common.Hash
291+ if currentIndex == 0 {
292+ parentBatchHash , err = utils .GetParentBatchHashFromCalldata (commitTx .Data ())
293+ if err != nil {
294+ return nil , fmt .Errorf ("failed to get parent batch header from calldata, tx hash: %s, err: %w" , vlog .TxHash .String (), err )
295+ }
296+ } else {
297+ // here we need to subtract 1 from the current index to get the parent batch hash.
298+ parentBatchHash = txBlobIndexMap [vlog .TxHash ][currentIndex - 1 ]
299+ }
300+ calculatedBatch , err := codec .NewDABatchFromParams (event .BatchIndex .Uint64 (), blobVersionedHash , parentBatchHash )
301+ if err != nil {
302+ return nil , fmt .Errorf ("failed to create new DA batch from params, batch index: %d, err: %w" , event .BatchIndex .Uint64 (), err )
303+ }
304+ if calculatedBatch .Hash () != event .BatchHash {
305+ return nil , fmt .Errorf ("batch hash mismatch for batch %d, expected: %s, got: %s" , event .BatchIndex , event .BatchHash .String (), calculatedBatch .Hash ().String ())
306+ }
307+
308+ blocks , err := e .getBatchBlockRangeFromBlob (ctx , codec , blobVersionedHash , blockTimestampsMap [vlog .BlockNumber ])
309+ if err != nil {
310+ return nil , fmt .Errorf ("failed to process versioned blob, blobVersionedHash: %s, block number: %d, blob index: %d, err: %w" ,
311+ blobVersionedHash .String (), vlog .BlockNumber , currentIndex , err )
312+ }
313+ if len (blocks ) == 0 {
314+ return nil , fmt .Errorf ("no blocks found in the blob, blobVersionedHash: %s, block number: %d, blob index: %d" ,
315+ blobVersionedHash .String (), vlog .BlockNumber , currentIndex )
316+ }
317+ startBlock = blocks [0 ].Number ()
318+ endBlock = blocks [len (blocks )- 1 ].Number ()
319+
320+ txBlobIndexMap [vlog .TxHash ] = append (txBlobIndexMap [vlog .TxHash ], event .BatchHash )
321+ }
255322 l1BatchEvents = append (l1BatchEvents , & orm.BatchEvent {
256323 BatchStatus : int (btypes .BatchStatusTypeCommitted ),
257324 BatchIndex : event .BatchIndex .Uint64 (),
@@ -260,8 +327,8 @@ func (e *L1EventParser) ParseL1BatchEventLogs(ctx context.Context, logs []types.
260327 EndBlockNumber : endBlock ,
261328 L1BlockNumber : vlog .BlockNumber ,
262329 })
263- case backendabi .L1RevertBatchEventSig :
264- event := backendabi.L1RevertBatchEvent {}
330+ case backendabi .L1RevertBatchV0EventSig :
331+ event := backendabi.L1RevertBatchV0Event {}
265332 if err := utils .UnpackLog (backendabi .IScrollChainABI , & event , "RevertBatch" , vlog ); err != nil {
266333 log .Error ("Failed to unpack RevertBatch event" , "err" , err )
267334 return nil , err
@@ -272,6 +339,19 @@ func (e *L1EventParser) ParseL1BatchEventLogs(ctx context.Context, logs []types.
272339 BatchHash : event .BatchHash .String (),
273340 L1BlockNumber : vlog .BlockNumber ,
274341 })
342+ case backendabi .L1RevertBatchV7EventSig :
343+ event := backendabi.L1RevertBatchV7Event {}
344+ if err := utils .UnpackLog (backendabi .IScrollChainABI , & event , "RevertBatch0" , vlog ); err != nil {
345+ log .Error ("Failed to unpack RevertBatch event" , "err" , err )
346+ return nil , err
347+ }
348+ for i := event .StartBatchIndex .Uint64 (); i <= event .FinishBatchIndex .Uint64 (); i ++ {
349+ l1BatchEvents = append (l1BatchEvents , & orm.BatchEvent {
350+ BatchStatus : int (btypes .BatchStatusTypeReverted ),
351+ BatchIndex : i ,
352+ L1BlockNumber : vlog .BlockNumber ,
353+ })
354+ }
275355 case backendabi .L1FinalizeBatchEventSig :
276356 event := backendabi.L1FinalizeBatchEvent {}
277357 if err := utils .UnpackLog (backendabi .IScrollChainABI , & event , "FinalizeBatch" , vlog ); err != nil {
@@ -389,3 +469,27 @@ func getRealFromAddress(ctx context.Context, eventSender common.Address, eventMe
389469 }
390470 return sender .String (), nil
391471}
472+
473+ func (e * L1EventParser ) getBatchBlockRangeFromBlob (ctx context.Context , codec encoding.Codec , blobVersionedHash common.Hash , l1BlockTime uint64 ) ([]encoding.DABlock , error ) {
474+ blob , err := e .blobClient .GetBlobByVersionedHashAndBlockTime (ctx , blobVersionedHash , l1BlockTime )
475+ if err != nil {
476+ return nil , fmt .Errorf ("failed to get blob %s: %w" , blobVersionedHash .Hex (), err )
477+ }
478+ if blob == nil {
479+ return nil , fmt .Errorf ("blob %s not found" , blobVersionedHash .Hex ())
480+ }
481+
482+ blobPayload , err := codec .DecodeBlob (blob )
483+ if err != nil {
484+ return nil , fmt .Errorf ("blob %s decode error: %w" , blobVersionedHash .Hex (), err )
485+ }
486+
487+ blocks := blobPayload .Blocks ()
488+ if len (blocks ) == 0 {
489+ return nil , fmt .Errorf ("empty blocks in blob %s" , blobVersionedHash .Hex ())
490+ }
491+
492+ log .Debug ("Successfully processed blob" , "blobVersionedHash" , blobVersionedHash .Hex (), "blocksCount" , len (blocks ))
493+
494+ return blocks , nil
495+ }
0 commit comments