From 98ee895c1c4b087a12abc912c8e40a346e26f8ad Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Mon, 1 Sep 2025 08:50:30 +0800 Subject: [PATCH 1/6] remove max_chunks_per_batch and max_block_num_per_chunk configuration parameters --- permissionless-batches/conf/relayer/config.json | 2 -- rollup/cmd/proposer_tool/app/app.go | 3 --- rollup/cmd/rollup_relayer/app/app.go | 3 --- rollup/conf/config.json | 2 -- rollup/internal/config/l2.go | 2 -- .../internal/controller/watcher/batch_proposer.go | 4 ++-- .../controller/watcher/batch_proposer_test.go | 12 ++---------- .../controller/watcher/bundle_proposer_test.go | 4 +--- .../internal/controller/watcher/chunk_proposer.go | 14 ++++++-------- .../controller/watcher/chunk_proposer_test.go | 13 ++----------- rollup/proposer-tool-config.json | 2 -- rollup/tests/rollup_test.go | 2 -- 12 files changed, 13 insertions(+), 50 deletions(-) diff --git a/permissionless-batches/conf/relayer/config.json b/permissionless-batches/conf/relayer/config.json index f7f785cb9c..a7d4061d48 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 @@ -23,7 +22,6 @@ "batch_proposer_config": { "propose_interval_milliseconds": 1000, "batch_timeout_sec": 300, - "max_chunks_per_batch": 45, "max_uncompressed_batch_bytes_size": 4194304 }, "bundle_proposer_config": { diff --git a/rollup/cmd/proposer_tool/app/app.go b/rollup/cmd/proposer_tool/app/app.go index e2429d3dc4..d725135cda 100644 --- a/rollup/cmd/proposer_tool/app/app.go +++ b/rollup/cmd/proposer_tool/app/app.go @@ -59,9 +59,6 @@ func action(ctx *cli.Context) error { } // sanity check config - if cfg.L2Config.BatchProposerConfig.MaxChunksPerBatch <= 0 { - log.Crit("cfg.L2Config.BatchProposerConfig.MaxChunksPerBatch must be greater than 0") - } if cfg.L2Config.ChunkProposerConfig.MaxL2GasPerChunk <= 0 { log.Crit("cfg.L2Config.ChunkProposerConfig.MaxL2GasPerChunk must be greater than 0") } diff --git a/rollup/cmd/rollup_relayer/app/app.go b/rollup/cmd/rollup_relayer/app/app.go index a7111d7be7..5f6d669afd 100644 --- a/rollup/cmd/rollup_relayer/app/app.go +++ b/rollup/cmd/rollup_relayer/app/app.go @@ -90,9 +90,6 @@ func action(ctx *cli.Context) error { if cfg.L2Config.RelayerConfig.BatchSubmission.MaxBatches < 1 { log.Crit("cfg.L2Config.RelayerConfig.SenderConfig.BatchSubmission.MaxBatches must be at least 1") } - if cfg.L2Config.BatchProposerConfig.MaxChunksPerBatch <= 0 { - log.Crit("cfg.L2Config.BatchProposerConfig.MaxChunksPerBatch must be greater than 0") - } if cfg.L2Config.ChunkProposerConfig.MaxL2GasPerChunk <= 0 { log.Crit("cfg.L2Config.ChunkProposerConfig.MaxL2GasPerChunk must be greater than 0") } diff --git a/rollup/conf/config.json b/rollup/conf/config.json index f6a634eda9..1d6475aa9b 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 @@ -100,7 +99,6 @@ "batch_proposer_config": { "propose_interval_milliseconds": 1000, "batch_timeout_sec": 300, - "max_chunks_per_batch": 45, "max_uncompressed_batch_bytes_size": 4194304 }, "bundle_proposer_config": { diff --git a/rollup/internal/config/l2.go b/rollup/internal/config/l2.go index 26da137ef2..1769294436 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"` @@ -41,7 +40,6 @@ type ChunkProposerConfig struct { type BatchProposerConfig struct { ProposeIntervalMilliseconds uint64 `json:"propose_interval_milliseconds"` BatchTimeoutSec uint64 `json:"batch_timeout_sec"` - MaxChunksPerBatch int `json:"max_chunks_per_batch"` MaxUncompressedBatchBytesSize uint64 `json:"max_uncompressed_batch_bytes_size"` } diff --git a/rollup/internal/controller/watcher/batch_proposer.go b/rollup/internal/controller/watcher/batch_proposer.go index 522ce07cb7..a073789e96 100644 --- a/rollup/internal/controller/watcher/batch_proposer.go +++ b/rollup/internal/controller/watcher/batch_proposer.go @@ -243,8 +243,8 @@ func (p *BatchProposer) proposeBatch() error { return fmt.Errorf("unsupported codec version: %v, expected at least %v", codec.Version(), p.minCodecVersion) } - // always take the minimum of the configured max chunks per batch and the codec's max chunks per batch - maxChunksThisBatch := min(codec.MaxNumChunksPerBatch(), p.cfg.MaxChunksPerBatch) + // use the codec's max chunks per batch limit + maxChunksThisBatch := codec.MaxNumChunksPerBatch() // select at most maxChunkNumPerBatch chunks dbChunks, err := p.chunkOrm.GetChunksGEIndex(p.ctx, firstUnbatchedChunkIndex, maxChunksThisBatch) diff --git a/rollup/internal/controller/watcher/batch_proposer_test.go b/rollup/internal/controller/watcher/batch_proposer_test.go index 526c93655f..318e6009e7 100644 --- a/rollup/internal/controller/watcher/batch_proposer_test.go +++ b/rollup/internal/controller/watcher/batch_proposer_test.go @@ -72,8 +72,7 @@ func testBatchProposerLimitsCodecV7(t *testing.T) { assert.NoError(t, err) cp := NewChunkProposer(context.Background(), &config.ChunkProposerConfig{ - MaxBlockNumPerChunk: 1, - MaxL2GasPerChunk: 20000000, + MaxL2GasPerChunk: 1100000, // Allow only 1 block per chunk ChunkTimeoutSec: 300, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV7, ¶ms.ChainConfig{ @@ -89,7 +88,6 @@ func testBatchProposerLimitsCodecV7(t *testing.T) { cp.TryProposeChunk() // chunk2 contains block2 bp := NewBatchProposer(context.Background(), &config.BatchProposerConfig{ - MaxChunksPerBatch: math.MaxInt32, BatchTimeoutSec: tt.batchTimeoutSec, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV7, ¶ms.ChainConfig{ @@ -154,7 +152,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, @@ -175,7 +172,6 @@ func testBatchProposerBlobSizeLimitCodecV7(t *testing.T) { } bp := NewBatchProposer(context.Background(), &config.BatchProposerConfig{ - MaxChunksPerBatch: math.MaxInt32, BatchTimeoutSec: math.MaxUint32, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV7, chainConfig, db, false /* rollup mode */, nil) @@ -227,7 +223,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, @@ -243,7 +238,6 @@ func testBatchProposerMaxChunkNumPerBatchLimitCodecV7(t *testing.T) { } bp := NewBatchProposer(context.Background(), &config.BatchProposerConfig{ - MaxChunksPerBatch: 45, BatchTimeoutSec: math.MaxUint32, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV7, chainConfig, db, false /* rollup mode */, nil) @@ -309,8 +303,7 @@ 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: 1100000, // One block per chunk via gas limit ChunkTimeoutSec: math.MaxUint32, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV8, chainConfig, db, nil) @@ -332,7 +325,6 @@ func testBatchProposerUncompressedBatchBytesLimitCodecV8(t *testing.T) { // Create batch proposer with 4KiB uncompressed batch bytes limit // Each chunk is ~3KiB, so 1 chunk (~3KiB) should fit, but 2 chunks (~6KiB) should exceed limit bp := NewBatchProposer(context.Background(), &config.BatchProposerConfig{ - MaxChunksPerBatch: math.MaxInt32, // No chunk count limit BatchTimeoutSec: math.MaxUint32, // No timeout limit MaxUncompressedBatchBytesSize: 4 * 1024, // 4KiB limit }, encoding.CodecV8, chainConfig, db, false /* rollup mode */, nil) diff --git a/rollup/internal/controller/watcher/bundle_proposer_test.go b/rollup/internal/controller/watcher/bundle_proposer_test.go index 7e2f27da43..13c3f95e9e 100644 --- a/rollup/internal/controller/watcher/bundle_proposer_test.go +++ b/rollup/internal/controller/watcher/bundle_proposer_test.go @@ -93,14 +93,12 @@ func testBundleProposerLimitsCodecV7(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: 1, - MaxL2GasPerChunk: math.MaxUint64, + MaxL2GasPerChunk: 1100000, // One block per chunk via gas limit ChunkTimeoutSec: math.MaxUint32, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV7, chainConfig, db, nil) bap := NewBatchProposer(context.Background(), &config.BatchProposerConfig{ - MaxChunksPerBatch: math.MaxInt32, BatchTimeoutSec: 0, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV7, chainConfig, db, false /* rollup mode */, nil) diff --git a/rollup/internal/controller/watcher/chunk_proposer.go b/rollup/internal/controller/watcher/chunk_proposer.go index 04e2ffaeae..cbec1ef035 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, 100000) 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 218bc4c9f4..23d4a2946c 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, @@ -130,7 +123,6 @@ func testChunkProposerBlobSizeLimitCodecV7(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: 255, MaxL2GasPerChunk: math.MaxUint64, ChunkTimeoutSec: math.MaxUint32, MaxUncompressedBatchBytesSize: math.MaxUint64, @@ -204,7 +196,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/proposer-tool-config.json b/rollup/proposer-tool-config.json index 433f367286..6685d224bc 100644 --- a/rollup/proposer-tool-config.json +++ b/rollup/proposer-tool-config.json @@ -2,14 +2,12 @@ "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 }, "batch_proposer_config": { "batch_timeout_sec": 72000000000, - "max_chunks_per_batch": 45, "max_uncompressed_batch_bytes_size": 4194304 }, "bundle_proposer_config": { diff --git a/rollup/tests/rollup_test.go b/rollup/tests/rollup_test.go index 4296d90146..2449fd59fc 100644 --- a/rollup/tests/rollup_test.go +++ b/rollup/tests/rollup_test.go @@ -118,14 +118,12 @@ func testCommitBatchAndFinalizeBundleCodecV7(t *testing.T) { } cp := watcher.NewChunkProposer(context.Background(), &config.ChunkProposerConfig{ - MaxBlockNumPerChunk: 100, MaxL2GasPerChunk: math.MaxUint64, ChunkTimeoutSec: 300, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV7, chainConfig, db, nil) bap := watcher.NewBatchProposer(context.Background(), &config.BatchProposerConfig{ - MaxChunksPerBatch: math.MaxInt32, BatchTimeoutSec: 300, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV7, chainConfig, db, false /* rollup mode */, nil) From bd372ded4c20325be987b9c26b7cd2a7ca74877f Mon Sep 17 00:00:00 2001 From: jonastheis Date: Mon, 1 Sep 2025 00:52:31 +0000 Subject: [PATCH 2/6] =?UTF-8?q?chore:=20auto=20version=20bump=E2=80=89[bot?= =?UTF-8?q?]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/version/version.go b/common/version/version.go index 5d3d41bc12..1234aadbdd 100644 --- a/common/version/version.go +++ b/common/version/version.go @@ -5,7 +5,7 @@ import ( "runtime/debug" ) -var tag = "v4.5.43" +var tag = "v4.5.44" var commit = func() string { if info, ok := debug.ReadBuildInfo(); ok { From 2206ca88f76e12d892d8f17bd340e2ed90170c72 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Mon, 8 Sep 2025 10:17:37 +0800 Subject: [PATCH 3/6] restore max_chunks_per_batch parameter --- permissionless-batches/conf/relayer/config.json | 1 + rollup/cmd/proposer_tool/app/app.go | 3 +++ rollup/cmd/rollup_relayer/app/app.go | 3 +++ rollup/conf/config.json | 1 + rollup/internal/config/l2.go | 1 + rollup/internal/controller/watcher/batch_proposer.go | 4 ++-- rollup/internal/controller/watcher/batch_proposer_test.go | 4 ++++ rollup/proposer-tool-config.json | 1 + rollup/tests/rollup_test.go | 1 + 9 files changed, 17 insertions(+), 2 deletions(-) diff --git a/permissionless-batches/conf/relayer/config.json b/permissionless-batches/conf/relayer/config.json index a7d4061d48..9b812fa99b 100644 --- a/permissionless-batches/conf/relayer/config.json +++ b/permissionless-batches/conf/relayer/config.json @@ -22,6 +22,7 @@ "batch_proposer_config": { "propose_interval_milliseconds": 1000, "batch_timeout_sec": 300, + "max_chunks_per_batch": 45, "max_uncompressed_batch_bytes_size": 4194304 }, "bundle_proposer_config": { diff --git a/rollup/cmd/proposer_tool/app/app.go b/rollup/cmd/proposer_tool/app/app.go index d725135cda..e2429d3dc4 100644 --- a/rollup/cmd/proposer_tool/app/app.go +++ b/rollup/cmd/proposer_tool/app/app.go @@ -59,6 +59,9 @@ func action(ctx *cli.Context) error { } // sanity check config + if cfg.L2Config.BatchProposerConfig.MaxChunksPerBatch <= 0 { + log.Crit("cfg.L2Config.BatchProposerConfig.MaxChunksPerBatch must be greater than 0") + } if cfg.L2Config.ChunkProposerConfig.MaxL2GasPerChunk <= 0 { log.Crit("cfg.L2Config.ChunkProposerConfig.MaxL2GasPerChunk must be greater than 0") } diff --git a/rollup/cmd/rollup_relayer/app/app.go b/rollup/cmd/rollup_relayer/app/app.go index 5f6d669afd..a7111d7be7 100644 --- a/rollup/cmd/rollup_relayer/app/app.go +++ b/rollup/cmd/rollup_relayer/app/app.go @@ -90,6 +90,9 @@ func action(ctx *cli.Context) error { if cfg.L2Config.RelayerConfig.BatchSubmission.MaxBatches < 1 { log.Crit("cfg.L2Config.RelayerConfig.SenderConfig.BatchSubmission.MaxBatches must be at least 1") } + if cfg.L2Config.BatchProposerConfig.MaxChunksPerBatch <= 0 { + log.Crit("cfg.L2Config.BatchProposerConfig.MaxChunksPerBatch must be greater than 0") + } if cfg.L2Config.ChunkProposerConfig.MaxL2GasPerChunk <= 0 { log.Crit("cfg.L2Config.ChunkProposerConfig.MaxL2GasPerChunk must be greater than 0") } diff --git a/rollup/conf/config.json b/rollup/conf/config.json index 1d6475aa9b..8055008cd6 100644 --- a/rollup/conf/config.json +++ b/rollup/conf/config.json @@ -99,6 +99,7 @@ "batch_proposer_config": { "propose_interval_milliseconds": 1000, "batch_timeout_sec": 300, + "max_chunks_per_batch": 45, "max_uncompressed_batch_bytes_size": 4194304 }, "bundle_proposer_config": { diff --git a/rollup/internal/config/l2.go b/rollup/internal/config/l2.go index 1769294436..91ea322cd0 100644 --- a/rollup/internal/config/l2.go +++ b/rollup/internal/config/l2.go @@ -40,6 +40,7 @@ type ChunkProposerConfig struct { type BatchProposerConfig struct { ProposeIntervalMilliseconds uint64 `json:"propose_interval_milliseconds"` BatchTimeoutSec uint64 `json:"batch_timeout_sec"` + MaxChunksPerBatch int `json:"max_chunks_per_batch"` MaxUncompressedBatchBytesSize uint64 `json:"max_uncompressed_batch_bytes_size"` } diff --git a/rollup/internal/controller/watcher/batch_proposer.go b/rollup/internal/controller/watcher/batch_proposer.go index a073789e96..522ce07cb7 100644 --- a/rollup/internal/controller/watcher/batch_proposer.go +++ b/rollup/internal/controller/watcher/batch_proposer.go @@ -243,8 +243,8 @@ func (p *BatchProposer) proposeBatch() error { return fmt.Errorf("unsupported codec version: %v, expected at least %v", codec.Version(), p.minCodecVersion) } - // use the codec's max chunks per batch limit - maxChunksThisBatch := codec.MaxNumChunksPerBatch() + // always take the minimum of the configured max chunks per batch and the codec's max chunks per batch + maxChunksThisBatch := min(codec.MaxNumChunksPerBatch(), p.cfg.MaxChunksPerBatch) // select at most maxChunkNumPerBatch chunks dbChunks, err := p.chunkOrm.GetChunksGEIndex(p.ctx, firstUnbatchedChunkIndex, maxChunksThisBatch) diff --git a/rollup/internal/controller/watcher/batch_proposer_test.go b/rollup/internal/controller/watcher/batch_proposer_test.go index 318e6009e7..d75924d30d 100644 --- a/rollup/internal/controller/watcher/batch_proposer_test.go +++ b/rollup/internal/controller/watcher/batch_proposer_test.go @@ -88,6 +88,7 @@ func testBatchProposerLimitsCodecV7(t *testing.T) { cp.TryProposeChunk() // chunk2 contains block2 bp := NewBatchProposer(context.Background(), &config.BatchProposerConfig{ + MaxChunksPerBatch: math.MaxInt32, BatchTimeoutSec: tt.batchTimeoutSec, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV7, ¶ms.ChainConfig{ @@ -172,6 +173,7 @@ func testBatchProposerBlobSizeLimitCodecV7(t *testing.T) { } bp := NewBatchProposer(context.Background(), &config.BatchProposerConfig{ + MaxChunksPerBatch: math.MaxInt32, BatchTimeoutSec: math.MaxUint32, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV7, chainConfig, db, false /* rollup mode */, nil) @@ -238,6 +240,7 @@ func testBatchProposerMaxChunkNumPerBatchLimitCodecV7(t *testing.T) { } bp := NewBatchProposer(context.Background(), &config.BatchProposerConfig{ + MaxChunksPerBatch: 45, BatchTimeoutSec: math.MaxUint32, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV7, chainConfig, db, false /* rollup mode */, nil) @@ -325,6 +328,7 @@ func testBatchProposerUncompressedBatchBytesLimitCodecV8(t *testing.T) { // Create batch proposer with 4KiB uncompressed batch bytes limit // Each chunk is ~3KiB, so 1 chunk (~3KiB) should fit, but 2 chunks (~6KiB) should exceed limit bp := NewBatchProposer(context.Background(), &config.BatchProposerConfig{ + MaxChunksPerBatch: math.MaxInt32, // No chunk count limit BatchTimeoutSec: math.MaxUint32, // No timeout limit MaxUncompressedBatchBytesSize: 4 * 1024, // 4KiB limit }, encoding.CodecV8, chainConfig, db, false /* rollup mode */, nil) diff --git a/rollup/proposer-tool-config.json b/rollup/proposer-tool-config.json index 6685d224bc..bd7cda5b33 100644 --- a/rollup/proposer-tool-config.json +++ b/rollup/proposer-tool-config.json @@ -8,6 +8,7 @@ }, "batch_proposer_config": { "batch_timeout_sec": 72000000000, + "max_chunks_per_batch": 45, "max_uncompressed_batch_bytes_size": 4194304 }, "bundle_proposer_config": { diff --git a/rollup/tests/rollup_test.go b/rollup/tests/rollup_test.go index 2449fd59fc..a77a122dac 100644 --- a/rollup/tests/rollup_test.go +++ b/rollup/tests/rollup_test.go @@ -124,6 +124,7 @@ func testCommitBatchAndFinalizeBundleCodecV7(t *testing.T) { }, encoding.CodecV7, chainConfig, db, nil) bap := watcher.NewBatchProposer(context.Background(), &config.BatchProposerConfig{ + MaxChunksPerBatch: math.MaxInt32, BatchTimeoutSec: 300, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV7, chainConfig, db, false /* rollup mode */, nil) From 065f42b5979cc5adf8b20ed9f9b21d7195771d80 Mon Sep 17 00:00:00 2001 From: jonastheis Date: Mon, 8 Sep 2025 02:23:33 +0000 Subject: [PATCH 4/6] =?UTF-8?q?chore:=20auto=20version=20bump=E2=80=89[bot?= =?UTF-8?q?]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/version/version.go b/common/version/version.go index 13a7597d4b..df872f409f 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 { From 2bef4e4205de06ab5b2237ab4414a2af3dbd3180 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Tue, 9 Sep 2025 16:57:34 +0800 Subject: [PATCH 5/6] address review comments --- rollup/internal/controller/watcher/bundle_proposer_test.go | 1 + rollup/internal/controller/watcher/chunk_proposer.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rollup/internal/controller/watcher/bundle_proposer_test.go b/rollup/internal/controller/watcher/bundle_proposer_test.go index 13c3f95e9e..bf824efc2c 100644 --- a/rollup/internal/controller/watcher/bundle_proposer_test.go +++ b/rollup/internal/controller/watcher/bundle_proposer_test.go @@ -99,6 +99,7 @@ func testBundleProposerLimitsCodecV7(t *testing.T) { }, encoding.CodecV7, chainConfig, db, nil) bap := NewBatchProposer(context.Background(), &config.BatchProposerConfig{ + MaxChunksPerBatch: math.MaxInt32, BatchTimeoutSec: 0, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV7, chainConfig, db, false /* rollup mode */, nil) diff --git a/rollup/internal/controller/watcher/chunk_proposer.go b/rollup/internal/controller/watcher/chunk_proposer.go index cbec1ef035..d6a0706377 100644 --- a/rollup/internal/controller/watcher/chunk_proposer.go +++ b/rollup/internal/controller/watcher/chunk_proposer.go @@ -233,7 +233,7 @@ func (p *ChunkProposer) ProposeChunk() error { // 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, 100000) + blocks, err := p.l2BlockOrm.GetL2BlocksGEHeight(p.ctx, unchunkedBlockHeight, 1000) if err != nil { return err } From 17805ea9e38d6e680da543690b1b15283d8c1438 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 10 Sep 2025 08:59:38 +0800 Subject: [PATCH 6/6] fix tests --- .../controller/watcher/batch_proposer_test.go | 12 +++-- .../watcher/bundle_proposer_test.go | 9 +++- .../controller/watcher/chunk_proposer_test.go | 46 ------------------- .../controller/watcher/watcher_test.go | 1 - 4 files changed, 14 insertions(+), 54 deletions(-) diff --git a/rollup/internal/controller/watcher/batch_proposer_test.go b/rollup/internal/controller/watcher/batch_proposer_test.go index d75924d30d..f86b81f71a 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,7 +72,7 @@ func testBatchProposerLimitsCodecV7(t *testing.T) { assert.NoError(t, err) cp := NewChunkProposer(context.Background(), &config.ChunkProposerConfig{ - MaxL2GasPerChunk: 1100000, // Allow only 1 block per chunk + MaxL2GasPerChunk: math.MaxUint64, ChunkTimeoutSec: 300, MaxUncompressedBatchBytesSize: math.MaxUint64, }, encoding.CodecV7, ¶ms.ChainConfig{ @@ -306,14 +306,14 @@ func testBatchProposerUncompressedBatchBytesLimitCodecV8(t *testing.T) { // Create chunk proposer with no uncompressed batch bytes limit for chunks cp := NewChunkProposer(context.Background(), &config.ChunkProposerConfig{ - MaxL2GasPerChunk: 1100000, // One block per chunk via gas limit + 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 @@ -322,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 bf824efc2c..29c8dfe0ab 100644 --- a/rollup/internal/controller/watcher/bundle_proposer_test.go +++ b/rollup/internal/controller/watcher/bundle_proposer_test.go @@ -86,14 +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{ - MaxL2GasPerChunk: 1100000, // One block per chunk via gas limit + 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_test.go b/rollup/internal/controller/watcher/chunk_proposer_test.go index 23d4a2946c..63fe72463b 100644 --- a/rollup/internal/controller/watcher/chunk_proposer_test.go +++ b/rollup/internal/controller/watcher/chunk_proposer_test.go @@ -103,52 +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{ - 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) diff --git a/rollup/internal/controller/watcher/watcher_test.go b/rollup/internal/controller/watcher/watcher_test.go index 1e76cc0a0e..e9c3f03730 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.