mirror of
https://github.com/scroll-tech/scroll.git
synced 2026-01-10 22:48:14 -05:00
fix(contracts): bug fixing based on openzeppelin's audit (#558)
Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com>
This commit is contained in:
@@ -63,28 +63,6 @@ Initialize the storage of L1ScrollMessenger.
|
||||
| _rollup | address | The address of ScrollChain contract. |
|
||||
| _messageQueue | address | The address of L1MessageQueue contract. |
|
||||
|
||||
### isL1MessageRelayed
|
||||
|
||||
```solidity
|
||||
function isL1MessageRelayed(bytes32) external view returns (bool)
|
||||
```
|
||||
|
||||
Mapping from relay id to relay status.
|
||||
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bytes32 | undefined |
|
||||
|
||||
#### Returns
|
||||
|
||||
| Name | Type | Description |
|
||||
|---|---|---|
|
||||
| _0 | bool | undefined |
|
||||
|
||||
### isL1MessageSent
|
||||
|
||||
```solidity
|
||||
|
||||
@@ -2,7 +2,16 @@
|
||||
/* eslint-disable node/no-missing-import */
|
||||
import { expect } from "chai";
|
||||
import { BigNumber, constants } from "ethers";
|
||||
import { concat, getAddress, hexlify, keccak256, randomBytes, RLP } from "ethers/lib/utils";
|
||||
import {
|
||||
concat,
|
||||
getAddress,
|
||||
hexlify,
|
||||
keccak256,
|
||||
randomBytes,
|
||||
RLP,
|
||||
stripZeros,
|
||||
TransactionTypes,
|
||||
} from "ethers/lib/utils";
|
||||
import { ethers } from "hardhat";
|
||||
import { L1MessageQueue, L2GasPriceOracle } from "../typechain";
|
||||
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
|
||||
@@ -94,8 +103,8 @@ describe("L1MessageQueue", async () => {
|
||||
|
||||
context("#computeTransactionHash", async () => {
|
||||
it("should succeed", async () => {
|
||||
const sender = hexlify(randomBytes(20));
|
||||
const target = hexlify(randomBytes(20));
|
||||
const sender = "0xb2a70fab1a45b1b9be443b6567849a1702bc1232";
|
||||
const target = "0xcb18150e4efefb6786130e289a5f61a82a5b86d7";
|
||||
const transactionType = "0x7E";
|
||||
|
||||
for (const nonce of [
|
||||
@@ -123,19 +132,30 @@ describe("L1MessageQueue", async () => {
|
||||
constants.MaxUint256,
|
||||
]) {
|
||||
for (const dataLen of [0, 1, 2, 3, 4, 55, 56, 100]) {
|
||||
const data = randomBytes(dataLen);
|
||||
const transactionPayload = RLP.encode([
|
||||
nonce.toHexString(),
|
||||
gasLimit.toHexString(),
|
||||
target,
|
||||
value.toHexString(),
|
||||
data,
|
||||
sender,
|
||||
]);
|
||||
const payload = concat([transactionType, transactionPayload]);
|
||||
const expectedHash = keccak256(payload);
|
||||
const computedHash = await queue.computeTransactionHash(sender, nonce, value, target, gasLimit, data);
|
||||
expect(expectedHash).to.eq(computedHash);
|
||||
const tests = [randomBytes(dataLen)];
|
||||
if (dataLen === 1) {
|
||||
for (const byte of [0, 1, 127, 128]) {
|
||||
tests.push(Uint8Array.from([byte]));
|
||||
}
|
||||
}
|
||||
for (const data of tests) {
|
||||
const transactionPayload = RLP.encode([
|
||||
stripZeros(nonce.toHexString()),
|
||||
stripZeros(gasLimit.toHexString()),
|
||||
target,
|
||||
stripZeros(value.toHexString()),
|
||||
data,
|
||||
sender,
|
||||
]);
|
||||
const payload = concat([transactionType, transactionPayload]);
|
||||
const expectedHash = keccak256(payload);
|
||||
const computedHash = await queue.computeTransactionHash(sender, nonce, value, target, gasLimit, data);
|
||||
if (computedHash !== expectedHash) {
|
||||
console.log(hexlify(transactionPayload));
|
||||
console.log(nonce, gasLimit, target, value, data, sender);
|
||||
}
|
||||
expect(expectedHash).to.eq(computedHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,9 +30,6 @@ contract L1ScrollMessenger is PausableUpgradeable, ScrollMessengerBase, IL1Scrol
|
||||
* Variables *
|
||||
*************/
|
||||
|
||||
/// @notice Mapping from relay id to relay status.
|
||||
mapping(bytes32 => bool) public isL1MessageRelayed;
|
||||
|
||||
/// @notice Mapping from L1 message hash to sent status.
|
||||
mapping(bytes32 => bool) public isL1MessageSent;
|
||||
|
||||
@@ -45,28 +42,6 @@ contract L1ScrollMessenger is PausableUpgradeable, ScrollMessengerBase, IL1Scrol
|
||||
/// @notice The address of L1MessageQueue contract.
|
||||
address public messageQueue;
|
||||
|
||||
// @note move to ScrollMessengerBase in next big refactor
|
||||
/// @dev The status of for non-reentrant check.
|
||||
uint256 private _lock_status;
|
||||
|
||||
/**********************
|
||||
* Function Modifiers *
|
||||
**********************/
|
||||
|
||||
modifier nonReentrant() {
|
||||
// On the first call to nonReentrant, _notEntered will be true
|
||||
require(_lock_status != _ENTERED, "ReentrancyGuard: reentrant call");
|
||||
|
||||
// Any calls to nonReentrant after this point will fail
|
||||
_lock_status = _ENTERED;
|
||||
|
||||
_;
|
||||
|
||||
// By storing the original value once again, a refund is triggered (see
|
||||
// https://eips.ethereum.org/EIPS/eip-2200)
|
||||
_lock_status = _NOT_ENTERED;
|
||||
}
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
@@ -162,9 +137,6 @@ contract L1ScrollMessenger is PausableUpgradeable, ScrollMessengerBase, IL1Scrol
|
||||
} else {
|
||||
emit FailedRelayedMessage(_xDomainCalldataHash);
|
||||
}
|
||||
|
||||
bytes32 _relayId = keccak256(abi.encodePacked(_xDomainCalldataHash, msg.sender, block.number));
|
||||
isL1MessageRelayed[_relayId] = true;
|
||||
}
|
||||
|
||||
/// @inheritdoc IL1ScrollMessenger
|
||||
|
||||
@@ -139,18 +139,27 @@ contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
|
||||
}
|
||||
}
|
||||
|
||||
function store_uint(_ptr, v) -> ptr {
|
||||
// This is used for both store uint and single byte.
|
||||
// Integer zero is special handled by geth to encode as `0x80`
|
||||
function store_uint_or_byte(_ptr, v, is_uint) -> ptr {
|
||||
ptr := _ptr
|
||||
switch lt(v, 128)
|
||||
case 1 {
|
||||
// single byte in the [0x00, 0x7f]
|
||||
mstore(ptr, shl(248, v))
|
||||
switch and(iszero(v), is_uint)
|
||||
case 1 {
|
||||
// integer 0
|
||||
mstore8(ptr, 0x80)
|
||||
}
|
||||
default {
|
||||
// single byte in the [0x00, 0x7f]
|
||||
mstore8(ptr, v)
|
||||
}
|
||||
ptr := add(ptr, 1)
|
||||
}
|
||||
default {
|
||||
// 1-32 bytes long
|
||||
let len := get_uint_bytes(v)
|
||||
mstore(ptr, shl(248, add(len, 0x80)))
|
||||
mstore8(ptr, add(len, 0x80))
|
||||
ptr := add(ptr, 1)
|
||||
mstore(ptr, shl(mul(8, sub(32, len)), v))
|
||||
ptr := add(ptr, len)
|
||||
@@ -160,7 +169,7 @@ contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
|
||||
function store_address(_ptr, v) -> ptr {
|
||||
ptr := _ptr
|
||||
// 20 bytes long
|
||||
mstore(ptr, shl(248, 0x94)) // 0x80 + 0x14
|
||||
mstore8(ptr, 0x94) // 0x80 + 0x14
|
||||
ptr := add(ptr, 1)
|
||||
mstore(ptr, shl(96, v))
|
||||
ptr := add(ptr, 0x14)
|
||||
@@ -170,21 +179,21 @@ contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
|
||||
// 4 byte for list payload length
|
||||
let start_ptr := add(mload(0x40), 5)
|
||||
let ptr := start_ptr
|
||||
ptr := store_uint(ptr, _queueIndex)
|
||||
ptr := store_uint(ptr, _gasLimit)
|
||||
ptr := store_uint_or_byte(ptr, _queueIndex, 1)
|
||||
ptr := store_uint_or_byte(ptr, _gasLimit, 1)
|
||||
ptr := store_address(ptr, _target)
|
||||
ptr := store_uint(ptr, _value)
|
||||
ptr := store_uint_or_byte(ptr, _value, 1)
|
||||
|
||||
switch eq(_data.length, 1)
|
||||
case 1 {
|
||||
// single byte
|
||||
ptr := store_uint(ptr, shr(248, calldataload(_data.offset)))
|
||||
ptr := store_uint_or_byte(ptr, byte(0, calldataload(_data.offset)), 0)
|
||||
}
|
||||
default {
|
||||
switch lt(_data.length, 56)
|
||||
case 1 {
|
||||
// a string is 0-55 bytes long
|
||||
mstore(ptr, shl(248, add(0x80, _data.length)))
|
||||
mstore8(ptr, add(0x80, _data.length))
|
||||
ptr := add(ptr, 1)
|
||||
calldatacopy(ptr, _data.offset, _data.length)
|
||||
ptr := add(ptr, _data.length)
|
||||
@@ -192,7 +201,7 @@ contract L1MessageQueue is OwnableUpgradeable, IL1MessageQueue {
|
||||
default {
|
||||
// a string is more than 55 bytes long
|
||||
let len_bytes := get_uint_bytes(_data.length)
|
||||
mstore(ptr, shl(248, add(0xb7, len_bytes)))
|
||||
mstore8(ptr, add(0xb7, len_bytes))
|
||||
ptr := add(ptr, 1)
|
||||
mstore(ptr, shl(mul(8, sub(32, len_bytes)), _data.length))
|
||||
ptr := add(ptr, len_bytes)
|
||||
|
||||
@@ -130,12 +130,7 @@ contract ScrollChain is OwnableUpgradeable, IScrollChain {
|
||||
*****************************/
|
||||
|
||||
/// @notice Import layer 2 genesis block
|
||||
/// @dev Although `_withdrawRoot` is always zero, we add this parameter for the convenience of unit testing.
|
||||
function importGenesisBatch(
|
||||
bytes calldata _batchHeader,
|
||||
bytes32 _stateRoot,
|
||||
bytes32 _withdrawRoot
|
||||
) external {
|
||||
function importGenesisBatch(bytes calldata _batchHeader, bytes32 _stateRoot) external {
|
||||
// check genesis batch header length
|
||||
require(_stateRoot != bytes32(0), "zero state root");
|
||||
|
||||
@@ -157,10 +152,9 @@ contract ScrollChain is OwnableUpgradeable, IScrollChain {
|
||||
|
||||
committedBatches[0] = _batchHash;
|
||||
finalizedStateRoots[0] = _stateRoot;
|
||||
withdrawRoots[0] = _withdrawRoot;
|
||||
|
||||
emit CommitBatch(_batchHash);
|
||||
emit FinalizeBatch(_batchHash, _stateRoot, _withdrawRoot);
|
||||
emit FinalizeBatch(_batchHash, _stateRoot, bytes32(0));
|
||||
}
|
||||
|
||||
/// @inheritdoc IScrollChain
|
||||
|
||||
@@ -62,28 +62,6 @@ contract L2ScrollMessenger is ScrollMessengerBase, PausableUpgradeable, IL2Scrol
|
||||
/// @notice The maximum number of times each L1 message can fail on L2.
|
||||
uint256 public maxFailedExecutionTimes;
|
||||
|
||||
// @note move to ScrollMessengerBase in next big refactor
|
||||
/// @dev The status of for non-reentrant check.
|
||||
uint256 private _lock_status;
|
||||
|
||||
/**********************
|
||||
* Function Modifiers *
|
||||
**********************/
|
||||
|
||||
modifier nonReentrant() {
|
||||
// On the first call to nonReentrant, _notEntered will be true
|
||||
require(_lock_status != _ENTERED, "ReentrancyGuard: reentrant call");
|
||||
|
||||
// Any calls to nonReentrant after this point will fail
|
||||
_lock_status = _ENTERED;
|
||||
|
||||
_;
|
||||
|
||||
// By storing the original value once again, a refund is triggered (see
|
||||
// https://eips.ethereum.org/EIPS/eip-2200)
|
||||
_lock_status = _NOT_ENTERED;
|
||||
}
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
@@ -126,14 +104,16 @@ contract L2ScrollMessenger is ScrollMessengerBase, PausableUpgradeable, IL2Scrol
|
||||
require(_expectedStateRoot != bytes32(0), "Block is not imported");
|
||||
|
||||
bytes32 _storageKey;
|
||||
// `mapping(bytes32 => bool) public isL1MessageSent` is the 105-nd slot of contract `L1ScrollMessenger`.
|
||||
// `mapping(bytes32 => bool) public isL1MessageSent` is the 155-th slot of contract `L1ScrollMessenger`.
|
||||
// + 1 from `Initializable`
|
||||
// + 50 from `OwnableUpgradeable`
|
||||
// + 50 from `ContextUpgradeable`
|
||||
// + 4 from `ScrollMessengerBase`
|
||||
// + 50 from `PausableUpgradeable`
|
||||
// + 2-nd in `L1ScrollMessenger`
|
||||
// + 1-st in `L1ScrollMessenger`
|
||||
assembly {
|
||||
mstore(0x00, _msgHash)
|
||||
mstore(0x20, 105)
|
||||
mstore(0x20, 155)
|
||||
_storageKey := keccak256(0x00, 0x40)
|
||||
}
|
||||
|
||||
@@ -161,14 +141,16 @@ contract L2ScrollMessenger is ScrollMessengerBase, PausableUpgradeable, IL2Scrol
|
||||
require(_expectedStateRoot != bytes32(0), "Block not imported");
|
||||
|
||||
bytes32 _storageKey;
|
||||
// `mapping(bytes32 => bool) public isL2MessageExecuted` is the 106-th slot of contract `L1ScrollMessenger`.
|
||||
// `mapping(bytes32 => bool) public isL2MessageExecuted` is the 156-th slot of contract `L1ScrollMessenger`.
|
||||
// + 1 from `Initializable`
|
||||
// + 50 from `OwnableUpgradeable`
|
||||
// + 50 from `ContextUpgradeable`
|
||||
// + 4 from `ScrollMessengerBase`
|
||||
// + 50 from `PausableUpgradeable`
|
||||
// + 3-rd in `L1ScrollMessenger`
|
||||
// + 2-nd in `L1ScrollMessenger`
|
||||
assembly {
|
||||
mstore(0x00, _msgHash)
|
||||
mstore(0x20, 106)
|
||||
mstore(0x20, 156)
|
||||
_storageKey := keccak256(0x00, 0x40)
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,8 @@ contract WETH9 {
|
||||
balanceOf[msg.sender] -= wad;
|
||||
}
|
||||
|
||||
payable(msg.sender).transfer(wad);
|
||||
(bool success, ) = msg.sender.call{value:wad}("");
|
||||
require(success, "withdraw ETH failed");
|
||||
|
||||
emit Withdrawal(msg.sender, wad);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,28 @@ abstract contract ScrollMessengerBase is OwnableUpgradeable, IScrollMessenger {
|
||||
/// @notice The address of fee vault, collecting cross domain messaging fee.
|
||||
address public feeVault;
|
||||
|
||||
// @note move to ScrollMessengerBase in next big refactor
|
||||
/// @dev The status of for non-reentrant check.
|
||||
uint256 private _lock_status;
|
||||
|
||||
/**********************
|
||||
* Function Modifiers *
|
||||
**********************/
|
||||
|
||||
modifier nonReentrant() {
|
||||
// On the first call to nonReentrant, _notEntered will be true
|
||||
require(_lock_status != _ENTERED, "ReentrancyGuard: reentrant call");
|
||||
|
||||
// Any calls to nonReentrant after this point will fail
|
||||
_lock_status = _ENTERED;
|
||||
|
||||
_;
|
||||
|
||||
// By storing the original value once again, a refund is triggered (see
|
||||
// https://eips.ethereum.org/EIPS/eip-2200)
|
||||
_lock_status = _NOT_ENTERED;
|
||||
}
|
||||
|
||||
/***************
|
||||
* Constructor *
|
||||
***************/
|
||||
|
||||
@@ -12,6 +12,10 @@ import {Whitelist} from "../L2/predeploys/Whitelist.sol";
|
||||
import {L1ScrollMessenger} from "../L1/L1ScrollMessenger.sol";
|
||||
import {L2ScrollMessenger} from "../L2/L2ScrollMessenger.sol";
|
||||
|
||||
import {MockRollupVerifier} from "./mocks/MockRollupVerifier.sol";
|
||||
|
||||
// solhint-disable no-inline-assembly
|
||||
|
||||
abstract contract L1GatewayTestBase is DSTestPlus {
|
||||
// from L1MessageQueue
|
||||
event QueueTransaction(
|
||||
@@ -44,6 +48,8 @@ abstract contract L1GatewayTestBase is DSTestPlus {
|
||||
EnforcedTxGateway internal enforcedTxGateway;
|
||||
ScrollChain internal rollup;
|
||||
|
||||
MockRollupVerifier internal verifier;
|
||||
|
||||
address internal feeVault;
|
||||
Whitelist private whitelist;
|
||||
|
||||
@@ -59,6 +65,7 @@ abstract contract L1GatewayTestBase is DSTestPlus {
|
||||
rollup = new ScrollChain(1233);
|
||||
enforcedTxGateway = new EnforcedTxGateway();
|
||||
whitelist = new Whitelist(address(this));
|
||||
verifier = new MockRollupVerifier();
|
||||
|
||||
// Deploy L2 contracts
|
||||
l2Messenger = new L2ScrollMessenger(address(0), address(0), address(0));
|
||||
@@ -74,7 +81,7 @@ abstract contract L1GatewayTestBase is DSTestPlus {
|
||||
);
|
||||
gasOracle.initialize(0, 0, 0, 0);
|
||||
gasOracle.updateWhitelist(address(whitelist));
|
||||
rollup.initialize(address(messageQueue), address(0), 44);
|
||||
rollup.initialize(address(messageQueue), address(verifier), 44);
|
||||
|
||||
address[] memory _accounts = new address[](1);
|
||||
_accounts[0] = address(this);
|
||||
@@ -82,11 +89,40 @@ abstract contract L1GatewayTestBase is DSTestPlus {
|
||||
}
|
||||
|
||||
function prepareL2MessageRoot(bytes32 messageHash) internal {
|
||||
bytes memory _batchHeader = new bytes(89);
|
||||
rollup.updateSequencer(address(this), true);
|
||||
rollup.updateProver(address(this), true);
|
||||
|
||||
// import genesis batch
|
||||
bytes memory batchHeader0 = new bytes(89);
|
||||
assembly {
|
||||
mstore(add(_batchHeader, add(0x20, 25)), 1)
|
||||
mstore(add(batchHeader0, add(0x20, 25)), 1)
|
||||
}
|
||||
rollup.importGenesisBatch(batchHeader0, bytes32(uint256(1)));
|
||||
bytes32 batchHash0 = rollup.committedBatches(0);
|
||||
|
||||
// commit one batch
|
||||
bytes[] memory chunks = new bytes[](1);
|
||||
bytes memory 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));
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
rollup.importGenesisBatch(_batchHeader, bytes32(uint256(1)), messageHash);
|
||||
rollup.finalizeBatchWithProof(
|
||||
batchHeader1,
|
||||
bytes32(uint256(1)),
|
||||
bytes32(uint256(2)),
|
||||
messageHash,
|
||||
new bytes(0)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,81 +12,47 @@ import {Whitelist} from "../L2/predeploys/Whitelist.sol";
|
||||
import {IL1ScrollMessenger, L1ScrollMessenger} from "../L1/L1ScrollMessenger.sol";
|
||||
import {L2ScrollMessenger} from "../L2/L2ScrollMessenger.sol";
|
||||
|
||||
contract L1ScrollMessengerTest is DSTestPlus {
|
||||
L2ScrollMessenger internal l2Messenger;
|
||||
|
||||
address internal feeVault;
|
||||
|
||||
L1ScrollMessenger internal l1Messenger;
|
||||
ScrollChain internal scrollChain;
|
||||
L1MessageQueue internal l1MessageQueue;
|
||||
L2GasPriceOracle internal gasOracle;
|
||||
EnforcedTxGateway internal enforcedTxGateway;
|
||||
Whitelist internal whitelist;
|
||||
import {L1GatewayTestBase} from "./L1GatewayTestBase.t.sol";
|
||||
|
||||
contract L1ScrollMessengerTest is L1GatewayTestBase {
|
||||
function setUp() public {
|
||||
// Deploy L2 contracts
|
||||
l2Messenger = new L2ScrollMessenger(address(0), address(0), address(0));
|
||||
|
||||
// Deploy L1 contracts
|
||||
scrollChain = new ScrollChain(0);
|
||||
l1MessageQueue = new L1MessageQueue();
|
||||
l1Messenger = new L1ScrollMessenger();
|
||||
gasOracle = new L2GasPriceOracle();
|
||||
enforcedTxGateway = new EnforcedTxGateway();
|
||||
whitelist = new Whitelist(address(this));
|
||||
|
||||
// Initialize L1 contracts
|
||||
l1Messenger.initialize(address(l2Messenger), feeVault, address(scrollChain), address(l1MessageQueue));
|
||||
l1MessageQueue.initialize(
|
||||
address(l1Messenger),
|
||||
address(scrollChain),
|
||||
address(enforcedTxGateway),
|
||||
address(gasOracle),
|
||||
10000000
|
||||
);
|
||||
gasOracle.initialize(0, 0, 0, 0);
|
||||
scrollChain.initialize(address(l1MessageQueue), address(0), 44);
|
||||
|
||||
gasOracle.updateWhitelist(address(whitelist));
|
||||
address[] memory _accounts = new address[](1);
|
||||
_accounts[0] = address(this);
|
||||
whitelist.updateWhitelistStatus(_accounts, true);
|
||||
L1GatewayTestBase.setUpBase();
|
||||
}
|
||||
|
||||
function testForbidCallMessageQueueFromL2() external {
|
||||
// import genesis batch
|
||||
bytes memory _batchHeader = new bytes(89);
|
||||
assembly {
|
||||
mstore(add(_batchHeader, add(0x20, 25)), 1)
|
||||
}
|
||||
scrollChain.importGenesisBatch(
|
||||
_batchHeader,
|
||||
bytes32(uint256(1)),
|
||||
bytes32(0x3152134c22e545ab5d345248502b4f04ef5b45f735f939c7fe6ddc0ffefc9c52)
|
||||
bytes32 _xDomainCalldataHash = keccak256(
|
||||
abi.encodeWithSignature(
|
||||
"relayMessage(address,address,uint256,uint256,bytes)",
|
||||
address(this),
|
||||
address(messageQueue),
|
||||
0,
|
||||
0,
|
||||
new bytes(0)
|
||||
)
|
||||
);
|
||||
prepareL2MessageRoot(_xDomainCalldataHash);
|
||||
|
||||
IL1ScrollMessenger.L2MessageProof memory proof;
|
||||
proof.batchIndex = scrollChain.lastFinalizedBatchIndex();
|
||||
proof.batchIndex = rollup.lastFinalizedBatchIndex();
|
||||
|
||||
hevm.expectRevert("Forbid to call message queue");
|
||||
l1Messenger.relayMessageWithProof(address(this), address(l1MessageQueue), 0, 0, new bytes(0), proof);
|
||||
l1Messenger.relayMessageWithProof(address(this), address(messageQueue), 0, 0, new bytes(0), proof);
|
||||
}
|
||||
|
||||
function testForbidCallSelfFromL2() external {
|
||||
// import genesis batch
|
||||
bytes memory _batchHeader = new bytes(89);
|
||||
assembly {
|
||||
mstore(add(_batchHeader, 57), 1)
|
||||
}
|
||||
scrollChain.importGenesisBatch(
|
||||
_batchHeader,
|
||||
bytes32(uint256(1)),
|
||||
bytes32(0xf7c03e2b13c88e3fca1410b228b001dd94e3f5ab4b4a4a6981d09a4eb3e5b631)
|
||||
bytes32 _xDomainCalldataHash = keccak256(
|
||||
abi.encodeWithSignature(
|
||||
"relayMessage(address,address,uint256,uint256,bytes)",
|
||||
address(this),
|
||||
address(l1Messenger),
|
||||
0,
|
||||
0,
|
||||
new bytes(0)
|
||||
)
|
||||
);
|
||||
|
||||
prepareL2MessageRoot(_xDomainCalldataHash);
|
||||
IL1ScrollMessenger.L2MessageProof memory proof;
|
||||
proof.batchIndex = scrollChain.lastFinalizedBatchIndex();
|
||||
proof.batchIndex = rollup.lastFinalizedBatchIndex();
|
||||
|
||||
hevm.expectRevert("Forbid to call self");
|
||||
l1Messenger.relayMessageWithProof(address(this), address(l1Messenger), 0, 0, new bytes(0), proof);
|
||||
@@ -110,7 +76,9 @@ contract L1ScrollMessengerTest is DSTestPlus {
|
||||
|
||||
function testReplayMessage(uint256 exceedValue, address refundAddress) external {
|
||||
hevm.assume(refundAddress.code.length == 0);
|
||||
hevm.assume(uint256(uint160(refundAddress)) > 100); // ignore some precompile contracts
|
||||
hevm.assume(uint256(uint160(refundAddress)) > uint256(100)); // ignore some precompile contracts
|
||||
hevm.assume(refundAddress != feeVault);
|
||||
hevm.assume(refundAddress != address(0x000000000000000000636F6e736F6c652e6c6f67)); // ignore console/console2
|
||||
|
||||
exceedValue = bound(exceedValue, 1, address(this).balance / 2);
|
||||
|
||||
@@ -170,7 +138,7 @@ contract L1ScrollMessengerTest is DSTestPlus {
|
||||
l1Messenger.sendMessage{value: _fee + value}(address(0), value, hex"0011220033", gasLimit);
|
||||
|
||||
// update max gas limit
|
||||
l1MessageQueue.updateMaxGasLimit(gasLimit);
|
||||
messageQueue.updateMaxGasLimit(gasLimit);
|
||||
l1Messenger.sendMessage{value: _fee + value}(address(0), value, hex"0011220033", gasLimit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ contract ScrollChainTest is DSTestPlus {
|
||||
assembly {
|
||||
mstore(add(batchHeader0, add(0x20, 25)), 1)
|
||||
}
|
||||
rollup.importGenesisBatch(batchHeader0, bytes32(uint256(1)), bytes32(uint256(0)));
|
||||
rollup.importGenesisBatch(batchHeader0, bytes32(uint256(1)));
|
||||
|
||||
// caller not sequencer, revert
|
||||
hevm.expectRevert("caller not sequencer");
|
||||
@@ -136,7 +136,7 @@ contract ScrollChainTest is DSTestPlus {
|
||||
assembly {
|
||||
mstore(add(batchHeader0, add(0x20, 25)), 1)
|
||||
}
|
||||
rollup.importGenesisBatch(batchHeader0, bytes32(uint256(1)), bytes32(uint256(0)));
|
||||
rollup.importGenesisBatch(batchHeader0, bytes32(uint256(1)));
|
||||
bytes32 batchHash0 = rollup.committedBatches(0);
|
||||
|
||||
bytes[] memory chunks = new bytes[](1);
|
||||
@@ -228,7 +228,7 @@ contract ScrollChainTest is DSTestPlus {
|
||||
assembly {
|
||||
mstore(add(batchHeader0, add(0x20, 25)), 1)
|
||||
}
|
||||
rollup.importGenesisBatch(batchHeader0, bytes32(uint256(1)), bytes32(uint256(0)));
|
||||
rollup.importGenesisBatch(batchHeader0, bytes32(uint256(1)));
|
||||
bytes32 batchHash0 = rollup.committedBatches(0);
|
||||
|
||||
bytes memory bitmap;
|
||||
@@ -243,28 +243,28 @@ contract ScrollChainTest is DSTestPlus {
|
||||
// 0000000000000000000000000000000000000000000000000000000000000000
|
||||
// 0000000000000000
|
||||
// 0001
|
||||
// 50c3caa727394b95dc4885b7d25033ed22ac772b985fb274f2a7c0699a11346d
|
||||
// a2277fd30bbbe74323309023b56035b376d7768ad237ae4fc46ead7dc9591ae1
|
||||
// => data hash for chunk0
|
||||
// bb88f47194a07d59ed17bc9b2015f83d0afea8f7892d9c5f0b6565563bf06b26
|
||||
// 9ef1e5694bdb014a1eea42be756a8f63bfd8781d6332e9ef3b5126d90c62f110
|
||||
// => data hash for all chunks
|
||||
// 038433daac85a0b03cd443ed50bc85e832c883061651ae2182b2984751e0b340
|
||||
// d9cb6bf9264006fcea490d5c261f7453ab95b1b26033a3805996791b8e3a62f3
|
||||
// => payload for batch header
|
||||
// 00
|
||||
// 0000000000000002
|
||||
// 0000000000000001
|
||||
// 0000000000000001
|
||||
// 038433daac85a0b03cd443ed50bc85e832c883061651ae2182b2984751e0b340
|
||||
// 0000000000000001
|
||||
// d9cb6bf9264006fcea490d5c261f7453ab95b1b26033a3805996791b8e3a62f3
|
||||
// 119b828c2a2798d2c957228ebeaff7e10bb099ae0d4e224f3eeb779ff61cba61
|
||||
// 0000000000000000000000000000000000000000000000000000000000000000
|
||||
// => hash for batch header
|
||||
// cef70bf80683c4d9b8b2813e90c314e8c56648e231300b8cfed9d666b0caf14e
|
||||
// 00847173b29b238cf319cde79512b7c213e5a8b4138daa7051914c4592b6dfc7
|
||||
bytes memory batchHeader1 = new bytes(89 + 32);
|
||||
assembly {
|
||||
mstore(add(batchHeader1, 0x20), 0) // version
|
||||
mstore(add(batchHeader1, add(0x20, 1)), shl(192, 1)) // batchIndex = 1
|
||||
mstore(add(batchHeader1, add(0x20, 9)), shl(192, 1)) // l1MessagePopped = 1
|
||||
mstore(add(batchHeader1, add(0x20, 17)), shl(192, 1)) // totalL1MessagePopped = 1
|
||||
mstore(add(batchHeader1, add(0x20, 25)), 0x038433daac85a0b03cd443ed50bc85e832c883061651ae2182b2984751e0b340) // dataHash
|
||||
mstore(add(batchHeader1, add(0x20, 25)), 0xd9cb6bf9264006fcea490d5c261f7453ab95b1b26033a3805996791b8e3a62f3) // dataHash
|
||||
mstore(add(batchHeader1, add(0x20, 57)), batchHash0) // parentBatchHash
|
||||
mstore(add(batchHeader1, add(0x20, 89)), 0) // bitmap0
|
||||
}
|
||||
@@ -280,7 +280,7 @@ contract ScrollChainTest is DSTestPlus {
|
||||
rollup.commitBatch(0, batchHeader0, chunks, bitmap);
|
||||
assertBoolEq(rollup.isBatchFinalized(1), false);
|
||||
bytes32 batchHash1 = rollup.committedBatches(1);
|
||||
assertEq(batchHash1, bytes32(0xcef70bf80683c4d9b8b2813e90c314e8c56648e231300b8cfed9d666b0caf14e));
|
||||
assertEq(batchHash1, bytes32(0x00847173b29b238cf319cde79512b7c213e5a8b4138daa7051914c4592b6dfc7));
|
||||
|
||||
// finalize batch1
|
||||
rollup.finalizeBatchWithProof(
|
||||
@@ -330,26 +330,26 @@ contract ScrollChainTest is DSTestPlus {
|
||||
// 012c
|
||||
// ... (some tx hashes)
|
||||
// => data hash for chunk2
|
||||
// 5c91563ee8be18cb94accfc83728f883ff5e3aa600fd0799e0a4e39afc7970b9
|
||||
// 0520f1fbe159af97fdf1d6cfcfe7605f99f7bfe3ed876e87b64250b1810df00b
|
||||
// => data hash for all chunks
|
||||
// bf38f308e0a87ed7bf92fa2da038fa1d59a7b9801eb0f6d487f8eef528632145
|
||||
// f52343299f6379fd15b20b23d51fc61b9b357b124be112686626b6278bcffa83
|
||||
// => payload for batch header
|
||||
// 00
|
||||
// 0000000000000002
|
||||
// 0000000000000108
|
||||
// 0000000000000109
|
||||
// bf38f308e0a87ed7bf92fa2da038fa1d59a7b9801eb0f6d487f8eef528632145
|
||||
// f52343299f6379fd15b20b23d51fc61b9b357b124be112686626b6278bcffa83
|
||||
// cef70bf80683c4d9b8b2813e90c314e8c56648e231300b8cfed9d666b0caf14e
|
||||
// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa800000000000000000000000000000000000000000000000000000000000000aa
|
||||
// => hash for batch header
|
||||
// 17fe6c12739f3a6261ae6db6486f41758dbd5d0508f19a5ca9ac37df67bbfec2
|
||||
// 2231cf185a5c07931584f970738b4cd2ae4fb39e2d90853b26746c7616ea71b9
|
||||
bytes memory batchHeader2 = new bytes(89 + 32 + 32);
|
||||
assembly {
|
||||
mstore(add(batchHeader2, 0x20), 0) // version
|
||||
mstore(add(batchHeader2, add(0x20, 1)), shl(192, 2)) // batchIndex = 2
|
||||
mstore(add(batchHeader2, add(0x20, 9)), shl(192, 264)) // l1MessagePopped = 264
|
||||
mstore(add(batchHeader2, add(0x20, 17)), shl(192, 265)) // totalL1MessagePopped = 265
|
||||
mstore(add(batchHeader2, add(0x20, 25)), 0xbf38f308e0a87ed7bf92fa2da038fa1d59a7b9801eb0f6d487f8eef528632145) // dataHash
|
||||
mstore(add(batchHeader2, add(0x20, 25)), 0xf52343299f6379fd15b20b23d51fc61b9b357b124be112686626b6278bcffa83) // dataHash
|
||||
mstore(add(batchHeader2, add(0x20, 57)), batchHash1) // parentBatchHash
|
||||
mstore(
|
||||
add(batchHeader2, add(0x20, 89)),
|
||||
@@ -398,7 +398,7 @@ contract ScrollChainTest is DSTestPlus {
|
||||
rollup.commitBatch(0, batchHeader1, chunks, bitmap);
|
||||
assertBoolEq(rollup.isBatchFinalized(2), false);
|
||||
bytes32 batchHash2 = rollup.committedBatches(2);
|
||||
assertEq(batchHash2, bytes32(0x17fe6c12739f3a6261ae6db6486f41758dbd5d0508f19a5ca9ac37df67bbfec2));
|
||||
assertEq(batchHash2, bytes32(0x2231cf185a5c07931584f970738b4cd2ae4fb39e2d90853b26746c7616ea71b9));
|
||||
|
||||
// verify committed batch correctly
|
||||
rollup.finalizeBatchWithProof(
|
||||
@@ -450,7 +450,7 @@ contract ScrollChainTest is DSTestPlus {
|
||||
assembly {
|
||||
mstore(add(batchHeader0, add(0x20, 25)), 1)
|
||||
}
|
||||
rollup.importGenesisBatch(batchHeader0, bytes32(uint256(1)), bytes32(uint256(0)));
|
||||
rollup.importGenesisBatch(batchHeader0, bytes32(uint256(1)));
|
||||
bytes32 batchHash0 = rollup.committedBatches(0);
|
||||
|
||||
bytes[] memory chunks = new bytes[](1);
|
||||
@@ -577,52 +577,52 @@ contract ScrollChainTest is DSTestPlus {
|
||||
// zero state root, revert
|
||||
batchHeader = new bytes(89);
|
||||
hevm.expectRevert("zero state root");
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(0), bytes32(0));
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(0));
|
||||
|
||||
// batch header length too small, revert
|
||||
batchHeader = new bytes(88);
|
||||
hevm.expectRevert("batch header length too small");
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)), bytes32(0));
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)));
|
||||
|
||||
// wrong bitmap length, revert
|
||||
batchHeader = new bytes(90);
|
||||
hevm.expectRevert("wrong bitmap length");
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)), bytes32(0));
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)));
|
||||
|
||||
// not all fields are zero, revert
|
||||
batchHeader = new bytes(89);
|
||||
batchHeader[0] = bytes1(uint8(1)); // version not zero
|
||||
hevm.expectRevert("not all fields are zero");
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)), bytes32(0));
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)));
|
||||
|
||||
batchHeader = new bytes(89);
|
||||
batchHeader[1] = bytes1(uint8(1)); // batchIndex not zero
|
||||
hevm.expectRevert("not all fields are zero");
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)), bytes32(0));
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)));
|
||||
|
||||
batchHeader = new bytes(89 + 32);
|
||||
assembly {
|
||||
mstore(add(batchHeader, add(0x20, 9)), shl(192, 1)) // l1MessagePopped not zero
|
||||
}
|
||||
hevm.expectRevert("not all fields are zero");
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)), bytes32(0));
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)));
|
||||
|
||||
batchHeader = new bytes(89);
|
||||
batchHeader[17] = bytes1(uint8(1)); // totalL1MessagePopped not zero
|
||||
hevm.expectRevert("not all fields are zero");
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)), bytes32(0));
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)));
|
||||
|
||||
// zero data hash, revert
|
||||
batchHeader = new bytes(89);
|
||||
hevm.expectRevert("zero data hash");
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)), bytes32(0));
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)));
|
||||
|
||||
// nonzero parent batch hash, revert
|
||||
batchHeader = new bytes(89);
|
||||
batchHeader[25] = bytes1(uint8(1)); // dataHash not zero
|
||||
batchHeader[57] = bytes1(uint8(1)); // parentBatchHash not zero
|
||||
hevm.expectRevert("nonzero parent batch hash");
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)), bytes32(0));
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)));
|
||||
|
||||
// import correctly
|
||||
batchHeader = new bytes(89);
|
||||
@@ -630,13 +630,13 @@ contract ScrollChainTest is DSTestPlus {
|
||||
assertEq(rollup.finalizedStateRoots(0), bytes32(0));
|
||||
assertEq(rollup.withdrawRoots(0), bytes32(0));
|
||||
assertEq(rollup.committedBatches(0), bytes32(0));
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)), bytes32(uint256(2)));
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)));
|
||||
assertEq(rollup.finalizedStateRoots(0), bytes32(uint256(1)));
|
||||
assertEq(rollup.withdrawRoots(0), bytes32(uint256(2)));
|
||||
assertEq(rollup.withdrawRoots(0), bytes32(0));
|
||||
assertGt(uint256(rollup.committedBatches(0)), 0);
|
||||
|
||||
// Genesis batch imported, revert
|
||||
hevm.expectRevert("Genesis batch imported");
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)), bytes32(uint256(2)));
|
||||
rollup.importGenesisBatch(batchHeader, bytes32(uint256(1)));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user