Commit be4cb583 authored by clabby's avatar clabby

Add invariant test for `minGasLimit`s in the L1 XDM's `relayMessage` fn

parent 0f347ab0
pragma solidity 0.8.15;
import { InvariantTest } from "forge-std/InvariantTest.sol";
import { Test } from "forge-std/Test.sol";
import { Messenger_Initializer } from "../CommonTest.t.sol";
import { Types } from "../../libraries/Types.sol";
import { Predeploys } from "../../libraries/Predeploys.sol";
import { Encoding } from "../../libraries/Encoding.sol";
import { Hashing } from "../../libraries/Hashing.sol";
import { OptimismPortal } from "../../L1/OptimismPortal.sol";
import { L1CrossDomainMessenger } from "../../L1/L1CrossDomainMessenger.sol";
contract RelayActor is Test {
// Storage slot of the l2Sender
uint256 constant senderSlotIndex = 50;
uint256 public numHashes;
bytes32[] public hashes;
bool public outOfGas = false;
OptimismPortal op;
L1CrossDomainMessenger xdm;
constructor(OptimismPortal _op, L1CrossDomainMessenger _xdm) {
op = _op;
xdm = _xdm;
}
/**
* Relays a message to the `L1CrossDomainMessenger` with a random `version`, `_minGasLimit`
* and `_message`.
*/
function relay(
uint16 _version,
uint32 _minGasLimit,
bytes memory _message
) external {
address target = address(0x04); // ID precompile
address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER;
// set the value of op.l2Sender() to be the L2 Cross Domain Messenger.
vm.store(address(op), bytes32(senderSlotIndex), bytes32(abi.encode(sender)));
// Restrict `_minGasLimit` to a number in the range of the block gas limit.
_minGasLimit = uint32(bound(_minGasLimit, 0, block.gaslimit));
// Restrict version to the range of [0, 1]
_version = _version % 2;
// Compute the cross domain message hash and store it in `hashes`.
// The `relayMessage` function will always encode the message as a version 1
// message after checking that the V0 hash has not already been relayed.
bytes32 _hash = Hashing.hashCrossDomainMessageV1(
Encoding.encodeVersionedNonce(0, _version),
sender,
target,
0, // value
_minGasLimit,
_message
);
// Act as the optimism portal and call `relayMessage` on the `L1CrossDomainMessenger` with
// the outer min gas limit.
vm.startPrank(address(op));
vm.expectCall(target, _message);
try
xdm.relayMessage{ gas: xdm.baseGas(_message, _minGasLimit) }(
Encoding.encodeVersionedNonce(0, _version),
sender,
target,
0, // value
_minGasLimit,
_message
)
{} catch {
// If any of these calls revert, set `outOfGas` to true to fail the invariant test.
// NOTE: This is to get around forge's invariant fuzzer ignoring reverted calls
// to this function.
outOfGas = true;
}
vm.stopPrank();
hashes.push(_hash);
numHashes += 1;
}
}
contract XDM_MinGasLimits is Messenger_Initializer, InvariantTest {
RelayActor actor;
function setUp() public override {
// Set up the `L1CrossDomainMessenger` and `OptimismPortal` contracts.
super.setUp();
// Deploy a relay actor
actor = new RelayActor(op, L1Messenger);
// Target the `RelayActor` contract
targetContract(address(actor));
// Target the actor's `relay` function
bytes4[] memory selectors = new bytes4[](1);
selectors[0] = actor.relay.selector;
targetSelector(FuzzSelector({ addr: address(actor), selectors: selectors }));
}
/**
* @custom:invariant A call to `relayMessage` should never revert if at least the proper minimum
* gas limits are supplied.
*
* There are two minimum gas limits here:
* - The outer min gas limit is for the call from the `OptimismPortal` to the
* `L1CrossDomainMessenger`, and it can be retrieved by calling the xdm's `baseGas` function
* with the `message` and inner limit.
*
* - The inner min gas limit is for the call from the `L1CrossDomainMessenger` to the target
* contract.
*/
function invariant_minGasLimits() public {
uint256 length = actor.numHashes();
for (uint256 i = 0; i < length; ++i) {
bytes32 hash = actor.hashes(i);
// the message hash is in the successfulMessages mapping
assertTrue(L1Messenger.successfulMessages(hash));
// it is not in the received messages mapping
assertFalse(L1Messenger.failedMessages(hash));
}
assertTrue(!actor.outOfGas());
}
}
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