Assessment reports>Cloak V1>Threat Model>finalizeBundle

Function: finalizeBundle(bytes batchHeader, uint256 totalL1MessagesPoppedOverall, bytes aggrProof)

This is the prover entry point that validates an aggregated proof for pending batches.

Inputs

  • batchHeader

    • Control: Prover (PROVER_ROLE).

    • Constraints: Must represent the latest committed batch.

    • Impact: Determines which batch index/hash are finalized and emitted.

  • totalL1MessagesPoppedOverall

    • Control: Prover (PROVER_ROLE).

    • Constraints: Should align with the queue state proven in aggrProof — used to getMessageRollingHash and _getEncryptionKey and must not exceed queue bounds.

    • Impact: Dictates which cross-domain messages are marked finalized and which encryption key is included in public inputs.

  • aggrProof

    • Control: Prover (PROVER_ROLE).

    • Constraints: Must satisfy IRollupVerifier.verifyBundleProof.

    • Impact: Successful verification authorizes updating finalization state.

Branches and code coverage

Intended branches

  • Reverts when the header does not correspond to a committed batch.

  • Reverts when finalizing an already verified batch.

  • Reverts when queue/proof validation fails.

  • Successful finalization updates indexes and finalizes queue entries.

Negative behavior

  • A caller without PROVER_ROLE reverts via onlyRole.

  • Paused-contract scenario (whenNotPaused) is not covered.

Function call analysis

  • this._finalizeBundle(batchHeader, totalL1MessagesPoppedOverall, aggrProof) -> this._beforeFinalizeBatch(batchHeader) -> this._loadBatchHeader(batchHeader, this.lastCommittedBatchIndex) -> BatchHeaderValidiumV0Codec.loadAndValidate(_batchHeader)

    • What is controllable? Entire header bytes supplied by the admin.

    • If the return value is controllable, how is it used and how can it go wrong? Returns pointer/length only when the header is well-formed — malformed data reverts before state changes.

    • What happens if it reverts, reenters or does other unusual control flow? N/A.

  • this._finalizeBundle(batchHeader, totalL1MessagesPoppedOverall, aggrProof) -> this._beforeFinalizeBatch(batchHeader) -> this._loadBatchHeader(batchHeader, this.lastCommittedBatchIndex) -> BatchHeaderValidiumV0Codec.getBatchIndex(batchPtr)

    • What is controllable? Derived from the decoded header.

    • If the return value is controllable, how is it used and how can it go wrong? Must be ≤ lastCommittedBatchIndex — out-of-range values revert.

    • What happens if it reverts, reenters or does other unusual control flow? N/A.

  • this._finalizeBundle(batchHeader, totalL1MessagesPoppedOverall, aggrProof) -> this._beforeFinalizeBatch(batchHeader) -> this._loadBatchHeader(batchHeader, this.lastCommittedBatchIndex) -> BatchHeaderValidiumV0Codec.computeBatchHash(batchPtr, length)

    • What is controllable? Derived from the decoded header.

    • If the return value is controllable, how is it used and how can it go wrong? The resulting hash must match storage.

    • What happens if it reverts, reenters or does other unusual control flow? N/A.

  • this._finalizeBundle(batchHeader, totalL1MessagesPoppedOverall, aggrProof) -> this._beforeFinalizeBatch(batchHeader) -> this._loadBatchHeader(batchHeader, this.lastCommittedBatchIndex)

    • What is controllable? Header inputs validated above.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the batch index.

    • What happens if it reverts, reenters or does other unusual control flow? N/A.

  • this._finalizeBundle(batchHeader, totalL1MessagesPoppedOverall, aggrProof) -> this._beforeFinalizeBatch(batchHeader) -> BatchHeaderValidiumV0Codec.getVersion(batchPtr)

    • What is controllable? Version byte embedded in the header.

    • If the return value is controllable, how is it used and how can it go wrong? N/A.

    • What happens if it reverts, reenters or does other unusual control flow? N/A.

  • this._finalizeBundle(batchHeader, totalL1MessagesPoppedOverall, aggrProof) -> IL1MessageQueueV2(this.messageQueueV2).getMessageRollingHash (totalL1MessagesPoppedOverall - 1)

    • What is controllable? Index argument derived from totalL1MessagesPoppedOverall.

    • If the return value is controllable, how is it used and how can it go wrong? Produces the queue hash included in public inputs.

    • What happens if it reverts, reenters or does other unusual control flow? N/A.

  • this._finalizeBundle(batchHeader, totalL1MessagesPoppedOverall, aggrProof) -> IRollupVerifier(this.verifier).verifyBundleProof(version, batchIndex, aggrProof, publicInputs)

    • What is controllable? Proof bytes from the prover.

    • If the return value is controllable, how is it used and how can it go wrong? Verification must succeed.

    • What happens if it reverts, reenters or does other unusual control flow? N/A.

  • this._finalizeBundle(batchHeader, totalL1MessagesPoppedOverall, aggrProof) -> this._afterFinalizeBatch(batchIndex, batchHash, totalL1MessagesPoppedOverall, postStateRoot, withdrawRoot) -> IL1MessageQueueV2(this.messageQueueV2).finalizePoppedCrossDomainMessage( totalL1MessagesPoppedOverall)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? Completes cross-domain--message finalization.

    • What happens if it reverts, reenters or does other unusual control flow? N/A.

Zellic © 2025Back to top ↑