From aee88557548c7de4126e8058662abed5c62fa43d Mon Sep 17 00:00:00 2001 From: corey Date: Mon, 11 May 2026 15:17:41 +0800 Subject: [PATCH] fix(derivation): guard against blockCount underflow on malformed batches batch.LastBlockNumber and the reference block (decoded startBlock for the V0->V1+ transition or parent header's LastBlockNumber for V1+) are not constrained by the L1 Rollup contract, so a malformed batch with LastBlockNumber below the reference would underflow blockCount and lead to a makeslice panic downstream in the blob-only path. Reject such batches with a clear error before subtracting. Co-authored-by: Cursor --- node/derivation/batch_info.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/node/derivation/batch_info.go b/node/derivation/batch_info.go index add7efe36..d9616634b 100644 --- a/node/derivation/batch_info.go +++ b/node/derivation/batch_info.go @@ -135,12 +135,22 @@ func (bi *BatchInfo) ParseBatch(batch geth.RPCRollupBatch) error { if err := startBlock.Decode(batchBytes[:60]); err != nil { return fmt.Errorf("decode chunk block context error:%v", err) } + // Guard against uint64 underflow for malformed batches whose + // LastBlockNumber is below the decoded start block. + if batch.LastBlockNumber < startBlock.Number { + return fmt.Errorf("invalid batch: lastBlockNumber %d < start block %d", batch.LastBlockNumber, startBlock.Number) + } blockCount = batch.LastBlockNumber - startBlock.Number + 1 } else { parentBatchBlock, err := parentBatchHeader.LastBlockNumber() if err != nil { return fmt.Errorf("decode batch header lastBlockNumber error:%v", err) } + // Guard against uint64 underflow for malformed batches whose + // LastBlockNumber is below the parent's lastBlockNumber. + if batch.LastBlockNumber < parentBatchBlock { + return fmt.Errorf("invalid batch: lastBlockNumber %d < parent lastBlockNumber %d", batch.LastBlockNumber, parentBatchBlock) + } blockCount = batch.LastBlockNumber - parentBatchBlock } }