Skip to content

Commit 0fd1107

Browse files
committed
use finalizeBundleWithProof for v4 and v6 batches
1 parent 42cc20e commit 0fd1107

File tree

5 files changed

+59
-124
lines changed

5 files changed

+59
-124
lines changed

src/L1/rollup/IScrollChain.sol

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -109,16 +109,4 @@ interface IScrollChain {
109109
/// @notice Finalize the initial Euclid batch.
110110
/// @param postStateRoot The state root after current batch.
111111
function finalizeEuclidInitialBatch(bytes32 postStateRoot) external;
112-
113-
/// @notice Finalize a list of committed batches (i.e. bundle) on layer 1 after Euclid upgrade.
114-
/// @param batchHeader The header of last batch in current bundle, see the encoding in comments of `commitBatch.
115-
/// @param postStateRoot The state root after current bundle.
116-
/// @param withdrawRoot The withdraw trie root after current batch.
117-
/// @param aggrProof The aggregation proof for current bundle.
118-
function finalizeBundlePostEuclid(
119-
bytes calldata batchHeader,
120-
bytes32 postStateRoot,
121-
bytes32 withdrawRoot,
122-
bytes calldata aggrProof
123-
) external;
124112
}

src/L1/rollup/ScrollChain.sol

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,6 @@ contract ScrollChain is OwnableUpgradeable, PausableUpgradeable, IScrollChain {
111111
/// @dev Thrown when SC finalize V5 batch before all v4 batches are finalized.
112112
error ErrorNotAllV4BatchFinalized();
113113

114-
/// @dev Thrown when prover finalize V5/V6 batches in zk trie logic.
115-
error ErrorFinalizeEuclidBatchWithZkTrieRoot();
116-
117114
/// @dev Thrown when the committed v5 batch doesn't contain only one chunk.
118115
error ErrorV5BatchNotContainsOnlyOneChunk();
119116

@@ -123,6 +120,9 @@ contract ScrollChain is OwnableUpgradeable, PausableUpgradeable, IScrollChain {
123120
/// @dev Thrown when the committed v5 batch contains some transactions (L1 or L2).
124121
error ErrorV5BatchContainsTransactions();
125122

123+
/// @dev Thrown when finalize v4/v5, v5/v6, v4/v5/v6 batches in the same bundle.
124+
error ErrorFinalizePreAndPostEuclidBatchInOneBundle();
125+
126126
/*************
127127
* Constants *
128128
*************/
@@ -370,7 +370,7 @@ contract ScrollChain is OwnableUpgradeable, PausableUpgradeable, IScrollChain {
370370
}
371371

372372
/// @inheritdoc IScrollChain
373-
/// @dev This function only finalize batches version <= 4.
373+
/// @dev All batches in the given bundle should have the same version and version <= 4 or version >= 6.
374374
function finalizeBundleWithProof(
375375
bytes calldata batchHeader,
376376
bytes32 postStateRoot,
@@ -387,8 +387,10 @@ contract ScrollChain is OwnableUpgradeable, PausableUpgradeable, IScrollChain {
387387
) = _beforeFinalizeBatch(batchHeader, postStateRoot);
388388

389389
uint256 euclidForkBatchIndex = initialEuclidBatchIndex;
390-
if (euclidForkBatchIndex > 0 && batchIndex >= euclidForkBatchIndex) {
391-
revert ErrorFinalizeEuclidBatchWithZkTrieRoot();
390+
// Make sure we don't finalize v4, v5 and v6 batches in the same bundle, that
391+
// means `batchIndex < euclidForkBatchIndex` or `prevBatchIndex >= euclidForkBatchIndex`.
392+
if (prevBatchIndex < euclidForkBatchIndex && euclidForkBatchIndex <= batchIndex) {
393+
revert ErrorFinalizePreAndPostEuclidBatchInOneBundle();
392394
}
393395

394396
bytes memory publicInputs = abi.encodePacked(
@@ -430,42 +432,6 @@ contract ScrollChain is OwnableUpgradeable, PausableUpgradeable, IScrollChain {
430432
emit FinalizeBatch(batchIndex, committedBatches[batchIndex], postStateRoot, withdrawRoot);
431433
}
432434

433-
/// @inheritdoc IScrollChain
434-
/// @dev This function only finalize batches version >= 6. If prover try to finalize v4, v5, v6 batches
435-
/// together, the verifier should revert. So we don't do any extra checks in this function.
436-
function finalizeBundlePostEuclid(
437-
bytes calldata batchHeader,
438-
bytes32 postStateRoot,
439-
bytes32 withdrawRoot,
440-
bytes calldata aggrProof
441-
) external override OnlyProver whenNotPaused {
442-
// actions before verification
443-
(
444-
uint256 version,
445-
bytes32 batchHash,
446-
uint256 batchIndex,
447-
uint256 totalL1MessagesPoppedOverall,
448-
uint256 prevBatchIndex
449-
) = _beforeFinalizeBatch(batchHeader, postStateRoot);
450-
451-
// construct the public input
452-
bytes memory publicInput = abi.encodePacked(
453-
uint256(layer2ChainId),
454-
finalizedStateRoots[prevBatchIndex], // _prevStateRoot
455-
committedBatches[prevBatchIndex], // _prevBatchHash
456-
postStateRoot,
457-
withdrawRoot,
458-
batchHash
459-
);
460-
461-
// verify bundle, choose the correct verifier based on the last batch
462-
// our off-chain service will make sure all unfinalized batches have the same batch version.
463-
IRollupVerifier(verifier).verifyBundleProof(version, batchIndex, aggrProof, publicInput);
464-
465-
// actions after verification
466-
_afterFinalizeBatch(batchIndex, batchHash, totalL1MessagesPoppedOverall, postStateRoot, withdrawRoot);
467-
}
468-
469435
/************************
470436
* Restricted Functions *
471437
************************/

src/libraries/verifier/ZkEvmVerifierPostEuclid.sol

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ contract ZkEvmVerifierPostEuclid is IZkEvmVerifierV2 {
4747

4848
/// @inheritdoc IZkEvmVerifierV2
4949
///
50-
/// @dev Encoding for `publicInput`
50+
/// @dev Encoding for `publicInput`. And this is exactly the same as `ZkEvmVerifierV2`.
5151
/// ```text
52-
/// | layer2ChainId | prevStateRoot | prevBatchHash | postStateRoot | withdrawRoot | batchHash |
53-
/// | 32 bytes | 32 bytes | 32 bytes | 32 bytes | 32 bytes | 32 bytes |
52+
/// | layer2ChainId | numBatches | prevStateRoot | prevBatchHash | postStateRoot | batchHash | withdrawRoot |
53+
/// | 8 bytes | 4 bytes | 32 bytes | 32 bytes | 32 bytes | 32 bytes | 32 bytes |
5454
/// ```
5555
function verify(bytes calldata bundleProof, bytes calldata publicInput) external view override {
5656
address _verifier = plonkVerifier;
@@ -60,8 +60,8 @@ contract ZkEvmVerifierPostEuclid is IZkEvmVerifierV2 {
6060
bool success;
6161

6262
// 1. the first 12 * 32 (0x180) bytes of `bundleProof` is `accumulator`
63-
// 2. the rest bytes of `bundleProof` is the actual `bundle_recursion_proof`
64-
// 3. Inserted between `accumulator` and `bundle_recursion_proof` are
63+
// 2. the rest bytes of `bundleProof` is the actual `bundle_proof`
64+
// 3. Inserted between `accumulator` and `bundle_proof` are
6565
// 32 * 34 (0x440) bytes, such that:
6666
// | start | end | field |
6767
// |---------------|---------------|-------------------------|

src/mocks/ScrollChainMockFinalize.sol

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,4 @@ contract ScrollChainMockFinalize is ScrollChain {
3939
// actions after verification
4040
_afterFinalizeBatch(batchIndex, batchHash, totalL1MessagesPoppedOverall, postStateRoot, withdrawRoot);
4141
}
42-
43-
/// @notice Finalize post Euclid bundle without proof, See the comments of {ScrollChain-finalizeBundlePostEuclid}.
44-
function finalizeBundlePostEuclidMock(
45-
bytes calldata batchHeader,
46-
bytes32 postStateRoot,
47-
bytes32 withdrawRoot
48-
) external OnlyProver whenNotPaused {
49-
// actions before verification
50-
(, bytes32 batchHash, uint256 batchIndex, uint256 totalL1MessagesPoppedOverall, ) = _beforeFinalizeBatch(
51-
batchHeader,
52-
postStateRoot
53-
);
54-
55-
// actions after verification
56-
_afterFinalizeBatch(batchIndex, batchHash, totalL1MessagesPoppedOverall, postStateRoot, withdrawRoot);
57-
}
5842
}

src/test/ScrollChain.t.sol

Lines changed: 46 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@ contract ScrollChainTest is DSTestPlus {
175175
rollup.commitBatchWithBlobProof(4, batchHeader0, chunks, bitmap, new bytes(0));
176176
hevm.stopPrank();
177177

178-
// revert when ErrorNoBlobFound
179178
// revert when ErrorNoBlobFound
180179
chunk0 = new bytes(1 + 60);
181180
chunk0[0] = bytes1(uint8(1)); // one block in this chunk
@@ -554,7 +553,7 @@ contract ScrollChainTest is DSTestPlus {
554553
messageQueue.appendCrossDomainMessage(address(this), 1000000, new bytes(0));
555554
}
556555

557-
(bytes memory batchHeader0, bytes memory batchHeader1, bytes memory batchHeader2) = _commitBatchV3();
556+
(, , bytes memory batchHeader2) = _commitBatchV3();
558557

559558
// 1 ~ 4, zero
560559
for (uint256 i = 1; i < 4; i++) {
@@ -654,10 +653,16 @@ contract ScrollChainTest is DSTestPlus {
654653
function testFinalizeEuclidInitialBatch() external {
655654
bytes[] memory headers = _prepareFinalizeBundle();
656655

656+
// commit v5 batch
657657
assertEq(rollup.initialEuclidBatchIndex(), 0);
658658
bytes memory v5Header = _commitBatch(5, headers[10], 0, 0);
659659
assertEq(rollup.initialEuclidBatchIndex(), 11);
660660

661+
// commit 3 v6 batches
662+
bytes memory v6Header1 = _commitBatch(6, v5Header, 1, 1);
663+
bytes memory v6Header2 = _commitBatch(6, v6Header1, 2, 1);
664+
bytes memory v6Header3 = _commitBatch(6, v6Header2, 3, 1);
665+
661666
// revert when caller is not owner
662667
hevm.startPrank(address(1));
663668
hevm.expectRevert("Ownable: caller is not the owner");
@@ -679,16 +684,42 @@ contract ScrollChainTest is DSTestPlus {
679684
hevm.expectRevert(ScrollChain.ErrorNotAllV4BatchFinalized.selector);
680685
rollup.finalizeEuclidInitialBatch(keccak256("011"));
681686

687+
// revert when ErrorFinalizePreAndPostEuclidBatchInOneBundle, v4+v5
688+
hevm.startPrank(address(0));
689+
hevm.expectRevert(ScrollChain.ErrorFinalizePreAndPostEuclidBatchInOneBundle.selector);
690+
rollup.finalizeBundleWithProof(v5Header, keccak256("011"), keccak256("111"), new bytes(0));
691+
hevm.stopPrank();
692+
693+
// revert when ErrorFinalizePreAndPostEuclidBatchInOneBundle, v4+v5+v6
694+
hevm.startPrank(address(0));
695+
hevm.expectRevert(ScrollChain.ErrorFinalizePreAndPostEuclidBatchInOneBundle.selector);
696+
rollup.finalizeBundleWithProof(v6Header1, keccak256("011"), keccak256("111"), new bytes(0));
697+
hevm.expectRevert(ScrollChain.ErrorFinalizePreAndPostEuclidBatchInOneBundle.selector);
698+
rollup.finalizeBundleWithProof(v6Header2, keccak256("011"), keccak256("111"), new bytes(0));
699+
hevm.expectRevert(ScrollChain.ErrorFinalizePreAndPostEuclidBatchInOneBundle.selector);
700+
rollup.finalizeBundleWithProof(v6Header3, keccak256("011"), keccak256("111"), new bytes(0));
701+
hevm.stopPrank();
702+
682703
// finalize batch 10
683704
hevm.startPrank(address(0));
684705
rollup.finalizeBundleWithProof(headers[10], keccak256("010"), keccak256("110"), new bytes(0));
685706
assertEq(rollup.lastFinalizedBatchIndex(), 10);
686707
hevm.stopPrank();
687708

688-
// revert when try to finalize batch 11 in finalizeBundleWithProof
709+
// revert when ErrorFinalizePreAndPostEuclidBatchInOneBundle, v5
689710
hevm.startPrank(address(0));
690-
hevm.expectRevert(ScrollChain.ErrorFinalizeEuclidBatchWithZkTrieRoot.selector);
691-
rollup.finalizeBundleWithProof(v5Header, keccak256("010"), keccak256("110"), new bytes(0));
711+
hevm.expectRevert(ScrollChain.ErrorFinalizePreAndPostEuclidBatchInOneBundle.selector);
712+
rollup.finalizeBundleWithProof(v5Header, keccak256("011"), keccak256("111"), new bytes(0));
713+
hevm.stopPrank();
714+
715+
// revert when ErrorFinalizePreAndPostEuclidBatchInOneBundle, v5+v6
716+
hevm.startPrank(address(0));
717+
hevm.expectRevert(ScrollChain.ErrorFinalizePreAndPostEuclidBatchInOneBundle.selector);
718+
rollup.finalizeBundleWithProof(v6Header1, keccak256("011"), keccak256("111"), new bytes(0));
719+
hevm.expectRevert(ScrollChain.ErrorFinalizePreAndPostEuclidBatchInOneBundle.selector);
720+
rollup.finalizeBundleWithProof(v6Header2, keccak256("011"), keccak256("111"), new bytes(0));
721+
hevm.expectRevert(ScrollChain.ErrorFinalizePreAndPostEuclidBatchInOneBundle.selector);
722+
rollup.finalizeBundleWithProof(v6Header3, keccak256("011"), keccak256("111"), new bytes(0));
692723
hevm.stopPrank();
693724

694725
// succeed, withdraw root should be same as batch 10
@@ -704,45 +735,12 @@ contract ScrollChainTest is DSTestPlus {
704735
// revert when ErrorStateRootIsZero
705736
hevm.expectRevert(ScrollChain.ErrorBatchIsAlreadyVerified.selector);
706737
rollup.finalizeEuclidInitialBatch(keccak256("011"));
707-
}
708-
709-
function testFinalizeBundlePostEuclid() external {
710-
bytes[] memory headers = _prepareFinalizeBundle();
711-
712-
assertEq(rollup.initialEuclidBatchIndex(), 0);
713-
bytes memory v5Header = _commitBatch(5, headers[10], 0, 0);
714-
assertEq(rollup.initialEuclidBatchIndex(), 11);
715-
716-
for (uint256 i = 1; i <= 10; ++i) {
717-
assertBoolEq(rollup.isBatchFinalized(i), false);
718-
}
719-
assertEq(messageQueue.nextUnfinalizedQueueIndex(), 0);
720-
hevm.prank(address(0));
721-
rollup.finalizeBundleWithProof(headers[10], keccak256("010"), keccak256("110"), new bytes(0));
722-
for (uint256 i = 1; i <= 10; ++i) {
723-
assertBoolEq(rollup.isBatchFinalized(i), true);
724-
}
725-
assertEq(messageQueue.nextUnfinalizedQueueIndex(), 10);
726-
727-
assertBoolEq(rollup.isBatchFinalized(11), false);
728-
rollup.finalizeEuclidInitialBatch(keccak256("011"));
729-
assertBoolEq(rollup.isBatchFinalized(11), true);
730-
assertEq(rollup.lastFinalizedBatchIndex(), 11);
731-
732-
// commit 3 v6 batches
733-
bytes memory v6Header1 = _commitBatch(6, v5Header, 1, 1);
734-
//revert();
735-
bytes memory v6Header2 = _commitBatch(6, v6Header1, 2, 1);
736-
bytes memory v6Header3 = _commitBatch(6, v6Header2, 3, 1);
737-
738-
// revert when ErrorCallerIsNotProver
739-
hevm.expectRevert(ScrollChain.ErrorCallerIsNotProver.selector);
740-
rollup.finalizeBundlePostEuclid(new bytes(0), bytes32(0), bytes32(0), new bytes(0));
741738

739+
// finalize 3 v6 batches
742740
// revert when ErrorStateRootIsZero
743741
hevm.startPrank(address(0));
744742
hevm.expectRevert(ScrollChain.ErrorStateRootIsZero.selector);
745-
rollup.finalizeBundlePostEuclid(v6Header1, bytes32(0), bytes32(0), new bytes(0));
743+
rollup.finalizeBundleWithProof(v6Header1, bytes32(0), bytes32(0), new bytes(0));
746744

747745
// finalize bundle with one batch
748746
assertEq(rollup.finalizedStateRoots(12), 0);
@@ -752,7 +750,7 @@ contract ScrollChainTest is DSTestPlus {
752750
assertEq(messageQueue.nextUnfinalizedQueueIndex(), 10);
753751
hevm.expectEmit(true, true, true, true);
754752
emit FinalizeBatch(12, keccak256(v6Header1), keccak256("001"), keccak256("101"));
755-
rollup.finalizeBundlePostEuclid(v6Header1, keccak256("001"), keccak256("101"), new bytes(0));
753+
rollup.finalizeBundleWithProof(v6Header1, keccak256("001"), keccak256("101"), new bytes(0));
756754
assertEq(rollup.finalizedStateRoots(12), keccak256("001"));
757755
assertEq(rollup.withdrawRoots(12), keccak256("101"));
758756
assertEq(rollup.lastFinalizedBatchIndex(), 12);
@@ -761,7 +759,7 @@ contract ScrollChainTest is DSTestPlus {
761759

762760
// revert when ErrorBatchIsAlreadyVerified
763761
hevm.expectRevert(ScrollChain.ErrorBatchIsAlreadyVerified.selector);
764-
rollup.finalizeBundlePostEuclid(v6Header1, keccak256("001"), keccak256("101"), new bytes(0));
762+
rollup.finalizeBundleWithProof(v6Header1, keccak256("001"), keccak256("101"), new bytes(0));
765763

766764
// finalize bundle with two batch
767765
assertEq(rollup.finalizedStateRoots(14), 0);
@@ -770,12 +768,11 @@ contract ScrollChainTest is DSTestPlus {
770768
assertEq(messageQueue.nextUnfinalizedQueueIndex(), 11);
771769
hevm.expectEmit(true, true, true, true);
772770
emit FinalizeBatch(14, keccak256(v6Header3), keccak256("003"), keccak256("103"));
773-
rollup.finalizeBundlePostEuclid(v6Header3, keccak256("003"), keccak256("103"), new bytes(0));
771+
rollup.finalizeBundleWithProof(v6Header3, keccak256("003"), keccak256("103"), new bytes(0));
774772
assertEq(rollup.finalizedStateRoots(14), keccak256("003"));
775773
assertEq(rollup.withdrawRoots(14), keccak256("103"));
776774
assertEq(rollup.lastFinalizedBatchIndex(), 14);
777775
assertEq(messageQueue.nextUnfinalizedQueueIndex(), 16);
778-
779776
hevm.stopPrank();
780777
}
781778

@@ -788,7 +785,7 @@ contract ScrollChainTest is DSTestPlus {
788785
messageQueue.appendCrossDomainMessage(address(this), 1000000, new bytes(0));
789786
}
790787

791-
(bytes memory batchHeader0, bytes memory batchHeader1, bytes memory batchHeader2) = _commitBatchV3();
788+
(, bytes memory batchHeader1, bytes memory batchHeader2) = _commitBatchV3();
792789

793790
// 1 ~ 4, zero
794791
for (uint256 i = 1; i < 4; i++) {
@@ -943,13 +940,13 @@ contract ScrollChainTest is DSTestPlus {
943940

944941
hevm.startPrank(address(0));
945942
hevm.expectRevert("Pausable: paused");
946-
rollup.commitBatchWithBlobProof(3, new bytes(0), new bytes[](0), new bytes(0), new bytes(0));
947-
hevm.expectRevert("Pausable: paused");
948943
rollup.commitBatchWithBlobProof(4, new bytes(0), new bytes[](0), new bytes(0), new bytes(0));
949944
hevm.expectRevert("Pausable: paused");
950-
rollup.finalizeBundleWithProof(new bytes(0), bytes32(0), bytes32(0), new bytes(0));
945+
rollup.commitBatchWithBlobProof(5, new bytes(0), new bytes[](0), new bytes(0), new bytes(0));
951946
hevm.expectRevert("Pausable: paused");
952-
rollup.finalizeBundlePostEuclid(new bytes(0), bytes32(0), bytes32(0), new bytes(0));
947+
rollup.commitBatchWithBlobProof(6, new bytes(0), new bytes[](0), new bytes(0), new bytes(0));
948+
hevm.expectRevert("Pausable: paused");
949+
rollup.finalizeBundleWithProof(new bytes(0), bytes32(0), bytes32(0), new bytes(0));
953950
hevm.stopPrank();
954951

955952
// unpause

0 commit comments

Comments
 (0)