@@ -2,13 +2,16 @@ package logic
2
2
3
3
import (
4
4
"context"
5
+ "fmt"
5
6
"math/big"
6
7
8
+ "github.com/scroll-tech/da-codec/encoding"
7
9
"github.com/scroll-tech/go-ethereum/common"
8
10
"github.com/scroll-tech/go-ethereum/core/types"
9
11
"github.com/scroll-tech/go-ethereum/crypto"
10
12
"github.com/scroll-tech/go-ethereum/ethclient"
11
13
"github.com/scroll-tech/go-ethereum/log"
14
+ "github.com/scroll-tech/go-ethereum/rollup/da_syncer/blob_client"
12
15
13
16
backendabi "scroll-tech/bridge-history-api/abi"
14
17
"scroll-tech/bridge-history-api/internal/config"
@@ -19,15 +22,17 @@ import (
19
22
20
23
// L1EventParser the l1 event parser
21
24
type L1EventParser struct {
22
- cfg * config.FetcherConfig
23
- client * ethclient.Client
25
+ cfg * config.FetcherConfig
26
+ client * ethclient.Client
27
+ blobClient blob_client.BlobClient
24
28
}
25
29
26
30
// 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 {
28
32
return & L1EventParser {
29
- cfg : cfg ,
30
- client : client ,
33
+ cfg : cfg ,
34
+ client : client ,
35
+ blobClient : blobClient ,
31
36
}
32
37
}
33
38
@@ -232,7 +237,20 @@ func (e *L1EventParser) ParseL1SingleCrossChainEventLogs(ctx context.Context, lo
232
237
}
233
238
234
239
// 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 CodecV7 introduced multiple CommitBatch events per transaction,
242
+ // each CommitBatch event corresponds to an individual blob containing block range data.
243
+ // To correctly process these events, we need to:
244
+ // 1. Parsing the associated blob data to extract the block range for each event
245
+ // 2. Tracking the parent batch hash for each processed CommitBatch event, to:
246
+ // - Validate the batch hash
247
+ // - Derive the index of the current batch
248
+ // In commitBatches and commitAndFinalizeBatch, the parent batch hash is passed in calldata,
249
+ // so that we can use it to get the first batch's parent batch hash.
250
+ // The index map serves this purpose with:
251
+ // Key: commit transaction hash
252
+ // Value: parent batch hashes (in order) for each processed CommitBatch event in the transaction
253
+ txBlobIndexMap := make (map [common.Hash ][]common.Hash )
236
254
var l1BatchEvents []* orm.BatchEvent
237
255
for _ , vlog := range logs {
238
256
switch vlog .Topics [0 ] {
@@ -247,11 +265,59 @@ func (e *L1EventParser) ParseL1BatchEventLogs(ctx context.Context, logs []types.
247
265
log .Error ("Failed to get commit batch tx or the tx is still pending" , "err" , err , "isPending" , isPending )
248
266
return nil , err
249
267
}
250
- startBlock , endBlock , err := utils .GetBatchRangeFromCalldata (commitTx .Data ())
268
+ version , startBlock , endBlock , err := utils .GetBatchVersionAndBlockRangeFromCalldata (commitTx .Data ())
251
269
if err != nil {
252
270
log .Error ("Failed to get batch range from calldata" , "hash" , commitTx .Hash ().String (), "height" , vlog .BlockNumber )
253
271
return nil , err
254
272
}
273
+ if version >= 7 { // It's a batch with version >= 7.
274
+ codec , err := encoding .CodecFromVersion (encoding .CodecVersion (version ))
275
+ if err != nil {
276
+ return nil , fmt .Errorf ("unsupported codec version: %v, err: %w" , version , err )
277
+ }
278
+
279
+ // we append the batch hash to the slice for the current commit transaction after processing the batch.
280
+ // that means the current index of the batch within the transaction is len(txBlobIndexMap[vlog.TxHash]).
281
+ currentIndex := len (txBlobIndexMap [vlog .TxHash ])
282
+ if currentIndex >= len (commitTx .BlobHashes ()) {
283
+ return nil , fmt .Errorf ("commit transaction %s has %d blobs, but trying to access index %d (batch index %d)" ,
284
+ vlog .TxHash .String (), len (commitTx .BlobHashes ()), currentIndex , event .BatchIndex .Uint64 ())
285
+ }
286
+ blobVersionedHash := commitTx .BlobHashes ()[currentIndex ]
287
+
288
+ // validate the batch hash
289
+ var parentBatchHash common.Hash
290
+ if currentIndex == 0 {
291
+ parentBatchHash , err = utils .GetParentBatchHashFromCalldata (commitTx .Data ())
292
+ if err != nil {
293
+ return nil , fmt .Errorf ("failed to get parent batch header from calldata, tx hash: %s, err: %w" , vlog .TxHash .String (), err )
294
+ }
295
+ } else {
296
+ // here we need to subtract 1 from the current index to get the parent batch hash.
297
+ parentBatchHash = txBlobIndexMap [vlog .TxHash ][currentIndex - 1 ]
298
+ }
299
+ calculatedBatch , err := codec .NewDABatchFromParams (event .BatchIndex .Uint64 (), blobVersionedHash , parentBatchHash )
300
+ if err != nil {
301
+ return nil , fmt .Errorf ("failed to create new DA batch from params, batch index: %d, err: %w" , event .BatchIndex .Uint64 (), err )
302
+ }
303
+ if calculatedBatch .Hash () != event .BatchHash {
304
+ return nil , fmt .Errorf ("batch hash mismatch for batch %d, expected: %s, got: %s" , event .BatchIndex , event .BatchHash .String (), calculatedBatch .Hash ().String ())
305
+ }
306
+
307
+ blocks , err := e .getBatchBlockRangeFromBlob (ctx , codec , blobVersionedHash , blockTimestampsMap [vlog .BlockNumber ])
308
+ if err != nil {
309
+ return nil , fmt .Errorf ("failed to process versioned blob, blobVersionedHash: %s, block number: %d, blob index: %d, err: %w" ,
310
+ blobVersionedHash .String (), vlog .BlockNumber , currentIndex , err )
311
+ }
312
+ if len (blocks ) == 0 {
313
+ return nil , fmt .Errorf ("no blocks found in the blob, blobVersionedHash: %s, block number: %d, blob index: %d" ,
314
+ blobVersionedHash .String (), vlog .BlockNumber , currentIndex )
315
+ }
316
+ startBlock = blocks [0 ].Number ()
317
+ endBlock = blocks [len (blocks )- 1 ].Number ()
318
+
319
+ txBlobIndexMap [vlog .TxHash ] = append (txBlobIndexMap [vlog .TxHash ], event .BatchHash )
320
+ }
255
321
l1BatchEvents = append (l1BatchEvents , & orm.BatchEvent {
256
322
BatchStatus : int (btypes .BatchStatusTypeCommitted ),
257
323
BatchIndex : event .BatchIndex .Uint64 (),
@@ -260,8 +326,8 @@ func (e *L1EventParser) ParseL1BatchEventLogs(ctx context.Context, logs []types.
260
326
EndBlockNumber : endBlock ,
261
327
L1BlockNumber : vlog .BlockNumber ,
262
328
})
263
- case backendabi .L1RevertBatchEventSig :
264
- event := backendabi.L1RevertBatchEvent {}
329
+ case backendabi .L1RevertBatchV0EventSig :
330
+ event := backendabi.L1RevertBatchV0Event {}
265
331
if err := utils .UnpackLog (backendabi .IScrollChainABI , & event , "RevertBatch" , vlog ); err != nil {
266
332
log .Error ("Failed to unpack RevertBatch event" , "err" , err )
267
333
return nil , err
@@ -272,6 +338,19 @@ func (e *L1EventParser) ParseL1BatchEventLogs(ctx context.Context, logs []types.
272
338
BatchHash : event .BatchHash .String (),
273
339
L1BlockNumber : vlog .BlockNumber ,
274
340
})
341
+ case backendabi .L1RevertBatchV7EventSig :
342
+ event := backendabi.L1RevertBatchV7Event {}
343
+ if err := utils .UnpackLog (backendabi .IScrollChainABI , & event , "RevertBatch0" , vlog ); err != nil {
344
+ log .Error ("Failed to unpack RevertBatch event" , "err" , err )
345
+ return nil , err
346
+ }
347
+ for i := event .StartBatchIndex .Uint64 (); i <= event .FinishBatchIndex .Uint64 (); i ++ {
348
+ l1BatchEvents = append (l1BatchEvents , & orm.BatchEvent {
349
+ BatchStatus : int (btypes .BatchStatusTypeReverted ),
350
+ BatchIndex : i ,
351
+ L1BlockNumber : vlog .BlockNumber ,
352
+ })
353
+ }
275
354
case backendabi .L1FinalizeBatchEventSig :
276
355
event := backendabi.L1FinalizeBatchEvent {}
277
356
if err := utils .UnpackLog (backendabi .IScrollChainABI , & event , "FinalizeBatch" , vlog ); err != nil {
@@ -389,3 +468,27 @@ func getRealFromAddress(ctx context.Context, eventSender common.Address, eventMe
389
468
}
390
469
return sender .String (), nil
391
470
}
471
+
472
+ func (e * L1EventParser ) getBatchBlockRangeFromBlob (ctx context.Context , codec encoding.Codec , versionedHash common.Hash , l1BlockTime uint64 ) ([]encoding.DABlock , error ) {
473
+ blob , err := e .blobClient .GetBlobByVersionedHashAndBlockTime (ctx , versionedHash , l1BlockTime )
474
+ if err != nil {
475
+ return nil , fmt .Errorf ("failed to get blob %s: %w" , versionedHash .Hex (), err )
476
+ }
477
+ if blob == nil {
478
+ return nil , fmt .Errorf ("blob %s not found" , versionedHash .Hex ())
479
+ }
480
+
481
+ blobPayload , err := codec .DecodeBlob (blob )
482
+ if err != nil {
483
+ return nil , fmt .Errorf ("blob %s decode error: %w" , versionedHash .Hex (), err )
484
+ }
485
+
486
+ blocks := blobPayload .Blocks ()
487
+ if len (blocks ) == 0 {
488
+ return nil , fmt .Errorf ("empty blocks in blob %s" , versionedHash .Hex ())
489
+ }
490
+
491
+ log .Debug ("Successfully processed blob" , "versionedHash" , versionedHash .Hex (), "blocksCount" , len (blocks ))
492
+
493
+ return blocks , nil
494
+ }
0 commit comments