diff --git a/contracts/contracts/l1/rollup/Rollup.sol b/contracts/contracts/l1/rollup/Rollup.sol index 68471420..d6fa04a2 100644 --- a/contracts/contracts/l1/rollup/Rollup.sol +++ b/contracts/contracts/l1/rollup/Rollup.sol @@ -238,12 +238,14 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { ) { require(batchDataInput.numL1Messages > 0, "l1msg delay"); } - _commitBatchWithBatchData(batchDataInput, batchSignatureInput); + uint256 submitterBitmap = IL1Staking(l1StakingContract).getStakerBitmap(_msgSender()); + _commitBatchWithBatchData(batchDataInput, batchSignatureInput, submitterBitmap); } function _commitBatchWithBatchData( BatchDataInput calldata batchDataInput, - BatchSignatureInput calldata batchSignatureInput + BatchSignatureInput calldata batchSignatureInput, + uint256 submitterBitmap ) internal { require(batchDataInput.version == 0 || batchDataInput.version == 1, "invalid version"); require(batchDataInput.prevStateRoot != bytes32(0), "previous state root is zero"); @@ -324,7 +326,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { batchDataInput.lastBlockNumber, // Before BLS is implemented, the accuracy of the sequencer set uploaded by rollup cannot be guaranteed. // Therefore, if the batch is successfully challenged, only the submitter will be punished. - IL1Staking(l1StakingContract).getStakerBitmap(_msgSender()) // => batchSignature.signedSequencersBitmap + submitterBitmap // => batchSignature.signedSequencersBitmap ); lastCommittedBatchIndex = _batchIndex; @@ -367,7 +369,7 @@ contract Rollup is IRollup, OwnableUpgradeable, PausableUpgradeable { } require(rollupDelay || l1MsgQueueDelayed, "invalid timing"); - _commitBatchWithBatchData(batchDataInput, batchSignatureInput); + _commitBatchWithBatchData(batchDataInput, batchSignatureInput,0); // get batch data from batch header (uint256 memPtr, bytes32 _batchHash) = _loadBatchHeader(_batchHeader); diff --git a/contracts/contracts/test/Rollup.t.sol b/contracts/contracts/test/Rollup.t.sol index f6744f91..407bbcb9 100644 --- a/contracts/contracts/test/Rollup.t.sol +++ b/contracts/contracts/test/Rollup.t.sol @@ -539,6 +539,43 @@ contract RollupCommitBatchWithProofTest is L1MessageBaseTest { ); } + /// @notice Test: commitBatchWithProof can be called by anyone (not only staker) when delay is met + /// @dev Ensures permissionless batch submission: any address can submit when rollup/L1 queue is stalled. + function test_commitBatchWithProof_anyone_can_call_when_delay_met() public { + _mockVerifierCall(); + _mockMessageQueueStalled(); + 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); + + // Caller is bob: not a staker, not owner. Anyone can submit when delay is met. + hevm.prank(bob); + rollup.commitBatchWithProof( + batchDataInput, + batchSignatureInput, + batchHeader1, + hex"deadbeef" + ); + + assertEq(rollup.lastCommittedBatchIndex(), 1); + assertTrue(rollup.batchExist(1)); + assertEq(rollup.committedStateRoots(1), postStateRoot); + } + /// @notice Test: commitBatchWithProof succeeds when queue is empty (no unfinalized messages) function test_commitBatchWithProof_succeeds_when_queue_empty() public { _mockVerifierCall();