diff --git a/contracts/contracts/l1/rollup/Rollup.sol b/contracts/contracts/l1/rollup/Rollup.sol index 2148bb60..68471420 100644 --- a/contracts/contracts/l1/rollup/Rollup.sol +++ b/contracts/contracts/l1/rollup/Rollup.sol @@ -668,6 +668,17 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { return batchDataStore[batchIndex].finalizeTimestamp > block.timestamp; } + /// @dev proveCommittedBatchState verifies the ZK proof for a committed batch. + function proveCommittedBatchState(bytes calldata _batchHeader, bytes calldata _batchProof) public view { + // get batch data from batch header + (uint256 memPtr, bytes32 _batchHash) = _loadBatchHeader(_batchHeader); + // check batch hash + uint256 _batchIndex = BatchHeaderCodecV0.getBatchIndex(memPtr); + require(committedBatches[_batchIndex] == _batchHash, "incorrect batch hash"); + + _verifyProof(memPtr, _batchProof); + } + /********************** * Internal Functions * **********************/ diff --git a/contracts/contracts/test/Rollup.t.sol b/contracts/contracts/test/Rollup.t.sol index c7fd2ae3..f6744f91 100644 --- a/contracts/contracts/test/Rollup.t.sol +++ b/contracts/contracts/test/Rollup.t.sol @@ -587,6 +587,48 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { assertEq(rollup.lastCommittedBatchIndex(), 1); } + + /// @notice Test: proveCommittedBatchState proves the state of a committed batch. + function test_proveCommittedBatchState() public { + _mockVerifierCall(); + _mockMessageQueueStalled(); + + // Warp time to simulate stall (> rollupDelayPeriod) + hevm.warp(block.timestamp + 7200); + + bytes32 prevStateRoot = bytes32(uint256(1)); + bytes32 postStateRoot = bytes32(uint256(2)); + bytes32 withdrawalRoot = getTreeRoot(); + + IRollup.BatchDataInput memory batchDataInput = IRollup.BatchDataInput({ + version: 0, + parentBatchHeader: batchHeader0, + lastBlockNumber: 1, + numL1Messages: 0, + prevStateRoot: prevStateRoot, + postStateRoot: postStateRoot, + withdrawalRoot: withdrawalRoot + }); + + bytes memory batchHeader1 = _createMatchingBatchHeader(1, 0, prevStateRoot, postStateRoot, withdrawalRoot); + + hevm.prank(alice); + rollup.commitBatchWithProof( + batchDataInput, + batchSignatureInput, + batchHeader1, + hex"deadbeef" // Non-empty proof required + ); + // Verify batch was committed (finalization happens separately via finalizeBatch) + assertEq(rollup.lastCommittedBatchIndex(), 1); + // finalizeTimestamp is set to block.timestamp, allowing immediate finalization + // but lastFinalizedBatchIndex is not updated until finalizeBatch is called + assertEq(rollup.lastFinalizedBatchIndex(), 0); + + bytes + memory proof = hex"ffea2d2e0a0f124b2bc411325821f76e40978468a0892f57f7de20c99a4fe762dbbdfbc929f5b68b89bdecd40143f36782957e6b818fb761be749d283b16daab432f249b0ddb5537d6b7a8275505a9213eb15db1ddb095bada27a03b6f9c4edb5fd8f7110c7438abff87fed406080f3a103ad45c41fdf89542ff037adfe314a39e5688931da3a1f52f19a3a942cd36dace89340bcff9a18420596f6a06e5d14e5230baba07d1fb0a5bd20beb246875f3ad238dc040c347b10795fff4d6a92ac057c61d672f1d17bbab356c0ade3c419fb1d991f879c2d4fa02b8c4c6ad2d78a8338e9c101e7ea8eb9f1fe61a698598959eed8a33919226a623aa1cd5881d2db0d7f1811921abbb34d035056eea6a70c6079d13de1f67ccf4b2c54398a30cbbf490c2206c111c5e8734d5ef6574d1520f0e68acf482d40f11ac18a8316cb524b3b4a8adb8178e4333eb170bc3a0abfe3d69ced1c5f5b781be739ad2c45b8971455681bcd625348a050a4c5ebc469bf5f8ddb95d541baea4b71e9430452e37c084b2d0ab3c104dfe6dfab22413bf9ea4b2009b5248ec471432ab7464546ffe15033df99dba08077a60ae40633c2a5511faba9e00683497059265ab8114546729007d1e50670dc0a2cecf23cbe58417b2cf51afbf3fd8da63d936d8a92b6e9203c89665a3f40447bc5f08016739567287e5e824c164dc0c7dea8e95eddda27c4966c4d6674516d1cf84241a61b7fadbc432ce6253be085ab86771bf573aa6e506b4c98254d0192a1924297c2e29dfa5b19d99a8ff4ca3975803020f6f46c3200e09d2fb47282f5ced534b0301e5f7501aa56dc77d534c25849d7165efdba546883dda634db60f2d4a9ab608827d63a37020466318f704e30ba4223106a8092f052926714a7a2819a9afb7fb970a9a6d3058cb01ecd4d82e2e20f8996b0995818ae9c3ca815008fd01cdf42f187f723e6965c3c5ee972c9bbef7e7633776cf1af533460565bb256c5c9c6c1c50b63785daabe702d838308659e02c338ba5b47cd0508000eb4426bc76e4760d380bf9d1eb28e1dbcc9cd3a562a6b35ead2d434bce87657ab0ab2cfac2e3c410132c4bef39559dc853bfbf8319447dd365d0a6f52277046b1fdf284f27e626f4f86165eaea9b41bd4bf348325975bf3685a041c4740d300a4222063a6038b5da62c56052c5ddd1d845b51ae2782cec83fcae3966d7f4692d34fe00000000000000000000000000000000000000000000000000000000"; + rollup.proveCommittedBatchState(batchHeader1, proof); + } } contract RollupCommitBatchTest is L1MessageBaseTest {