mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-23 13:16:42 +00:00
feat(L1 follower): adjust to recent CodecV7 and contract changes (#1120)
* 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] * adjust to renaming in CodecV7 * implement carrying forward of L1 MessageQueue index * fix issue after upgrading from old storage to new format where batchIndex was 0 and all batches would be skipped * add new RevertBatch event * add commitBatches to be able to read calldata of CodecV7/EuclidV2 committed batches * implement finding of L1 message queue height for initial batch in recovery mode * add sanity checks for computed batches from events and batch hashes given via calldata from commit transaction * update ScrollChain ABI * chore: auto version bump [bot] * remove initial batch form DAQueue * go mod tidy * fix underflow bug when l1DeploymentBlock==0 * fix bug with wrong parentBatchHash of first batch of batches submitted in a single tx * update to latest da-codec * address review comments * address review comments * fix bug when l1MessageV2StartIndex==0 serialized to [] (empty slice) which would always be decoded to non-existing instead of 0 * chore: auto version bump [bot] * cache go dependencies in Dockerfile.mockccc * chore: auto version bump [bot] * add INFO log when reverting rollup events in L1 follower mode * change LastProcessedMessageQueueIndex of finalize event to totalL1MessagesPoppedOverall * cleanup * chore: auto version bump [bot] --------- 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>
This commit is contained in:
parent
87e196052a
commit
40ebbd6491
24 changed files with 756 additions and 231 deletions
|
|
@ -3,3 +3,5 @@
|
||||||
build/_workspace
|
build/_workspace
|
||||||
build/_bin
|
build/_bin
|
||||||
tests/testdata
|
tests/testdata
|
||||||
|
|
||||||
|
tmp/
|
||||||
|
|
@ -7,14 +7,18 @@ ARG SCROLL_LIB_PATH=/scroll/lib
|
||||||
# Build Geth in a stock Go builder container
|
# Build Geth in a stock Go builder container
|
||||||
FROM scrolltech/go-rust-builder:go-1.21-rust-nightly-2023-12-03 as builder
|
FROM scrolltech/go-rust-builder:go-1.21-rust-nightly-2023-12-03 as builder
|
||||||
|
|
||||||
ADD . /go-ethereum
|
WORKDIR /go-ethereum
|
||||||
RUN cd /go-ethereum && env GO111MODULE=on go run build/ci.go install ./cmd/geth
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download -x
|
||||||
|
|
||||||
|
ADD . ./
|
||||||
|
RUN env GO111MODULE=on go run build/ci.go install ./cmd/geth
|
||||||
|
|
||||||
# Pull Geth into a second stage deploy alpine container
|
# Pull Geth into a second stage deploy alpine container
|
||||||
FROM ubuntu:20.04
|
FROM ubuntu:20.04
|
||||||
|
|
||||||
RUN apt-get -qq update \
|
#RUN apt-get -qq update \
|
||||||
&& apt-get -qq install -y --no-install-recommends ca-certificates
|
# && apt-get -qq install -y --no-install-recommends ca-certificates
|
||||||
|
|
||||||
ENV CGO_LDFLAGS="-ldl"
|
ENV CGO_LDFLAGS="-ldl"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,33 @@
|
||||||
package rawdb
|
package rawdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/scroll-tech/go-ethereum/ethdb"
|
"github.com/scroll-tech/go-ethereum/ethdb"
|
||||||
"github.com/scroll-tech/go-ethereum/log"
|
"github.com/scroll-tech/go-ethereum/log"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WriteDASyncedL1BlockNumber writes the highest synced L1 block number to the database.
|
type DAProcessedBatchMeta struct {
|
||||||
func WriteDASyncedL1BlockNumber(db ethdb.KeyValueWriter, L1BlockNumber uint64) {
|
BatchIndex uint64
|
||||||
value := big.NewInt(0).SetUint64(L1BlockNumber).Bytes()
|
L1BlockNumber uint64
|
||||||
|
TotalL1MessagesPopped uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteDAProcessedBatchMeta writes the batch metadata of the latest processed DA batch.
|
||||||
|
func WriteDAProcessedBatchMeta(db ethdb.KeyValueWriter, daProcessedBatchMeta *DAProcessedBatchMeta) {
|
||||||
|
value, err := rlp.EncodeToBytes(daProcessedBatchMeta)
|
||||||
|
if err != nil {
|
||||||
|
log.Crit("failed to RLP encode committed batch metadata", "batch index", daProcessedBatchMeta.BatchIndex, "committed batch meta", daProcessedBatchMeta, "err", err)
|
||||||
|
}
|
||||||
if err := db.Put(daSyncedL1BlockNumberKey, value); err != nil {
|
if err := db.Put(daSyncedL1BlockNumberKey, value); err != nil {
|
||||||
log.Crit("Failed to update DA synced L1 block number", "err", err)
|
log.Crit("Failed to update DAProcessedBatchMeta", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadDASyncedL1BlockNumber retrieves the highest synced L1 block number.
|
// ReadDAProcessedBatchMeta retrieves the batch metadata of the latest processed DA batch.
|
||||||
func ReadDASyncedL1BlockNumber(db ethdb.Reader) *uint64 {
|
func ReadDAProcessedBatchMeta(db ethdb.Reader) *DAProcessedBatchMeta {
|
||||||
data, err := db.Get(daSyncedL1BlockNumberKey)
|
data, err := db.Get(daSyncedL1BlockNumberKey)
|
||||||
if err != nil && isNotFoundErr(err) {
|
if err != nil && isNotFoundErr(err) {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -29,11 +39,25 @@ func ReadDASyncedL1BlockNumber(db ethdb.Reader) *uint64 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
number := new(big.Int).SetBytes(data)
|
// Try decoding from the newest format for future proofness, then the older one for old data.
|
||||||
if !number.IsUint64() {
|
daProcessedBatchMeta := new(DAProcessedBatchMeta)
|
||||||
log.Crit("Unexpected DA synced L1 block number in database", "number", number)
|
if err = rlp.Decode(bytes.NewReader(data), daProcessedBatchMeta); err == nil {
|
||||||
|
return daProcessedBatchMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
value := number.Uint64()
|
// Before storing DAProcessedBatchMeta we used to store a single uint64 value for the L1 block number.
|
||||||
return &value
|
l1BlockNumber := new(big.Int).SetBytes(data)
|
||||||
|
if !l1BlockNumber.IsUint64() {
|
||||||
|
log.Crit("Unexpected DA synced L1 block number in database", "number", l1BlockNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can simply set only the L1BlockNumber because carrying forward the totalL1MessagesPopped is not required before EuclidV2 (CodecV7)
|
||||||
|
// (the parentTotalL1MessagePopped is given via the parentBatchHeader).
|
||||||
|
// Nodes need to update to the new version to be able to continue syncing after EuclidV2 (CodecV7). Therefore,
|
||||||
|
// the only nodes that might read a uint64 value are nodes that were running L1 follower before the EuclidV2.
|
||||||
|
return &DAProcessedBatchMeta{
|
||||||
|
BatchIndex: 0,
|
||||||
|
L1BlockNumber: l1BlockNumber.Uint64(),
|
||||||
|
TotalL1MessagesPopped: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -383,9 +383,13 @@ func ReadFirstQueueIndexNotInL2Block(db ethdb.Reader, l2BlockHash common.Hash) *
|
||||||
|
|
||||||
// WriteL1MessageV2StartIndex writes the start index of L1 messages that are from L1MessageQueueV2.
|
// WriteL1MessageV2StartIndex writes the start index of L1 messages that are from L1MessageQueueV2.
|
||||||
func WriteL1MessageV2StartIndex(db ethdb.KeyValueWriter, queueIndex uint64) {
|
func WriteL1MessageV2StartIndex(db ethdb.KeyValueWriter, queueIndex uint64) {
|
||||||
value := big.NewInt(0).SetUint64(queueIndex).Bytes()
|
// Write with binary.BigEndian.PutUint64 to ensure that 0 values are written as 8 bytes.
|
||||||
|
// big.NewInt(0).SetUint64(l1BlockNumber).Bytes() would write 0 as empty slice which leads to problems when reading
|
||||||
|
// the value as non-existent and 0 are not distinguishable.
|
||||||
|
var buf [8]byte
|
||||||
|
binary.BigEndian.PutUint64(buf[:], queueIndex)
|
||||||
|
|
||||||
if err := db.Put(l1MessageV2StartIndexKey, value); err != nil {
|
if err := db.Put(l1MessageV2StartIndexKey, buf[:]); err != nil {
|
||||||
log.Crit("Failed to update L1MessageV2 start index", "err", err)
|
log.Crit("Failed to update L1MessageV2 start index", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -402,13 +406,11 @@ func ReadL1MessageV2StartIndex(db ethdb.Reader) *uint64 {
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if len(data) != 8 {
|
||||||
number := new(big.Int).SetBytes(data)
|
return nil
|
||||||
if !number.IsUint64() {
|
|
||||||
log.Crit("Unexpected number for L1MessageV2 start index", "number", number)
|
|
||||||
}
|
}
|
||||||
|
res := binary.BigEndian.Uint64(data)
|
||||||
|
|
||||||
res := number.Uint64()
|
|
||||||
return &res
|
return &res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ type CommittedBatchMeta struct {
|
||||||
ChunkBlockRanges []*ChunkBlockRange
|
ChunkBlockRanges []*ChunkBlockRange
|
||||||
|
|
||||||
// introduced with CodecV7
|
// introduced with CodecV7
|
||||||
LastL1MessageQueueHash common.Hash
|
PostL1MessageQueueHash common.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
type committedBatchMetaV0 struct {
|
type committedBatchMetaV0 struct {
|
||||||
|
|
@ -170,7 +170,7 @@ func WriteCommittedBatchMeta(db ethdb.KeyValueWriter, batchIndex uint64, committ
|
||||||
committedBatchMetaToStore = &committedBatchMetaV7{
|
committedBatchMetaToStore = &committedBatchMetaV7{
|
||||||
Version: committedBatchMeta.Version,
|
Version: committedBatchMeta.Version,
|
||||||
ChunkBlockRanges: committedBatchMeta.ChunkBlockRanges,
|
ChunkBlockRanges: committedBatchMeta.ChunkBlockRanges,
|
||||||
LastL1MessageQueueHash: committedBatchMeta.LastL1MessageQueueHash,
|
LastL1MessageQueueHash: committedBatchMeta.PostL1MessageQueueHash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -202,7 +202,7 @@ func ReadCommittedBatchMeta(db ethdb.Reader, batchIndex uint64) (*CommittedBatch
|
||||||
return &CommittedBatchMeta{
|
return &CommittedBatchMeta{
|
||||||
Version: cbm7.Version,
|
Version: cbm7.Version,
|
||||||
ChunkBlockRanges: cbm7.ChunkBlockRanges,
|
ChunkBlockRanges: cbm7.ChunkBlockRanges,
|
||||||
LastL1MessageQueueHash: cbm7.LastL1MessageQueueHash,
|
PostL1MessageQueueHash: cbm7.LastL1MessageQueueHash,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,7 +214,7 @@ func ReadCommittedBatchMeta(db ethdb.Reader, batchIndex uint64) (*CommittedBatch
|
||||||
return &CommittedBatchMeta{
|
return &CommittedBatchMeta{
|
||||||
Version: cbm0.Version,
|
Version: cbm0.Version,
|
||||||
ChunkBlockRanges: cbm0.ChunkBlockRanges,
|
ChunkBlockRanges: cbm0.ChunkBlockRanges,
|
||||||
LastL1MessageQueueHash: common.Hash{},
|
PostL1MessageQueueHash: common.Hash{},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,7 @@ func TestWriteReadDeleteCommittedBatchMeta(t *testing.T) {
|
||||||
meta: &CommittedBatchMeta{
|
meta: &CommittedBatchMeta{
|
||||||
Version: 7,
|
Version: 7,
|
||||||
ChunkBlockRanges: []*ChunkBlockRange{{StartBlockNumber: 0, EndBlockNumber: 10}},
|
ChunkBlockRanges: []*ChunkBlockRange{{StartBlockNumber: 0, EndBlockNumber: 10}},
|
||||||
LastL1MessageQueueHash: common.Hash{1, 2, 3, 4, 5, 6, 7},
|
PostL1MessageQueueHash: common.Hash{1, 2, 3, 4, 5, 6, 7},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -190,7 +190,7 @@ func TestWriteReadDeleteCommittedBatchMeta(t *testing.T) {
|
||||||
meta: &CommittedBatchMeta{
|
meta: &CommittedBatchMeta{
|
||||||
Version: 255,
|
Version: 255,
|
||||||
ChunkBlockRanges: []*ChunkBlockRange{{StartBlockNumber: 0, EndBlockNumber: 10}, {StartBlockNumber: 11, EndBlockNumber: 20}},
|
ChunkBlockRanges: []*ChunkBlockRange{{StartBlockNumber: 0, EndBlockNumber: 10}, {StartBlockNumber: 11, EndBlockNumber: 20}},
|
||||||
LastL1MessageQueueHash: common.Hash{255},
|
PostL1MessageQueueHash: common.Hash{255},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -237,7 +237,7 @@ func TestOverwriteCommittedBatchMeta(t *testing.T) {
|
||||||
newMeta := &CommittedBatchMeta{
|
newMeta := &CommittedBatchMeta{
|
||||||
Version: 255,
|
Version: 255,
|
||||||
ChunkBlockRanges: []*ChunkBlockRange{{StartBlockNumber: 0, EndBlockNumber: 20}, {StartBlockNumber: 21, EndBlockNumber: 30}},
|
ChunkBlockRanges: []*ChunkBlockRange{{StartBlockNumber: 0, EndBlockNumber: 20}, {StartBlockNumber: 21, EndBlockNumber: 30}},
|
||||||
LastL1MessageQueueHash: common.Hash{255},
|
PostL1MessageQueueHash: common.Hash{255},
|
||||||
}
|
}
|
||||||
|
|
||||||
// write initial meta
|
// write initial meta
|
||||||
|
|
@ -282,5 +282,5 @@ func compareCommittedBatchMeta(a, b *CommittedBatchMeta) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.LastL1MessageQueueHash == b.LastL1MessageQueueHash
|
return a.PostL1MessageQueueHash == b.PostL1MessageQueueHash
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
go.mod
2
go.mod
|
|
@ -51,7 +51,7 @@ require (
|
||||||
github.com/prometheus/tsdb v0.7.1
|
github.com/prometheus/tsdb v0.7.1
|
||||||
github.com/rjeczalik/notify v0.9.1
|
github.com/rjeczalik/notify v0.9.1
|
||||||
github.com/rs/cors v1.7.0
|
github.com/rs/cors v1.7.0
|
||||||
github.com/scroll-tech/da-codec v0.1.3-0.20250210041951-d028c537b995
|
github.com/scroll-tech/da-codec v0.1.3-0.20250226072559-f8a8d3898f54
|
||||||
github.com/scroll-tech/zktrie v0.8.4
|
github.com/scroll-tech/zktrie v0.8.4
|
||||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||||
github.com/sourcegraph/conc v0.3.0
|
github.com/sourcegraph/conc v0.3.0
|
||||||
|
|
|
||||||
4
go.sum
4
go.sum
|
|
@ -396,8 +396,8 @@ github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncj
|
||||||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/scroll-tech/da-codec v0.1.3-0.20250210041951-d028c537b995 h1:Zo1p42CUS9pADSKoDD0ZoDxf4dQ3gttqWZlV+RSeImk=
|
github.com/scroll-tech/da-codec v0.1.3-0.20250226072559-f8a8d3898f54 h1:qVpsVu1J91opTn6HYeuzWcBRVhQmPR8g05i+PlOjlI4=
|
||||||
github.com/scroll-tech/da-codec v0.1.3-0.20250210041951-d028c537b995/go.mod h1:UZhhjzqYsyEhcvY0Y+SP+oMdeOUqFn/UXpbAYuPGzg0=
|
github.com/scroll-tech/da-codec v0.1.3-0.20250226072559-f8a8d3898f54/go.mod h1:xECEHZLVzbdUn+tNbRJhRIjLGTOTmnFQuTgUTeVLX58=
|
||||||
github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE=
|
github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE=
|
||||||
github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk=
|
github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk=
|
||||||
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import (
|
||||||
const (
|
const (
|
||||||
VersionMajor = 5 // Major version component of the current release
|
VersionMajor = 5 // Major version component of the current release
|
||||||
VersionMinor = 8 // Minor version component of the current release
|
VersionMinor = 8 // Minor version component of the current release
|
||||||
VersionPatch = 17 // Patch version component of the current release
|
VersionPatch = 18 // Patch version component of the current release
|
||||||
VersionMeta = "mainnet" // Version metadata to append to the version string
|
VersionMeta = "mainnet" // Version metadata to append to the version string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,9 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/common"
|
"github.com/scroll-tech/go-ethereum/common"
|
||||||
"github.com/scroll-tech/go-ethereum/core/rawdb"
|
"github.com/scroll-tech/go-ethereum/core/rawdb"
|
||||||
"github.com/scroll-tech/go-ethereum/ethdb"
|
"github.com/scroll-tech/go-ethereum/ethdb"
|
||||||
|
"github.com/scroll-tech/go-ethereum/log"
|
||||||
"github.com/scroll-tech/go-ethereum/rollup/da_syncer/da"
|
"github.com/scroll-tech/go-ethereum/rollup/da_syncer/da"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/l1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BatchQueue is a pipeline stage that reads all batch events from DAQueue and provides only finalized batches to the next stage.
|
// BatchQueue is a pipeline stage that reads all batch events from DAQueue and provides only finalized batches to the next stage.
|
||||||
|
|
@ -17,21 +19,24 @@ type BatchQueue struct {
|
||||||
lastFinalizedBatchIndex uint64
|
lastFinalizedBatchIndex uint64
|
||||||
batches *common.Heap[da.Entry]
|
batches *common.Heap[da.Entry]
|
||||||
batchesMap *common.ShrinkingMap[uint64, *common.HeapElement[da.Entry]]
|
batchesMap *common.ShrinkingMap[uint64, *common.HeapElement[da.Entry]]
|
||||||
|
|
||||||
|
previousBatch *rawdb.DAProcessedBatchMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBatchQueue(DAQueue *DAQueue, db ethdb.Database) *BatchQueue {
|
func NewBatchQueue(DAQueue *DAQueue, db ethdb.Database, lastProcessedBatch *rawdb.DAProcessedBatchMeta) *BatchQueue {
|
||||||
return &BatchQueue{
|
return &BatchQueue{
|
||||||
DAQueue: DAQueue,
|
DAQueue: DAQueue,
|
||||||
db: db,
|
db: db,
|
||||||
lastFinalizedBatchIndex: 0,
|
lastFinalizedBatchIndex: lastProcessedBatch.BatchIndex,
|
||||||
batches: common.NewHeap[da.Entry](),
|
batches: common.NewHeap[da.Entry](),
|
||||||
batchesMap: common.NewShrinkingMap[uint64, *common.HeapElement[da.Entry]](1000),
|
batchesMap: common.NewShrinkingMap[uint64, *common.HeapElement[da.Entry]](1000),
|
||||||
|
previousBatch: lastProcessedBatch,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NextBatch finds next finalized batch and returns data, that was committed in that batch
|
// NextBatch finds next finalized batch and returns data, that was committed in that batch
|
||||||
func (bq *BatchQueue) NextBatch(ctx context.Context) (da.Entry, error) {
|
func (bq *BatchQueue) NextBatch(ctx context.Context) (da.EntryWithBlocks, error) {
|
||||||
if batch := bq.getFinalizedBatch(); batch != nil {
|
if batch := bq.nextFinalizedBatch(); batch != nil {
|
||||||
return batch, nil
|
return batch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,13 +55,15 @@ func (bq *BatchQueue) NextBatch(ctx context.Context) (da.Entry, error) {
|
||||||
case da.CommitBatchV0Type, da.CommitBatchWithBlobType:
|
case da.CommitBatchV0Type, da.CommitBatchWithBlobType:
|
||||||
bq.addBatch(daEntry)
|
bq.addBatch(daEntry)
|
||||||
case da.RevertBatchType:
|
case da.RevertBatchType:
|
||||||
bq.deleteBatch(daEntry)
|
if err = bq.handleRevertEvent(daEntry.Event()); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to handle revert event: %w", err)
|
||||||
|
}
|
||||||
case da.FinalizeBatchType:
|
case da.FinalizeBatchType:
|
||||||
if daEntry.BatchIndex() > bq.lastFinalizedBatchIndex {
|
if daEntry.BatchIndex() > bq.lastFinalizedBatchIndex {
|
||||||
bq.lastFinalizedBatchIndex = daEntry.BatchIndex()
|
bq.lastFinalizedBatchIndex = daEntry.BatchIndex()
|
||||||
}
|
}
|
||||||
|
|
||||||
if batch := bq.getFinalizedBatch(); batch != nil {
|
if batch := bq.nextFinalizedBatch(); batch != nil {
|
||||||
return batch, nil
|
return batch, nil
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
@ -65,16 +72,17 @@ func (bq *BatchQueue) NextBatch(ctx context.Context) (da.Entry, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFinalizedBatch returns next finalized batch if there is available
|
// nextFinalizedBatch returns next finalized batch if there is available
|
||||||
func (bq *BatchQueue) getFinalizedBatch() da.Entry {
|
func (bq *BatchQueue) nextFinalizedBatch() da.EntryWithBlocks {
|
||||||
if bq.batches.Len() == 0 {
|
if bq.batches.Len() == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
batch := bq.batches.Peek().Value()
|
batch := bq.batches.Peek().Value()
|
||||||
|
// we process all batches smaller or equal to the last finalized batch index -> this reflects bundles of multiple batches
|
||||||
|
// where we only receive the finalize event for the last batch of the bundle.
|
||||||
if batch.BatchIndex() <= bq.lastFinalizedBatchIndex {
|
if batch.BatchIndex() <= bq.lastFinalizedBatchIndex {
|
||||||
bq.deleteBatch(batch)
|
return bq.processAndDeleteBatch(batch)
|
||||||
return batch
|
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -85,25 +93,87 @@ func (bq *BatchQueue) addBatch(batch da.Entry) {
|
||||||
bq.batchesMap.Set(batch.BatchIndex(), heapElement)
|
bq.batchesMap.Set(batch.BatchIndex(), heapElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteBatch deletes data committed in the batch from map, because this batch is reverted or finalized
|
func (bq *BatchQueue) handleRevertEvent(event l1.RollupEvent) error {
|
||||||
// updates DASyncedL1BlockNumber
|
switch event.Type() {
|
||||||
func (bq *BatchQueue) deleteBatch(batch da.Entry) {
|
case l1.RevertEventV0Type:
|
||||||
batchHeapElement, exists := bq.batchesMap.Get(batch.BatchIndex())
|
revertBatch, ok := event.(*l1.RevertBatchEventV0)
|
||||||
if !exists {
|
if !ok {
|
||||||
return
|
return fmt.Errorf("unexpected type of revert event: %T, expected RevertEventV0Type", event)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("reverting batch due to RevertEventV0Type", "batchIndex", revertBatch.BatchIndex())
|
||||||
|
|
||||||
|
bq.deleteBatch(revertBatch.BatchIndex().Uint64())
|
||||||
|
case l1.RevertEventV7Type:
|
||||||
|
revertBatch, ok := event.(*l1.RevertBatchEventV7)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type of revert event: %T, expected RevertEventV7Type", event)
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete all batches from revertBatch.StartBatchIndex (inclusive) to revertBatch.FinishBatchIndex (inclusive)
|
||||||
|
for i := revertBatch.StartBatchIndex().Uint64(); i <= revertBatch.FinishBatchIndex().Uint64(); i++ {
|
||||||
|
log.Info("reverting batch due to RevertEventV7Type", "batchIndex", i)
|
||||||
|
bq.deleteBatch(i)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unexpected type of revert event: %T", event)
|
||||||
}
|
}
|
||||||
|
|
||||||
bq.batchesMap.Delete(batch.BatchIndex())
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bq *BatchQueue) deleteBatch(batchIndex uint64) (deleted bool) {
|
||||||
|
batchHeapElement, exists := bq.batchesMap.Get(batchIndex)
|
||||||
|
if !exists {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
bq.batchesMap.Delete(batchIndex)
|
||||||
bq.batches.Remove(batchHeapElement)
|
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
|
return true
|
||||||
// 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) {
|
// processAndDeleteBatch processes a batch and deletes the batch from map. Stores the syncing progress on disk.
|
||||||
|
func (bq *BatchQueue) processAndDeleteBatch(batch da.Entry) da.EntryWithBlocks {
|
||||||
|
if !bq.deleteBatch(batch.BatchIndex()) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
entryWithBlocks, ok := batch.(da.EntryWithBlocks)
|
||||||
|
if !ok {
|
||||||
|
// this should only happen if we delete a reverted batch
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// sanity check that the next batch is the one we expect. If not, we skip the batch.
|
||||||
|
if bq.previousBatch.BatchIndex > 0 && bq.previousBatch.BatchIndex+1 != entryWithBlocks.BatchIndex() {
|
||||||
|
log.Info("BatchQueue: skipping batch ", "currentBatch", entryWithBlocks.BatchIndex(), "previousBatch", bq.previousBatch.BatchIndex)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// carry forward the total L1 messages popped from the previous batch
|
||||||
|
entryWithBlocks.SetParentTotalL1MessagePopped(bq.previousBatch.TotalL1MessagesPopped)
|
||||||
|
|
||||||
|
// we store the previous batch as it has been completely processed which we know because the next batch is requested within the pipeline.
|
||||||
|
// In case of a restart or crash we can continue from the last processed batch (and its metadata).
|
||||||
|
rawdb.WriteDAProcessedBatchMeta(bq.db, bq.previousBatch)
|
||||||
|
|
||||||
|
log.Info("processing batch", "batchIndex", entryWithBlocks.BatchIndex(), "L1BlockNumber", entryWithBlocks.L1BlockNumber(), "totalL1MessagesPopped", entryWithBlocks.TotalL1MessagesPopped(), "previousBatch", bq.previousBatch.BatchIndex, "previousL1BlockNumber", bq.previousBatch.L1BlockNumber, "previous TotalL1MessagesPopped", bq.previousBatch.TotalL1MessagesPopped)
|
||||||
|
|
||||||
|
bq.previousBatch = &rawdb.DAProcessedBatchMeta{
|
||||||
|
L1BlockNumber: entryWithBlocks.L1BlockNumber(),
|
||||||
|
BatchIndex: entryWithBlocks.BatchIndex(),
|
||||||
|
TotalL1MessagesPopped: entryWithBlocks.TotalL1MessagesPopped(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return entryWithBlocks
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bq *BatchQueue) Reset(lastProcessedBatchMeta *rawdb.DAProcessedBatchMeta) {
|
||||||
bq.batches.Clear()
|
bq.batches.Clear()
|
||||||
bq.batchesMap.Clear()
|
bq.batchesMap.Clear()
|
||||||
bq.lastFinalizedBatchIndex = 0
|
bq.lastFinalizedBatchIndex = lastProcessedBatchMeta.BatchIndex
|
||||||
bq.DAQueue.Reset(height)
|
bq.previousBatch = lastProcessedBatchMeta
|
||||||
|
bq.DAQueue.Reset(lastProcessedBatchMeta)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/scroll-tech/go-ethereum/core/rawdb"
|
||||||
"github.com/scroll-tech/go-ethereum/rollup/da_syncer/da"
|
"github.com/scroll-tech/go-ethereum/rollup/da_syncer/da"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -34,23 +35,20 @@ func (bq *BlockQueue) NextBlock(ctx context.Context) (*da.PartialBlock, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bq *BlockQueue) getBlocksFromBatch(ctx context.Context) error {
|
func (bq *BlockQueue) getBlocksFromBatch(ctx context.Context) error {
|
||||||
daEntry, err := bq.batchQueue.NextBatch(ctx)
|
entryWithBlocks, err := bq.batchQueue.NextBatch(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
entryWithBlocks, ok := daEntry.(da.EntryWithBlocks)
|
bq.blocks, err = entryWithBlocks.Blocks()
|
||||||
// this should never happen because we only receive CommitBatch entries
|
if err != nil {
|
||||||
if !ok {
|
return fmt.Errorf("failed to get blocks from entry: %w", err)
|
||||||
return fmt.Errorf("unexpected type of daEntry: %T", daEntry)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bq.blocks = entryWithBlocks.Blocks()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bq *BlockQueue) Reset(height uint64) {
|
func (bq *BlockQueue) Reset(lastProcessedBatchMeta *rawdb.DAProcessedBatchMeta) {
|
||||||
bq.blocks = make([]*da.PartialBlock, 0)
|
bq.blocks = make([]*da.PartialBlock, 0)
|
||||||
bq.batchQueue.Reset(height)
|
bq.batchQueue.Reset(lastProcessedBatchMeta)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ func (ds *CalldataBlobSource) processRollupEventsToDA(rollupEvents l1.RollupEven
|
||||||
// add commit event to the list of previous commit events, so we can process events created in the same tx together
|
// add commit event to the list of previous commit events, so we can process events created in the same tx together
|
||||||
lastCommitTransactionHash = commitEvent.TxHash()
|
lastCommitTransactionHash = commitEvent.TxHash()
|
||||||
lastCommitEvents = append(lastCommitEvents, commitEvent)
|
lastCommitEvents = append(lastCommitEvents, commitEvent)
|
||||||
case l1.RevertEventType:
|
case l1.RevertEventV0Type, l1.RevertEventV7Type:
|
||||||
// if we have any previous commit events, we need to create a new DA before processing the revert event
|
// if we have any previous commit events, we need to create a new DA before processing the revert event
|
||||||
if len(lastCommitEvents) > 0 {
|
if len(lastCommitEvents) > 0 {
|
||||||
if err = getAndAppendCommitBatchDA(); err != nil {
|
if err = getAndAppendCommitBatchDA(); err != nil {
|
||||||
|
|
@ -152,13 +152,7 @@ func (ds *CalldataBlobSource) processRollupEventsToDA(rollupEvents l1.RollupEven
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
revertEvent, ok := rollupEvent.(*l1.RevertBatchEvent)
|
entry = NewRevertBatch(rollupEvent)
|
||||||
// this should never happen because we just check event type
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected type of rollup event: %T", rollupEvent)
|
|
||||||
}
|
|
||||||
|
|
||||||
entry = NewRevertBatch(revertEvent)
|
|
||||||
entries = append(entries, entry)
|
entries = append(entries, entry)
|
||||||
case l1.FinalizeEventType:
|
case l1.FinalizeEventType:
|
||||||
// if we have any previous commit events, we need to create a new DA before processing the finalized event
|
// if we have any previous commit events, we need to create a new DA before processing the finalized event
|
||||||
|
|
@ -235,15 +229,15 @@ func (ds *CalldataBlobSource) getCommitBatchDA(commitEvents []*l1.CommitBatchEve
|
||||||
}
|
}
|
||||||
|
|
||||||
switch codec.Version() {
|
switch codec.Version() {
|
||||||
case 0:
|
case encoding.CodecV0:
|
||||||
if entry, err = NewCommitBatchDAV0(ds.db, codec, commitEvent, args.ParentBatchHeader, args.Chunks, args.SkippedL1MessageBitmap); err != nil {
|
if entry, err = NewCommitBatchDAV0(ds.db, codec, commitEvent, args.ParentBatchHeader, args.Chunks, args.SkippedL1MessageBitmap); err != nil {
|
||||||
return nil, fmt.Errorf("failed to decode DA, batch index: %d, err: %w", commitEvent.BatchIndex().Uint64(), err)
|
return nil, fmt.Errorf("failed to decode DA, batch index: %d, err: %w", commitEvent.BatchIndex().Uint64(), err)
|
||||||
}
|
}
|
||||||
case 1, 2, 3, 4, 5, 6:
|
case encoding.CodecV1, encoding.CodecV2, encoding.CodecV3, encoding.CodecV4, encoding.CodecV5, encoding.CodecV6:
|
||||||
if entry, err = NewCommitBatchDAV1(ds.ctx, ds.db, ds.blobClient, codec, commitEvent, args.ParentBatchHeader, args.Chunks, args.SkippedL1MessageBitmap, args.BlobHashes, blockHeader.Time); err != nil {
|
if entry, err = NewCommitBatchDAV1(ds.ctx, ds.db, ds.blobClient, codec, commitEvent, args.ParentBatchHeader, args.Chunks, args.SkippedL1MessageBitmap, args.BlobHashes, blockHeader.Time); err != nil {
|
||||||
return nil, fmt.Errorf("failed to decode DA, batch index: %d, err: %w", commitEvent.BatchIndex().Uint64(), err)
|
return nil, fmt.Errorf("failed to decode DA, batch index: %d, err: %w", commitEvent.BatchIndex().Uint64(), err)
|
||||||
}
|
}
|
||||||
default: // CodecVersion 7 and above
|
default: // CodecV7 and above
|
||||||
if i >= len(args.BlobHashes) {
|
if i >= len(args.BlobHashes) {
|
||||||
return nil, fmt.Errorf("not enough blob hashes for commit transaction: %s, index in tx: %d, batch index: %d, hash: %s", firstCommitEvent.TxHash(), i, commitEvent.BatchIndex().Uint64(), commitEvent.BatchHash().Hex())
|
return nil, fmt.Errorf("not enough blob hashes for commit transaction: %s, index in tx: %d, batch index: %d, hash: %s", firstCommitEvent.TxHash(), i, commitEvent.BatchIndex().Uint64(), commitEvent.BatchHash().Hex())
|
||||||
}
|
}
|
||||||
|
|
@ -251,7 +245,7 @@ func (ds *CalldataBlobSource) getCommitBatchDA(commitEvents []*l1.CommitBatchEve
|
||||||
|
|
||||||
var parentBatchHash common.Hash
|
var parentBatchHash common.Hash
|
||||||
if previousEvent == nil {
|
if previousEvent == nil {
|
||||||
parentBatchHash = common.BytesToHash(args.ParentBatchHeader)
|
parentBatchHash = args.ParentBatchHash
|
||||||
} else {
|
} else {
|
||||||
parentBatchHash = previousEvent.BatchHash()
|
parentBatchHash = previousEvent.BatchHash()
|
||||||
}
|
}
|
||||||
|
|
@ -265,5 +259,14 @@ func (ds *CalldataBlobSource) getCommitBatchDA(commitEvents []*l1.CommitBatchEve
|
||||||
entries = append(entries, entry)
|
entries = append(entries, entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if codec.Version() >= encoding.CodecV7 {
|
||||||
|
// sanity check that the last batch hash from the tx is equal to the last batch hash from the commit events.
|
||||||
|
// this means that all batches in the transaction have been successfully processed.
|
||||||
|
lastBatch := entries[len(entries)-1]
|
||||||
|
if args.LastBatchHash != lastBatch.Event().BatchHash() {
|
||||||
|
return nil, fmt.Errorf("last batch hash from tx is not equal to the one from commit events: LastBatchHash in calldata of tx: %s, last batch hash from events: %s", args.LastBatchHash.Hex(), lastBatch.Event().BatchHash().Hex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return entries, nil
|
return entries, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type CommitBatchDAV0 struct {
|
type CommitBatchDAV0 struct {
|
||||||
|
db ethdb.Database
|
||||||
|
|
||||||
version encoding.CodecVersion
|
version encoding.CodecVersion
|
||||||
batchIndex uint64
|
batchIndex uint64
|
||||||
parentTotalL1MessagePopped uint64
|
parentTotalL1MessagePopped uint64
|
||||||
|
l1MessagesPopped int
|
||||||
skippedL1MessageBitmap []byte
|
skippedL1MessageBitmap []byte
|
||||||
chunks []*encoding.DAChunkRawTx
|
chunks []*encoding.DAChunkRawTx
|
||||||
l1Txs []*types.L1MessageTx
|
|
||||||
|
|
||||||
event *l1.CommitBatchEvent
|
event *l1.CommitBatchEvent
|
||||||
}
|
}
|
||||||
|
|
@ -50,18 +52,15 @@ func NewCommitBatchDAV0WithChunks(db ethdb.Database,
|
||||||
event *l1.CommitBatchEvent,
|
event *l1.CommitBatchEvent,
|
||||||
) (*CommitBatchDAV0, error) {
|
) (*CommitBatchDAV0, error) {
|
||||||
parentTotalL1MessagePopped := getBatchTotalL1MessagePopped(parentBatchHeader)
|
parentTotalL1MessagePopped := getBatchTotalL1MessagePopped(parentBatchHeader)
|
||||||
l1Txs, err := getL1Messages(db, parentTotalL1MessagePopped, skippedL1MessageBitmap, getTotalMessagesPoppedFromChunks(decodedChunks))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get L1 messages for v0 batch %d: %w", batchIndex, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &CommitBatchDAV0{
|
return &CommitBatchDAV0{
|
||||||
|
db: db,
|
||||||
version: version,
|
version: version,
|
||||||
batchIndex: batchIndex,
|
batchIndex: batchIndex,
|
||||||
parentTotalL1MessagePopped: parentTotalL1MessagePopped,
|
parentTotalL1MessagePopped: parentTotalL1MessagePopped,
|
||||||
|
l1MessagesPopped: getTotalMessagesPoppedFromChunks(decodedChunks),
|
||||||
skippedL1MessageBitmap: skippedL1MessageBitmap,
|
skippedL1MessageBitmap: skippedL1MessageBitmap,
|
||||||
chunks: decodedChunks,
|
chunks: decodedChunks,
|
||||||
l1Txs: l1Txs,
|
|
||||||
event: event,
|
event: event,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
@ -110,7 +109,12 @@ func (c *CommitBatchDAV0) CompareTo(other Entry) int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CommitBatchDAV0) Blocks() []*PartialBlock {
|
func (c *CommitBatchDAV0) Blocks() ([]*PartialBlock, error) {
|
||||||
|
l1Txs, err := getL1Messages(c.db, c.parentTotalL1MessagePopped, c.skippedL1MessageBitmap, c.l1MessagesPopped)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get L1 messages for v0 batch %d: %w", c.batchIndex, err)
|
||||||
|
}
|
||||||
|
|
||||||
var blocks []*PartialBlock
|
var blocks []*PartialBlock
|
||||||
l1TxPointer := 0
|
l1TxPointer := 0
|
||||||
|
|
||||||
|
|
@ -120,8 +124,8 @@ func (c *CommitBatchDAV0) Blocks() []*PartialBlock {
|
||||||
// create txs
|
// create txs
|
||||||
txs := make(types.Transactions, 0, daBlock.NumTransactions())
|
txs := make(types.Transactions, 0, daBlock.NumTransactions())
|
||||||
// insert l1 msgs
|
// insert l1 msgs
|
||||||
for l1TxPointer < len(c.l1Txs) && c.l1Txs[l1TxPointer].QueueIndex < curL1TxIndex+uint64(daBlock.NumL1Messages()) {
|
for l1TxPointer < len(l1Txs) && l1Txs[l1TxPointer].QueueIndex < curL1TxIndex+uint64(daBlock.NumL1Messages()) {
|
||||||
l1Tx := types.NewTx(c.l1Txs[l1TxPointer])
|
l1Tx := types.NewTx(l1Txs[l1TxPointer])
|
||||||
txs = append(txs, l1Tx)
|
txs = append(txs, l1Tx)
|
||||||
l1TxPointer++
|
l1TxPointer++
|
||||||
}
|
}
|
||||||
|
|
@ -144,7 +148,19 @@ func (c *CommitBatchDAV0) Blocks() []*PartialBlock {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return blocks
|
return blocks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommitBatchDAV0) SetParentTotalL1MessagePopped(totalL1MessagePopped uint64) {
|
||||||
|
// we ignore setting parentTotalL1MessagePopped from outside as it is calculated from parent batch header for V0 batches
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommitBatchDAV0) TotalL1MessagesPopped() uint64 {
|
||||||
|
return c.parentTotalL1MessagePopped + uint64(c.l1MessagesPopped)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommitBatchDAV0) L1MessagesPoppedInBatch() uint64 {
|
||||||
|
return uint64(c.l1MessagesPopped)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTotalMessagesPoppedFromChunks(decodedChunks []*encoding.DAChunkRawTx) int {
|
func getTotalMessagesPoppedFromChunks(decodedChunks []*encoding.DAChunkRawTx) int {
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type CommitBatchDAV7 struct {
|
type CommitBatchDAV7 struct {
|
||||||
version encoding.CodecVersion
|
db ethdb.Database
|
||||||
batchIndex uint64
|
|
||||||
initialL1MessageIndex uint64
|
version encoding.CodecVersion
|
||||||
blocks []encoding.DABlock
|
batchIndex uint64
|
||||||
transactions []types.Transactions
|
versionedHashes []common.Hash
|
||||||
l1Txs []types.Transactions
|
blobPayload encoding.DABlobPayload
|
||||||
versionedHashes []common.Hash
|
|
||||||
|
parentTotalL1MessagePopped uint64
|
||||||
|
l1MessagesPopped uint64
|
||||||
|
|
||||||
event *l1.CommitBatchEvent
|
event *l1.CommitBatchEvent
|
||||||
}
|
}
|
||||||
|
|
@ -71,20 +73,14 @@ func NewCommitBatchDAV7(ctx context.Context, db ethdb.Database,
|
||||||
return nil, fmt.Errorf("failed to decode blob: %w", err)
|
return nil, fmt.Errorf("failed to decode blob: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
l1Txs, err := getL1MessagesV7(db, blobPayload.Blocks(), blobPayload.InitialL1MessageIndex())
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get L1 messages for v7 batch %d: %w", commitEvent.BatchIndex().Uint64(), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &CommitBatchDAV7{
|
return &CommitBatchDAV7{
|
||||||
version: codec.Version(),
|
db: db,
|
||||||
batchIndex: commitEvent.BatchIndex().Uint64(),
|
version: codec.Version(),
|
||||||
initialL1MessageIndex: blobPayload.InitialL1MessageIndex(),
|
batchIndex: commitEvent.BatchIndex().Uint64(),
|
||||||
blocks: blobPayload.Blocks(),
|
versionedHashes: []common.Hash{blobVersionedHash},
|
||||||
transactions: blobPayload.Transactions(),
|
blobPayload: blobPayload,
|
||||||
l1Txs: l1Txs,
|
l1MessagesPopped: getL1MessagesPoppedFromBlocks(blobPayload.Blocks()),
|
||||||
versionedHashes: []common.Hash{blobVersionedHash},
|
event: commitEvent,
|
||||||
event: commitEvent,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,18 +113,26 @@ func (c *CommitBatchDAV7) Event() l1.RollupEvent {
|
||||||
return c.event
|
return c.event
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CommitBatchDAV7) Blocks() []*PartialBlock {
|
func (c *CommitBatchDAV7) Blocks() ([]*PartialBlock, error) {
|
||||||
|
initialL1MessageIndex := c.parentTotalL1MessagePopped
|
||||||
|
|
||||||
|
l1Txs, err := getL1MessagesV7(c.db, c.blobPayload.Blocks(), initialL1MessageIndex)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get L1 messages for v7 batch %d: %w", c.event.BatchIndex().Uint64(), err)
|
||||||
|
}
|
||||||
|
|
||||||
var blocks []*PartialBlock
|
var blocks []*PartialBlock
|
||||||
|
|
||||||
for i, daBlock := range c.blocks {
|
for i, daBlock := range c.blobPayload.Blocks() {
|
||||||
// create txs
|
// create txs
|
||||||
txs := make(types.Transactions, 0, daBlock.NumTransactions())
|
txs := make(types.Transactions, 0, daBlock.NumTransactions())
|
||||||
|
|
||||||
// insert L1 messages
|
// insert L1 messages
|
||||||
txs = append(txs, c.l1Txs[i]...)
|
txs = append(txs, l1Txs[i]...)
|
||||||
|
// TODO: sanity check L1 messages with prev and post hashes
|
||||||
|
|
||||||
// insert L2 txs
|
// insert L2 txs
|
||||||
txs = append(txs, c.transactions[i]...)
|
txs = append(txs, c.blobPayload.Transactions()[i]...)
|
||||||
|
|
||||||
block := NewPartialBlock(
|
block := NewPartialBlock(
|
||||||
&PartialHeader{
|
&PartialHeader{
|
||||||
|
|
@ -143,7 +147,19 @@ func (c *CommitBatchDAV7) Blocks() []*PartialBlock {
|
||||||
blocks = append(blocks, block)
|
blocks = append(blocks, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
return blocks
|
return blocks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommitBatchDAV7) SetParentTotalL1MessagePopped(totalL1MessagePopped uint64) {
|
||||||
|
c.parentTotalL1MessagePopped = totalL1MessagePopped
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommitBatchDAV7) TotalL1MessagesPopped() uint64 {
|
||||||
|
return c.parentTotalL1MessagePopped + c.l1MessagesPopped
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommitBatchDAV7) L1MessagesPoppedInBatch() uint64 {
|
||||||
|
return c.l1MessagesPopped
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CommitBatchDAV7) Version() encoding.CodecVersion {
|
func (c *CommitBatchDAV7) Version() encoding.CodecVersion {
|
||||||
|
|
@ -153,8 +169,8 @@ func (c *CommitBatchDAV7) Version() encoding.CodecVersion {
|
||||||
func (c *CommitBatchDAV7) Chunks() []*encoding.DAChunkRawTx {
|
func (c *CommitBatchDAV7) Chunks() []*encoding.DAChunkRawTx {
|
||||||
return []*encoding.DAChunkRawTx{
|
return []*encoding.DAChunkRawTx{
|
||||||
{
|
{
|
||||||
Blocks: c.blocks,
|
Blocks: c.blobPayload.Blocks(),
|
||||||
Transactions: c.transactions,
|
Transactions: c.blobPayload.Transactions(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -189,3 +205,13 @@ func getL1MessagesV7(db ethdb.Database, blocks []encoding.DABlock, initialL1Mess
|
||||||
|
|
||||||
return allTxs, nil
|
return allTxs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getL1MessagesPoppedFromBlocks(blocks []encoding.DABlock) uint64 {
|
||||||
|
var totalL1MessagePopped uint64
|
||||||
|
|
||||||
|
for _, block := range blocks {
|
||||||
|
totalL1MessagePopped += uint64(block.NumL1Messages())
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalL1MessagePopped
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,13 @@ type Entry interface {
|
||||||
|
|
||||||
type EntryWithBlocks interface {
|
type EntryWithBlocks interface {
|
||||||
Entry
|
Entry
|
||||||
Blocks() []*PartialBlock
|
Blocks() ([]*PartialBlock, error)
|
||||||
Version() encoding.CodecVersion
|
Version() encoding.CodecVersion
|
||||||
Chunks() []*encoding.DAChunkRawTx
|
Chunks() []*encoding.DAChunkRawTx
|
||||||
BlobVersionedHashes() []common.Hash
|
BlobVersionedHashes() []common.Hash
|
||||||
|
SetParentTotalL1MessagePopped(uint64)
|
||||||
|
TotalL1MessagesPopped() uint64
|
||||||
|
L1MessagesPoppedInBatch() uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type Entries []Entry
|
type Entries []Entry
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type RevertBatch struct {
|
type RevertBatch struct {
|
||||||
event *l1.RevertBatchEvent
|
event l1.RollupEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRevertBatch(event *l1.RevertBatchEvent) *RevertBatch {
|
func NewRevertBatch(event l1.RollupEvent) *RevertBatch {
|
||||||
return &RevertBatch{
|
return &RevertBatch{
|
||||||
event: event,
|
event: event,
|
||||||
}
|
}
|
||||||
|
|
@ -21,6 +21,7 @@ func (r *RevertBatch) Type() Type {
|
||||||
func (r *RevertBatch) L1BlockNumber() uint64 {
|
func (r *RevertBatch) L1BlockNumber() uint64 {
|
||||||
return r.event.BlockNumber()
|
return r.event.BlockNumber()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RevertBatch) BatchIndex() uint64 {
|
func (r *RevertBatch) BatchIndex() uint64 {
|
||||||
return r.event.BatchIndex().Uint64()
|
return r.event.BatchIndex().Uint64()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,25 +4,23 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/scroll-tech/go-ethereum/log"
|
"github.com/scroll-tech/go-ethereum/core/rawdb"
|
||||||
"github.com/scroll-tech/go-ethereum/rollup/da_syncer/da"
|
"github.com/scroll-tech/go-ethereum/rollup/da_syncer/da"
|
||||||
"github.com/scroll-tech/go-ethereum/rollup/da_syncer/serrors"
|
"github.com/scroll-tech/go-ethereum/rollup/da_syncer/serrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DAQueue is a pipeline stage that reads DA entries from a DataSource and provides them to the next stage.
|
// DAQueue is a pipeline stage that reads DA entries from a DataSource and provides them to the next stage.
|
||||||
type DAQueue struct {
|
type DAQueue struct {
|
||||||
l1height uint64
|
l1height uint64
|
||||||
initialBatch uint64
|
|
||||||
|
|
||||||
dataSourceFactory *DataSourceFactory
|
dataSourceFactory *DataSourceFactory
|
||||||
dataSource DataSource
|
dataSource DataSource
|
||||||
da da.Entries
|
da da.Entries
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDAQueue(l1height uint64, initialBatch uint64, dataSourceFactory *DataSourceFactory) *DAQueue {
|
func NewDAQueue(l1height uint64, dataSourceFactory *DataSourceFactory) *DAQueue {
|
||||||
return &DAQueue{
|
return &DAQueue{
|
||||||
l1height: l1height,
|
l1height: l1height,
|
||||||
initialBatch: initialBatch,
|
|
||||||
dataSourceFactory: dataSourceFactory,
|
dataSourceFactory: dataSourceFactory,
|
||||||
dataSource: nil,
|
dataSource: nil,
|
||||||
da: make(da.Entries, 0),
|
da: make(da.Entries, 0),
|
||||||
|
|
@ -47,11 +45,6 @@ func (dq *DAQueue) NextDA(ctx context.Context) (da.Entry, error) {
|
||||||
daEntry := dq.da[0]
|
daEntry := dq.da[0]
|
||||||
dq.da = dq.da[1:]
|
dq.da = dq.da[1:]
|
||||||
|
|
||||||
if daEntry.BatchIndex() < dq.initialBatch {
|
|
||||||
log.Debug("Skipping DA entry due to initial batch requirement", "batchIndex", daEntry.BatchIndex(), "initialBatch", dq.initialBatch)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
return daEntry, nil
|
return daEntry, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -86,8 +79,8 @@ func (dq *DAQueue) DataSource() DataSource {
|
||||||
return dq.dataSource
|
return dq.dataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dq *DAQueue) Reset(height uint64) {
|
func (dq *DAQueue) Reset(lastProcessedBatchMeta *rawdb.DAProcessedBatchMeta) {
|
||||||
dq.l1height = height
|
dq.l1height = lastProcessedBatchMeta.L1BlockNumber
|
||||||
dq.dataSource = nil
|
dq.dataSource = nil
|
||||||
dq.da = make(da.Entries, 0)
|
dq.da = make(da.Entries, 0)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
136
rollup/da_syncer/l1_message_queue_height_finder.go
Normal file
136
rollup/da_syncer/l1_message_queue_height_finder.go
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
package da_syncer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/scroll-tech/go-ethereum/ethdb"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/da_syncer/blob_client"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/da_syncer/da"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/l1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type L1MessageQueueHeightFinder struct {
|
||||||
|
ctx context.Context
|
||||||
|
calldataBlobSource *da.CalldataBlobSource
|
||||||
|
l1Reader *l1.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewL1MessageQueueHeightFinder(ctx context.Context, l1height uint64, l1Reader *l1.Reader, blobClient blob_client.BlobClient, db ethdb.Database) (*L1MessageQueueHeightFinder, error) {
|
||||||
|
calldataBlobSource, err := da.NewCalldataBlobSource(ctx, l1height, l1Reader, blobClient, db)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create calldata blob source: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &L1MessageQueueHeightFinder{
|
||||||
|
ctx: ctx,
|
||||||
|
calldataBlobSource: calldataBlobSource,
|
||||||
|
l1Reader: l1Reader,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TotalL1MessagesPoppedBefore finds the total L1 messages popped (L1 message queue height) before target batch.
|
||||||
|
// It does so by:
|
||||||
|
// 1. find bundle in which target batch was finalized
|
||||||
|
// 2. fetch the tx of the bundle to get the height of the L1 message queue after the bundle
|
||||||
|
// 3. with this information we can calculate the L1 message count for each batch from last finalized bundle to the target batch.
|
||||||
|
func (f *L1MessageQueueHeightFinder) TotalL1MessagesPoppedBefore(targetBatch uint64) (uint64, error) {
|
||||||
|
batches := make(map[uint64]da.EntryWithBlocks)
|
||||||
|
|
||||||
|
finalizedBundle, err := f.findFinalizedBundle(targetBatch, batches)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to find the bundle in which the target batch was finalized")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. fetch tx of the bundle to get the TotalL1MessagesPoppedOverall after the bundle and the first batch within the bundle.
|
||||||
|
args, err := f.l1Reader.FetchFinalizeTxDataPostEuclidV2(finalizedBundle.Event().(*l1.FinalizeBatchEvent))
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to fetch finalize tx data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. with this information we can calculate the L1 message queue height for target batch: for each batch from last finalized batch to the target batch subtract L1 messages popped in the batch from L1 message queue height
|
||||||
|
lastBatchInBundle := finalizedBundle.BatchIndex()
|
||||||
|
|
||||||
|
var l1MessageQueueHeight uint64
|
||||||
|
// totalL1MessagesPoppedOverall is the number of messages processed after the bundle -> subtract 1 to get the last message in the bundle
|
||||||
|
if args.TotalL1MessagesPoppedOverall.Uint64() > 0 {
|
||||||
|
l1MessageQueueHeight = args.TotalL1MessagesPoppedOverall.Uint64() - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := lastBatchInBundle; i >= targetBatch; i-- {
|
||||||
|
batch, ok := batches[i]
|
||||||
|
if !ok {
|
||||||
|
return 0, fmt.Errorf("batch %d not found", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
if batch.L1MessagesPoppedInBatch() > l1MessageQueueHeight {
|
||||||
|
return 0, fmt.Errorf("L1 message queue height is less than L1 messages popped in batch %d (%d < %d)", i, l1MessageQueueHeight, batch.L1MessagesPoppedInBatch())
|
||||||
|
}
|
||||||
|
l1MessageQueueHeight -= batch.L1MessagesPoppedInBatch()
|
||||||
|
}
|
||||||
|
|
||||||
|
return l1MessageQueueHeight, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *L1MessageQueueHeightFinder) findFinalizedBundle(targetBatch uint64, batches map[uint64]da.EntryWithBlocks) (*da.FinalizeBatch, error) {
|
||||||
|
for {
|
||||||
|
// 1. find bundle in which target batch was finalized
|
||||||
|
daEntries, err := f.calldataBlobSource.NextData()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get next data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, daEntry := range daEntries {
|
||||||
|
switch daEntry.Type() {
|
||||||
|
case da.CommitBatchV0Type, da.CommitBatchWithBlobType:
|
||||||
|
daEntryWithBlocks, ok := daEntry.(da.EntryWithBlocks)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unexpected type of daEntry: %T, expected EntryWithBlocks", daEntry)
|
||||||
|
}
|
||||||
|
|
||||||
|
// save the batch for later use
|
||||||
|
batches[daEntry.BatchIndex()] = daEntryWithBlocks
|
||||||
|
case da.RevertBatchType:
|
||||||
|
if err = f.handleRevertEvent(batches, daEntry.Event()); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to handle revert event: %w", err)
|
||||||
|
}
|
||||||
|
case da.FinalizeBatchType:
|
||||||
|
// the finalized event is triggered only for the last batch in the bundle:
|
||||||
|
// we found the bundle in which the target batch was finalized
|
||||||
|
if daEntry.BatchIndex() >= targetBatch {
|
||||||
|
return daEntry.(*da.FinalizeBatch), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unexpected type of daEntry: %T", daEntry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *L1MessageQueueHeightFinder) handleRevertEvent(batches map[uint64]da.EntryWithBlocks, event l1.RollupEvent) error {
|
||||||
|
switch event.Type() {
|
||||||
|
case l1.RevertEventV0Type:
|
||||||
|
revertBatch, ok := event.(*l1.RevertBatchEventV0)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type of revert event: %T, expected RevertEventV0Type", event)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(batches, revertBatch.BatchIndex().Uint64())
|
||||||
|
case l1.RevertEventV7Type:
|
||||||
|
revertBatch, ok := event.(*l1.RevertBatchEventV7)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type of revert event: %T, expected RevertEventV7Type", event)
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete all batches from revertBatch.StartBatchIndex (inclusive) to revertBatch.FinishBatchIndex (inclusive)
|
||||||
|
for i := revertBatch.StartBatchIndex().Uint64(); i <= revertBatch.FinishBatchIndex().Uint64(); i++ {
|
||||||
|
delete(batches, i)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unexpected type of revert event: %T", event)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -79,29 +79,51 @@ func NewSyncingPipeline(ctx context.Context, blockchain *core.BlockChain, genesi
|
||||||
}
|
}
|
||||||
|
|
||||||
dataSourceFactory := NewDataSourceFactory(blockchain, genesisConfig, config, l1Reader, blobClientList, db)
|
dataSourceFactory := NewDataSourceFactory(blockchain, genesisConfig, config, l1Reader, blobClientList, db)
|
||||||
var initialL1Block uint64
|
var lastProcessedBatchMeta *rawdb.DAProcessedBatchMeta
|
||||||
if config.RecoveryMode {
|
if config.RecoveryMode {
|
||||||
initialL1Block = config.InitialL1Block
|
if config.InitialL1Block == 0 {
|
||||||
if initialL1Block == 0 {
|
|
||||||
return nil, errors.New("sync from DA: initial L1 block must be set in recovery mode")
|
return nil, errors.New("sync from DA: initial L1 block must be set in recovery mode")
|
||||||
}
|
}
|
||||||
if config.InitialBatch == 0 {
|
if config.InitialBatch == 0 {
|
||||||
return nil, errors.New("sync from DA: initial batch must be set in recovery mode")
|
return nil, errors.New("sync from DA: initial batch must be set in recovery mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("sync from DA: initializing pipeline in recovery mode", "initialL1Block", initialL1Block, "initialBatch", config.InitialBatch)
|
l1MessageQueueHeightFinder, err := NewL1MessageQueueHeightFinder(ctx, config.InitialL1Block, l1Reader, blobClientList, db)
|
||||||
} else {
|
if err != nil {
|
||||||
initialL1Block = l1DeploymentBlock - 1
|
return nil, fmt.Errorf("failed to create L1MessageQueueHeightFinder: %w", err)
|
||||||
config.InitialL1Block = initialL1Block
|
|
||||||
from := rawdb.ReadDASyncedL1BlockNumber(db)
|
|
||||||
if from != nil {
|
|
||||||
initialL1Block = *from
|
|
||||||
}
|
}
|
||||||
log.Info("sync from DA: initializing pipeline", "initialL1Block", initialL1Block)
|
|
||||||
|
l1MessageQueueHeightBeforeInitialBatch, err := l1MessageQueueHeightFinder.TotalL1MessagesPoppedBefore(config.InitialBatch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to find L1 message queue height before initial batch: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
lastProcessedBatchMeta = &rawdb.DAProcessedBatchMeta{
|
||||||
|
BatchIndex: config.InitialBatch,
|
||||||
|
L1BlockNumber: config.InitialL1Block,
|
||||||
|
TotalL1MessagesPopped: l1MessageQueueHeightBeforeInitialBatch,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("sync from DA: initializing pipeline in recovery mode", "initialL1Block", config.InitialL1Block, "initialBatch", config.InitialBatch, "L1BlockNumber", lastProcessedBatchMeta.L1BlockNumber, "TotalL1MessagesPopped", lastProcessedBatchMeta.TotalL1MessagesPopped)
|
||||||
|
} else {
|
||||||
|
lastProcessedBatchMeta = rawdb.ReadDAProcessedBatchMeta(db)
|
||||||
|
if lastProcessedBatchMeta == nil {
|
||||||
|
var l1BlockNumber uint64
|
||||||
|
if l1DeploymentBlock > 0 {
|
||||||
|
l1BlockNumber = l1DeploymentBlock - 1
|
||||||
|
}
|
||||||
|
lastProcessedBatchMeta = &rawdb.DAProcessedBatchMeta{
|
||||||
|
BatchIndex: 0,
|
||||||
|
L1BlockNumber: l1BlockNumber,
|
||||||
|
TotalL1MessagesPopped: 0,
|
||||||
|
}
|
||||||
|
rawdb.WriteDAProcessedBatchMeta(db, lastProcessedBatchMeta)
|
||||||
|
}
|
||||||
|
log.Info("sync from DA: initializing pipeline", "BatchIndex", lastProcessedBatchMeta.BatchIndex, "L1BlockNumber", lastProcessedBatchMeta.L1BlockNumber, "TotalL1MessagesPopped", lastProcessedBatchMeta.TotalL1MessagesPopped)
|
||||||
}
|
}
|
||||||
|
|
||||||
daQueue := NewDAQueue(initialL1Block, config.InitialBatch, dataSourceFactory)
|
daQueue := NewDAQueue(lastProcessedBatchMeta.L1BlockNumber, dataSourceFactory)
|
||||||
batchQueue := NewBatchQueue(daQueue, db)
|
batchQueue := NewBatchQueue(daQueue, db, lastProcessedBatchMeta)
|
||||||
blockQueue := NewBlockQueue(batchQueue)
|
blockQueue := NewBlockQueue(batchQueue)
|
||||||
daSyncer := NewDASyncer(blockchain, config.L2EndBlock)
|
daSyncer := NewDASyncer(blockchain, config.L2EndBlock)
|
||||||
|
|
||||||
|
|
@ -260,12 +282,21 @@ func (s *SyncingPipeline) Stop() {
|
||||||
|
|
||||||
func (s *SyncingPipeline) reset(resetCounter int) {
|
func (s *SyncingPipeline) reset(resetCounter int) {
|
||||||
amount := 100 * uint64(resetCounter)
|
amount := 100 * uint64(resetCounter)
|
||||||
syncedL1Height := s.config.InitialL1Block
|
|
||||||
from := rawdb.ReadDASyncedL1BlockNumber(s.db)
|
lastProcessedBatchMeta := rawdb.ReadDAProcessedBatchMeta(s.db)
|
||||||
if from != nil && *from+amount > syncedL1Height {
|
if lastProcessedBatchMeta == nil {
|
||||||
syncedL1Height = *from - amount
|
lastProcessedBatchMeta = &rawdb.DAProcessedBatchMeta{
|
||||||
rawdb.WriteDASyncedL1BlockNumber(s.db, syncedL1Height)
|
BatchIndex: 0,
|
||||||
|
L1BlockNumber: s.config.InitialL1Block - amount,
|
||||||
|
TotalL1MessagesPopped: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
log.Info("resetting syncing pipeline", "syncedL1Height", syncedL1Height)
|
|
||||||
s.blockQueue.Reset(syncedL1Height)
|
if lastProcessedBatchMeta.L1BlockNumber > amount {
|
||||||
|
lastProcessedBatchMeta.L1BlockNumber -= amount
|
||||||
|
rawdb.WriteDAProcessedBatchMeta(s.db, lastProcessedBatchMeta)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("resetting syncing pipeline", "batch index", lastProcessedBatchMeta.BatchIndex, "L1BlockNumber", lastProcessedBatchMeta.L1BlockNumber, "TotalL1MessagesPopped", lastProcessedBatchMeta.TotalL1MessagesPopped)
|
||||||
|
s.blockQueue.Reset(lastProcessedBatchMeta)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
124
rollup/l1/abi.go
124
rollup/l1/abi.go
File diff suppressed because one or more lines are too long
|
|
@ -12,13 +12,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEventSignatures(t *testing.T) {
|
func TestEventSignatures(t *testing.T) {
|
||||||
assert.Equal(t, crypto.Keccak256Hash([]byte("CommitBatch(uint256,bytes32)")), ScrollChainABI.Events["CommitBatch"].ID)
|
assert.Equal(t, crypto.Keccak256Hash([]byte("CommitBatch(uint256,bytes32)")), ScrollChainABI.Events[commitBatchEventName].ID)
|
||||||
assert.Equal(t, crypto.Keccak256Hash([]byte("RevertBatch(uint256,bytes32)")), ScrollChainABI.Events["RevertBatch"].ID)
|
assert.Equal(t, crypto.Keccak256Hash([]byte("RevertBatch(uint256,bytes32)")), ScrollChainABI.Events[revertBatchV0EventName].ID)
|
||||||
assert.Equal(t, crypto.Keccak256Hash([]byte("FinalizeBatch(uint256,bytes32,bytes32,bytes32)")), ScrollChainABI.Events["FinalizeBatch"].ID)
|
assert.Equal(t, crypto.Keccak256Hash([]byte("RevertBatch(uint256,uint256)")), ScrollChainABI.Events[revertBatchV7EventName].ID)
|
||||||
|
assert.Equal(t, crypto.Keccak256Hash([]byte("FinalizeBatch(uint256,bytes32,bytes32,bytes32)")), ScrollChainABI.Events[finalizeBatchEventName].ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnpackLog(t *testing.T) {
|
func TestUnpackLog(t *testing.T) {
|
||||||
mockBatchIndex := big.NewInt(123)
|
mockBatchIndex := big.NewInt(123)
|
||||||
|
finishMockBatchIndex := big.NewInt(125)
|
||||||
mockBatchHash := crypto.Keccak256Hash([]byte("mockBatch"))
|
mockBatchHash := crypto.Keccak256Hash([]byte("mockBatch"))
|
||||||
mockStateRoot := crypto.Keccak256Hash([]byte("mockStateRoot"))
|
mockStateRoot := crypto.Keccak256Hash([]byte("mockStateRoot"))
|
||||||
mockWithdrawRoot := crypto.Keccak256Hash([]byte("mockWithdrawRoot"))
|
mockWithdrawRoot := crypto.Keccak256Hash([]byte("mockWithdrawRoot"))
|
||||||
|
|
@ -42,16 +44,40 @@ func TestUnpackLog(t *testing.T) {
|
||||||
&CommitBatchEventUnpacked{},
|
&CommitBatchEventUnpacked{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
revertBatchEventName,
|
revertBatchV0EventName,
|
||||||
types.Log{
|
types.Log{
|
||||||
Data: nil,
|
Data: nil,
|
||||||
Topics: []common.Hash{ScrollChainABI.Events[revertBatchEventName].ID, common.BigToHash(mockBatchIndex), mockBatchHash},
|
Topics: []common.Hash{ScrollChainABI.Events[revertBatchV0EventName].ID, common.BigToHash(mockBatchIndex), mockBatchHash},
|
||||||
},
|
},
|
||||||
&RevertBatchEventUnpacked{
|
&RevertBatchEventV0Unpacked{
|
||||||
BatchIndex: mockBatchIndex,
|
BatchIndex: mockBatchIndex,
|
||||||
BatchHash: mockBatchHash,
|
BatchHash: mockBatchHash,
|
||||||
},
|
},
|
||||||
&RevertBatchEventUnpacked{},
|
&RevertBatchEventV0Unpacked{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
revertBatchV7EventName,
|
||||||
|
types.Log{
|
||||||
|
Data: nil,
|
||||||
|
Topics: []common.Hash{ScrollChainABI.Events[revertBatchV7EventName].ID, common.BigToHash(mockBatchIndex), common.BigToHash(mockBatchIndex)},
|
||||||
|
},
|
||||||
|
&RevertBatchEventV7Unpacked{
|
||||||
|
StartBatchIndex: mockBatchIndex,
|
||||||
|
FinishBatchIndex: mockBatchIndex,
|
||||||
|
},
|
||||||
|
&RevertBatchEventV7Unpacked{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
revertBatchV7EventName,
|
||||||
|
types.Log{
|
||||||
|
Data: nil,
|
||||||
|
Topics: []common.Hash{ScrollChainABI.Events[revertBatchV7EventName].ID, common.BigToHash(mockBatchIndex), common.BigToHash(finishMockBatchIndex)},
|
||||||
|
},
|
||||||
|
&RevertBatchEventV7Unpacked{
|
||||||
|
StartBatchIndex: mockBatchIndex,
|
||||||
|
FinishBatchIndex: finishMockBatchIndex,
|
||||||
|
},
|
||||||
|
&RevertBatchEventV7Unpacked{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
finalizeBatchEventName,
|
finalizeBatchEventName,
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
commitBatchEventName = "CommitBatch"
|
commitBatchEventName = "CommitBatch"
|
||||||
revertBatchEventName = "RevertBatch"
|
revertBatchV0EventName = "RevertBatch"
|
||||||
|
revertBatchV7EventName = "RevertBatch0"
|
||||||
finalizeBatchEventName = "FinalizeBatch"
|
finalizeBatchEventName = "FinalizeBatch"
|
||||||
nextUnfinalizedQueueIndex = "nextUnfinalizedQueueIndex"
|
nextUnfinalizedQueueIndex = "nextUnfinalizedQueueIndex"
|
||||||
lastFinalizedBatchIndex = "lastFinalizedBatchIndex"
|
lastFinalizedBatchIndex = "lastFinalizedBatchIndex"
|
||||||
|
|
@ -32,7 +33,8 @@ type Reader struct {
|
||||||
scrollChainABI *abi.ABI
|
scrollChainABI *abi.ABI
|
||||||
l1MessageQueueABI *abi.ABI
|
l1MessageQueueABI *abi.ABI
|
||||||
l1CommitBatchEventSignature common.Hash
|
l1CommitBatchEventSignature common.Hash
|
||||||
l1RevertBatchEventSignature common.Hash
|
l1RevertBatchEventV0Signature common.Hash
|
||||||
|
l1RevertBatchEventV7Signature common.Hash
|
||||||
l1FinalizeBatchEventSignature common.Hash
|
l1FinalizeBatchEventSignature common.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,7 +62,8 @@ func NewReader(ctx context.Context, config Config, l1Client Client) (*Reader, er
|
||||||
scrollChainABI: ScrollChainABI,
|
scrollChainABI: ScrollChainABI,
|
||||||
l1MessageQueueABI: L1MessageQueueABIManual,
|
l1MessageQueueABI: L1MessageQueueABIManual,
|
||||||
l1CommitBatchEventSignature: ScrollChainABI.Events[commitBatchEventName].ID,
|
l1CommitBatchEventSignature: ScrollChainABI.Events[commitBatchEventName].ID,
|
||||||
l1RevertBatchEventSignature: ScrollChainABI.Events[revertBatchEventName].ID,
|
l1RevertBatchEventV0Signature: ScrollChainABI.Events[revertBatchV0EventName].ID,
|
||||||
|
l1RevertBatchEventV7Signature: ScrollChainABI.Events[revertBatchV7EventName].ID,
|
||||||
l1FinalizeBatchEventSignature: ScrollChainABI.Events[finalizeBatchEventName].ID,
|
l1FinalizeBatchEventSignature: ScrollChainABI.Events[finalizeBatchEventName].ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,10 +175,11 @@ func (r *Reader) FetchRollupEventsInRange(from, to uint64) (RollupEvents, error)
|
||||||
},
|
},
|
||||||
Topics: make([][]common.Hash, 1),
|
Topics: make([][]common.Hash, 1),
|
||||||
}
|
}
|
||||||
query.Topics[0] = make([]common.Hash, 3)
|
query.Topics[0] = make([]common.Hash, 4)
|
||||||
query.Topics[0][0] = r.l1CommitBatchEventSignature
|
query.Topics[0][0] = r.l1CommitBatchEventSignature
|
||||||
query.Topics[0][1] = r.l1RevertBatchEventSignature
|
query.Topics[0][1] = r.l1RevertBatchEventV0Signature
|
||||||
query.Topics[0][2] = r.l1FinalizeBatchEventSignature
|
query.Topics[0][2] = r.l1RevertBatchEventV7Signature
|
||||||
|
query.Topics[0][3] = r.l1FinalizeBatchEventSignature
|
||||||
|
|
||||||
logsBatch, err := r.client.FilterLogs(r.ctx, query)
|
logsBatch, err := r.client.FilterLogs(r.ctx, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -203,10 +207,11 @@ func (r *Reader) FetchRollupEventsInRangeWithCallback(from, to uint64, callback
|
||||||
},
|
},
|
||||||
Topics: make([][]common.Hash, 1),
|
Topics: make([][]common.Hash, 1),
|
||||||
}
|
}
|
||||||
query.Topics[0] = make([]common.Hash, 3)
|
query.Topics[0] = make([]common.Hash, 4)
|
||||||
query.Topics[0][0] = r.l1CommitBatchEventSignature
|
query.Topics[0][0] = r.l1CommitBatchEventSignature
|
||||||
query.Topics[0][1] = r.l1RevertBatchEventSignature
|
query.Topics[0][1] = r.l1RevertBatchEventV0Signature
|
||||||
query.Topics[0][2] = r.l1FinalizeBatchEventSignature
|
query.Topics[0][2] = r.l1RevertBatchEventV7Signature
|
||||||
|
query.Topics[0][3] = r.l1FinalizeBatchEventSignature
|
||||||
|
|
||||||
logsBatch, err := r.client.FilterLogs(r.ctx, query)
|
logsBatch, err := r.client.FilterLogs(r.ctx, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -245,7 +250,7 @@ func (r *Reader) processLogsToRollupEvents(logs []types.Log) (RollupEvents, erro
|
||||||
if err = UnpackLog(r.scrollChainABI, event, commitBatchEventName, vLog); err != nil {
|
if err = UnpackLog(r.scrollChainABI, event, commitBatchEventName, vLog); err != nil {
|
||||||
return nil, fmt.Errorf("failed to unpack commit rollup event log, err: %w", err)
|
return nil, fmt.Errorf("failed to unpack commit rollup event log, err: %w", err)
|
||||||
}
|
}
|
||||||
log.Trace("found new CommitBatch event", "batch index", event.BatchIndex.Uint64())
|
log.Trace("found new CommitBatch event", "batch index", event.BatchIndex.Uint64(), "batch hash", event.BatchHash.Hex())
|
||||||
rollupEvent = &CommitBatchEvent{
|
rollupEvent = &CommitBatchEvent{
|
||||||
batchIndex: event.BatchIndex,
|
batchIndex: event.BatchIndex,
|
||||||
batchHash: event.BatchHash,
|
batchHash: event.BatchHash,
|
||||||
|
|
@ -254,26 +259,39 @@ func (r *Reader) processLogsToRollupEvents(logs []types.Log) (RollupEvents, erro
|
||||||
blockNumber: vLog.BlockNumber,
|
blockNumber: vLog.BlockNumber,
|
||||||
}
|
}
|
||||||
|
|
||||||
case r.l1RevertBatchEventSignature:
|
case r.l1RevertBatchEventV0Signature:
|
||||||
event := &RevertBatchEventUnpacked{}
|
event := &RevertBatchEventV0Unpacked{}
|
||||||
if err = UnpackLog(r.scrollChainABI, event, revertBatchEventName, vLog); err != nil {
|
if err = UnpackLog(r.scrollChainABI, event, revertBatchV0EventName, vLog); err != nil {
|
||||||
return nil, fmt.Errorf("failed to unpack revert rollup event log, err: %w", err)
|
return nil, fmt.Errorf("failed to unpack revert V0 rollup event log, err: %w", err)
|
||||||
}
|
}
|
||||||
log.Trace("found new RevertBatchType event", "batch index", event.BatchIndex.Uint64())
|
log.Trace("found new RevertBatchV0Type event", "batch index", event.BatchIndex.Uint64(), "batch hash", event.BatchHash.Hex())
|
||||||
rollupEvent = &RevertBatchEvent{
|
rollupEvent = &RevertBatchEventV0{
|
||||||
batchIndex: event.BatchIndex,
|
batchIndex: event.BatchIndex,
|
||||||
batchHash: event.BatchHash,
|
batchHash: event.BatchHash,
|
||||||
txHash: vLog.TxHash,
|
txHash: vLog.TxHash,
|
||||||
blockHash: vLog.BlockHash,
|
blockHash: vLog.BlockHash,
|
||||||
blockNumber: vLog.BlockNumber,
|
blockNumber: vLog.BlockNumber,
|
||||||
}
|
}
|
||||||
|
case r.l1RevertBatchEventV7Signature:
|
||||||
|
event := &RevertBatchEventV7Unpacked{}
|
||||||
|
if err = UnpackLog(r.scrollChainABI, event, revertBatchV7EventName, vLog); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to unpack revert V7 rollup event log, err: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Trace("found new RevertBatchV7Type event", "start batch index", event.StartBatchIndex.Uint64(), "finish batch index", event.FinishBatchIndex.Uint64())
|
||||||
|
rollupEvent = &RevertBatchEventV7{
|
||||||
|
startBatchIndex: event.StartBatchIndex,
|
||||||
|
finishBatchIndex: event.FinishBatchIndex,
|
||||||
|
txHash: vLog.TxHash,
|
||||||
|
blockHash: vLog.BlockHash,
|
||||||
|
blockNumber: vLog.BlockNumber,
|
||||||
|
}
|
||||||
case r.l1FinalizeBatchEventSignature:
|
case r.l1FinalizeBatchEventSignature:
|
||||||
event := &FinalizeBatchEventUnpacked{}
|
event := &FinalizeBatchEventUnpacked{}
|
||||||
if err = UnpackLog(r.scrollChainABI, event, finalizeBatchEventName, vLog); err != nil {
|
if err = UnpackLog(r.scrollChainABI, event, finalizeBatchEventName, vLog); err != nil {
|
||||||
return nil, fmt.Errorf("failed to unpack finalized rollup event log, err: %w", err)
|
return nil, fmt.Errorf("failed to unpack finalized rollup event log, err: %w", err)
|
||||||
}
|
}
|
||||||
log.Trace("found new FinalizeBatchType event", "batch index", event.BatchIndex.Uint64())
|
log.Trace("found new FinalizeBatchType event", "batch index", event.BatchIndex.Uint64(), "batch hash", event.BatchHash.Hex())
|
||||||
rollupEvent = &FinalizeBatchEvent{
|
rollupEvent = &FinalizeBatchEvent{
|
||||||
batchIndex: event.BatchIndex,
|
batchIndex: event.BatchIndex,
|
||||||
batchHash: event.BatchHash,
|
batchHash: event.BatchHash,
|
||||||
|
|
@ -375,6 +393,11 @@ func (r *Reader) FetchCommitTxData(commitEvent *CommitBatchEvent) (*CommitBatchA
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to decode calldata into commitBatch args %s, values: %+v, err: %w", commitBatchWithBlobProofMethodName, values, err)
|
return nil, fmt.Errorf("failed to decode calldata into commitBatch args %s, values: %+v, err: %w", commitBatchWithBlobProofMethodName, values, err)
|
||||||
}
|
}
|
||||||
|
} else if method.Name == commitBatchesV7MethodName {
|
||||||
|
args, err = newCommitBatchArgsFromCommitBatchesV7(method, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode calldata into commitBatch args %s, values: %+v, err: %w", commitBatchesV7MethodName, values, err)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("unknown method name for commit transaction: %s", method.Name)
|
return nil, fmt.Errorf("unknown method name for commit transaction: %s", method.Name)
|
||||||
}
|
}
|
||||||
|
|
@ -383,3 +406,36 @@ func (r *Reader) FetchCommitTxData(commitEvent *CommitBatchEvent) (*CommitBatchA
|
||||||
|
|
||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Reader) FetchFinalizeTxDataPostEuclidV2(event *FinalizeBatchEvent) (*FinalizeBatchArgs, error) {
|
||||||
|
tx, err := r.fetchTx(event.TxHash(), event.BlockHash())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
txData := tx.Data()
|
||||||
|
|
||||||
|
if len(txData) < methodIDLength {
|
||||||
|
return nil, fmt.Errorf("transaction data is too short, length of tx data: %v, minimum length required: %v", len(txData), methodIDLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
method, err := r.scrollChainABI.MethodById(txData[:methodIDLength])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get method by ID, ID: %v, err: %w", txData[:methodIDLength], err)
|
||||||
|
}
|
||||||
|
values, err := method.Inputs.Unpack(txData[methodIDLength:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to unpack transaction data using ABI, tx data: %v, err: %w", txData, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var args *FinalizeBatchArgs
|
||||||
|
if method.Name == finalizeBundlePostEuclidV2MethodName {
|
||||||
|
args, err = newFinalizeBatchArgs(method, values)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode calldata into finalizeBatch args %s, values: %+v, err: %w", finalizeBundlePostEuclidV2MethodName, values, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("unknown method name for finalize transaction: %s", method.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,9 @@ func (s *RollupSyncService) updateRollupEvents(daEntries da.Entries) error {
|
||||||
|
|
||||||
case da.RevertBatchType:
|
case da.RevertBatchType:
|
||||||
log.Trace("found new RevertBatch event", "batch index", entry.BatchIndex())
|
log.Trace("found new RevertBatch event", "batch index", entry.BatchIndex())
|
||||||
rawdb.DeleteCommittedBatchMeta(s.db, entry.BatchIndex())
|
if err := s.handleRevertEvent(entry.Event()); err != nil {
|
||||||
|
return fmt.Errorf("failed to handle revert event, batch index: %v, err: %w", entry.BatchIndex(), err)
|
||||||
|
}
|
||||||
|
|
||||||
case da.FinalizeBatchType:
|
case da.FinalizeBatchType:
|
||||||
event, ok := entry.Event().(*l1.FinalizeBatchEvent)
|
event, ok := entry.Event().(*l1.FinalizeBatchEvent)
|
||||||
|
|
@ -321,6 +323,33 @@ func (s *RollupSyncService) updateRollupEvents(daEntries da.Entries) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *RollupSyncService) handleRevertEvent(event l1.RollupEvent) error {
|
||||||
|
switch event.Type() {
|
||||||
|
case l1.RevertEventV0Type:
|
||||||
|
revertBatch, ok := event.(*l1.RevertBatchEventV0)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type of revert event: %T, expected RevertEventV0Type", event)
|
||||||
|
}
|
||||||
|
|
||||||
|
rawdb.DeleteCommittedBatchMeta(s.db, revertBatch.BatchIndex().Uint64())
|
||||||
|
|
||||||
|
case l1.RevertEventV7Type:
|
||||||
|
revertBatch, ok := event.(*l1.RevertBatchEventV7)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type of revert event: %T, expected RevertEventV7Type", event)
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete all batches from revertBatch.StartBatchIndex (inclusive) to revertBatch.FinishBatchIndex (inclusive)
|
||||||
|
for i := revertBatch.StartBatchIndex().Uint64(); i <= revertBatch.FinishBatchIndex().Uint64(); i++ {
|
||||||
|
rawdb.DeleteCommittedBatchMeta(s.db, i)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unexpected type of revert event: %T", event)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *RollupSyncService) getLocalChunksForBatch(chunkBlockRanges []*rawdb.ChunkBlockRange) ([]*encoding.Chunk, error) {
|
func (s *RollupSyncService) getLocalChunksForBatch(chunkBlockRanges []*rawdb.ChunkBlockRange) ([]*encoding.Chunk, error) {
|
||||||
if len(chunkBlockRanges) == 0 {
|
if len(chunkBlockRanges) == 0 {
|
||||||
return nil, fmt.Errorf("chunkBlockRanges is empty")
|
return nil, fmt.Errorf("chunkBlockRanges is empty")
|
||||||
|
|
@ -377,7 +406,7 @@ func (s *RollupSyncService) getCommittedBatchMeta(commitedBatch da.EntryWithBloc
|
||||||
return &rawdb.CommittedBatchMeta{
|
return &rawdb.CommittedBatchMeta{
|
||||||
Version: 0,
|
Version: 0,
|
||||||
ChunkBlockRanges: []*rawdb.ChunkBlockRange{{StartBlockNumber: 0, EndBlockNumber: 0}},
|
ChunkBlockRanges: []*rawdb.ChunkBlockRange{{StartBlockNumber: 0, EndBlockNumber: 0}},
|
||||||
LastL1MessageQueueHash: common.Hash{},
|
PostL1MessageQueueHash: common.Hash{},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -386,8 +415,8 @@ func (s *RollupSyncService) getCommittedBatchMeta(commitedBatch da.EntryWithBloc
|
||||||
return nil, fmt.Errorf("failed to decode block ranges from chunks, batch index: %v, err: %w", commitedBatch.BatchIndex(), err)
|
return nil, fmt.Errorf("failed to decode block ranges from chunks, batch index: %v, err: %w", commitedBatch.BatchIndex(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// With CodecV7 the batch creation changed. We need to compute and store LastL1MessageQueueHash.
|
// With CodecV7 the batch creation changed. We need to compute and store PostL1MessageQueueHash.
|
||||||
// InitialL1MessageQueueHash of a batch == LastL1MessageQueueHash of the previous batch.
|
// PrevL1MessageQueueHash of a batch == PostL1MessageQueueHash of the previous batch.
|
||||||
// We need to do this for every committed batch (instead of finalized batch) because the L1MessageQueueHash
|
// We need to do this for every committed batch (instead of finalized batch) because the L1MessageQueueHash
|
||||||
// is a continuous hash of all L1 messages over all batches. With bundles we only receive the finalize event
|
// is a continuous hash of all L1 messages over all batches. With bundles we only receive the finalize event
|
||||||
// for the last batch of the bundle.
|
// for the last batch of the bundle.
|
||||||
|
|
@ -399,12 +428,12 @@ func (s *RollupSyncService) getCommittedBatchMeta(commitedBatch da.EntryWithBloc
|
||||||
}
|
}
|
||||||
|
|
||||||
// If parent batch has a lower version this means this is the first batch of CodecV7.
|
// If parent batch has a lower version this means this is the first batch of CodecV7.
|
||||||
// In this case we need to compute the InitialL1MessageQueueHash from the empty hash.
|
// In this case we need to compute the prevL1MessageQueueHash from the empty hash.
|
||||||
var initialL1MessageQueueHash common.Hash
|
var prevL1MessageQueueHash common.Hash
|
||||||
if encoding.CodecVersion(parentCommittedBatchMeta.Version) < commitedBatch.Version() {
|
if encoding.CodecVersion(parentCommittedBatchMeta.Version) < commitedBatch.Version() {
|
||||||
initialL1MessageQueueHash = common.Hash{}
|
prevL1MessageQueueHash = common.Hash{}
|
||||||
} else {
|
} else {
|
||||||
initialL1MessageQueueHash = parentCommittedBatchMeta.LastL1MessageQueueHash
|
prevL1MessageQueueHash = parentCommittedBatchMeta.PostL1MessageQueueHash
|
||||||
}
|
}
|
||||||
|
|
||||||
chunks, err := s.getLocalChunksForBatch(chunkRanges)
|
chunks, err := s.getLocalChunksForBatch(chunkRanges)
|
||||||
|
|
@ -419,7 +448,7 @@ func (s *RollupSyncService) getCommittedBatchMeta(commitedBatch da.EntryWithBloc
|
||||||
return nil, fmt.Errorf("invalid argument: chunk count is not 1 for CodecV7, batch index: %v", commitedBatch.BatchIndex())
|
return nil, fmt.Errorf("invalid argument: chunk count is not 1 for CodecV7, batch index: %v", commitedBatch.BatchIndex())
|
||||||
}
|
}
|
||||||
|
|
||||||
lastL1MessageQueueHash, err = encoding.MessageQueueV2ApplyL1MessagesFromBlocks(initialL1MessageQueueHash, chunks[0].Blocks)
|
lastL1MessageQueueHash, err = encoding.MessageQueueV2ApplyL1MessagesFromBlocks(prevL1MessageQueueHash, chunks[0].Blocks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to apply L1 messages from blocks, batch index: %v, err: %w", chunks[0], err)
|
return nil, fmt.Errorf("failed to apply L1 messages from blocks, batch index: %v, err: %w", chunks[0], err)
|
||||||
}
|
}
|
||||||
|
|
@ -428,7 +457,7 @@ func (s *RollupSyncService) getCommittedBatchMeta(commitedBatch da.EntryWithBloc
|
||||||
return &rawdb.CommittedBatchMeta{
|
return &rawdb.CommittedBatchMeta{
|
||||||
Version: uint8(commitedBatch.Version()),
|
Version: uint8(commitedBatch.Version()),
|
||||||
ChunkBlockRanges: chunkRanges,
|
ChunkBlockRanges: chunkRanges,
|
||||||
LastL1MessageQueueHash: lastL1MessageQueueHash,
|
PostL1MessageQueueHash: lastL1MessageQueueHash,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -490,12 +519,11 @@ func validateBatch(batchIndex uint64, event *l1.FinalizeBatchEvent, parentFinali
|
||||||
}
|
}
|
||||||
|
|
||||||
batch = &encoding.Batch{
|
batch = &encoding.Batch{
|
||||||
Index: batchIndex,
|
Index: batchIndex,
|
||||||
ParentBatchHash: parentFinalizedBatchMeta.BatchHash,
|
ParentBatchHash: parentFinalizedBatchMeta.BatchHash,
|
||||||
InitialL1MessageIndex: parentFinalizedBatchMeta.TotalL1MessagePopped,
|
Blocks: startChunk.Blocks,
|
||||||
Blocks: startChunk.Blocks,
|
PrevL1MessageQueueHash: parentCommittedBatchMeta.PostL1MessageQueueHash,
|
||||||
InitialL1MessageQueueHash: parentCommittedBatchMeta.LastL1MessageQueueHash,
|
PostL1MessageQueueHash: committedBatchMeta.PostL1MessageQueueHash,
|
||||||
LastL1MessageQueueHash: committedBatchMeta.LastL1MessageQueueHash,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,10 @@ type mockEntryWithBlocks struct {
|
||||||
versionedHashes []common.Hash
|
versionedHashes []common.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m mockEntryWithBlocks) L1MessagesPoppedInBatch() uint64 {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
func (m mockEntryWithBlocks) Type() da.Type {
|
func (m mockEntryWithBlocks) Type() da.Type {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
@ -181,7 +185,7 @@ func (m mockEntryWithBlocks) Event() l1.RollupEvent {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m mockEntryWithBlocks) Blocks() []*da.PartialBlock {
|
func (m mockEntryWithBlocks) Blocks() ([]*da.PartialBlock, error) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -193,6 +197,14 @@ func (m mockEntryWithBlocks) Chunks() []*encoding.DAChunkRawTx {
|
||||||
return m.chunks
|
return m.chunks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m mockEntryWithBlocks) SetParentTotalL1MessagePopped(totalL1MessagePopped uint64) {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockEntryWithBlocks) TotalL1MessagesPopped() uint64 {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
func (m mockEntryWithBlocks) BlobVersionedHashes() []common.Hash {
|
func (m mockEntryWithBlocks) BlobVersionedHashes() []common.Hash {
|
||||||
return m.versionedHashes
|
return m.versionedHashes
|
||||||
}
|
}
|
||||||
|
|
@ -667,11 +679,10 @@ func TestValidateBatchCodecV7(t *testing.T) {
|
||||||
{
|
{
|
||||||
block1 := replaceBlockNumber(readBlockFromJSON(t, "./testdata/blockTrace_02.json"), 1)
|
block1 := replaceBlockNumber(readBlockFromJSON(t, "./testdata/blockTrace_02.json"), 1)
|
||||||
batch1 := &encoding.Batch{
|
batch1 := &encoding.Batch{
|
||||||
Index: 1,
|
Index: 1,
|
||||||
InitialL1MessageIndex: 0,
|
PrevL1MessageQueueHash: common.Hash{},
|
||||||
InitialL1MessageQueueHash: common.Hash{},
|
PostL1MessageQueueHash: common.Hash{},
|
||||||
LastL1MessageQueueHash: common.Hash{},
|
Blocks: []*encoding.Block{block1},
|
||||||
Blocks: []*encoding.Block{block1},
|
|
||||||
}
|
}
|
||||||
batch1LastBlock := batch1.Blocks[len(batch1.Blocks)-1]
|
batch1LastBlock := batch1.Blocks[len(batch1.Blocks)-1]
|
||||||
|
|
||||||
|
|
@ -690,7 +701,7 @@ func TestValidateBatchCodecV7(t *testing.T) {
|
||||||
|
|
||||||
committedBatchMeta1 = &rawdb.CommittedBatchMeta{
|
committedBatchMeta1 = &rawdb.CommittedBatchMeta{
|
||||||
Version: uint8(encoding.CodecV7),
|
Version: uint8(encoding.CodecV7),
|
||||||
LastL1MessageQueueHash: common.Hash{},
|
PostL1MessageQueueHash: common.Hash{},
|
||||||
}
|
}
|
||||||
|
|
||||||
var endBlock1 uint64
|
var endBlock1 uint64
|
||||||
|
|
@ -708,12 +719,11 @@ func TestValidateBatchCodecV7(t *testing.T) {
|
||||||
// finalize 3 batches with CodecV7 at once
|
// finalize 3 batches with CodecV7 at once
|
||||||
block2 := replaceBlockNumber(readBlockFromJSON(t, "./testdata/blockTrace_03.json"), 2)
|
block2 := replaceBlockNumber(readBlockFromJSON(t, "./testdata/blockTrace_03.json"), 2)
|
||||||
batch2 := &encoding.Batch{
|
batch2 := &encoding.Batch{
|
||||||
Index: 2,
|
Index: 2,
|
||||||
ParentBatchHash: finalizedBatchMeta1.BatchHash,
|
ParentBatchHash: finalizedBatchMeta1.BatchHash,
|
||||||
InitialL1MessageIndex: 0,
|
PrevL1MessageQueueHash: common.Hash{},
|
||||||
InitialL1MessageQueueHash: common.Hash{},
|
PostL1MessageQueueHash: common.Hash{},
|
||||||
LastL1MessageQueueHash: common.Hash{},
|
Blocks: []*encoding.Block{block2},
|
||||||
Blocks: []*encoding.Block{block2},
|
|
||||||
}
|
}
|
||||||
batch2LastBlock := batch2.Blocks[len(batch2.Blocks)-1]
|
batch2LastBlock := batch2.Blocks[len(batch2.Blocks)-1]
|
||||||
|
|
||||||
|
|
@ -724,12 +734,11 @@ func TestValidateBatchCodecV7(t *testing.T) {
|
||||||
LastL1MessageQueueHashBatch3, err := encoding.MessageQueueV2ApplyL1MessagesFromBlocks(common.Hash{}, []*encoding.Block{block3})
|
LastL1MessageQueueHashBatch3, err := encoding.MessageQueueV2ApplyL1MessagesFromBlocks(common.Hash{}, []*encoding.Block{block3})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
batch3 := &encoding.Batch{
|
batch3 := &encoding.Batch{
|
||||||
Index: 3,
|
Index: 3,
|
||||||
ParentBatchHash: daBatch2.Hash(),
|
ParentBatchHash: daBatch2.Hash(),
|
||||||
InitialL1MessageIndex: 0,
|
PrevL1MessageQueueHash: common.Hash{},
|
||||||
InitialL1MessageQueueHash: common.Hash{},
|
PostL1MessageQueueHash: LastL1MessageQueueHashBatch3,
|
||||||
LastL1MessageQueueHash: LastL1MessageQueueHashBatch3,
|
Blocks: []*encoding.Block{block3},
|
||||||
Blocks: []*encoding.Block{block3},
|
|
||||||
}
|
}
|
||||||
batch3LastBlock := batch3.Blocks[len(batch3.Blocks)-1]
|
batch3LastBlock := batch3.Blocks[len(batch3.Blocks)-1]
|
||||||
|
|
||||||
|
|
@ -740,12 +749,11 @@ func TestValidateBatchCodecV7(t *testing.T) {
|
||||||
LastL1MessageQueueHashBatch4, err := encoding.MessageQueueV2ApplyL1MessagesFromBlocks(LastL1MessageQueueHashBatch3, []*encoding.Block{block4})
|
LastL1MessageQueueHashBatch4, err := encoding.MessageQueueV2ApplyL1MessagesFromBlocks(LastL1MessageQueueHashBatch3, []*encoding.Block{block4})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
batch4 := &encoding.Batch{
|
batch4 := &encoding.Batch{
|
||||||
Index: 4,
|
Index: 4,
|
||||||
ParentBatchHash: daBatch3.Hash(),
|
ParentBatchHash: daBatch3.Hash(),
|
||||||
InitialL1MessageIndex: 1,
|
PrevL1MessageQueueHash: LastL1MessageQueueHashBatch3,
|
||||||
InitialL1MessageQueueHash: LastL1MessageQueueHashBatch3,
|
PostL1MessageQueueHash: LastL1MessageQueueHashBatch4,
|
||||||
LastL1MessageQueueHash: LastL1MessageQueueHashBatch4,
|
Blocks: []*encoding.Block{block4},
|
||||||
Blocks: []*encoding.Block{block4},
|
|
||||||
}
|
}
|
||||||
batch4LastBlock := batch4.Blocks[len(batch4.Blocks)-1]
|
batch4LastBlock := batch4.Blocks[len(batch4.Blocks)-1]
|
||||||
|
|
||||||
|
|
@ -764,17 +772,17 @@ func TestValidateBatchCodecV7(t *testing.T) {
|
||||||
|
|
||||||
committedBatchMeta2 := &rawdb.CommittedBatchMeta{
|
committedBatchMeta2 := &rawdb.CommittedBatchMeta{
|
||||||
Version: uint8(encoding.CodecV7),
|
Version: uint8(encoding.CodecV7),
|
||||||
LastL1MessageQueueHash: common.Hash{},
|
PostL1MessageQueueHash: common.Hash{},
|
||||||
}
|
}
|
||||||
|
|
||||||
committedBatchMeta3 := &rawdb.CommittedBatchMeta{
|
committedBatchMeta3 := &rawdb.CommittedBatchMeta{
|
||||||
Version: uint8(encoding.CodecV7),
|
Version: uint8(encoding.CodecV7),
|
||||||
LastL1MessageQueueHash: LastL1MessageQueueHashBatch3,
|
PostL1MessageQueueHash: LastL1MessageQueueHashBatch3,
|
||||||
}
|
}
|
||||||
|
|
||||||
committedBatchMeta4 := &rawdb.CommittedBatchMeta{
|
committedBatchMeta4 := &rawdb.CommittedBatchMeta{
|
||||||
Version: uint8(encoding.CodecV7),
|
Version: uint8(encoding.CodecV7),
|
||||||
LastL1MessageQueueHash: LastL1MessageQueueHashBatch4,
|
PostL1MessageQueueHash: LastL1MessageQueueHashBatch4,
|
||||||
}
|
}
|
||||||
|
|
||||||
endBlock2, finalizedBatchMeta2, err := validateBatch(2, event2, finalizedBatchMeta1, committedBatchMeta1, committedBatchMeta2, []*encoding.Chunk{{Blocks: batch2.Blocks}}, nil)
|
endBlock2, finalizedBatchMeta2, err := validateBatch(2, event2, finalizedBatchMeta1, committedBatchMeta1, committedBatchMeta2, []*encoding.Chunk{{Blocks: batch2.Blocks}}, nil)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue