go-ethereum/rollup/da_syncer/batch_queue.go
Jonas Theis 65a0d4e87d
feat(permissionless batches): recovery mode after permissionless batches (#1115)
* port changes from #1013

* port changes from #1068

* go.mod tidy

* fix compile error

* fix goimports

* fix log

* address review comments

* upgrade golang.org/x/net to 0.23.0

* port changes from #1018

* fix tests and linter errors

* address review comments

* refactor rollup sync service / verifier to use CalldataBlobSource to retrieve data from L1

* add configuration and initialize blob clients

* fix unit tests

* remove unused code

* address review comments

* address more review comments

* implement first version of new da-codec and to handle multiple batches submitted in one transaction

* add CommitBatchDAV7 and handle multiple commit events submitted in a single transactions

* fix bug due to previous batch being empty when processing the first batch within a set of batches

* Allow using MPT

* update to latest da-codec

* add field to CommittedBatchMeta to store LastL1MessageQueueHash for CodecV7 batches

* adjust rollup verifier to support CodecV7 batches

* address review comments

* fix issues after merge

* go mod tidy

* fix unit tests

* update da-codec

* add test TestValidateBatchCodecV7

* go mod tidy

* do not log error on shutdown

* add sanity check for version to deserialization of committedBatchMetaV7

* port changes from #1073

* chore: auto version bump [bot]

* address review comments

* add more logs

* disable ENRUpdater if DA sync mode is enabled

* exit pipeline if context is cancelled

* correctly handle override by setting the head of the chain to the parent's height so that created blocks will always become part of canonical chain

* fix error with genesis event being nil

* chore: auto version bump [bot]

* chore: auto version bump [bot]

* goimports

---------

Co-authored-by: Ömer Faruk Irmak <omerfirmak@gmail.com>
Co-authored-by: Thegaram <Thegaram@users.noreply.github.com>
Co-authored-by: jonastheis <jonastheis@users.noreply.github.com>
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
2025-02-25 15:25:05 +01:00

109 lines
3.1 KiB
Go

package da_syncer
import (
"context"
"fmt"
"github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/core/rawdb"
"github.com/scroll-tech/go-ethereum/ethdb"
"github.com/scroll-tech/go-ethereum/rollup/da_syncer/da"
)
// BatchQueue is a pipeline stage that reads all batch events from DAQueue and provides only finalized batches to the next stage.
type BatchQueue struct {
DAQueue *DAQueue
db ethdb.Database
lastFinalizedBatchIndex uint64
batches *common.Heap[da.Entry]
batchesMap *common.ShrinkingMap[uint64, *common.HeapElement[da.Entry]]
}
func NewBatchQueue(DAQueue *DAQueue, db ethdb.Database) *BatchQueue {
return &BatchQueue{
DAQueue: DAQueue,
db: db,
lastFinalizedBatchIndex: 0,
batches: common.NewHeap[da.Entry](),
batchesMap: common.NewShrinkingMap[uint64, *common.HeapElement[da.Entry]](1000),
}
}
// NextBatch finds next finalized batch and returns data, that was committed in that batch
func (bq *BatchQueue) NextBatch(ctx context.Context) (da.Entry, error) {
if batch := bq.getFinalizedBatch(); batch != nil {
return batch, nil
}
for {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
daEntry, err := bq.DAQueue.NextDA(ctx)
if err != nil {
return nil, err
}
switch daEntry.Type() {
case da.CommitBatchV0Type, da.CommitBatchWithBlobType:
bq.addBatch(daEntry)
case da.RevertBatchType:
bq.deleteBatch(daEntry)
case da.FinalizeBatchType:
if daEntry.BatchIndex() > bq.lastFinalizedBatchIndex {
bq.lastFinalizedBatchIndex = daEntry.BatchIndex()
}
if batch := bq.getFinalizedBatch(); batch != nil {
return batch, nil
}
default:
return nil, fmt.Errorf("unexpected type of daEntry: %T", daEntry)
}
}
}
// getFinalizedBatch returns next finalized batch if there is available
func (bq *BatchQueue) getFinalizedBatch() da.Entry {
if bq.batches.Len() == 0 {
return nil
}
batch := bq.batches.Peek().Value()
if batch.BatchIndex() <= bq.lastFinalizedBatchIndex {
bq.deleteBatch(batch)
return batch
} else {
return nil
}
}
func (bq *BatchQueue) addBatch(batch da.Entry) {
heapElement := bq.batches.Push(batch)
bq.batchesMap.Set(batch.BatchIndex(), heapElement)
}
// deleteBatch deletes data committed in the batch from map, because this batch is reverted or finalized
// updates DASyncedL1BlockNumber
func (bq *BatchQueue) deleteBatch(batch da.Entry) {
batchHeapElement, exists := bq.batchesMap.Get(batch.BatchIndex())
if !exists {
return
}
bq.batchesMap.Delete(batch.BatchIndex())
bq.batches.Remove(batchHeapElement)
// we store here min height of currently loaded batches to be able to start syncing from the same place in case of restart
// TODO: we should store this information when the batch is done being processed to avoid inconsistencies
rawdb.WriteDASyncedL1BlockNumber(bq.db, batch.L1BlockNumber()-1)
}
func (bq *BatchQueue) Reset(height uint64) {
bq.batches.Clear()
bq.batchesMap.Clear()
bq.lastFinalizedBatchIndex = 0
bq.DAQueue.Reset(height)
}