From a3c5f29ec9e13aa820ee8d7aacfb7dafffe19fcc Mon Sep 17 00:00:00 2001 From: corey Date: Fri, 24 Apr 2026 17:44:22 +0800 Subject: [PATCH] fix(derivation): advance L1 message cursor for skipped blocks When a node starts from a snapshot, blocks in the current batch whose number is <= the local L2 height are skipped to avoid re-injecting L1 messages. However, the L1 message cursor (totalL1MessagePopped) was not advanced for those skipped blocks, causing subsequent blocks in the same batch to read L1 messages from the wrong offset. This could fail the length check, or worse, prepend incorrect L1 transactions to a block's SafeL2Data. Always advance the cursor by block.l1MsgNum, even when the block is skipped, so that the per-batch L1 message offsets stay aligned with the batch encoding. Also fix the error message to print the number of L1 messages received instead of the entire slice. Made-with: Cursor --- node/derivation/derivation.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/node/derivation/derivation.go b/node/derivation/derivation.go index 8fb311b0e..e8b632575 100644 --- a/node/derivation/derivation.go +++ b/node/derivation/derivation.go @@ -566,8 +566,12 @@ func (d *Derivation) parseBatch(batch geth.RPCRollupBatch, l2Height uint64) (*Ba func (d *Derivation) handleL1Message(rollupData *BatchInfo, parentTotalL1MessagePopped, l2Height uint64) error { totalL1MessagePopped := parentTotalL1MessagePopped for bIndex, block := range rollupData.blockContexts { - // This may happen to nodes started from snapshot, in which case we will no longer handle L1Msg + // Nodes started from a snapshot may have already executed earlier blocks in + // this batch. We skip injecting L1 messages for those blocks, but the L1 + // message cursor must still advance so that subsequent blocks in the same + // batch read their L1 messages from the correct offset. if block.Number <= l2Height { + totalL1MessagePopped += uint64(block.l1MsgNum) continue } var l1Transactions []*eth.Transaction @@ -576,7 +580,7 @@ func (d *Derivation) handleL1Message(rollupData *BatchInfo, parentTotalL1Message return fmt.Errorf("get l1 message error:%v", err) } if len(l1Messages) != int(block.l1MsgNum) { - return fmt.Errorf("invalid l1 msg num,expect %v,have %v", block.l1MsgNum, l1Messages) + return fmt.Errorf("invalid l1 msg num,expect %v,have %v", block.l1MsgNum, len(l1Messages)) } totalL1MessagePopped += uint64(block.l1MsgNum) if len(l1Messages) > 0 {