Commit 58e3da1f authored by Skeletor Spaceman's avatar Skeletor Spaceman Committed by GitHub

feat: remove cross l2 inbox execute message (#185) (#13626)

* feat: remove cross l2 inbox execute message (#185)

* feat: remove cross l2 inbox execute message

* feat: remove cross l2 inbox execute message

* feat: remove cross l2 inbox identifier checks (#186)

* feat: remove cross l2 inbox identifier checks

* fix: clear emit and validate naming

* fix: pre pr (#187)

---------
Co-authored-by: default avatarAgusDuha <81362284+agusduha@users.noreply.github.com>
parent 5209734b
......@@ -188,27 +188,6 @@ func (_Inbox *InboxTransactorRaw) Transact(opts *bind.TransactOpts, method strin
return _Inbox.Contract.contract.Transact(opts, method, params...)
}
// ExecuteMessage is a paid mutator transaction binding the contract method 0x5984c53e.
//
// Solidity: function executeMessage((address,uint256,uint256,uint256,uint256) _id, address _target, bytes _message) payable returns()
func (_Inbox *InboxTransactor) ExecuteMessage(opts *bind.TransactOpts, _id Identifier, _target common.Address, _message []byte) (*types.Transaction, error) {
return _Inbox.contract.Transact(opts, "executeMessage", _id, _target, _message)
}
// ExecuteMessage is a paid mutator transaction binding the contract method 0x5984c53e.
//
// Solidity: function executeMessage((address,uint256,uint256,uint256,uint256) _id, address _target, bytes _message) payable returns()
func (_Inbox *InboxSession) ExecuteMessage(_id Identifier, _target common.Address, _message []byte) (*types.Transaction, error) {
return _Inbox.Contract.ExecuteMessage(&_Inbox.TransactOpts, _id, _target, _message)
}
// ExecuteMessage is a paid mutator transaction binding the contract method 0x5984c53e.
//
// Solidity: function executeMessage((address,uint256,uint256,uint256,uint256) _id, address _target, bytes _message) payable returns()
func (_Inbox *InboxTransactorSession) ExecuteMessage(_id Identifier, _target common.Address, _message []byte) (*types.Transaction, error) {
return _Inbox.Contract.ExecuteMessage(&_Inbox.TransactOpts, _id, _target, _message)
}
// ValidateMessage is a paid mutator transaction binding the contract method 0xab4d6f75.
//
// Solidity: function validateMessage((address,uint256,uint256,uint256,uint256) _id, bytes32 _msgHash) returns()
......
......@@ -13,12 +13,6 @@ struct Identifier {
/// @notice Interface for the CrossL2Inbox contract.
interface ICrossL2Inbox {
/// @notice Executes a cross chain message on the destination chain.
/// @param _id An Identifier pointing to the initiating message.
/// @param _target Account that is called with _msg.
/// @param _message The message payload, matching the initiating message.
function executeMessage(Identifier calldata _id, address _target, bytes calldata _message) external payable;
/// @notice Validates a cross chain message on the destination chain
/// and emits an ExecutingMessage event. This function is useful
/// for applications that understand the schema of the _message payload and want to
......
......@@ -298,18 +298,17 @@ func TestInteropBlockBuilding(t *testing.T) {
t.Log("Testing invalid message")
{
bobAddr := s2.Address(chainA, "Bob") // direct it to a random account without code
ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
defer cancel()
// Send an executing message, but with different payload.
// Emitting an executing message, but with different payload.
if s2.(*interopE2ESystem).config.mempoolFiltering {
// We expect the traqnsaction to be filtered out by the mempool if mempool filtering is enabled.
// ExecuteMessage the ErrTxFilteredOut error is checked when sending the tx.
_, err := s2.ExecuteMessage(ctx, chainB, "Alice", identifier, bobAddr, invalidPayload, gethCore.ErrTxFilteredOut)
// ValidateMessage the ErrTxFilteredOut error is checked when sending the tx.
_, err := s2.ValidateMessage(ctx, chainB, "Alice", identifier, invalidPayloadHash, gethCore.ErrTxFilteredOut)
require.ErrorContains(t, err, gethCore.ErrTxFilteredOut.Error())
} else {
// We expect the miner to be unable to include this tx, and confirmation to thus time out, if mempool filtering is disabled.
_, err := s2.ExecuteMessage(ctx, chainB, "Alice", identifier, bobAddr, invalidPayload, nil)
_, err := s2.ValidateMessage(ctx, chainB, "Alice", identifier, invalidPayloadHash, nil)
require.ErrorIs(t, err, ctx.Err())
require.ErrorIs(t, ctx.Err(), context.DeadlineExceeded)
}
......@@ -317,11 +316,10 @@ func TestInteropBlockBuilding(t *testing.T) {
t.Log("Testing valid message now")
{
bobAddr := s2.Address(chainA, "Bob") // direct it to a random account without code
ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
defer cancel()
// Send an executing message with the correct identifier / payload
rec, err := s2.ExecuteMessage(ctx, chainB, "Alice", identifier, bobAddr, msgPayload, nil)
// Emit an executing message with the correct identifier / payload
rec, err := s2.ValidateMessage(ctx, chainB, "Alice", identifier, payloadHash, nil)
require.NoError(t, err, "expecting tx to be confirmed")
t.Logf("confirmed executing msg in block %s", rec.BlockNumber)
}
......
......@@ -106,14 +106,13 @@ type SuperSystem interface {
EmitData(ctx context.Context, network string, username string, data string) *types.Receipt
// AddDependency adds a dependency (by chain ID) to the given chain
AddDependency(ctx context.Context, network string, dep *big.Int) *types.Receipt
// ExecuteMessage calls the CrossL2Inbox executeMessage function
ExecuteMessage(
// ValidateMessage calls the CrossL2Inbox ValidateMessage function
ValidateMessage(
ctx context.Context,
id string,
sender string,
msgIdentifier supervisortypes.Identifier,
target common.Address,
message []byte,
msgHash [32]byte,
expectedError error,
) (*types.Receipt, error)
// Access a contract on a network by name
......@@ -733,17 +732,16 @@ func (s *interopE2ESystem) SendL2Tx(
newApply)
}
// ExecuteMessage calls the CrossL2Inbox executeMessage function
// ValidateMessage calls the CrossL2Inbox ValidateMessage function
// it uses the L2's chain ID, username key, and geth client.
// expectedError represents the error returned by `ExecuteMessage` if it is expected.
// expectedError represents the error returned by `ValidateMessage` if it is expected.
// the returned err is related to `WaitMined`
func (s *interopE2ESystem) ExecuteMessage(
func (s *interopE2ESystem) ValidateMessage(
ctx context.Context,
id string,
sender string,
msgIdentifier supervisortypes.Identifier,
target common.Address,
message []byte,
msgHash [32]byte,
expectedError error,
) (*types.Receipt, error) {
secret := s.UserKey(id, sender)
......@@ -762,14 +760,14 @@ func (s *interopE2ESystem) ExecuteMessage(
Timestamp: new(big.Int).SetUint64(msgIdentifier.Timestamp),
ChainId: msgIdentifier.ChainID.ToBig(),
}
tx, err := contract.InboxTransactor.ExecuteMessage(auth, identifier, target, message)
tx, err := contract.InboxTransactor.ValidateMessage(auth, identifier, msgHash)
if expectedError != nil {
require.ErrorContains(s.t, err, expectedError.Error())
return nil, err
} else {
require.NoError(s.t, err)
}
s.logger.Info("Executing message", "tx", tx.Hash(), "to", tx.To(), "target", target, "data", hexutil.Bytes(tx.Data()))
s.logger.Info("Validating message", "tx", tx.Hash(), "to", tx.To(), "data", hexutil.Bytes(tx.Data()))
return bind.WaitMined(ctx, s.L2GethClient(id), tx)
}
......
......@@ -43,8 +43,7 @@ func TestDecodeExecutingMessageLog(t *testing.T) {
// uint256 timestamp;
// uint256 chainId;
// }
// function executeMessage(Identifier calldata _id,
// address _target, bytes calldata _message) external payable;
// event ExecutingMessage(bytes32 indexed msgHash, Identifier id);
originAddr := common.HexToAddress("0x5fbdb2315678afecb367f032d93f642f64180aa3")
payloadHash := common.HexToHash("0xc3f57e1f0dd62a4f77787d834029bfeaab8894022c47edbe13b044fb658c9190")
......
......@@ -23,15 +23,6 @@ interface ICrossL2Inbox {
/// @notice Thrown when a non-written transient storage slot is attempted to be read from.
error NotEntered();
/// @notice Thrown when trying to execute a cross chain message with an invalid Identifier timestamp.
error InvalidTimestamp();
/// @notice Thrown when trying to execute a cross chain message with an invalid Identifier chain ID.
error InvalidChainId();
/// @notice Thrown when trying to execute a cross chain message and the target call fails.
error TargetCallFailed();
/// @notice Thrown when trying to execute a cross chain message on a deposit transaction.
error NoExecutingDeposits();
......@@ -60,12 +51,6 @@ interface ICrossL2Inbox {
function setInteropStart() external;
/// @notice Executes a cross chain message on the destination chain.
/// @param _id An Identifier pointing to the initiating message.
/// @param _target Account that is called with _msg.
/// @param _message The message payload, matching the initiating message.
function executeMessage(Identifier calldata _id, address _target, bytes calldata _message) external payable;
/// @notice Validates a cross chain message on the destination chain
/// and emits an ExecutingMessage event. This function is useful
/// for applications that understand the schema of the _message payload and want to
......
......@@ -25,56 +25,6 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "origin",
"type": "address"
},
{
"internalType": "uint256",
"name": "blockNumber",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "logIndex",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "timestamp",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "chainId",
"type": "uint256"
}
],
"internalType": "struct Identifier",
"name": "_id",
"type": "tuple"
},
{
"internalType": "address",
"name": "_target",
"type": "address"
},
{
"internalType": "bytes",
"name": "_message",
"type": "bytes"
}
],
"name": "executeMessage",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "interopStart",
......@@ -243,16 +193,6 @@
"name": "InteropStartAlreadySet",
"type": "error"
},
{
"inputs": [],
"name": "InvalidChainId",
"type": "error"
},
{
"inputs": [],
"name": "InvalidTimestamp",
"type": "error"
},
{
"inputs": [],
"name": "NoExecutingDeposits",
......@@ -272,10 +212,5 @@
"inputs": [],
"name": "ReentrantCall",
"type": "error"
},
{
"inputs": [],
"name": "TargetCallFailed",
"type": "error"
}
]
\ No newline at end of file
......@@ -48,8 +48,8 @@
"sourceCodeHash": "0xfa56426153227e798150f6becc30a33fd20a3c6e0d73c797a3922dd631acbb57"
},
"src/L2/CrossL2Inbox.sol": {
"initCodeHash": "0x7a189f6dff6c19ec6f1e94d84a0d9d98a320a68812f957e50bf8b63224bb0dce",
"sourceCodeHash": "0x9bbfabb19b7f572dadae797786c2f87d892693650151bd8de6eadee3e03fc559"
"initCodeHash": "0x2bc4a3765004f9a9e6e5278753bce3c3d53cc95da62efcc0cb10c50d8c806cd4",
"sourceCodeHash": "0x661d7659f09b7f909e8bd5e6c41e8c98f2091036ed2123b7e18a1a74120bd849"
},
"src/L2/ETHLiquidity.sol": {
"initCodeHash": "0xbb16de6a3f678db7301694a000f315154f25f9660c8dcec4b0bef20bc7cfdebd",
......
......@@ -4,11 +4,9 @@ pragma solidity 0.8.25;
// Libraries
import { Predeploys } from "src/libraries/Predeploys.sol";
import { TransientContext, TransientReentrancyAware } from "src/libraries/TransientContext.sol";
import { SafeCall } from "src/libraries/SafeCall.sol";
// Interfaces
import { ISemver } from "interfaces/universal/ISemver.sol";
import { IDependencySet } from "interfaces/L2/IDependencySet.sol";
import { IL1BlockInterop } from "interfaces/L2/IL1BlockInterop.sol";
/// @notice Thrown when the caller is not DEPOSITOR_ACCOUNT when calling `setInteropStart()`
......@@ -20,15 +18,6 @@ error InteropStartAlreadySet();
/// @notice Thrown when a non-written transient storage slot is attempted to be read from.
error NotEntered();
/// @notice Thrown when trying to execute a cross chain message with an invalid Identifier timestamp.
error InvalidTimestamp();
/// @notice Thrown when trying to execute a cross chain message with an invalid Identifier chain ID.
error InvalidChainId();
/// @notice Thrown when trying to execute a cross chain message and the target call fails.
error TargetCallFailed();
/// @notice Thrown when trying to execute a cross chain message on a deposit transaction.
error NoExecutingDeposits();
......@@ -76,8 +65,8 @@ contract CrossL2Inbox is ISemver, TransientReentrancyAware {
address internal constant DEPOSITOR_ACCOUNT = 0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001;
/// @notice Semantic version.
/// @custom:semver 1.0.0-beta.11
string public constant version = "1.0.0-beta.11";
/// @custom:semver 1.0.0-beta.12
string public constant version = "1.0.0-beta.12";
/// @notice Emitted when a cross chain message is being executed.
/// @param msgHash Hash of message payload being executed.
......@@ -137,37 +126,6 @@ contract CrossL2Inbox is ISemver, TransientReentrancyAware {
return TransientContext.get(CHAINID_SLOT);
}
/// @notice Executes a cross chain message on the destination chain.
/// @param _id Identifier of the message.
/// @param _target Target address to call.
/// @param _message Message payload to call target with.
function executeMessage(
Identifier calldata _id,
address _target,
bytes memory _message
)
external
payable
reentrantAware
{
// We need to know if this is being called on a depositTx
if (IL1BlockInterop(Predeploys.L1_BLOCK_ATTRIBUTES).isDeposit()) revert NoExecutingDeposits();
// Check the Identifier.
_checkIdentifier(_id);
// Store the Identifier in transient storage.
_storeIdentifier(_id);
// Call the target account with the message payload.
bool success = SafeCall.call(_target, msg.value, _message);
// Revert if the target call failed.
if (!success) revert TargetCallFailed();
emit ExecutingMessage(keccak256(_message), _id);
}
/// @notice Validates a cross chain message on the destination chain
/// and emits an ExecutingMessage event. This function is useful
/// for applications that understand the schema of the _message payload and want to
......@@ -178,23 +136,9 @@ contract CrossL2Inbox is ISemver, TransientReentrancyAware {
// We need to know if this is being called on a depositTx
if (IL1BlockInterop(Predeploys.L1_BLOCK_ATTRIBUTES).isDeposit()) revert NoExecutingDeposits();
// Check the Identifier.
_checkIdentifier(_id);
emit ExecutingMessage(_msgHash, _id);
}
/// @notice Validates that for a given cross chain message identifier,
/// it's timestamp is not in the future and the source chainId
/// is in the destination chain's dependency set.
/// @param _id Identifier of the message.
function _checkIdentifier(Identifier calldata _id) internal view {
if (_id.timestamp > block.timestamp || _id.timestamp <= interopStart()) revert InvalidTimestamp();
if (!IDependencySet(Predeploys.L1_BLOCK_ATTRIBUTES).isInDependencySet(_id.chainId)) {
revert InvalidChainId();
}
}
/// @notice Stores the Identifier in transient storage.
/// @param _id Identifier to store.
function _storeIdentifier(Identifier calldata _id) internal {
......
......@@ -14,9 +14,6 @@ import {
Identifier,
NotEntered,
NoExecutingDeposits,
InvalidTimestamp,
InvalidChainId,
TargetCallFailed,
NotDepositor,
InteropStartAlreadySet
} from "src/L2/CrossL2Inbox.sol";
......@@ -139,316 +136,6 @@ contract CrossL2InboxTest is Test {
crossL2Inbox.setInteropStart();
}
/// @dev Tests that the `executeMessage` function succeeds.
function testFuzz_executeMessage_succeeds(
Identifier memory _id,
address _target,
bytes calldata _message,
uint256 _value
)
external
payable
setInteropStart
{
// Ensure that the id's timestamp is valid (less than or equal to the current block timestamp and greater than
// interop start time)
_id.timestamp = bound(_id.timestamp, interopStartTime + 1, block.timestamp);
// Ensure that the target call is payable if value is sent
if (_value > 0) assumePayable(_target);
// Ensure target is not a forge address.
assumeNotForgeAddress(_target);
// Ensure is not a deposit transaction
vm.mockCall({
callee: Predeploys.L1_BLOCK_ATTRIBUTES,
data: abi.encodeCall(IL1BlockInterop.isDeposit, ()),
returnData: abi.encode(false)
});
// Ensure that the target call does not revert
vm.mockCall({ callee: _target, msgValue: _value, data: _message, returnData: abi.encode(true) });
// Ensure that the chain ID is in the dependency set
vm.mockCall({
callee: Predeploys.L1_BLOCK_ATTRIBUTES,
data: abi.encodeCall(IL1BlockInterop.isInDependencySet, (_id.chainId)),
returnData: abi.encode(true)
});
// Ensure that the contract has enough balance to send with value
vm.deal(address(this), _value);
// Look for the call to the target contract
vm.expectCall({ callee: _target, msgValue: _value, data: _message });
// Look for the emit ExecutingMessage event
vm.expectEmit(Predeploys.CROSS_L2_INBOX);
emit CrossL2Inbox.ExecutingMessage(keccak256(_message), _id);
// Call the executeMessage function
crossL2Inbox.executeMessage{ value: _value }({ _id: _id, _target: _target, _message: _message });
// Check that the Identifier was stored correctly, but first we have to increment. This is because
// `executeMessage` increments + decrements the transient call depth, so we need to increment to have the
// getters use the right call depth.
CrossL2InboxWithModifiableTransientStorage(Predeploys.CROSS_L2_INBOX).increment();
assertEq(crossL2Inbox.origin(), _id.origin);
assertEq(crossL2Inbox.blockNumber(), _id.blockNumber);
assertEq(crossL2Inbox.logIndex(), _id.logIndex);
assertEq(crossL2Inbox.timestamp(), _id.timestamp);
assertEq(crossL2Inbox.chainId(), _id.chainId);
}
/// @dev Mock reentrant function that calls the `executeMessage` function.
/// @param _id Identifier to pass to the `executeMessage` function.
function mockReentrant(Identifier calldata _id) external payable {
crossL2Inbox.executeMessage({ _id: _id, _target: address(0), _message: "" });
}
/// @dev Tests that the `executeMessage` function successfully handles reentrant calls.
function testFuzz_executeMessage_reentrant_succeeds(
Identifier memory _id1, // identifier passed to `executeMessage` by the initial call.
Identifier memory _id2, // identifier passed to `executeMessage` by the reentrant call.
uint256 _value
)
external
payable
setInteropStart
{
// Ensure that the ids' timestamp are valid (less than or equal to the current block timestamp and greater than
// interop start time)
_id1.timestamp = bound(_id1.timestamp, interopStartTime + 1, block.timestamp);
_id2.timestamp = bound(_id2.timestamp, interopStartTime + 1, block.timestamp);
// Ensure is not a deposit transaction
vm.mockCall({
callee: Predeploys.L1_BLOCK_ATTRIBUTES,
data: abi.encodeCall(IL1BlockInterop.isDeposit, ()),
returnData: abi.encode(false)
});
// Ensure that id1's chain ID is in the dependency set
vm.mockCall({
callee: Predeploys.L1_BLOCK_ATTRIBUTES,
data: abi.encodeCall(IL1BlockInterop.isInDependencySet, (_id1.chainId)),
returnData: abi.encode(true)
});
// Ensure that id2's chain ID is in the dependency set
vm.mockCall({
callee: Predeploys.L1_BLOCK_ATTRIBUTES,
data: abi.encodeCall(IL1BlockInterop.isInDependencySet, (_id2.chainId)),
returnData: abi.encode(true)
});
// Set the target and message for the reentrant call
address target = address(this);
bytes memory message = abi.encodeCall(this.mockReentrant, (_id2));
// Ensure that the contract has enough balance to send with value
vm.deal(address(this), _value);
// Look for the call to the target contract
vm.expectCall({ callee: target, msgValue: _value, data: message });
// Call the executeMessage function
crossL2Inbox.executeMessage{ value: _value }({ _id: _id1, _target: target, _message: message });
// Check that the reentrant function didn't update Identifier in transient storage at first call's call depth
CrossL2InboxWithModifiableTransientStorage(Predeploys.CROSS_L2_INBOX).increment();
assertEq(crossL2Inbox.origin(), _id1.origin);
assertEq(crossL2Inbox.blockNumber(), _id1.blockNumber);
assertEq(crossL2Inbox.logIndex(), _id1.logIndex);
assertEq(crossL2Inbox.timestamp(), _id1.timestamp);
assertEq(crossL2Inbox.chainId(), _id1.chainId);
// Check that the reentrant function updated the Identifier at deeper call depth
CrossL2InboxWithModifiableTransientStorage(Predeploys.CROSS_L2_INBOX).increment();
assertEq(crossL2Inbox.origin(), _id2.origin);
assertEq(crossL2Inbox.blockNumber(), _id2.blockNumber);
assertEq(crossL2Inbox.logIndex(), _id2.logIndex);
assertEq(crossL2Inbox.timestamp(), _id2.timestamp);
assertEq(crossL2Inbox.chainId(), _id2.chainId);
}
/// @dev Tests that the `executeMessage` function reverts if the transaction comes from a deposit.
function testFuzz_executeMessage_isDeposit_reverts(
Identifier calldata _id,
address _target,
bytes calldata _message,
uint256 _value
)
external
{
// Ensure it is a deposit transaction
vm.mockCall({
callee: Predeploys.L1_BLOCK_ATTRIBUTES,
data: abi.encodeCall(IL1BlockInterop.isDeposit, ()),
returnData: abi.encode(true)
});
// Ensure that the contract has enough balance to send with value
vm.deal(address(this), _value);
// Expect a revert with the NoExecutingDeposits selector
vm.expectRevert(NoExecutingDeposits.selector);
// Call the executeMessage function
crossL2Inbox.executeMessage{ value: _value }({ _id: _id, _target: _target, _message: _message });
}
/// @dev Tests that the `executeMessage` function reverts when called with an identifier with an invalid timestamp.
function testFuzz_executeMessage_invalidTimestamp_reverts(
Identifier memory _id,
address _target,
bytes calldata _message,
uint256 _value
)
external
setInteropStart
{
// Ensure that the id's timestamp is invalid (greater than the current block timestamp)
_id.timestamp = bound(_id.timestamp, block.timestamp + 1, type(uint256).max);
// Ensure is not a deposit transaction
vm.mockCall({
callee: Predeploys.L1_BLOCK_ATTRIBUTES,
data: abi.encodeCall(IL1BlockInterop.isDeposit, ()),
returnData: abi.encode(false)
});
// Ensure that the contract has enough balance to send with value
vm.deal(address(this), _value);
// Expect a revert with the InvalidTimestamp selector
vm.expectRevert(InvalidTimestamp.selector);
// Call the executeMessage function
crossL2Inbox.executeMessage{ value: _value }({ _id: _id, _target: _target, _message: _message });
}
/// @dev Tests that the `executeMessage` function reverts when called with an identifier with a timestamp earlier
/// than INTEROP_START timestamp
function testFuzz_executeMessage_invalidTimestampInteropStart_reverts(
Identifier memory _id,
address _target,
bytes calldata _message,
uint256 _value
)
external
setInteropStart
{
// Ensure that the id's timestamp is invalid (less than or equal to interopStartTime)
_id.timestamp = bound(_id.timestamp, 0, crossL2Inbox.interopStart());
// Ensure that the contract has enough balance to send with value
vm.deal(address(this), _value);
// Ensure is not a deposit transaction
vm.mockCall({
callee: Predeploys.L1_BLOCK_ATTRIBUTES,
data: abi.encodeCall(IL1BlockInterop.isDeposit, ()),
returnData: abi.encode(false)
});
// Expect a revert with the InvalidTimestamp selector
vm.expectRevert(InvalidTimestamp.selector);
// Call the executeMessage function
crossL2Inbox.executeMessage{ value: _value }({ _id: _id, _target: _target, _message: _message });
}
/// @dev Tests that the `executeMessage` function reverts when called with an identifier with a chain ID not in
/// dependency set.
function testFuzz_executeMessage_invalidChainId_reverts(
Identifier memory _id,
address _target,
bytes calldata _message,
uint256 _value
)
external
setInteropStart
{
// Ensure that the id's timestamp is valid (less than or equal to the current block timestamp and greater than
// interop start time)
_id.timestamp = bound(_id.timestamp, interopStartTime + 1, block.timestamp);
// Ensure is not a deposit transaction
vm.mockCall({
callee: Predeploys.L1_BLOCK_ATTRIBUTES,
data: abi.encodeCall(IL1BlockInterop.isDeposit, ()),
returnData: abi.encode(false)
});
// Ensure that the chain ID is NOT in the dependency set
vm.mockCall({
callee: Predeploys.L1_BLOCK_ATTRIBUTES,
data: abi.encodeCall(IL1BlockInterop.isInDependencySet, (_id.chainId)),
returnData: abi.encode(false)
});
// Ensure that the contract has enough balance to send with value
vm.deal(address(this), _value);
// Expect a revert with the InvalidChainId selector
vm.expectRevert(InvalidChainId.selector);
// Call the executeMessage function
crossL2Inbox.executeMessage{ value: _value }({ _id: _id, _target: _target, _message: _message });
}
/// @dev Tests that the `executeMessage` function reverts when the target call fails.
function testFuzz_executeMessage_targetCallFailed_reverts(
Identifier memory _id,
address _target,
bytes calldata _message,
uint256 _value
)
external
setInteropStart
{
// Ensure that the id's timestamp is valid (less than or equal to the current block timestamp and greater than
// interop start time)
_id.timestamp = bound(_id.timestamp, interopStartTime + 1, block.timestamp);
// Ensure that the target call is payable if value is sent
if (_value > 0) assumePayable(_target);
// Ensure target is not a forge address.
assumeNotForgeAddress(_target);
// Ensure that the target call reverts
vm.mockCallRevert({ callee: _target, msgValue: _value, data: _message, revertData: abi.encode(false) });
// Ensure is not a deposit transaction
vm.mockCall({
callee: Predeploys.L1_BLOCK_ATTRIBUTES,
data: abi.encodeCall(IL1BlockInterop.isDeposit, ()),
returnData: abi.encode(false)
});
// Ensure that the chain ID is in the dependency set
vm.mockCall({
callee: Predeploys.L1_BLOCK_ATTRIBUTES,
data: abi.encodeCall(IL1BlockInterop.isInDependencySet, (_id.chainId)),
returnData: abi.encode(true)
});
// Ensure that the contract has enough balance to send with value
vm.deal(address(this), _value);
// Look for the call to the target contract
vm.expectCall({ callee: _target, msgValue: _value, data: _message });
// Expect a revert with the TargetCallFailed selector
vm.expectRevert(TargetCallFailed.selector);
// Call the executeMessage function
crossL2Inbox.executeMessage{ value: _value }({ _id: _id, _target: _target, _message: _message });
}
function testFuzz_validateMessage_succeeds(Identifier memory _id, bytes32 _messageHash) external setInteropStart {
// Ensure that the id's timestamp is valid (less than or equal to the current block timestamp and greater than
// interop start time)
......@@ -487,92 +174,6 @@ contract CrossL2InboxTest is Test {
// Expect a revert with the NoExecutingDeposits selector
vm.expectRevert(NoExecutingDeposits.selector);
// Call the executeMessage function
crossL2Inbox.validateMessage(_id, _messageHash);
}
/// @dev Tests that the `validateMessage` function reverts when called with an identifier with a timestamp later
/// than current block.timestamp.
function testFuzz_validateMessage_invalidTimestamp_reverts(
Identifier memory _id,
bytes32 _messageHash
)
external
setInteropStart
{
// Ensure is not a deposit transaction
vm.mockCall({
callee: Predeploys.L1_BLOCK_ATTRIBUTES,
data: abi.encodeCall(IL1BlockInterop.isDeposit, ()),
returnData: abi.encode(false)
});
// Ensure that the id's timestamp is invalid (greater than the current block timestamp)
_id.timestamp = bound(_id.timestamp, block.timestamp + 1, type(uint256).max);
// Expect a revert with the InvalidTimestamp selector
vm.expectRevert(InvalidTimestamp.selector);
// Call the validateMessage function
crossL2Inbox.validateMessage(_id, _messageHash);
}
/// @dev Tests that the `validateMessage` function reverts when called with an identifier with a timestamp earlier
/// than INTEROP_START timestamp
function testFuzz_validateMessage_invalidTimestampInteropStart_reverts(
Identifier memory _id,
bytes32 _messageHash
)
external
setInteropStart
{
// Ensure that the id's timestamp is invalid (less than or equal to interopStartTime)
_id.timestamp = bound(_id.timestamp, 0, crossL2Inbox.interopStart());
// Ensure is not a deposit transaction
vm.mockCall({
callee: Predeploys.L1_BLOCK_ATTRIBUTES,
data: abi.encodeCall(IL1BlockInterop.isDeposit, ()),
returnData: abi.encode(false)
});
// Expect a revert with the InvalidTimestamp selector
vm.expectRevert(InvalidTimestamp.selector);
// Call the validateMessage function
crossL2Inbox.validateMessage(_id, _messageHash);
}
/// @dev Tests that the `validateMessage` function reverts when called with an identifier with a chain ID not in the
/// dependency set.
function testFuzz_validateMessage_invalidChainId_reverts(
Identifier memory _id,
bytes32 _messageHash
)
external
setInteropStart
{
// Ensure that the timestamp is valid (less than or equal to the current block timestamp and greater than
// interopStartTime)
_id.timestamp = bound(_id.timestamp, interopStartTime + 1, block.timestamp);
// Ensure that the chain ID is NOT in the dependency set.
vm.mockCall({
callee: Predeploys.L1_BLOCK_ATTRIBUTES,
data: abi.encodeCall(IL1BlockInterop.isInDependencySet, (_id.chainId)),
returnData: abi.encode(false)
});
// Ensure is not a deposit transaction
vm.mockCall({
callee: Predeploys.L1_BLOCK_ATTRIBUTES,
data: abi.encodeCall(IL1BlockInterop.isDeposit, ()),
returnData: abi.encode(false)
});
// Expect a revert with the InvalidChainId selector
vm.expectRevert(InvalidChainId.selector);
// Call the validateMessage function
crossL2Inbox.validateMessage(_id, _messageHash);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment