Compare commits

...

1 Commits

Author SHA1 Message Date
zimpha
7c9d6e1143 add force finalize batch for testnet 2023-07-26 09:54:11 +08:00
2 changed files with 125 additions and 0 deletions

View File

@@ -393,6 +393,62 @@ contract ScrollChain is OwnableUpgradeable, IScrollChain {
emit UpdateMaxNumL2TxInChunk(_oldMaxNumL2TxInChunk, _maxNumL2TxInChunk);
}
function forceFinalizeBatch(
bytes calldata _batchHeader,
bytes32 _prevStateRoot,
bytes32 _postStateRoot,
bytes32 _withdrawRoot
) external onlyOwner {
require(_prevStateRoot != bytes32(0), "previous state root is zero");
require(_postStateRoot != bytes32(0), "new state root is zero");
// compute batch hash and verify
(uint256 memPtr, bytes32 _batchHash) = _loadBatchHeader(_batchHeader);
uint256 _batchIndex = BatchHeaderV0Codec.batchIndex(memPtr);
require(committedBatches[_batchIndex] == _batchHash, "incorrect batch hash");
// verify previous state root.
require(finalizedStateRoots[_batchIndex - 1] == _prevStateRoot, "incorrect previous state root");
// avoid duplicated verification
require(finalizedStateRoots[_batchIndex] == bytes32(0), "batch already verified");
// check and update lastFinalizedBatchIndex
unchecked {
require(lastFinalizedBatchIndex + 1 == _batchIndex, "incorrect batch index");
lastFinalizedBatchIndex = _batchIndex;
}
// record state root and withdraw root
finalizedStateRoots[_batchIndex] = _postStateRoot;
withdrawRoots[_batchIndex] = _withdrawRoot;
// Pop finalized and non-skipped message from L1MessageQueue.
uint256 _l1MessagePopped = BatchHeaderV0Codec.l1MessagePopped(memPtr);
if (_l1MessagePopped > 0) {
IL1MessageQueue _queue = IL1MessageQueue(messageQueue);
unchecked {
uint256 _startIndex = BatchHeaderV0Codec.totalL1MessagePopped(memPtr) - _l1MessagePopped;
for (uint256 i = 0; i < _l1MessagePopped; i += 256) {
uint256 _count = 256;
if (_l1MessagePopped - i < _count) {
_count = _l1MessagePopped - i;
}
uint256 _skippedBitmap = BatchHeaderV0Codec.skippedBitmap(memPtr, i / 256);
_queue.popCrossDomainMessage(_startIndex, _count, _skippedBitmap);
_startIndex += 256;
}
}
}
emit FinalizeBatch(_batchIndex, _batchHash, _postStateRoot, _withdrawRoot);
}
/**********************
* Internal Functions *
**********************/

View File

@@ -446,6 +446,75 @@ contract ScrollChainTest is DSTestPlus {
}
}
function testForceFinalizeBatch() public {
// caller not owner, revert
hevm.startPrank(address(1));
hevm.expectRevert("Ownable: caller is not the owner");
rollup.forceFinalizeBatch(new bytes(0), bytes32(0), bytes32(0), bytes32(0));
hevm.stopPrank();
rollup.updateSequencer(address(this), true);
bytes memory batchHeader0 = new bytes(89);
// import genesis batch
assembly {
mstore(add(batchHeader0, add(0x20, 25)), 1)
}
rollup.importGenesisBatch(batchHeader0, bytes32(uint256(1)));
bytes32 batchHash0 = rollup.committedBatches(0);
bytes[] memory chunks = new bytes[](1);
bytes memory chunk0;
// commit one batch
chunk0 = new bytes(1 + 60);
chunk0[0] = bytes1(uint8(1)); // one block in this chunk
chunks[0] = chunk0;
rollup.commitBatch(0, batchHeader0, chunks, new bytes(0));
assertGt(uint256(rollup.committedBatches(1)), 0);
bytes memory batchHeader1 = new bytes(89);
assembly {
mstore(add(batchHeader1, 0x20), 0) // version
mstore(add(batchHeader1, add(0x20, 1)), shl(192, 1)) // batchIndex
mstore(add(batchHeader1, add(0x20, 9)), 0) // l1MessagePopped
mstore(add(batchHeader1, add(0x20, 17)), 0) // totalL1MessagePopped
mstore(add(batchHeader1, add(0x20, 25)), 0x246394445f4fe64ed5598554d55d1682d6fb3fe04bf58eb54ef81d1189fafb51) // dataHash
mstore(add(batchHeader1, add(0x20, 57)), batchHash0) // parentBatchHash
}
// incorrect batch hash, revert
hevm.expectRevert("incorrect batch hash");
batchHeader1[0] = bytes1(uint8(1)); // change version to 1
rollup.forceFinalizeBatch(batchHeader1, bytes32(uint256(1)), bytes32(uint256(2)), bytes32(0));
batchHeader1[0] = bytes1(uint8(0)); // change back
// batch header length too small, revert
hevm.expectRevert("batch header length too small");
rollup.forceFinalizeBatch(new bytes(88), bytes32(uint256(1)), bytes32(uint256(2)), bytes32(0));
// wrong bitmap length, revert
hevm.expectRevert("wrong bitmap length");
rollup.forceFinalizeBatch(new bytes(90), bytes32(uint256(1)), bytes32(uint256(2)), bytes32(0));
// incorrect previous state root, revert
hevm.expectRevert("incorrect previous state root");
rollup.forceFinalizeBatch(batchHeader1, bytes32(uint256(2)), bytes32(uint256(2)), bytes32(0));
// verify success
assertBoolEq(rollup.isBatchFinalized(1), false);
rollup.forceFinalizeBatch(batchHeader1, bytes32(uint256(1)), bytes32(uint256(2)), bytes32(uint256(3)));
assertBoolEq(rollup.isBatchFinalized(1), true);
assertEq(rollup.finalizedStateRoots(1), bytes32(uint256(2)));
assertEq(rollup.withdrawRoots(1), bytes32(uint256(3)));
assertEq(rollup.lastFinalizedBatchIndex(), 1);
// batch already verified, revert
hevm.expectRevert("batch already verified");
rollup.forceFinalizeBatch(batchHeader1, bytes32(uint256(1)), bytes32(uint256(2)), bytes32(uint256(3)));
}
function testRevertBatch() public {
// caller not owner, revert
hevm.startPrank(address(1));