diff --git a/yarn-project/prover-client/src/light/lightweight_checkpoint_builder.test.ts b/yarn-project/prover-client/src/light/lightweight_checkpoint_builder.test.ts index 0777f473ab69..218870d8a3af 100644 --- a/yarn-project/prover-client/src/light/lightweight_checkpoint_builder.test.ts +++ b/yarn-project/prover-client/src/light/lightweight_checkpoint_builder.test.ts @@ -328,5 +328,35 @@ describe('LightweightCheckpointBuilder', () => { await fork.close(); }); + + it('adding a block with a mismatched block number fails with archive tree leaf index mismatch', async () => { + const checkpointNumber = CheckpointNumber(1); + const slotNumber = SlotNumber(15); + + const constants = makeCheckpointConstants(slotNumber); + const l1ToL2Messages: Fr[] = []; + const previousCheckpointOutHashes: Fr[] = []; + + const fork = await worldState.fork(); + + const checkpointBuilder = await LightweightCheckpointBuilder.startNewCheckpoint( + checkpointNumber, + constants, + l1ToL2Messages, + previousCheckpointOutHashes, + fork, + ); + + // Pass block number 5 when the archive tree expects block 1. + // After updateArchive, nextAvailableLeafIndex will be 2 but expectedNextLeafIndex will be 6. + const wrongBlockNumber = BlockNumber(5); + const globalVariables = makeGlobalVariables(wrongBlockNumber, slotNumber); + + await expect(checkpointBuilder.addBlock(globalVariables, [], { insertTxsEffects: true })).rejects.toThrow( + /Archive tree next leaf index mismatch/, + ); + + await fork.close(); + }); }); }); diff --git a/yarn-project/prover-client/src/light/lightweight_checkpoint_builder.ts b/yarn-project/prover-client/src/light/lightweight_checkpoint_builder.ts index d8784c80cd39..1e72a75d7684 100644 --- a/yarn-project/prover-client/src/light/lightweight_checkpoint_builder.ts +++ b/yarn-project/prover-client/src/light/lightweight_checkpoint_builder.ts @@ -220,6 +220,13 @@ export class LightweightCheckpointBuilder { timings.updateArchive = msUpdateArchive; this.lastArchives.push(newArchive); + const expectedNextLeafIndex = Number(globalVariables.blockNumber) + 1; + if (newArchive.nextAvailableLeafIndex !== expectedNextLeafIndex) { + throw new Error( + `Archive tree next leaf index mismatch after building block ${globalVariables.blockNumber} (expected ${expectedNextLeafIndex} but got ${newArchive.nextAvailableLeafIndex})`, + ); + } + const indexWithinCheckpoint = IndexWithinCheckpoint(this.blocks.length); const block = new L2Block(newArchive, header, body, this.checkpointNumber, indexWithinCheckpoint); this.blocks.push(block);