diff --git a/mise.toml b/mise.toml index 97f3610d1365a..11901cab175d3 100644 --- a/mise.toml +++ b/mise.toml @@ -29,9 +29,9 @@ just = "1.37.0" # Foundry is a special case because it supplies multiple binaries at the same # GitHub release, so we need to use the aliasing trick to get mise to not error # The git ref here should be on the `stable` branch. -forge = "nightly-5d16800a64e5357fbb2493e4cae061756d145981" -cast = "nightly-5d16800a64e5357fbb2493e4cae061756d145981" -anvil = "nightly-5d16800a64e5357fbb2493e4cae061756d145981" +forge = "v1.0.0" +cast = "v1.0.0" +anvil = "v1.0.0" # Other dependencies codecov-uploader = "0.8.0" diff --git a/packages/contracts-bedrock/test/libraries/Bytes.t.sol b/packages/contracts-bedrock/test/libraries/Bytes.t.sol index 57c5950058ddf..9c1d08974171e 100644 --- a/packages/contracts-bedrock/test/libraries/Bytes.t.sol +++ b/packages/contracts-bedrock/test/libraries/Bytes.t.sol @@ -7,7 +7,15 @@ import { Test } from "forge-std/Test.sol"; // Target contract import { Bytes } from "src/libraries/Bytes.sol"; +contract Bytes_Harness { + function exposed_slice(bytes memory _input, uint256 _start, uint256 _length) public pure returns (bytes memory) { + return Bytes.slice(_input, _start, _length); + } +} + contract Bytes_slice_Test is Test { + Bytes_Harness harness; + /// @notice Tests that the `slice` function works as expected when starting from index 0. function test_slice_fromZeroIdx_works() public pure { bytes memory input = hex"11223344556677889900"; @@ -124,6 +132,12 @@ contract Bytes_slice_Test is Test { } contract Bytes_slice_TestFail is Test { + Bytes_Harness harness; + + function setUp() public { + harness = new Bytes_Harness(); + } + /// @notice Tests that, when given an input bytes array of length `n`, the `slice` function will /// always revert if `_start + _length > n`. function testFuzz_slice_outOfBounds_reverts(bytes memory _input, uint256 _start, uint256 _length) public { @@ -142,7 +156,7 @@ contract Bytes_slice_TestFail is Test { } vm.expectRevert("slice_outOfBounds"); - Bytes.slice(_input, _start, _length); + harness.exposed_slice(_input, _start, _length); } /// @notice Tests that, when given a length `n` that is greater than `type(uint256).max - 31`, @@ -152,7 +166,7 @@ contract Bytes_slice_TestFail is Test { _length = uint256(bound(_length, type(uint256).max - 30, type(uint256).max)); vm.expectRevert("slice_overflow"); - Bytes.slice(_input, _start, _length); + harness.exposed_slice(_input, _start, _length); } /// @notice Tests that, when given a start index `n` that is greater than @@ -169,7 +183,7 @@ contract Bytes_slice_TestFail is Test { vm.assume(_start > type(uint256).max - _length); vm.expectRevert("slice_overflow"); - Bytes.slice(_input, _start, _length); + harness.exposed_slice(_input, _start, _length); } } diff --git a/packages/contracts-bedrock/test/libraries/GasPayingToken.t.sol b/packages/contracts-bedrock/test/libraries/GasPayingToken.t.sol index b2b87eeee41a6..0276fdf8a2611 100644 --- a/packages/contracts-bedrock/test/libraries/GasPayingToken.t.sol +++ b/packages/contracts-bedrock/test/libraries/GasPayingToken.t.sol @@ -7,9 +7,21 @@ import { Constants } from "src/libraries/Constants.sol"; import { Test } from "forge-std/Test.sol"; import { LibString } from "@solady/utils/LibString.sol"; +contract GasPayingToken_Harness { + function exposed_sanitize(string memory _str) public pure returns (bytes32) { + return GasPayingToken.sanitize(_str); + } +} + /// @title GasPayingToken_Roundtrip_Test /// @notice Tests the roundtrip of setting and getting the gas paying token. contract GasPayingToken_Roundtrip_Test is Test { + GasPayingToken_Harness harness; + + function setUp() public { + harness = new GasPayingToken_Harness(); + } + /// @dev Test that the gas paying token correctly sets values in storage. function testFuzz_set_succeeds(address _token, uint8 _decimals, bytes32 _name, bytes32 _symbol) external { GasPayingToken.set(_token, _decimals, _name, _symbol); @@ -104,7 +116,7 @@ contract GasPayingToken_Roundtrip_Test is Test { vm.expectRevert("GasPayingToken: string cannot be greater than 32 bytes"); - GasPayingToken.sanitize(_str); + harness.exposed_sanitize(_str); } /// @dev Test that `sanitize` works as expected when the input string is empty. diff --git a/packages/contracts-bedrock/test/libraries/rlp/RLPReader.t.sol b/packages/contracts-bedrock/test/libraries/rlp/RLPReader.t.sol index f4fe712dc3026..c3570d07f00ab 100644 --- a/packages/contracts-bedrock/test/libraries/rlp/RLPReader.t.sol +++ b/packages/contracts-bedrock/test/libraries/rlp/RLPReader.t.sol @@ -6,6 +6,7 @@ import { Test } from "forge-std/Test.sol"; import { RLPReader } from "src/libraries/rlp/RLPReader.sol"; import "src/libraries/rlp/RLPErrors.sol"; +/// @notice Here we allow internal reverts as readRawBytes uses memory allocations and can only be tested internally contract RLPReader_readBytes_Test is Test { function test_readBytes_bytestring00_succeeds() external pure { assertEq(RLPReader.readBytes(hex"00"), hex"00"); @@ -19,26 +20,31 @@ contract RLPReader_readBytes_Test is Test { assertEq(RLPReader.readBytes(hex"7f"), hex"7f"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readBytes_revertListItem_reverts() external { vm.expectRevert(UnexpectedList.selector); RLPReader.readBytes(hex"c7c0c1c0c3c0c1c0"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readBytes_invalidStringLength_reverts() external { vm.expectRevert(ContentLengthMismatch.selector); RLPReader.readBytes(hex"b9"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readBytes_invalidListLength_reverts() external { vm.expectRevert(ContentLengthMismatch.selector); RLPReader.readBytes(hex"ff"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readBytes_invalidRemainder_reverts() external { vm.expectRevert(InvalidDataRemainder.selector); RLPReader.readBytes(hex"800a"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readBytes_invalidPrefix_reverts() external { vm.expectRevert(InvalidHeader.selector); RLPReader.readBytes(hex"810a"); @@ -102,6 +108,7 @@ contract RLPReader_readList_Test is Test { } } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_listLongerThan32Elements_reverts() external { vm.expectRevert(stdError.indexOOBError); RLPReader.readList(hex"e1454545454545454545454545454545454545454545454545454545454545454545"); @@ -135,36 +142,43 @@ contract RLPReader_readList_Test is Test { assertEq(RLPReader.readRawBytes(list[3]), hex"ca846b6579348476616c34"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_invalidShortList_reverts() external { vm.expectRevert(ContentLengthMismatch.selector); RLPReader.readList(hex"efdebd"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_longStringLength_reverts() external { vm.expectRevert(ContentLengthMismatch.selector); RLPReader.readList(hex"efb83600"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_notLongEnough_reverts() external { vm.expectRevert(ContentLengthMismatch.selector); RLPReader.readList(hex"efdebdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_int32Overflow_reverts() external { vm.expectRevert(ContentLengthMismatch.selector); RLPReader.readList(hex"bf0f000000000000021111"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_int32Overflow2_reverts() external { vm.expectRevert(ContentLengthMismatch.selector); RLPReader.readList(hex"ff0f000000000000021111"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_incorrectLengthInArray_reverts() external { vm.expectRevert(InvalidHeader.selector); RLPReader.readList(hex"b9002100dc2b275d0f74e8a53e6f4ec61b27f24278820be3f82ea2110e582081b0565df0"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_leadingZerosInLongLengthArray1_reverts() external { vm.expectRevert(InvalidHeader.selector); RLPReader.readList( @@ -172,11 +186,13 @@ contract RLPReader_readList_Test is Test { ); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_leadingZerosInLongLengthArray2_reverts() external { vm.expectRevert(InvalidHeader.selector); RLPReader.readList(hex"b800"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_leadingZerosInLongLengthList1_reverts() external { vm.expectRevert(InvalidHeader.selector); RLPReader.readList( @@ -184,51 +200,61 @@ contract RLPReader_readList_Test is Test { ); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_nonOptimalLongLengthArray1_reverts() external { vm.expectRevert(InvalidHeader.selector); RLPReader.readList(hex"b81000112233445566778899aabbccddeeff"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_nonOptimalLongLengthArray2_reverts() external { vm.expectRevert(InvalidHeader.selector); RLPReader.readList(hex"b801ff"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_invalidValue_reverts() external { vm.expectRevert(ContentLengthMismatch.selector); RLPReader.readList(hex"91"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_invalidRemainder_reverts() external { vm.expectRevert(InvalidDataRemainder.selector); RLPReader.readList(hex"c000"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_notEnoughContentForString1_reverts() external { vm.expectRevert(ContentLengthMismatch.selector); RLPReader.readList(hex"ba010000aabbccddeeff"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_notEnoughContentForString2_reverts() external { vm.expectRevert(ContentLengthMismatch.selector); RLPReader.readList(hex"b840ffeeddccbbaa99887766554433221100"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_notEnoughContentForList1_reverts() external { vm.expectRevert(ContentLengthMismatch.selector); RLPReader.readList(hex"f90180"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_notEnoughContentForList2_reverts() external { vm.expectRevert(ContentLengthMismatch.selector); RLPReader.readList(hex"ffffffffffffffffff0001020304050607"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_longStringLessThan56Bytes_reverts() external { vm.expectRevert(InvalidHeader.selector); RLPReader.readList(hex"b80100"); } + /// forge-config: default.allow_internal_expect_revert = true function test_readList_longListLessThan56Bytes_reverts() external { vm.expectRevert(InvalidHeader.selector); RLPReader.readList(hex"f80100"); diff --git a/packages/contracts-bedrock/test/libraries/trie/MerkleTrie.t.sol b/packages/contracts-bedrock/test/libraries/trie/MerkleTrie.t.sol index e6d04d971db57..a608015294aa0 100644 --- a/packages/contracts-bedrock/test/libraries/trie/MerkleTrie.t.sol +++ b/packages/contracts-bedrock/test/libraries/trie/MerkleTrie.t.sol @@ -7,12 +7,20 @@ import { RLPReader } from "src/libraries/rlp/RLPReader.sol"; import { FFIInterface } from "test/setup/FFIInterface.sol"; import "src/libraries/rlp/RLPErrors.sol"; +contract MerkleTrie_Harness { + function exposed_get(bytes memory _key, bytes[] memory _proof, bytes32 _root) public pure returns (bytes memory) { + return MerkleTrie.get(_key, _proof, _root); + } +} + contract MerkleTrie_get_Test is Test { FFIInterface constant ffi = FFIInterface(address(uint160(uint256(keccak256(abi.encode("optimism.ffi")))))); + MerkleTrie_Harness harness; function setUp() public { vm.etch(address(ffi), vm.getDeployedCode("FFIInterface.sol:FFIInterface")); vm.label(address(ffi), "FFIInterface"); + harness = new MerkleTrie_Harness(); } function test_get_validProof1_succeeds() external pure { @@ -150,7 +158,7 @@ contract MerkleTrie_get_Test is Test { proof[2] = hex"ca83206262856176616c32"; vm.expectRevert("MerkleTrie: path remainder must share all nibbles with key"); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } function test_get_nonexistentKey2_reverts() external { @@ -160,7 +168,7 @@ contract MerkleTrie_get_Test is Test { proof[0] = hex"e68416b65793a03101b4447781f1e6c51ce76c709274fc80bd064f3a58ff981b6015348a826386"; vm.expectRevert("MerkleTrie: path remainder must share all nibbles with key"); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } function test_get_wrongKeyProof_reverts() external { @@ -173,7 +181,7 @@ contract MerkleTrie_get_Test is Test { proof[2] = hex"d687206e6f746865728d33343938683472697568677765"; vm.expectRevert("MerkleTrie: invalid internal node hash"); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } function test_get_corruptedProof_reverts() external { @@ -189,7 +197,7 @@ contract MerkleTrie_get_Test is Test { proof[4] = hex"ca83206262856176616c32"; vm.expectRevert(UnexpectedString.selector); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } function test_get_invalidDataRemainder_reverts() external { @@ -201,7 +209,7 @@ contract MerkleTrie_get_Test is Test { proof[2] = hex"c32081aa000000000000000000000000000000"; vm.expectRevert(InvalidDataRemainder.selector); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } function test_get_invalidInternalNodeHash_reverts() external { @@ -214,7 +222,7 @@ contract MerkleTrie_get_Test is Test { proof[2] = hex"de2a9c6a46b6ea71ab9e881c8420570cf19e833c85df6026b04f085016e78f"; vm.expectRevert("MerkleTrie: invalid internal node hash"); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } function test_get_zeroBranchValueLength_reverts() external { @@ -225,7 +233,7 @@ contract MerkleTrie_get_Test is Test { proof[1] = hex"d98080808080808080808080c43b82aabbc43c82aacc80808080"; vm.expectRevert("MerkleTrie: value length must be greater than zero (branch)"); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } function test_get_zeroLengthKey_reverts() external { @@ -235,7 +243,7 @@ contract MerkleTrie_get_Test is Test { proof[0] = hex"c78320f00082b443"; vm.expectRevert("MerkleTrie: empty key"); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } function test_get_smallerPathThanKey1_reverts() external { @@ -247,7 +255,7 @@ contract MerkleTrie_get_Test is Test { proof[2] = hex"c582202381aa"; vm.expectRevert("MerkleTrie: path remainder must share all nibbles with key"); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } function test_get_smallerPathThanKey2_reverts() external { @@ -260,7 +268,7 @@ contract MerkleTrie_get_Test is Test { proof[2] = hex"e48200bba0a6911545ed01c2d3f4e15b8b27c7bfba97738bd5e6dd674dd07033428a4c53af"; vm.expectRevert("MerkleTrie: path remainder must share all nibbles with key"); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } function test_get_extraProofElements_reverts() external { @@ -273,7 +281,7 @@ contract MerkleTrie_get_Test is Test { proof[3] = hex"c32081aa"; vm.expectRevert("MerkleTrie: value node must be last node in proof (leaf)"); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } /// @notice The `bytes4` parameter is to enable parallel fuzz runs; it is ignored. @@ -292,7 +300,7 @@ contract MerkleTrie_get_Test is Test { bytes32 rootHash = keccak256(abi.encodePacked(root)); vm.expectRevert("MerkleTrie: invalid root hash"); - MerkleTrie.get(key, proof, rootHash); + harness.exposed_get(key, proof, rootHash); } /// @notice The `bytes4` parameter is to enable parallel fuzz runs; it is ignored. @@ -302,7 +310,7 @@ contract MerkleTrie_get_Test is Test { (bytes32 root, bytes memory key,, bytes[] memory proof) = ffi.getMerkleTrieFuzzCase("extra_proof_elems"); vm.expectRevert("MerkleTrie: value node must be last node in proof (leaf)"); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } /// @notice The `bytes4` parameter is to enable parallel fuzz runs; it is ignored. @@ -312,7 +320,7 @@ contract MerkleTrie_get_Test is Test { ffi.getMerkleTrieFuzzCase("invalid_large_internal_hash"); vm.expectRevert("MerkleTrie: invalid large internal hash"); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } /// @notice The `bytes4` parameter is to enable parallel fuzz runs; it is ignored. @@ -322,7 +330,7 @@ contract MerkleTrie_get_Test is Test { ffi.getMerkleTrieFuzzCase("invalid_internal_node_hash"); vm.expectRevert("MerkleTrie: invalid internal node hash"); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } /// @notice The `bytes4` parameter is to enable parallel fuzz runs; it is ignored. @@ -331,7 +339,7 @@ contract MerkleTrie_get_Test is Test { (bytes32 root, bytes memory key,, bytes[] memory proof) = ffi.getMerkleTrieFuzzCase("corrupted_proof"); vm.expectRevert(UnexpectedString.selector); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } /// @notice The `bytes4` parameter is to enable parallel fuzz runs; it is ignored. @@ -341,7 +349,7 @@ contract MerkleTrie_get_Test is Test { (bytes32 root, bytes memory key,, bytes[] memory proof) = ffi.getMerkleTrieFuzzCase("invalid_data_remainder"); vm.expectRevert(InvalidDataRemainder.selector); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } /// @notice The `bytes4` parameter is to enable parallel fuzz runs; it is ignored. @@ -353,7 +361,7 @@ contract MerkleTrie_get_Test is Test { // Ambiguous revert check- all that we care is that it *does* fail. This case may // fail within different branches. vm.expectRevert(); // nosemgrep: sol-safety-expectrevert-no-args - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } /// @notice The `bytes4` parameter is to enable parallel fuzz runs; it is ignored. @@ -362,7 +370,7 @@ contract MerkleTrie_get_Test is Test { (bytes32 root, bytes memory key,, bytes[] memory proof) = ffi.getMerkleTrieFuzzCase("empty_key"); vm.expectRevert("MerkleTrie: empty key"); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } /// @notice The `bytes4` parameter is to enable parallel fuzz runs; it is ignored. @@ -371,7 +379,7 @@ contract MerkleTrie_get_Test is Test { (bytes32 root, bytes memory key,, bytes[] memory proof) = ffi.getMerkleTrieFuzzCase("partial_proof"); vm.expectRevert("MerkleTrie: ran out of proof elements"); - MerkleTrie.get(key, proof, root); + harness.exposed_get(key, proof, root); } /// @notice Tests that `get` reverts if a proof node has an unknown prefix @@ -387,7 +395,7 @@ contract MerkleTrie_get_Test is Test { prefix = uint8(bound(prefix, 0x40, 0xff)); } - MerkleTrieWrapper wrapper = new MerkleTrieWrapper(); + MerkleTrie_Harness wrapper = new MerkleTrie_Harness(); bytes memory key = abi.encodePacked( keccak256(abi.encodePacked(bytes32(0xa15bc60c955c405d20d9149c709e2460f1c2d9a497496a7f46004d1772c3054c))) @@ -412,7 +420,7 @@ contract MerkleTrie_get_Test is Test { (proof[0], proof[1], proof[2], proof[3], root) = rehashOtherElements(proof[4]); vm.expectRevert("MerkleTrie: received a node with an unknown prefix"); - wrapper.get(key, proof, root); + wrapper.exposed_get(key, proof, root); } /// @notice Tests that `get` reverts if a proof node is unparsable i.e list length is not 2 or 17 @@ -422,7 +430,7 @@ contract MerkleTrie_get_Test is Test { listLen++; } - MerkleTrieWrapper wrapper = new MerkleTrieWrapper(); + MerkleTrie_Harness wrapper = new MerkleTrie_Harness(); bytes memory key = abi.encodePacked( keccak256(abi.encodePacked(bytes32(0xa15bc60c955c405d20d9149c709e2460f1c2d9a497496a7f46004d1772c3054c))) @@ -443,7 +451,7 @@ contract MerkleTrie_get_Test is Test { bytes32 root = keccak256(proof[0]); // Should not revert - wrapper.get(key, proof, root); + wrapper.exposed_get(key, proof, root); if (listLen > 3) { // Node with list > 3 @@ -457,7 +465,7 @@ contract MerkleTrie_get_Test is Test { (proof[0], proof[1], proof[2], proof[3], root) = rehashOtherElements(proof[4]); vm.expectRevert("MerkleTrie: received an unparseable node"); - wrapper.get(key, proof, root); + wrapper.exposed_get(key, proof, root); } else if (listLen == 1) { // Node with list of 1 proof[4] = hex"e09f204dcf44e265ba93879b2da89e1b16ab48fc5eb8e31bc16b0612d6da8463f1"; @@ -465,7 +473,7 @@ contract MerkleTrie_get_Test is Test { (proof[0], proof[1], proof[2], proof[3], root) = rehashOtherElements(proof[4]); vm.expectRevert("MerkleTrie: received an unparseable node"); - wrapper.get(key, proof, root); + wrapper.exposed_get(key, proof, root); } else if (listLen == 3) { // Node with list of 3 proof[4] = @@ -474,7 +482,7 @@ contract MerkleTrie_get_Test is Test { (proof[0], proof[1], proof[2], proof[3], root) = rehashOtherElements(proof[4]); vm.expectRevert("MerkleTrie: received an unparseable node"); - wrapper.get(key, proof, root); + wrapper.exposed_get(key, proof, root); } } @@ -507,9 +515,3 @@ contract MerkleTrie_get_Test is Test { root_ = keccak256(proof0_); } } - -contract MerkleTrieWrapper { - function get(bytes memory key, bytes[] memory proof, bytes32 root) external pure returns (bytes memory) { - return MerkleTrie.get(key, proof, root); - } -}