feat(feynman): support codecv8 in rollup-verifier (#1206)

* feat: support codecv8

* address comments

* update da-codec commit

* update da-codec commit

* bump version

---------

Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
This commit is contained in:
colin 2025-06-26 20:19:27 +08:00 committed by GitHub
parent c604c90159
commit 941913b278
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 152 additions and 7 deletions

View file

@ -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
)

View file

@ -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{

View file

@ -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)