diff --git a/params/version.go b/params/version.go index 897b9f4262b0..29165efc44b9 100644 --- a/params/version.go +++ b/params/version.go @@ -24,7 +24,7 @@ import ( const ( VersionMajor = 5 // Major version component of the current release VersionMinor = 8 // Minor version component of the current release - VersionPatch = 61 // Patch version component of the current release + VersionPatch = 62 // Patch version component of the current release VersionMeta = "mainnet" // Version metadata to append to the version string ) diff --git a/rollup/rollup_sync_service/rollup_sync_service.go b/rollup/rollup_sync_service/rollup_sync_service.go index 8aba65a1d422..d466b675105f 100644 --- a/rollup/rollup_sync_service/rollup_sync_service.go +++ b/rollup/rollup_sync_service/rollup_sync_service.go @@ -464,13 +464,13 @@ 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) } - // With CodecV7 the batch creation changed. We need to compute and store PostL1MessageQueueHash. + // With >= CodecV7 the batch creation changed. We need to compute and store PostL1MessageQueueHash. // 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 // 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. var lastL1MessageQueueHash common.Hash - if commitedBatch.Version() == encoding.CodecV7 { + if commitedBatch.Version() >= encoding.CodecV7 { parentCommittedBatchMeta, err := rawdb.ReadCommittedBatchMeta(s.db, commitedBatch.BatchIndex()-1) if err != nil { return nil, fmt.Errorf("failed to read parent committed batch meta, batch index: %v, err: %w", commitedBatch.BatchIndex()-1, errors.Join(ErrMissingBatchEvent, err)) @@ -493,11 +493,11 @@ func (s *RollupSyncService) getCommittedBatchMeta(commitedBatch da.EntryWithBloc return nil, fmt.Errorf("failed to get local node info, batch index: %v, err: %w", commitedBatch.BatchIndex(), err) } - // There is no chunks encoded in a batch anymore with CodecV7. + // There is no chunks encoded in a batch anymore with >= CodecV7. // For compatibility reason here we still use a single chunk to store the block ranges of the batch. // We make sure that there is really only one chunk which contains all blocks of the batch. if len(chunks) != 1 { - 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 CodecV%v, batch index: %v", commitedBatch.Version(), commitedBatch.BatchIndex()) } lastL1MessageQueueHash, err = encoding.MessageQueueV2ApplyL1MessagesFromBlocks(prevL1MessageQueueHash, chunks[0].Blocks) @@ -563,11 +563,11 @@ func validateBatch(batchIndex uint64, event *l1.FinalizeBatchEvent, parentFinali Chunks: chunks, } } else { - // With CodecV7 the batch creation changed. There is no chunks encoded in a batch anymore. + // With >= CodecV7 the batch creation changed. There is no chunks encoded in a batch anymore. // For compatibility reason here we still use a single chunk to store the block ranges of the batch. // We make sure that there is really only one chunk which contains all blocks of the batch. if len(chunks) != 1 { - return 0, nil, fmt.Errorf("invalid argument: chunk count is not 1 for CodecV7, batch index: %v", batchIndex) + return 0, nil, fmt.Errorf("invalid argument: chunk count is not 1 for CodecV%v, batch index: %v", committedBatchMeta.Version, batchIndex) } batch = &encoding.Batch{ diff --git a/rollup/rollup_sync_service/rollup_sync_service_test.go b/rollup/rollup_sync_service/rollup_sync_service_test.go index e6f6d7339697..cf8c3d535fca 100644 --- a/rollup/rollup_sync_service/rollup_sync_service_test.go +++ b/rollup/rollup_sync_service/rollup_sync_service_test.go @@ -816,6 +816,151 @@ func TestValidateBatchCodecV7(t *testing.T) { }, finalizedBatchMeta4) } +func TestValidateBatchCodecV8(t *testing.T) { + codecV8 := encoding.NewDACodecV8() + + var finalizedBatchMeta1 *rawdb.FinalizedBatchMeta + var committedBatchMeta1 *rawdb.CommittedBatchMeta + { + block1 := replaceBlockNumber(readBlockFromJSON(t, "./testdata/blockTrace_02.json"), 1) + batch1 := &encoding.Batch{ + Index: 1, + PrevL1MessageQueueHash: common.Hash{}, + PostL1MessageQueueHash: common.Hash{}, + Blocks: []*encoding.Block{block1}, + } + batch1LastBlock := batch1.Blocks[len(batch1.Blocks)-1] + + daBatch1, err := codecV8.NewDABatch(batch1) + require.NoError(t, err) + + event1 := l1.NewFinalizeBatchEvent( + new(big.Int).SetUint64(batch1.Index), + daBatch1.Hash(), + batch1LastBlock.Header.Root, + batch1LastBlock.WithdrawRoot, + common.HexToHash("0x1"), + common.HexToHash("0x1"), + 1, + ) + + committedBatchMeta1 = &rawdb.CommittedBatchMeta{ + Version: uint8(encoding.CodecV8), + PostL1MessageQueueHash: common.Hash{}, + } + + var endBlock1 uint64 + endBlock1, finalizedBatchMeta1, err = validateBatch(event1.BatchIndex().Uint64(), event1, &rawdb.FinalizedBatchMeta{}, &rawdb.CommittedBatchMeta{}, committedBatchMeta1, []*encoding.Chunk{{Blocks: batch1.Blocks}}, nil) + require.NoError(t, err) + require.EqualValues(t, 1, endBlock1) + require.Equal(t, &rawdb.FinalizedBatchMeta{ + BatchHash: daBatch1.Hash(), + TotalL1MessagePopped: 0, + StateRoot: batch1LastBlock.Header.Root, + WithdrawRoot: batch1LastBlock.WithdrawRoot, + }, finalizedBatchMeta1) + } + + // finalize 3 batches with CodecV8 at once + block2 := replaceBlockNumber(readBlockFromJSON(t, "./testdata/blockTrace_03.json"), 2) + batch2 := &encoding.Batch{ + Index: 2, + ParentBatchHash: finalizedBatchMeta1.BatchHash, + PrevL1MessageQueueHash: common.Hash{}, + PostL1MessageQueueHash: common.Hash{}, + Blocks: []*encoding.Block{block2}, + } + batch2LastBlock := batch2.Blocks[len(batch2.Blocks)-1] + + daBatch2, err := codecV8.NewDABatch(batch2) + require.NoError(t, err) + + block3 := replaceBlockNumber(readBlockFromJSON(t, "./testdata/blockTrace_06.json"), 3) + LastL1MessageQueueHashBatch3, err := encoding.MessageQueueV2ApplyL1MessagesFromBlocks(common.Hash{}, []*encoding.Block{block3}) + require.NoError(t, err) + batch3 := &encoding.Batch{ + Index: 3, + ParentBatchHash: daBatch2.Hash(), + PrevL1MessageQueueHash: common.Hash{}, + PostL1MessageQueueHash: LastL1MessageQueueHashBatch3, + Blocks: []*encoding.Block{block3}, + } + batch3LastBlock := batch3.Blocks[len(batch3.Blocks)-1] + + daBatch3, err := codecV8.NewDABatch(batch3) + require.NoError(t, err) + + block4 := replaceBlockNumber(readBlockFromJSON(t, "./testdata/blockTrace_07.json"), 4) + LastL1MessageQueueHashBatch4, err := encoding.MessageQueueV2ApplyL1MessagesFromBlocks(LastL1MessageQueueHashBatch3, []*encoding.Block{block4}) + require.NoError(t, err) + batch4 := &encoding.Batch{ + Index: 4, + ParentBatchHash: daBatch3.Hash(), + PrevL1MessageQueueHash: LastL1MessageQueueHashBatch3, + PostL1MessageQueueHash: LastL1MessageQueueHashBatch4, + Blocks: []*encoding.Block{block4}, + } + batch4LastBlock := batch4.Blocks[len(batch4.Blocks)-1] + + daBatch4, err := codecV8.NewDABatch(batch4) + require.NoError(t, err) + + event2 := l1.NewFinalizeBatchEvent( + new(big.Int).SetUint64(batch4.Index), + daBatch4.Hash(), + batch4LastBlock.Header.Root, + batch4LastBlock.WithdrawRoot, + common.HexToHash("0x1"), + common.HexToHash("0x1"), + 1, + ) + + committedBatchMeta2 := &rawdb.CommittedBatchMeta{ + Version: uint8(encoding.CodecV8), + PostL1MessageQueueHash: common.Hash{}, + } + + committedBatchMeta3 := &rawdb.CommittedBatchMeta{ + Version: uint8(encoding.CodecV8), + PostL1MessageQueueHash: LastL1MessageQueueHashBatch3, + } + + committedBatchMeta4 := &rawdb.CommittedBatchMeta{ + Version: uint8(encoding.CodecV8), + PostL1MessageQueueHash: LastL1MessageQueueHashBatch4, + } + + endBlock2, finalizedBatchMeta2, err := validateBatch(2, event2, finalizedBatchMeta1, committedBatchMeta1, committedBatchMeta2, []*encoding.Chunk{{Blocks: batch2.Blocks}}, nil) + require.NoError(t, err) + require.EqualValues(t, 2, endBlock2) + require.Equal(t, &rawdb.FinalizedBatchMeta{ + BatchHash: daBatch2.Hash(), + TotalL1MessagePopped: 0, + StateRoot: batch2LastBlock.Header.Root, + WithdrawRoot: batch2LastBlock.WithdrawRoot, + }, finalizedBatchMeta2) + + endBlock3, finalizedBatchMeta3, err := validateBatch(3, event2, finalizedBatchMeta2, committedBatchMeta2, committedBatchMeta3, []*encoding.Chunk{{Blocks: batch3.Blocks}}, nil) + require.NoError(t, err) + require.EqualValues(t, 3, endBlock3) + require.Equal(t, &rawdb.FinalizedBatchMeta{ + BatchHash: daBatch3.Hash(), + TotalL1MessagePopped: 1, + StateRoot: batch3LastBlock.Header.Root, + WithdrawRoot: batch3LastBlock.WithdrawRoot, + }, finalizedBatchMeta3) + + endBlock4, finalizedBatchMeta4, err := validateBatch(4, event2, finalizedBatchMeta3, committedBatchMeta3, committedBatchMeta4, []*encoding.Chunk{{Blocks: batch4.Blocks}}, nil) + require.NoError(t, err) + require.EqualValues(t, 4, endBlock4) + require.Equal(t, &rawdb.FinalizedBatchMeta{ + BatchHash: daBatch4.Hash(), + TotalL1MessagePopped: 6, + StateRoot: batch4LastBlock.Header.Root, + WithdrawRoot: batch4LastBlock.WithdrawRoot, + }, finalizedBatchMeta4) +} + func readBlockFromJSON(t *testing.T, filename string) *encoding.Block { data, err := os.ReadFile(filename) assert.NoError(t, err)