From de7f6e56a9698e29ebfcc64c354e7ebec75dd315 Mon Sep 17 00:00:00 2001 From: Jonas Theis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 10 Sep 2025 14:16:13 +0800 Subject: [PATCH] refactor(rollup relayer): remove `max_block_num_per_chunk` configuration parameter (#1729) Co-authored-by: jonastheis --- common/version/version.go | 2 +- .../conf/relayer/config.json | 1 - rollup/conf/config.json | 1 - rollup/internal/config/l2.go | 1 - .../controller/watcher/batch_proposer_test.go | 16 +++-- .../watcher/bundle_proposer_test.go | 10 +++- .../controller/watcher/chunk_proposer.go | 14 ++--- .../controller/watcher/chunk_proposer_test.go | 59 +------------------ .../controller/watcher/watcher_test.go | 1 - rollup/proposer-tool-config.json | 1 - rollup/tests/rollup_test.go | 1 - 11 files changed, 23 insertions(+), 84 deletions(-) diff --git a/common/version/version.go b/common/version/version.go index 13a7597d4..df872f409 100644 --- a/common/version/version.go +++ b/common/version/version.go @@ -5,7 +5,7 @@ import ( "runtime/debug" ) -var tag = "v4.5.45" +var tag = "v4.5.46" var commit = func() string { if info, ok := debug.ReadBuildInfo(); ok { diff --git a/permissionless-batches/conf/relayer/config.json b/permissionless-batches/conf/relayer/config.json index f7f785cb9..9b812fa99 100644 --- a/permissionless-batches/conf/relayer/config.json +++ b/permissionless-batches/conf/relayer/config.json @@ -15,7 +15,6 @@ }, "chunk_proposer_config": { "propose_interval_milliseconds": 100, - "max_block_num_per_chunk": 100, "max_l2_gas_per_chunk": 20000000, "chunk_timeout_sec": 300, "max_uncompressed_batch_bytes_size": 4194304 diff --git a/rollup/conf/config.json b/rollup/conf/config.json index f6a634eda..8055008cd 100644 --- a/rollup/conf/config.json +++ b/rollup/conf/config.json @@ -92,7 +92,6 @@ }, "chunk_proposer_config": { "propose_interval_milliseconds": 100, - "max_block_num_per_chunk": 100, "max_l2_gas_per_chunk": 20000000, "chunk_timeout_sec": 300, "max_uncompressed_batch_bytes_size": 4194304 diff --git a/rollup/internal/config/l2.go b/rollup/internal/config/l2.go index 26da137ef..91ea322cd 100644 --- a/rollup/internal/config/l2.go +++ b/rollup/internal/config/l2.go @@ -31,7 +31,6 @@ type L2Config struct { // ChunkProposerConfig loads chunk_proposer configuration items. type ChunkProposerConfig struct { ProposeIntervalMilliseconds uint64 `json:"propose_interval_milliseconds"` - MaxBlockNumPerChunk uint64 `json:"max_block_num_per_chunk"` MaxL2GasPerChunk uint64 `json:"max_l2_gas_per_chunk"` ChunkTimeoutSec uint64 `json:"chunk_timeout_sec"` MaxUncompressedBatchBytesSize uint64 `json:"max_uncompressed_batch_bytes_size"` diff --git a/rollup/internal/controller/watcher/batch_proposer_test.go b/rollup/internal/controller/watcher/batch_proposer_test.go index 526c93655..f86b81f71 100644 --- a/rollup/internal/controller/watcher/batch_proposer_test.go +++ b/rollup/internal/controller/watcher/batch_proposer_test.go @@ -36,7 +36,7 @@ func testBatchProposerLimitsCodecV7(t *testing.T) { name: "Timeout", batchTimeoutSec: 0, expectedBatchesLen: 1, - expectedChunksInFirstBatch: 2, + expectedChunksInFirstBatch: 1, }, } @@ -72,8 +72,7 @@ func testBatchProposerLimitsCodecV7(t *testing.T) { assert.NoError(t, err) cp := NewChunkProposer(context.Background(), &config.ChunkProposerConfig{ - MaxBlockNumPerChunk: 1, - MaxL2GasPerChunk: 20000000, + MaxL2GasPerChunk: math.MaxUint64, ChunkTimeoutSec: 300, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV7, ¶ms.ChainConfig{ @@ -154,7 +153,6 @@ func testBatchProposerBlobSizeLimitCodecV7(t *testing.T) { 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)} cp := NewChunkProposer(context.Background(), &config.ChunkProposerConfig{ - MaxBlockNumPerChunk: math.MaxUint64, MaxL2GasPerChunk: math.MaxUint64, ChunkTimeoutSec: 0, MaxUncompressedBatchBytesSize: math.MaxUint64, @@ -227,7 +225,6 @@ func testBatchProposerMaxChunkNumPerBatchLimitCodecV7(t *testing.T) { 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)} cp := NewChunkProposer(context.Background(), &config.ChunkProposerConfig{ - MaxBlockNumPerChunk: math.MaxUint64, MaxL2GasPerChunk: math.MaxUint64, ChunkTimeoutSec: 0, MaxUncompressedBatchBytesSize: math.MaxUint64, @@ -309,15 +306,14 @@ func testBatchProposerUncompressedBatchBytesLimitCodecV8(t *testing.T) { // Create chunk proposer with no uncompressed batch bytes limit for chunks cp := NewChunkProposer(context.Background(), &config.ChunkProposerConfig{ - MaxBlockNumPerChunk: 1, // One block per chunk - MaxL2GasPerChunk: math.MaxUint64, + MaxL2GasPerChunk: 1200000, // One block per chunk via gas limit ChunkTimeoutSec: math.MaxUint32, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV8, chainConfig, db, nil) // Insert 2 blocks with large calldata and create 2 chunks l2BlockOrm := orm.NewL2Block(db) - for i := uint64(1); i <= 2; i++ { + for i := uint64(1); i <= 3; i++ { blockCopy := *block blockCopy.Header = &gethTypes.Header{} *blockCopy.Header = *block.Header @@ -326,7 +322,9 @@ func testBatchProposerUncompressedBatchBytesLimitCodecV8(t *testing.T) { err := l2BlockOrm.InsertL2Blocks(context.Background(), []*encoding.Block{&blockCopy}) assert.NoError(t, err) - cp.TryProposeChunk() // Each call creates one chunk with one block + cp.TryProposeChunk() // Each chunk will contain 1 block (~3KiB) + // We create 2 chunks here, as we have 3 blocks and reach the gas limit for the 1st chunk with the 2nd block + // and the 2nd chunk with the 3rd block. } // Create batch proposer with 4KiB uncompressed batch bytes limit diff --git a/rollup/internal/controller/watcher/bundle_proposer_test.go b/rollup/internal/controller/watcher/bundle_proposer_test.go index 7e2f27da4..29c8dfe0a 100644 --- a/rollup/internal/controller/watcher/bundle_proposer_test.go +++ b/rollup/internal/controller/watcher/bundle_proposer_test.go @@ -86,15 +86,19 @@ func testBundleProposerLimitsCodecV7(t *testing.T) { _, err = batchOrm.InsertBatch(context.Background(), batch, encoding.CodecV0, utils.BatchMetrics{}) assert.NoError(t, err) + block3 := *block1 + block3.Header = &gethTypes.Header{} + *block3.Header = *block1.Header + block3.Header.Number = new(big.Int).SetUint64(block2.Header.Number.Uint64() + 1) + l2BlockOrm := orm.NewL2Block(db) - err = l2BlockOrm.InsertL2Blocks(context.Background(), []*encoding.Block{block1, block2}) + err = l2BlockOrm.InsertL2Blocks(context.Background(), []*encoding.Block{block1, block2, &block3}) assert.NoError(t, err) 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)} cp := NewChunkProposer(context.Background(), &config.ChunkProposerConfig{ - MaxBlockNumPerChunk: 1, - MaxL2GasPerChunk: math.MaxUint64, + MaxL2GasPerChunk: 1152994, // One block per chunk via gas limit ChunkTimeoutSec: math.MaxUint32, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV7, chainConfig, db, nil) diff --git a/rollup/internal/controller/watcher/chunk_proposer.go b/rollup/internal/controller/watcher/chunk_proposer.go index 04e2ffaea..d6a070637 100644 --- a/rollup/internal/controller/watcher/chunk_proposer.go +++ b/rollup/internal/controller/watcher/chunk_proposer.go @@ -54,7 +54,6 @@ type ChunkProposer struct { // NewChunkProposer creates a new ChunkProposer instance. func NewChunkProposer(ctx context.Context, cfg *config.ChunkProposerConfig, minCodecVersion encoding.CodecVersion, chainCfg *params.ChainConfig, db *gorm.DB, reg prometheus.Registerer) *ChunkProposer { log.Info("new chunk proposer", - "maxBlockNumPerChunk", cfg.MaxBlockNumPerChunk, "maxL2GasPerChunk", cfg.MaxL2GasPerChunk, "chunkTimeoutSec", cfg.ChunkTimeoutSec, "maxBlobSize", maxBlobSize) @@ -232,10 +231,9 @@ func (p *ChunkProposer) ProposeChunk() error { return err } - maxBlocksThisChunk := p.cfg.MaxBlockNumPerChunk - - // select at most maxBlocksThisChunk blocks - blocks, err := p.l2BlockOrm.GetL2BlocksGEHeight(p.ctx, unchunkedBlockHeight, int(maxBlocksThisChunk)) + // select blocks without a hard limit on count in practice (use a large value) + // The actual limits will be enforced by gas, timeout, and blob size constraints + blocks, err := p.l2BlockOrm.GetL2BlocksGEHeight(p.ctx, unchunkedBlockHeight, 1000) if err != nil { return err } @@ -251,7 +249,7 @@ func (p *ChunkProposer) ProposeChunk() error { currentHardfork := encoding.GetHardforkName(p.chainCfg, blocks[i].Header.Number.Uint64(), blocks[i].Header.Time) if currentHardfork != hardforkName { blocks = blocks[:i] - maxBlocksThisChunk = uint64(i) // update maxBlocksThisChunk to trigger chunking, because these blocks are the last blocks before the hardfork + // Truncate blocks at hardfork boundary break } } @@ -324,8 +322,8 @@ func (p *ChunkProposer) ProposeChunk() error { } currentTimeSec := uint64(time.Now().Unix()) - if metrics.FirstBlockTimestamp+p.cfg.ChunkTimeoutSec < currentTimeSec || metrics.NumBlocks == maxBlocksThisChunk { - log.Info("reached maximum number of blocks in chunk or first block timeout", + if metrics.FirstBlockTimestamp+p.cfg.ChunkTimeoutSec < currentTimeSec { + log.Info("first block timeout reached", "block count", len(chunk.Blocks), "start block number", chunk.Blocks[0].Header.Number, "start block timestamp", metrics.FirstBlockTimestamp, diff --git a/rollup/internal/controller/watcher/chunk_proposer_test.go b/rollup/internal/controller/watcher/chunk_proposer_test.go index 218bc4c9f..63fe72463 100644 --- a/rollup/internal/controller/watcher/chunk_proposer_test.go +++ b/rollup/internal/controller/watcher/chunk_proposer_test.go @@ -22,7 +22,6 @@ import ( func testChunkProposerLimitsCodecV7(t *testing.T) { tests := []struct { name string - maxBlockNum uint64 maxL2Gas uint64 chunkTimeoutSec uint64 expectedChunksLen int @@ -30,14 +29,12 @@ func testChunkProposerLimitsCodecV7(t *testing.T) { }{ { name: "NoLimitReached", - maxBlockNum: 100, maxL2Gas: 20_000_000, chunkTimeoutSec: 1000000000000, expectedChunksLen: 0, }, { name: "Timeout", - maxBlockNum: 100, maxL2Gas: 20_000_000, chunkTimeoutSec: 0, expectedChunksLen: 1, @@ -45,15 +42,13 @@ func testChunkProposerLimitsCodecV7(t *testing.T) { }, { name: "MaxL2GasPerChunkIs0", - maxBlockNum: 10, maxL2Gas: 0, chunkTimeoutSec: 1000000000000, expectedChunksLen: 0, }, { - name: "MaxBlockNumPerChunkIs1", - maxBlockNum: 1, - maxL2Gas: 20_000_000, + name: "SingleBlockByGasLimit", + maxL2Gas: 1_100_000, chunkTimeoutSec: 1000000000000, expectedChunksLen: 1, expectedBlocksInFirstChunk: 1, @@ -62,7 +57,6 @@ func testChunkProposerLimitsCodecV7(t *testing.T) { // In this test the second block is not included in the chunk because together // with the first block it exceeds the maxL2GasPerChunk limit. name: "MaxL2GasPerChunkIsSecondBlock", - maxBlockNum: 10, maxL2Gas: 1_153_000, chunkTimeoutSec: 1000000000000, expectedChunksLen: 1, @@ -85,7 +79,6 @@ func testChunkProposerLimitsCodecV7(t *testing.T) { assert.NoError(t, err) cp := NewChunkProposer(context.Background(), &config.ChunkProposerConfig{ - MaxBlockNumPerChunk: tt.maxBlockNum, MaxL2GasPerChunk: tt.maxL2Gas, ChunkTimeoutSec: tt.chunkTimeoutSec, MaxUncompressedBatchBytesSize: math.MaxUint64, @@ -110,53 +103,6 @@ func testChunkProposerLimitsCodecV7(t *testing.T) { } } -func testChunkProposerBlobSizeLimitCodecV7(t *testing.T) { - db := setupDB(t) - defer database.CloseDB(db) - block := readBlockFromJSON(t, "../../../testdata/blockTrace_03.json") - for i := uint64(0); i < 510; i++ { - l2BlockOrm := orm.NewL2Block(db) - block.Header.Number = new(big.Int).SetUint64(i + 1) - block.Header.Time = i + 1 - err := l2BlockOrm.InsertL2Blocks(context.Background(), []*encoding.Block{block}) - assert.NoError(t, err) - } - - // Add genesis chunk. - chunkOrm := orm.NewChunk(db) - _, 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) - - 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)} - - cp := NewChunkProposer(context.Background(), &config.ChunkProposerConfig{ - MaxBlockNumPerChunk: 255, - MaxL2GasPerChunk: math.MaxUint64, - ChunkTimeoutSec: math.MaxUint32, - MaxUncompressedBatchBytesSize: math.MaxUint64, - }, encoding.CodecV7, chainConfig, db, nil) - - for i := 0; i < 2; i++ { - cp.TryProposeChunk() - } - - chunkOrm = orm.NewChunk(db) - chunks, err := chunkOrm.GetChunksGEIndex(context.Background(), 1, 0) - assert.NoError(t, err) - - var expectedNumChunks int = 2 - var numBlocksMultiplier uint64 = 255 - assert.Len(t, chunks, expectedNumChunks) - - for i, chunk := range chunks { - expected := numBlocksMultiplier * (uint64(i) + 1) - if expected > 2000 { - expected = 2000 - } - assert.Equal(t, expected, chunk.EndBlockNumber) - } -} - func testChunkProposerUncompressedBatchBytesLimitCodecV8(t *testing.T) { db := setupDB(t) defer database.CloseDB(db) @@ -204,7 +150,6 @@ func testChunkProposerUncompressedBatchBytesLimitCodecV8(t *testing.T) { // Set max_uncompressed_batch_bytes_size to 4KiB (4 * 1024) // One block (~3KiB) should fit, but two blocks (~6KiB) should exceed the limit cp := NewChunkProposer(context.Background(), &config.ChunkProposerConfig{ - MaxBlockNumPerChunk: math.MaxUint64, // No block number limit MaxL2GasPerChunk: math.MaxUint64, // No gas limit ChunkTimeoutSec: math.MaxUint32, // No timeout limit MaxUncompressedBatchBytesSize: 4 * 1024, // 4KiB limit diff --git a/rollup/internal/controller/watcher/watcher_test.go b/rollup/internal/controller/watcher/watcher_test.go index 1e76cc0a0..e9c3f0373 100644 --- a/rollup/internal/controller/watcher/watcher_test.go +++ b/rollup/internal/controller/watcher/watcher_test.go @@ -102,7 +102,6 @@ func TestFunction(t *testing.T) { // Run chunk proposer test cases. t.Run("TestChunkProposerLimitsCodecV7", testChunkProposerLimitsCodecV7) - t.Run("TestChunkProposerBlobSizeLimitCodecV7", testChunkProposerBlobSizeLimitCodecV7) t.Run("TestChunkProposerUncompressedBatchBytesLimitCodecV8", testChunkProposerUncompressedBatchBytesLimitCodecV8) // Run batch proposer test cases. diff --git a/rollup/proposer-tool-config.json b/rollup/proposer-tool-config.json index 433f36728..bd7cda5b3 100644 --- a/rollup/proposer-tool-config.json +++ b/rollup/proposer-tool-config.json @@ -2,7 +2,6 @@ "l2_config": { "endpoint": "https://rpc.scroll.io", "chunk_proposer_config": { - "max_block_num_per_chunk": 100, "max_l2_gas_per_chunk": 20000000, "chunk_timeout_sec": 72000000000, "max_uncompressed_batch_bytes_size": 4194304 diff --git a/rollup/tests/rollup_test.go b/rollup/tests/rollup_test.go index 4296d9014..a77a122da 100644 --- a/rollup/tests/rollup_test.go +++ b/rollup/tests/rollup_test.go @@ -118,7 +118,6 @@ func testCommitBatchAndFinalizeBundleCodecV7(t *testing.T) { } cp := watcher.NewChunkProposer(context.Background(), &config.ChunkProposerConfig{ - MaxBlockNumPerChunk: 100, MaxL2GasPerChunk: math.MaxUint64, ChunkTimeoutSec: 300, MaxUncompressedBatchBytesSize: math.MaxUint64,