Commit 322bf55a authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

contracts-bedrock: L1Block interop (#10344)

* contracts-bedrock: L1Block interop

Ports the `L1Block` contract from the `feat/interop` branch to
develop using a pattern where we can extend the contracts.
This sort of pattern may not always work but is an experiment
in reducing feature branches.

* contracts-bedrock: reorder params for func in L1BlockInterop

* contracts-bedrock: add missing test for L1Block

* contracts-bedrock: refactor tests for L1BlockInterop

* contracts-bedrock: add L1BlockInterop to differential-testing.go

* contracts-bedrock: add test for testDiff_encodeSetL1BlockValuesInterop_succeeds in Encoding tests

* op-node: add L1BlockInterop to derive l1_block_info

* op-node: add FuzzL1InfoInteropRoundTrip

* op-node: add tests for L1Block to l1_block_info

* contracts-bedrock: update snapshots for L1Block, L1BlockInterop

* contracts-bedrock: update semver-lock for L1Block, L1BlockInterop

* Revert "op-node: add tests for L1Block to l1_block_info"

This reverts commit d2e599e43b774cf9a5de474db1f5aa744885ce91.

* Revert "op-node: add FuzzL1InfoInteropRoundTrip"

This reverts commit e14007c0fb7dd723bcd66235696da19e378fa974.

* Revert "op-node: add L1BlockInterop to derive l1_block_info"

This reverts commit 4bb279bb4a504227ca05de38818bfbddbdae3c98.

* Revert "contracts-bedrock: add test for testDiff_encodeSetL1BlockValuesInterop_succeeds in Encoding tests"

This reverts commit 12f9a07cd71d504b1ea57a753d95b8e6439caa57.

* Revert "contracts-bedrock: add L1BlockInterop to differential-testing.go"

This reverts commit 209669de69d35b456494602cb64ffc435689602d.

* contracts-bedrock: drop redundant test in tests for L1BlockInterop

* contracts-bedrock: fix order of function args in L1Block

* contracts-bedrock: update semver-lock for L1Block

---------
Co-authored-by: default avatarDiego <105765223+0xfuturistic@users.noreply.github.com>
parent 3204cb08
...@@ -64,8 +64,12 @@ ...@@ -64,8 +64,12 @@
"sourceCodeHash": "0xde06becce9514f46ba78b4cb0732c7a714d49ba8f131258d56a5f5b22b51be7e" "sourceCodeHash": "0xde06becce9514f46ba78b4cb0732c7a714d49ba8f131258d56a5f5b22b51be7e"
}, },
"src/L2/L1Block.sol": { "src/L2/L1Block.sol": {
"initCodeHash": "0xda6828a2a6e02d9fde7d5d9947f51b207f31abf5dbb538dd968cd491164e2115", "initCodeHash": "0x42d17698899f06e6cf38823bea3dbaff32ba32ebcb2974f928f93d005a3ea91b",
"sourceCodeHash": "0x775c399d93a729e1d3fe9a67c015f529f0c17a5986f93cd8d0f7806414fc5cdc" "sourceCodeHash": "0x723fb55d63110783697aa8e9bba017c267b9e0a24639ec684d3147e47b68ae28"
},
"src/L2/L1BlockInterop.sol": {
"initCodeHash": "0xddac768887de4053c8e8b92bc9bc621c9bb31df90018be4308dd4e21b1b1085f",
"sourceCodeHash": "0xc93a12fbf00ace5f92051f4a57bb3584b5b773c33fd3c40be771c3b4fbf878e9"
}, },
"src/L2/L1FeeVault.sol": { "src/L2/L1FeeVault.sol": {
"initCodeHash": "0x2744d34573be83206d1b75d049d18a7bb37f9058e68c0803e5008c46b0dc2474", "initCodeHash": "0x2744d34573be83206d1b75d049d18a7bb37f9058e68c0803e5008c46b0dc2474",
......
...@@ -220,7 +220,7 @@ ...@@ -220,7 +220,7 @@
"type": "string" "type": "string"
} }
], ],
"stateMutability": "view", "stateMutability": "pure",
"type": "function" "type": "function"
} }
] ]
\ No newline at end of file
[
{
"inputs": [],
"name": "DEPOSITOR_ACCOUNT",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "baseFeeScalar",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "basefee",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "batcherHash",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "blobBaseFee",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "blobBaseFeeScalar",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "dependencySet",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "dependencySetSize",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "hash",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_chainId",
"type": "uint256"
}
],
"name": "isInDependencySet",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "l1FeeOverhead",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "l1FeeScalar",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "number",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "sequenceNumber",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "_number",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "_timestamp",
"type": "uint64"
},
{
"internalType": "uint256",
"name": "_basefee",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "_hash",
"type": "bytes32"
},
{
"internalType": "uint64",
"name": "_sequenceNumber",
"type": "uint64"
},
{
"internalType": "bytes32",
"name": "_batcherHash",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "_l1FeeOverhead",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_l1FeeScalar",
"type": "uint256"
}
],
"name": "setL1BlockValues",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "setL1BlockValuesEcotone",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "setL1BlockValuesInterop",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "timestamp",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "version",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "pure",
"type": "function"
}
]
\ No newline at end of file
[
{
"bytes": "8",
"label": "number",
"offset": 0,
"slot": "0",
"type": "uint64"
},
{
"bytes": "8",
"label": "timestamp",
"offset": 8,
"slot": "0",
"type": "uint64"
},
{
"bytes": "32",
"label": "basefee",
"offset": 0,
"slot": "1",
"type": "uint256"
},
{
"bytes": "32",
"label": "hash",
"offset": 0,
"slot": "2",
"type": "bytes32"
},
{
"bytes": "8",
"label": "sequenceNumber",
"offset": 0,
"slot": "3",
"type": "uint64"
},
{
"bytes": "4",
"label": "blobBaseFeeScalar",
"offset": 8,
"slot": "3",
"type": "uint32"
},
{
"bytes": "4",
"label": "baseFeeScalar",
"offset": 12,
"slot": "3",
"type": "uint32"
},
{
"bytes": "32",
"label": "batcherHash",
"offset": 0,
"slot": "4",
"type": "bytes32"
},
{
"bytes": "32",
"label": "l1FeeOverhead",
"offset": 0,
"slot": "5",
"type": "uint256"
},
{
"bytes": "32",
"label": "l1FeeScalar",
"offset": 0,
"slot": "6",
"type": "uint256"
},
{
"bytes": "32",
"label": "blobBaseFee",
"offset": 0,
"slot": "7",
"type": "uint256"
},
{
"bytes": "32",
"label": "dependencySet",
"offset": 0,
"slot": "8",
"type": "uint256[]"
}
]
\ No newline at end of file
...@@ -49,8 +49,10 @@ contract L1Block is ISemver { ...@@ -49,8 +49,10 @@ contract L1Block is ISemver {
/// @notice The latest L1 blob base fee. /// @notice The latest L1 blob base fee.
uint256 public blobBaseFee; uint256 public blobBaseFee;
/// @custom:semver 1.2.0 /// @custom:semver 1.3.0
string public constant version = "1.2.0"; function version() public pure virtual returns (string memory) {
return "1.3.0";
}
/// @custom:legacy /// @custom:legacy
/// @notice Updates the L1 block values. /// @notice Updates the L1 block values.
...@@ -105,7 +107,6 @@ contract L1Block is ISemver { ...@@ -105,7 +107,6 @@ contract L1Block is ISemver {
mstore(0x00, 0x3cc50b45) // 0x3cc50b45 is the 4-byte selector of "NotDepositor()" mstore(0x00, 0x3cc50b45) // 0x3cc50b45 is the 4-byte selector of "NotDepositor()"
revert(0x1C, 0x04) // returns the stored 4-byte selector from above revert(0x1C, 0x04) // returns the stored 4-byte selector from above
} }
let data := calldataload(4)
// sequencenum (uint64), blobBaseFeeScalar (uint32), baseFeeScalar (uint32) // sequencenum (uint64), blobBaseFeeScalar (uint32), baseFeeScalar (uint32)
sstore(sequenceNumber.slot, shr(128, calldataload(4))) sstore(sequenceNumber.slot, shr(128, calldataload(4)))
// number (uint64) and timestamp (uint64) // number (uint64) and timestamp (uint64)
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { L1Block } from "src/L2/L1Block.sol";
/// @notice Thrown when a non-depositor account attempts to set L1 block values.
error NotDepositor();
/// @notice Thrown when dependencySetSize does not match the length of the dependency set.
error DependencySetSizeMismatch();
/// @custom:proxied
/// @custom:predeploy 0x4200000000000000000000000000000000000015
/// @title L1BlockInterop
/// @notice Interop extenstions of L1Block.
contract L1BlockInterop is L1Block {
/// @notice The chain IDs of the interop dependency set.
uint256[] public dependencySet;
/// @custom:semver 1.3.0+interop
function version() public pure override returns (string memory) {
return string.concat(super.version(), "+interop");
}
/// @notice Updates the L1 block values for an Interop upgraded chain.
/// Params are packed and passed in as raw msg.data instead of ABI to reduce calldata size.
/// Params are expected to be in the following order:
/// 1. _baseFeeScalar L1 base fee scalar
/// 2. _blobBaseFeeScalar L1 blob base fee scalar
/// 3. _sequenceNumber Number of L2 blocks since epoch start.
/// 4. _timestamp L1 timestamp.
/// 5. _number L1 blocknumber.
/// 6. _basefee L1 base fee.
/// 7. _blobBaseFee L1 blob base fee.
/// 8. _hash L1 blockhash.
/// 9. _batcherHash Versioned hash to authenticate batcher by.
/// 10. _dependencySetSize Size of the interop dependency set.
/// 11. _dependencySet Array of chain IDs for the interop dependency set.
function setL1BlockValuesInterop() external {
assembly {
// Revert if the caller is not the depositor account.
if xor(caller(), DEPOSITOR_ACCOUNT) {
mstore(0x00, 0x3cc50b45) // 0x3cc50b45 is the 4-byte selector of "NotDepositor()"
revert(0x1C, 0x04) // returns the stored 4-byte selector from above
}
// sequencenum (uint64), blobBaseFeeScalar (uint32), baseFeeScalar (uint32)
sstore(sequenceNumber.slot, shr(128, calldataload(4)))
// number (uint64) and timestamp (uint64)
sstore(number.slot, shr(128, calldataload(20)))
sstore(basefee.slot, calldataload(36)) // uint256
sstore(blobBaseFee.slot, calldataload(68)) // uint256
sstore(hash.slot, calldataload(100)) // bytes32
sstore(batcherHash.slot, calldataload(132)) // bytes32
// Load dependencySetSize from calldata (at offset 164 after calldata for setL1BlockValuesEcotone ends)
let dependencySetSize_ := shr(248, calldataload(164))
// Revert if dependencySetSize_ doesn't match the length of dependencySet in calldata
if xor(add(165, mul(dependencySetSize_, 0x20)), calldatasize()) {
mstore(0x00, 0x44165b6a) // 0x44165b6a is the 4-byte selector of "DependencySetSizeMismatch()"
revert(0x1C, 0x04) // returns the stored 4-byte selector from above
}
// Use memory to hash and get the start index of dependencySet
mstore(0x00, dependencySet.slot)
let dependencySetStartIndex := keccak256(0x00, 0x20)
// Iterate over calldata dependencySet and write to store dependencySet
for { let i := 0 } lt(i, dependencySetSize_) { i := add(i, 1) } {
// Load value from calldata and write to storage (dependencySet) at index
let val := calldataload(add(165, mul(i, 0x20)))
sstore(add(dependencySetStartIndex, i), val)
}
// Update length of dependencySet array
sstore(dependencySet.slot, dependencySetSize_)
}
}
/// @notice Returns true if a chain ID is in the interop dependency set and false otherwise.
/// Every chain ID is in the interop dependency set of itself.
/// @param _chainId The chain ID to check.
/// @return True if the chain ID to check is in the interop dependency set. False otherwise.
function isInDependencySet(uint256 _chainId) public view returns (bool) {
// Every chain ID is in the interop dependency set of itself.
if (_chainId == block.chainid) {
return true;
}
uint256 length = dependencySet.length;
for (uint256 i = 0; i < length;) {
if (dependencySet[i] == _chainId) {
return true;
}
unchecked {
i++;
}
}
return false;
}
/// @notice Returns the size of the interop dependency set.
/// @return The size of the interop dependency set.
function dependencySetSize() external view returns (uint8) {
return uint8(dependencySet.length);
}
}
...@@ -173,4 +173,52 @@ library Encoding { ...@@ -173,4 +173,52 @@ library Encoding {
batcherHash batcherHash
); );
} }
/// @notice Returns an appropriately encoded call to L1Block.setL1BlockValuesInterop
/// @param _baseFeeScalar L1 base fee Scalar
/// @param _blobBaseFeeScalar L1 blob base fee Scalar
/// @param _sequenceNumber Number of L2 blocks since epoch start.
/// @param _timestamp L1 timestamp.
/// @param _number L1 blocknumber.
/// @param _baseFee L1 base fee.
/// @param _blobBaseFee L1 blob base fee.
/// @param _hash L1 blockhash.
/// @param _batcherHash Versioned hash to authenticate batcher by.
/// @param _dependencySet Array of the chain IDs in the interop dependency set.
function encodeSetL1BlockValuesInterop(
uint32 _baseFeeScalar,
uint32 _blobBaseFeeScalar,
uint64 _sequenceNumber,
uint64 _timestamp,
uint64 _number,
uint256 _baseFee,
uint256 _blobBaseFee,
bytes32 _hash,
bytes32 _batcherHash,
uint256[] memory _dependencySet
)
internal
pure
returns (bytes memory)
{
require(_dependencySet.length <= type(uint8).max, "Encoding: dependency set length is too large");
// Check that the batcher hash is just the address with 0 padding to the left for version 0.
require(uint160(uint256(_batcherHash)) == uint256(_batcherHash), "Encoding: invalid batcher hash");
bytes4 functionSignature = bytes4(keccak256("setL1BlockValuesInterop()"));
return abi.encodePacked(
functionSignature,
_baseFeeScalar,
_blobBaseFeeScalar,
_sequenceNumber,
_timestamp,
_number,
_baseFee,
_blobBaseFee,
_hash,
_batcherHash,
uint8(_dependencySet.length),
_dependencySet
);
}
} }
...@@ -60,6 +60,21 @@ contract L1BlockBedrock_Test is L1BlockTest { ...@@ -60,6 +60,21 @@ contract L1BlockBedrock_Test is L1BlockTest {
_l1FeeScalar: type(uint256).max _l1FeeScalar: type(uint256).max
}); });
} }
/// @dev Tests that `setL1BlockValues` reverts if sender address is not the depositor
function test_updatesValues_notDepositor_reverts() external {
vm.expectRevert("L1Block: only the depositor account can set L1 block values");
l1Block.setL1BlockValues({
_number: type(uint64).max,
_timestamp: type(uint64).max,
_basefee: type(uint256).max,
_hash: keccak256(abi.encode(1)),
_sequenceNumber: type(uint64).max,
_batcherHash: bytes32(type(uint256).max),
_l1FeeOverhead: type(uint256).max,
_l1FeeScalar: type(uint256).max
});
}
} }
contract L1BlockEcotone_Test is L1BlockTest { contract L1BlockEcotone_Test is L1BlockTest {
...@@ -127,8 +142,8 @@ contract L1BlockEcotone_Test is L1BlockTest { ...@@ -127,8 +142,8 @@ contract L1BlockEcotone_Test is L1BlockTest {
assertTrue(success, "function call failed"); assertTrue(success, "function call failed");
} }
/// @dev Tests that `setL1BlockValuesEcotone` fails if sender address is not the depositor /// @dev Tests that `setL1BlockValuesEcotone` reverts if sender address is not the depositor
function test_setL1BlockValuesEcotone_notDepositor_fails() external { function test_setL1BlockValuesEcotone_notDepositor_reverts() external {
bytes memory functionCallDataPacked = Encoding.encodeSetL1BlockValuesEcotone( bytes memory functionCallDataPacked = Encoding.encodeSetL1BlockValuesEcotone(
type(uint32).max, type(uint32).max,
type(uint32).max, type(uint32).max,
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol";
import { Encoding } from "src/libraries/Encoding.sol";
import { L1BlockInterop, DependencySetSizeMismatch, NotDepositor } from "src/L2/L1BlockInterop.sol";
contract L1BlockInteropTest is Test {
L1BlockInterop l1Block;
address depositor;
function setUp() public {
l1Block = new L1BlockInterop();
depositor = l1Block.DEPOSITOR_ACCOUNT();
}
/// @dev Tests that setL1BlockValuesInterop updates the values appropriately.
function testFuzz_setL1BlockValuesInterop_succeeds(
uint32 _baseFeeScalar,
uint32 _blobBaseFeeScalar,
uint64 _sequenceNumber,
uint64 _timestamp,
uint64 _number,
uint256 _baseFee,
uint256 _blobBaseFee,
bytes32 _hash,
bytes32 _batcherHash,
uint256[] calldata _dependencySet
)
external
{
vm.assume(_dependencySet.length <= type(uint8).max);
vm.assume(uint160(uint256(_batcherHash)) == uint256(_batcherHash));
bytes memory functionCallDataPacked = Encoding.encodeSetL1BlockValuesInterop({
_baseFeeScalar: _baseFeeScalar,
_blobBaseFeeScalar: _blobBaseFeeScalar,
_sequenceNumber: _sequenceNumber,
_timestamp: _timestamp,
_number: _number,
_baseFee: _baseFee,
_blobBaseFee: _blobBaseFee,
_hash: _hash,
_batcherHash: _batcherHash,
_dependencySet: _dependencySet
});
vm.prank(depositor);
(bool success,) = address(l1Block).call(functionCallDataPacked);
assertTrue(success, "Function call failed");
assertEq(l1Block.baseFeeScalar(), _baseFeeScalar);
assertEq(l1Block.blobBaseFeeScalar(), _blobBaseFeeScalar);
assertEq(l1Block.sequenceNumber(), _sequenceNumber);
assertEq(l1Block.timestamp(), _timestamp);
assertEq(l1Block.number(), _number);
assertEq(l1Block.basefee(), _baseFee);
assertEq(l1Block.blobBaseFee(), _blobBaseFee);
assertEq(l1Block.hash(), _hash);
assertEq(l1Block.batcherHash(), _batcherHash);
assertEq(l1Block.dependencySetSize(), _dependencySet.length);
for (uint256 i = 0; i < _dependencySet.length; i++) {
assertEq(l1Block.dependencySet(i), _dependencySet[i]);
assertTrue(l1Block.isInDependencySet(_dependencySet[i]));
}
// ensure we didn't accidentally pollute the 128 bits of the sequencenum+scalars slot that
// should be empty
bytes32 scalarsSlot = vm.load(address(l1Block), bytes32(uint256(3)));
bytes32 mask128 = hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000";
assertEq(0, scalarsSlot & mask128);
// ensure we didn't accidentally pollute the 128 bits of the number & timestamp slot that
// should be empty
bytes32 numberTimestampSlot = vm.load(address(l1Block), bytes32(uint256(0)));
assertEq(0, numberTimestampSlot & mask128);
}
/// @dev Tests that `setL1BlockValuesInterop` succeeds if sender address is the depositor
function test_setL1BlockValuesInterop_isDepositor_succeeds() external {
bytes memory functionCallDataPacked = Encoding.encodeSetL1BlockValuesInterop({
_baseFeeScalar: type(uint32).max,
_blobBaseFeeScalar: type(uint32).max,
_sequenceNumber: type(uint64).max,
_timestamp: type(uint64).max,
_number: type(uint64).max,
_baseFee: type(uint256).max,
_blobBaseFee: type(uint256).max,
_hash: bytes32(type(uint256).max),
_batcherHash: bytes32(0),
_dependencySet: new uint256[](0)
});
vm.prank(depositor);
(bool success,) = address(l1Block).call(functionCallDataPacked);
assertTrue(success, "function call failed");
}
/// @dev Tests that `setL1BlockValuesInterop` reverts if sender address is not the depositor
function test_setL1BlockValuesInterop_isDepositor_reverts() external {
bytes memory functionCallDataPacked = Encoding.encodeSetL1BlockValuesInterop({
_baseFeeScalar: type(uint32).max,
_blobBaseFeeScalar: type(uint32).max,
_sequenceNumber: type(uint64).max,
_timestamp: type(uint64).max,
_number: type(uint64).max,
_baseFee: type(uint256).max,
_blobBaseFee: type(uint256).max,
_hash: bytes32(type(uint256).max),
_batcherHash: bytes32(0),
_dependencySet: new uint256[](0)
});
(bool success, bytes memory data) = address(l1Block).call(functionCallDataPacked);
assertTrue(!success, "function call should have failed");
// make sure return value is the expected function selector for "NotDepositor()"
assertEq(bytes4(data), NotDepositor.selector);
}
/// @dev Tests that `setL1BlockValuesInterop` reverts if _dependencySetSize is not the same as
/// the length of _dependencySet. (bad path)
function testFuzz_setL1BlockValuesInterop_dependencySetSizeMatch_reverts(
uint8 _notDependencySetSize,
uint256[] calldata _dependencySet
)
external
{
vm.assume(_dependencySet.length <= type(uint8).max);
vm.assume(_notDependencySetSize != _dependencySet.length);
bytes memory functionCallDataPacked = abi.encodePacked(
bytes4(keccak256("setL1BlockValuesInterop()")),
type(uint32).max,
type(uint32).max,
type(uint64).max,
type(uint64).max,
type(uint64).max,
type(uint256).max,
type(uint256).max,
bytes32(type(uint256).max),
bytes32(type(uint256).max),
_notDependencySetSize,
_dependencySet
);
vm.prank(depositor);
(bool success, bytes memory data) = address(l1Block).call(functionCallDataPacked);
assertTrue(!success, "function call should have failed");
// make sure return value is the expected function selector for "DependencySetSizeMismatch()"
assertEq(bytes4(data), DependencySetSizeMismatch.selector);
}
/// @dev Tests that an arbitrary dependency set can be set and that ìsInDependencySet returns
/// the expected results.
function testFuzz_isInDependencySet_succeeds(
uint32 _baseFeeScalar,
uint32 _blobBaseFeeScalar,
uint64 _sequenceNumber,
uint64 _timestamp,
uint64 _number,
uint256 _baseFee,
uint256 _blobBaseFee,
bytes32 _hash,
bytes32 _batcherHash,
uint256[] calldata _dependencySet
)
external
{
vm.assume(_dependencySet.length <= type(uint8).max);
vm.assume(uint160(uint256(_batcherHash)) == uint256(_batcherHash));
bytes memory functionCallDataPacked = Encoding.encodeSetL1BlockValuesInterop({
_baseFeeScalar: _baseFeeScalar,
_blobBaseFeeScalar: _blobBaseFeeScalar,
_sequenceNumber: _sequenceNumber,
_timestamp: _timestamp,
_number: _number,
_baseFee: _baseFee,
_blobBaseFee: _blobBaseFee,
_hash: _hash,
_batcherHash: _batcherHash,
_dependencySet: _dependencySet
});
vm.prank(depositor);
(bool success,) = address(l1Block).call(functionCallDataPacked);
assertTrue(success, "Function call failed");
assertEq(l1Block.dependencySetSize(), _dependencySet.length);
for (uint256 i = 0; i < _dependencySet.length; i++) {
assertTrue(l1Block.isInDependencySet(_dependencySet[i]));
}
}
/// @dev Tests that `isInDependencySet` returns true when the current chain ID is passed as the input
function test_isInDependencySet_isChainId_succeeds() external view {
assertTrue(l1Block.isInDependencySet(block.chainid));
}
/// @dev Tests that `isInDependencySet` reverts when the input chain ID is not in the dependency set
function testFuzz_isInDependencySet_reverts(uint256 _chainId) external {
vm.assume(_chainId != 1);
uint256[] memory dependencySet = new uint256[](1);
dependencySet[0] = 1;
bytes memory functionCallDataPacked = Encoding.encodeSetL1BlockValuesInterop({
_baseFeeScalar: 0,
_blobBaseFeeScalar: 0,
_sequenceNumber: 0,
_timestamp: 0,
_number: 0,
_baseFee: 0,
_blobBaseFee: 0,
_hash: bytes32(0),
_batcherHash: bytes32(0),
_dependencySet: dependencySet
});
vm.prank(depositor);
(bool success,) = address(l1Block).call(functionCallDataPacked);
assertTrue(success, "Function call failed");
assertFalse(l1Block.isInDependencySet(_chainId));
}
/// @dev Tests that `isInDependencySet` returns false when the dependency set is empty
function testFuzz_isInDependencySet_dependencySetEmpty_succeeds(uint256 _chainId) external view {
assertTrue(l1Block.dependencySetSize() == 0);
assertFalse(l1Block.isInDependencySet(_chainId));
}
}
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