fix(l2geth-verifier): only check last batch of the bundle (#904)

* fix(l2geth-verifier): only check the last batch of each bundle

* refactor function comments

* add more logs to debug

* fix the bug

* Revert "add more logs to debug"

This reverts commit 4befe9fe739275988b4bf34999bd1aad4d7a1d0e.

* tweak

* TestValidateBatchInFinalizeByBundle

* update da-codec dependency

* move rawdb.WriteFinalizedBatchMeta outside the loop

* use batch writer

* change log.Crit to log.Error
This commit is contained in:
colin 2024-07-17 20:01:40 +08:00 committed by GitHub
parent 0cecc1986e
commit 0360eba836
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 133 additions and 53 deletions

2
go.mod
View file

@ -50,7 +50,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.1-0.20240703091800-5b6cded48ab7 github.com/scroll-tech/da-codec v0.1.1-0.20240716101216-c55ed9455cf4
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/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4

4
go.sum
View file

@ -392,8 +392,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.1-0.20240703091800-5b6cded48ab7 h1:UfiLBLCAMBk9bsTP3fc1fETpNVFSQapQVdLcZveyV0M= github.com/scroll-tech/da-codec v0.1.1-0.20240716101216-c55ed9455cf4 h1:40Lby3huKNFZ2EXzxqVpADB+caepDRrNRoUgTsCKN88=
github.com/scroll-tech/da-codec v0.1.1-0.20240703091800-5b6cded48ab7/go.mod h1:D6XEESeNVJkQJlv3eK+FyR+ufPkgVQbJzERylQi53Bs= github.com/scroll-tech/da-codec v0.1.1-0.20240716101216-c55ed9455cf4/go.mod h1:D6XEESeNVJkQJlv3eK+FyR+ufPkgVQbJzERylQi53Bs=
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=

View file

@ -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 = 5 // Minor version component of the current release VersionMinor = 5 // Minor version component of the current release
VersionPatch = 12 // Patch version component of the current release VersionPatch = 13 // 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
) )

View file

@ -242,26 +242,31 @@ func (s *RollupSyncService) parseAndUpdateRollupEventLogs(logs []types.Log, endB
} }
var highestFinalizedBlockNumber uint64 var highestFinalizedBlockNumber uint64
batchWriter := s.db.NewBatch()
for index := startBatchIndex; index <= batchIndex; index++ { for index := startBatchIndex; index <= batchIndex; index++ {
parentBatchMeta, chunks, err := s.getLocalInfoForBatch(index) parentBatchMeta, chunks, err := s.getLocalInfoForBatch(index)
if err != nil { if err != nil {
return fmt.Errorf("failed to get local node info, batch index: %v, err: %w", index, err) return fmt.Errorf("failed to get local node info, batch index: %v, err: %w", index, err)
} }
endBlock, finalizedBatchMeta, err := validateBatch(event, parentBatchMeta, chunks, s.bc.Config(), s.stack) endBlock, finalizedBatchMeta, err := validateBatch(index, event, parentBatchMeta, chunks, s.bc.Config(), s.stack)
if err != nil { if err != nil {
return fmt.Errorf("fatal: validateBatch failed: finalize event: %v, err: %w", event, err) return fmt.Errorf("fatal: validateBatch failed: finalize event: %v, err: %w", event, err)
} }
rawdb.WriteFinalizedBatchMeta(s.db, index, finalizedBatchMeta) rawdb.WriteFinalizedBatchMeta(batchWriter, index, finalizedBatchMeta)
highestFinalizedBlockNumber = endBlock
if index%100 == 0 { if index%100 == 0 {
log.Info("finalized batch progress", "batch index", index, "finalized l2 block height", endBlock) log.Info("finalized batch progress", "batch index", index, "finalized l2 block height", endBlock)
} }
highestFinalizedBlockNumber = endBlock
} }
if err := batchWriter.Write(); err != nil {
log.Error("fatal: failed to batch write finalized batch meta to database", "startBatchIndex", startBatchIndex, "endBatchIndex", batchIndex,
"batchCount", batchIndex-startBatchIndex+1, "highestFinalizedBlockNumber", highestFinalizedBlockNumber, "err", err)
return fmt.Errorf("failed to batch write finalized batch meta to database: %w", err)
}
rawdb.WriteFinalizedL2BlockNumber(s.db, highestFinalizedBlockNumber) rawdb.WriteFinalizedL2BlockNumber(s.db, highestFinalizedBlockNumber)
rawdb.WriteLastFinalizedBatchIndex(s.db, batchIndex) rawdb.WriteLastFinalizedBatchIndex(s.db, batchIndex)
log.Debug("write finalized l2 block number", "batch index", batchIndex, "finalized l2 block height", highestFinalizedBlockNumber) log.Debug("write finalized l2 block number", "batch index", batchIndex, "finalized l2 block height", highestFinalizedBlockNumber)
@ -423,42 +428,48 @@ func (s *RollupSyncService) decodeChunkBlockRanges(txData []byte) ([]*rawdb.Chun
} }
// validateBatch verifies the consistency between the L1 contract and L2 node data. // validateBatch verifies the consistency between the L1 contract and L2 node data.
// It performs the following checks:
// 1. Recalculates the batch hash locally
// 2. Compares local state root, local withdraw root, and locally calculated batch hash with L1 data (for the last batch only when "finalize by bundle")
//
// The function will terminate the node and exit if any consistency check fails. // The function will terminate the node and exit if any consistency check fails.
// It returns the number of the end block, a finalized batch meta data, and an error if any. //
func validateBatch(event *L1FinalizeBatchEvent, parentBatchMeta *rawdb.FinalizedBatchMeta, chunks []*encoding.Chunk, chainCfg *params.ChainConfig, stack *node.Node) (uint64, *rawdb.FinalizedBatchMeta, error) { // Parameters:
// - batchIndex: batch index of the validated batch
// - event: L1 finalize batch event data
// - parentBatchMeta: metadata of the parent batch
// - chunks: slice of chunk data for the current batch
// - chainCfg: chain configuration to identify the codec version
// - stack: node stack to terminate the node in case of inconsistency
//
// Returns:
// - uint64: the end block height of the batch
// - *rawdb.FinalizedBatchMeta: finalized batch metadata
// - error: any error encountered during validation
//
// Note: This function is compatible with both "finalize by batch" and "finalize by bundle" methods.
// In "finalize by bundle", only the last batch of each bundle is fully verified.
// This check still ensures the correctness of all batch hashes in the bundle due to the parent-child relationship between batch hashes.
func validateBatch(batchIndex uint64, event *L1FinalizeBatchEvent, parentBatchMeta *rawdb.FinalizedBatchMeta, chunks []*encoding.Chunk, chainCfg *params.ChainConfig, stack *node.Node) (uint64, *rawdb.FinalizedBatchMeta, error) {
if len(chunks) == 0 { if len(chunks) == 0 {
return 0, nil, fmt.Errorf("invalid argument: length of chunks is 0, batch index: %v", event.BatchIndex.Uint64()) return 0, nil, fmt.Errorf("invalid argument: length of chunks is 0, batch index: %v", batchIndex)
} }
startChunk := chunks[0] startChunk := chunks[0]
if len(startChunk.Blocks) == 0 { if len(startChunk.Blocks) == 0 {
return 0, nil, fmt.Errorf("invalid argument: block count of start chunk is 0, batch index: %v", event.BatchIndex.Uint64()) return 0, nil, fmt.Errorf("invalid argument: block count of start chunk is 0, batch index: %v", batchIndex)
} }
startBlock := startChunk.Blocks[0] startBlock := startChunk.Blocks[0]
endChunk := chunks[len(chunks)-1] endChunk := chunks[len(chunks)-1]
if len(endChunk.Blocks) == 0 { if len(endChunk.Blocks) == 0 {
return 0, nil, fmt.Errorf("invalid argument: block count of end chunk is 0, batch index: %v", event.BatchIndex.Uint64()) return 0, nil, fmt.Errorf("invalid argument: block count of end chunk is 0, batch index: %v", batchIndex)
} }
endBlock := endChunk.Blocks[len(endChunk.Blocks)-1] endBlock := endChunk.Blocks[len(endChunk.Blocks)-1]
localStateRoot := endBlock.Header.Root
if localStateRoot != event.StateRoot {
log.Error("State root mismatch", "batch index", event.BatchIndex.Uint64(), "start block", startBlock.Header.Number.Uint64(), "end block", endBlock.Header.Number.Uint64(), "parent batch hash", parentBatchMeta.BatchHash.Hex(), "l1 finalized state root", event.StateRoot.Hex(), "l2 state root", localStateRoot.Hex())
stack.Close()
os.Exit(1)
}
localWithdrawRoot := endBlock.WithdrawRoot
if localWithdrawRoot != event.WithdrawRoot {
log.Error("Withdraw root mismatch", "batch index", event.BatchIndex.Uint64(), "start block", startBlock.Header.Number.Uint64(), "end block", endBlock.Header.Number.Uint64(), "parent batch hash", parentBatchMeta.BatchHash.Hex(), "l1 finalized withdraw root", event.WithdrawRoot.Hex(), "l2 withdraw root", localWithdrawRoot.Hex())
stack.Close()
os.Exit(1)
}
// Note: All params of batch are calculated locally based on the block data. // Note: All params of batch are calculated locally based on the block data.
batch := &encoding.Batch{ batch := &encoding.Batch{
Index: event.BatchIndex.Uint64(), Index: batchIndex,
TotalL1MessagePoppedBefore: parentBatchMeta.TotalL1MessagePopped, TotalL1MessagePoppedBefore: parentBatchMeta.TotalL1MessagePopped,
ParentBatchHash: parentBatchMeta.BatchHash, ParentBatchHash: parentBatchMeta.BatchHash,
Chunks: chunks, Chunks: chunks,
@ -468,31 +479,54 @@ func validateBatch(event *L1FinalizeBatchEvent, parentBatchMeta *rawdb.Finalized
if startBlock.Header.Number.Uint64() == 0 || !chainCfg.IsBernoulli(startBlock.Header.Number) { // codecv0: genesis batch or batches before Bernoulli if startBlock.Header.Number.Uint64() == 0 || !chainCfg.IsBernoulli(startBlock.Header.Number) { // codecv0: genesis batch or batches before Bernoulli
daBatch, err := codecv0.NewDABatch(batch) daBatch, err := codecv0.NewDABatch(batch)
if err != nil { if err != nil {
return 0, nil, fmt.Errorf("failed to create codecv0 DA batch, batch index: %v, err: %w", event.BatchIndex.Uint64(), err) return 0, nil, fmt.Errorf("failed to create codecv0 DA batch, batch index: %v, err: %w", batchIndex, err)
} }
localBatchHash = daBatch.Hash() localBatchHash = daBatch.Hash()
} else if !chainCfg.IsCurie(startBlock.Header.Number) { // codecv1: batches after Bernoulli and before Curie } else if !chainCfg.IsCurie(startBlock.Header.Number) { // codecv1: batches after Bernoulli and before Curie
daBatch, err := codecv1.NewDABatch(batch) daBatch, err := codecv1.NewDABatch(batch)
if err != nil { if err != nil {
return 0, nil, fmt.Errorf("failed to create codecv1 DA batch, batch index: %v, err: %w", event.BatchIndex.Uint64(), err) return 0, nil, fmt.Errorf("failed to create codecv1 DA batch, batch index: %v, err: %w", batchIndex, err)
} }
localBatchHash = daBatch.Hash() localBatchHash = daBatch.Hash()
} else if !chainCfg.IsDarwin(startBlock.Header.Time) { // codecv2: batches after Curie and before Darwin } else if !chainCfg.IsDarwin(startBlock.Header.Time) { // codecv2: batches after Curie and before Darwin
daBatch, err := codecv2.NewDABatch(batch) daBatch, err := codecv2.NewDABatch(batch)
if err != nil { if err != nil {
return 0, nil, fmt.Errorf("failed to create codecv2 DA batch, batch index: %v, err: %w", event.BatchIndex.Uint64(), err) return 0, nil, fmt.Errorf("failed to create codecv2 DA batch, batch index: %v, err: %w", batchIndex, err)
} }
localBatchHash = daBatch.Hash() localBatchHash = daBatch.Hash()
} else { // codecv3: batches after Darwin } else { // codecv3: batches after Darwin
daBatch, err := codecv3.NewDABatch(batch) daBatch, err := codecv3.NewDABatch(batch)
if err != nil { if err != nil {
return 0, nil, fmt.Errorf("failed to create codecv3 DA batch, batch index: %v, err: %w", event.BatchIndex.Uint64(), err) return 0, nil, fmt.Errorf("failed to create codecv3 DA batch, batch index: %v, err: %w", batchIndex, err)
} }
localBatchHash = daBatch.Hash() localBatchHash = daBatch.Hash()
} }
// Note: If the batch headers match, this ensures the consistency of blocks and transactions localStateRoot := endBlock.Header.Root
localWithdrawRoot := endBlock.WithdrawRoot
// Note: If the state root, withdraw root, and batch headers match, this ensures the consistency of blocks and transactions
// (including skipped transactions) between L1 and L2. // (including skipped transactions) between L1 and L2.
//
// Only check when batch index matches the index of the event. This is compatible with both "finalize by batch" and "finalize by bundle":
// - finalize by batch: check all batches
// - finalize by bundle: check the last batch, because only one event (containing the info of the last batch) is emitted per bundle
if batchIndex == event.BatchIndex.Uint64() {
if localStateRoot != event.StateRoot {
log.Error("State root mismatch", "batch index", event.BatchIndex.Uint64(), "start block", startBlock.Header.Number.Uint64(), "end block", endBlock.Header.Number.Uint64(), "parent batch hash", parentBatchMeta.BatchHash.Hex(), "l1 finalized state root", event.StateRoot.Hex(), "l2 state root", localStateRoot.Hex())
stack.Close()
os.Exit(1)
}
if localWithdrawRoot != event.WithdrawRoot {
log.Error("Withdraw root mismatch", "batch index", event.BatchIndex.Uint64(), "start block", startBlock.Header.Number.Uint64(), "end block", endBlock.Header.Number.Uint64(), "parent batch hash", parentBatchMeta.BatchHash.Hex(), "l1 finalized withdraw root", event.WithdrawRoot.Hex(), "l2 withdraw root", localWithdrawRoot.Hex())
stack.Close()
os.Exit(1)
}
// Verify batch hash
// This check ensures the correctness of all batch hashes in the bundle
// due to the parent-child relationship between batch hashes
if localBatchHash != event.BatchHash { if localBatchHash != event.BatchHash {
log.Error("Batch hash mismatch", "batch index", event.BatchIndex.Uint64(), "start block", startBlock.Header.Number.Uint64(), "end block", endBlock.Header.Number.Uint64(), "parent batch hash", parentBatchMeta.BatchHash.Hex(), "parent TotalL1MessagePopped", parentBatchMeta.TotalL1MessagePopped, "l1 finalized batch hash", event.BatchHash.Hex(), "l2 batch hash", localBatchHash.Hex()) log.Error("Batch hash mismatch", "batch index", event.BatchIndex.Uint64(), "start block", startBlock.Header.Number.Uint64(), "end block", endBlock.Header.Number.Uint64(), "parent batch hash", parentBatchMeta.BatchHash.Hex(), "parent TotalL1MessagePopped", parentBatchMeta.TotalL1MessagePopped, "l1 finalized batch hash", event.BatchHash.Hex(), "l2 batch hash", localBatchHash.Hex())
chunksJson, err := json.Marshal(chunks) chunksJson, err := json.Marshal(chunks)
@ -503,6 +537,7 @@ func validateBatch(event *L1FinalizeBatchEvent, parentBatchMeta *rawdb.Finalized
stack.Close() stack.Close()
os.Exit(1) os.Exit(1)
} }
}
totalL1MessagePopped := parentBatchMeta.TotalL1MessagePopped totalL1MessagePopped := parentBatchMeta.TotalL1MessagePopped
for _, chunk := range chunks { for _, chunk := range chunks {

View file

@ -552,7 +552,7 @@ func TestValidateBatchCodecv0(t *testing.T) {
WithdrawRoot: chunk3.Blocks[len(chunk3.Blocks)-1].WithdrawRoot, WithdrawRoot: chunk3.Blocks[len(chunk3.Blocks)-1].WithdrawRoot,
} }
endBlock1, finalizedBatchMeta1, err := validateBatch(event1, parentBatchMeta1, []*encoding.Chunk{chunk1, chunk2, chunk3}, chainConfig, nil) endBlock1, finalizedBatchMeta1, err := validateBatch(event1.BatchIndex.Uint64(), event1, parentBatchMeta1, []*encoding.Chunk{chunk1, chunk2, chunk3}, chainConfig, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, uint64(13), endBlock1) assert.Equal(t, uint64(13), endBlock1)
@ -572,7 +572,7 @@ func TestValidateBatchCodecv0(t *testing.T) {
StateRoot: chunk4.Blocks[len(chunk4.Blocks)-1].Header.Root, StateRoot: chunk4.Blocks[len(chunk4.Blocks)-1].Header.Root,
WithdrawRoot: chunk4.Blocks[len(chunk4.Blocks)-1].WithdrawRoot, WithdrawRoot: chunk4.Blocks[len(chunk4.Blocks)-1].WithdrawRoot,
} }
endBlock2, finalizedBatchMeta2, err := validateBatch(event2, parentBatchMeta2, []*encoding.Chunk{chunk4}, chainConfig, nil) endBlock2, finalizedBatchMeta2, err := validateBatch(event2.BatchIndex.Uint64(), event2, parentBatchMeta2, []*encoding.Chunk{chunk4}, chainConfig, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, uint64(17), endBlock2) assert.Equal(t, uint64(17), endBlock2)
@ -605,7 +605,7 @@ func TestValidateBatchCodecv1(t *testing.T) {
WithdrawRoot: chunk3.Blocks[len(chunk3.Blocks)-1].WithdrawRoot, WithdrawRoot: chunk3.Blocks[len(chunk3.Blocks)-1].WithdrawRoot,
} }
endBlock1, finalizedBatchMeta1, err := validateBatch(event1, parentBatchMeta1, []*encoding.Chunk{chunk1, chunk2, chunk3}, chainConfig, nil) endBlock1, finalizedBatchMeta1, err := validateBatch(event1.BatchIndex.Uint64(), event1, parentBatchMeta1, []*encoding.Chunk{chunk1, chunk2, chunk3}, chainConfig, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, uint64(13), endBlock1) assert.Equal(t, uint64(13), endBlock1)
@ -625,7 +625,7 @@ func TestValidateBatchCodecv1(t *testing.T) {
StateRoot: chunk4.Blocks[len(chunk4.Blocks)-1].Header.Root, StateRoot: chunk4.Blocks[len(chunk4.Blocks)-1].Header.Root,
WithdrawRoot: chunk4.Blocks[len(chunk4.Blocks)-1].WithdrawRoot, WithdrawRoot: chunk4.Blocks[len(chunk4.Blocks)-1].WithdrawRoot,
} }
endBlock2, finalizedBatchMeta2, err := validateBatch(event2, parentBatchMeta2, []*encoding.Chunk{chunk4}, chainConfig, nil) endBlock2, finalizedBatchMeta2, err := validateBatch(event2.BatchIndex.Uint64(), event2, parentBatchMeta2, []*encoding.Chunk{chunk4}, chainConfig, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, uint64(17), endBlock2) assert.Equal(t, uint64(17), endBlock2)
@ -658,7 +658,7 @@ func TestValidateBatchCodecv2(t *testing.T) {
WithdrawRoot: chunk3.Blocks[len(chunk3.Blocks)-1].WithdrawRoot, WithdrawRoot: chunk3.Blocks[len(chunk3.Blocks)-1].WithdrawRoot,
} }
endBlock1, finalizedBatchMeta1, err := validateBatch(event1, parentBatchMeta1, []*encoding.Chunk{chunk1, chunk2, chunk3}, chainConfig, nil) endBlock1, finalizedBatchMeta1, err := validateBatch(event1.BatchIndex.Uint64(), event1, parentBatchMeta1, []*encoding.Chunk{chunk1, chunk2, chunk3}, chainConfig, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, uint64(13), endBlock1) assert.Equal(t, uint64(13), endBlock1)
@ -678,7 +678,7 @@ func TestValidateBatchCodecv2(t *testing.T) {
StateRoot: chunk4.Blocks[len(chunk4.Blocks)-1].Header.Root, StateRoot: chunk4.Blocks[len(chunk4.Blocks)-1].Header.Root,
WithdrawRoot: chunk4.Blocks[len(chunk4.Blocks)-1].WithdrawRoot, WithdrawRoot: chunk4.Blocks[len(chunk4.Blocks)-1].WithdrawRoot,
} }
endBlock2, finalizedBatchMeta2, err := validateBatch(event2, parentBatchMeta2, []*encoding.Chunk{chunk4}, chainConfig, nil) endBlock2, finalizedBatchMeta2, err := validateBatch(event2.BatchIndex.Uint64(), event2, parentBatchMeta2, []*encoding.Chunk{chunk4}, chainConfig, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, uint64(17), endBlock2) assert.Equal(t, uint64(17), endBlock2)
@ -711,7 +711,7 @@ func TestValidateBatchCodecv3(t *testing.T) {
WithdrawRoot: chunk3.Blocks[len(chunk3.Blocks)-1].WithdrawRoot, WithdrawRoot: chunk3.Blocks[len(chunk3.Blocks)-1].WithdrawRoot,
} }
endBlock1, finalizedBatchMeta1, err := validateBatch(event1, parentBatchMeta1, []*encoding.Chunk{chunk1, chunk2, chunk3}, chainConfig, nil) endBlock1, finalizedBatchMeta1, err := validateBatch(event1.BatchIndex.Uint64(), event1, parentBatchMeta1, []*encoding.Chunk{chunk1, chunk2, chunk3}, chainConfig, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, uint64(13), endBlock1) assert.Equal(t, uint64(13), endBlock1)
@ -731,7 +731,7 @@ func TestValidateBatchCodecv3(t *testing.T) {
StateRoot: chunk4.Blocks[len(chunk4.Blocks)-1].Header.Root, StateRoot: chunk4.Blocks[len(chunk4.Blocks)-1].Header.Root,
WithdrawRoot: chunk4.Blocks[len(chunk4.Blocks)-1].WithdrawRoot, WithdrawRoot: chunk4.Blocks[len(chunk4.Blocks)-1].WithdrawRoot,
} }
endBlock2, finalizedBatchMeta2, err := validateBatch(event2, parentBatchMeta2, []*encoding.Chunk{chunk4}, chainConfig, nil) endBlock2, finalizedBatchMeta2, err := validateBatch(event2.BatchIndex.Uint64(), event2, parentBatchMeta2, []*encoding.Chunk{chunk4}, chainConfig, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, uint64(17), endBlock2) assert.Equal(t, uint64(17), endBlock2)
@ -758,7 +758,7 @@ func TestValidateBatchUpgrades(t *testing.T) {
WithdrawRoot: chunk1.Blocks[len(chunk1.Blocks)-1].WithdrawRoot, WithdrawRoot: chunk1.Blocks[len(chunk1.Blocks)-1].WithdrawRoot,
} }
endBlock1, finalizedBatchMeta1, err := validateBatch(event1, parentBatchMeta1, []*encoding.Chunk{chunk1}, chainConfig, nil) endBlock1, finalizedBatchMeta1, err := validateBatch(event1.BatchIndex.Uint64(), event1, parentBatchMeta1, []*encoding.Chunk{chunk1}, chainConfig, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, uint64(2), endBlock1) assert.Equal(t, uint64(2), endBlock1)
@ -778,7 +778,7 @@ func TestValidateBatchUpgrades(t *testing.T) {
StateRoot: chunk2.Blocks[len(chunk2.Blocks)-1].Header.Root, StateRoot: chunk2.Blocks[len(chunk2.Blocks)-1].Header.Root,
WithdrawRoot: chunk2.Blocks[len(chunk2.Blocks)-1].WithdrawRoot, WithdrawRoot: chunk2.Blocks[len(chunk2.Blocks)-1].WithdrawRoot,
} }
endBlock2, finalizedBatchMeta2, err := validateBatch(event2, parentBatchMeta2, []*encoding.Chunk{chunk2}, chainConfig, nil) endBlock2, finalizedBatchMeta2, err := validateBatch(event2.BatchIndex.Uint64(), event2, parentBatchMeta2, []*encoding.Chunk{chunk2}, chainConfig, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, uint64(3), endBlock2) assert.Equal(t, uint64(3), endBlock2)
@ -798,7 +798,7 @@ func TestValidateBatchUpgrades(t *testing.T) {
StateRoot: chunk3.Blocks[len(chunk3.Blocks)-1].Header.Root, StateRoot: chunk3.Blocks[len(chunk3.Blocks)-1].Header.Root,
WithdrawRoot: chunk3.Blocks[len(chunk3.Blocks)-1].WithdrawRoot, WithdrawRoot: chunk3.Blocks[len(chunk3.Blocks)-1].WithdrawRoot,
} }
endBlock3, finalizedBatchMeta3, err := validateBatch(event3, parentBatchMeta3, []*encoding.Chunk{chunk3}, chainConfig, nil) endBlock3, finalizedBatchMeta3, err := validateBatch(event3.BatchIndex.Uint64(), event3, parentBatchMeta3, []*encoding.Chunk{chunk3}, chainConfig, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, uint64(13), endBlock3) assert.Equal(t, uint64(13), endBlock3)
@ -818,7 +818,7 @@ func TestValidateBatchUpgrades(t *testing.T) {
StateRoot: chunk4.Blocks[len(chunk4.Blocks)-1].Header.Root, StateRoot: chunk4.Blocks[len(chunk4.Blocks)-1].Header.Root,
WithdrawRoot: chunk4.Blocks[len(chunk4.Blocks)-1].WithdrawRoot, WithdrawRoot: chunk4.Blocks[len(chunk4.Blocks)-1].WithdrawRoot,
} }
endBlock4, finalizedBatchMeta4, err := validateBatch(event4, parentBatchMeta4, []*encoding.Chunk{chunk4}, chainConfig, nil) endBlock4, finalizedBatchMeta4, err := validateBatch(event4.BatchIndex.Uint64(), event4, parentBatchMeta4, []*encoding.Chunk{chunk4}, chainConfig, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, uint64(17), endBlock4) assert.Equal(t, uint64(17), endBlock4)
@ -831,6 +831,51 @@ func TestValidateBatchUpgrades(t *testing.T) {
assert.Equal(t, parentBatchMeta5, finalizedBatchMeta4) assert.Equal(t, parentBatchMeta5, finalizedBatchMeta4)
} }
func TestValidateBatchInFinalizeByBundle(t *testing.T) {
chainConfig := &params.ChainConfig{BernoulliBlock: big.NewInt(0), CurieBlock: big.NewInt(0), DarwinTime: func() *uint64 { t := uint64(0); return &t }()}
block1 := readBlockFromJSON(t, "./testdata/blockTrace_02.json")
block2 := readBlockFromJSON(t, "./testdata/blockTrace_03.json")
block3 := readBlockFromJSON(t, "./testdata/blockTrace_04.json")
block4 := readBlockFromJSON(t, "./testdata/blockTrace_05.json")
chunk1 := &encoding.Chunk{Blocks: []*encoding.Block{block1}}
chunk2 := &encoding.Chunk{Blocks: []*encoding.Block{block2}}
chunk3 := &encoding.Chunk{Blocks: []*encoding.Block{block3}}
chunk4 := &encoding.Chunk{Blocks: []*encoding.Block{block4}}
event := &L1FinalizeBatchEvent{
BatchIndex: big.NewInt(3),
BatchHash: common.HexToHash("0xaa6dc7cc432c8d46a9373e1e96d829a1e24e52fe0468012ff062793ea8f5b55e"),
StateRoot: chunk4.Blocks[len(chunk4.Blocks)-1].Header.Root,
WithdrawRoot: chunk4.Blocks[len(chunk4.Blocks)-1].WithdrawRoot,
}
endBlock1, finalizedBatchMeta1, err := validateBatch(0, event, &rawdb.FinalizedBatchMeta{}, []*encoding.Chunk{chunk1}, chainConfig, nil)
assert.NoError(t, err)
assert.Equal(t, uint64(2), endBlock1)
endBlock2, finalizedBatchMeta2, err := validateBatch(1, event, finalizedBatchMeta1, []*encoding.Chunk{chunk2}, chainConfig, nil)
assert.NoError(t, err)
assert.Equal(t, uint64(3), endBlock2)
endBlock3, finalizedBatchMeta3, err := validateBatch(2, event, finalizedBatchMeta2, []*encoding.Chunk{chunk3}, chainConfig, nil)
assert.NoError(t, err)
assert.Equal(t, uint64(13), endBlock3)
endBlock4, finalizedBatchMeta4, err := validateBatch(3, event, finalizedBatchMeta3, []*encoding.Chunk{chunk4}, chainConfig, nil)
assert.NoError(t, err)
assert.Equal(t, uint64(17), endBlock4)
parentBatchMeta5 := &rawdb.FinalizedBatchMeta{
BatchHash: event.BatchHash,
TotalL1MessagePopped: 42,
StateRoot: event.StateRoot,
WithdrawRoot: event.WithdrawRoot,
}
assert.Equal(t, parentBatchMeta5, finalizedBatchMeta4)
}
func readBlockFromJSON(t *testing.T, filename string) *encoding.Block { func readBlockFromJSON(t *testing.T, filename string) *encoding.Block {
data, err := os.ReadFile(filename) data, err := os.ReadFile(filename)
assert.NoError(t, err) assert.NoError(t, err)