diff --git a/common/version/version.go b/common/version/version.go index d77ad10a66..0c65036565 100644 --- a/common/version/version.go +++ b/common/version/version.go @@ -5,7 +5,7 @@ import ( "runtime/debug" ) -var tag = "v4.7.6" +var tag = "v4.7.7" var commit = func() string { if info, ok := debug.ReadBuildInfo(); ok { diff --git a/rollup/internal/controller/watcher/chunk_proposer.go b/rollup/internal/controller/watcher/chunk_proposer.go index d6a0706377..843abaf542 100644 --- a/rollup/internal/controller/watcher/chunk_proposer.go +++ b/rollup/internal/controller/watcher/chunk_proposer.go @@ -245,11 +245,13 @@ func (p *ChunkProposer) ProposeChunk() error { // Ensure all blocks in the same chunk use the same hardfork name // If a different hardfork name is found, truncate the blocks slice at that point hardforkName := encoding.GetHardforkName(p.chainCfg, blocks[0].Header.Number.Uint64(), blocks[0].Header.Time) + hardforkBoundary := false for i := 1; i < len(blocks); i++ { currentHardfork := encoding.GetHardforkName(p.chainCfg, blocks[i].Header.Number.Uint64(), blocks[i].Header.Time) if currentHardfork != hardforkName { - blocks = blocks[:i] // Truncate blocks at hardfork boundary + blocks = blocks[:i] + hardforkBoundary = true break } } @@ -321,6 +323,19 @@ func (p *ChunkProposer) ProposeChunk() error { return fmt.Errorf("failed to calculate chunk metrics: %w", calcErr) } + // No breaking condition met, but hardfork boundary reached + if hardforkBoundary { + log.Info("hardfork boundary reached, proposing chunk", + "block count", len(chunk.Blocks), + "codec version", codecVersion, + "start block number", chunk.Blocks[0].Header.Number, + "end block number", chunk.Blocks[len(chunk.Blocks)-1].Header.Number) + + p.recordAllChunkMetrics(metrics) + return p.updateDBChunkInfo(&chunk, codecVersion, metrics) + } + + // No breaking condition met, check for timeout currentTimeSec := uint64(time.Now().Unix()) if metrics.FirstBlockTimestamp+p.cfg.ChunkTimeoutSec < currentTimeSec { log.Info("first block timeout reached", diff --git a/rollup/internal/controller/watcher/chunk_proposer_test.go b/rollup/internal/controller/watcher/chunk_proposer_test.go index 63fe72463b..21342ef9c8 100644 --- a/rollup/internal/controller/watcher/chunk_proposer_test.go +++ b/rollup/internal/controller/watcher/chunk_proposer_test.go @@ -19,6 +19,8 @@ import ( "scroll-tech/rollup/internal/utils" ) +func newUint64(val uint64) *uint64 { return &val } + func testChunkProposerLimitsCodecV7(t *testing.T) { tests := []struct { name string @@ -26,6 +28,7 @@ func testChunkProposerLimitsCodecV7(t *testing.T) { chunkTimeoutSec uint64 expectedChunksLen int expectedBlocksInFirstChunk int // only be checked when expectedChunksLen > 0 + GalileoTime *uint64 }{ { name: "NoLimitReached", @@ -62,6 +65,14 @@ func testChunkProposerLimitsCodecV7(t *testing.T) { expectedChunksLen: 1, expectedBlocksInFirstChunk: 1, }, + { + name: "SingleBlockByForkBoundary", + maxL2Gas: 20_000_000, + chunkTimeoutSec: 1000000000000, + expectedChunksLen: 1, + expectedBlocksInFirstChunk: 1, + GalileoTime: newUint64(1669364525), // timestamp of `block2` + }, } for _, tt := range tests { @@ -78,11 +89,26 @@ func testChunkProposerLimitsCodecV7(t *testing.T) { _, err = chunkOrm.InsertChunk(context.Background(), &encoding.Chunk{Blocks: []*encoding.Block{{Header: &gethTypes.Header{Number: big.NewInt(0)}}}}, encoding.CodecV0, utils.ChunkMetrics{}) assert.NoError(t, err) + // Initialize the chunk proposer. + chainConfig := ¶ms.ChainConfig{ + LondonBlock: big.NewInt(0), + BernoulliBlock: big.NewInt(0), + CurieBlock: big.NewInt(0), + DarwinTime: new(uint64), + DarwinV2Time: new(uint64), + EuclidTime: new(uint64), + EuclidV2Time: new(uint64), + FeynmanTime: new(uint64), + GalileoTime: tt.GalileoTime, + } + cp := NewChunkProposer(context.Background(), &config.ChunkProposerConfig{ MaxL2GasPerChunk: tt.maxL2Gas, ChunkTimeoutSec: tt.chunkTimeoutSec, MaxUncompressedBatchBytesSize: math.MaxUint64, - }, encoding.CodecV7, ¶ms.ChainConfig{LondonBlock: big.NewInt(0), BernoulliBlock: big.NewInt(0), CurieBlock: big.NewInt(0), DarwinTime: new(uint64), DarwinV2Time: new(uint64), EuclidTime: new(uint64), EuclidV2Time: new(uint64)}, db, nil) + }, encoding.CodecV7, chainConfig, db, nil) + + // Run one round of chunk proposing. cp.TryProposeChunk() chunks, err := chunkOrm.GetChunksGEIndex(context.Background(), 1, 0)