diff --git a/.gas-snapshot b/.gas-snapshot index 35ce343d44..333e32ccc3 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -732,25 +732,26 @@ LibPRNGTest:testPRNGShuffleGas() (gas: 1610927) LibPRNGTest:testPRNGUniform() (gas: 559430) LibPRNGTest:testStandardNormalWad() (gas: 4425913) LibPRNGTest:test__codesize() (gas: 14289) -LibRLPTest:testComputeAddressDifferential(address,uint256) (runs: 299, μ: 4184, ~: 3982) +LibRLPTest:testComputeAddressDifferential(address,uint256) (runs: 299, μ: 4191, ~: 3950) LibRLPTest:testComputeAddressForLargeNonces() (gas: 1760) LibRLPTest:testComputeAddressForSmallNonces() (gas: 1007) LibRLPTest:testComputeAddressOriginalForLargeNonces() (gas: 3766) -LibRLPTest:testComputeAddressOriginalForSmallNonces() (gas: 2207) -LibRLPTest:testRLPEncodeAddressDifferential(address) (runs: 299, μ: 341127, ~: 25910) -LibRLPTest:testRLPEncodeBool(bool) (runs: 299, μ: 27501, ~: 27507) +LibRLPTest:testComputeAddressOriginalForSmallNonces() (gas: 2185) +LibRLPTest:testRLPEncodeAddressDifferential(address) (runs: 299, μ: 395252, ~: 647525) +LibRLPTest:testRLPEncodeAddressViaList(address,address) (runs: 299, μ: 272884, ~: 27588) +LibRLPTest:testRLPEncodeBool(bool) (runs: 299, μ: 27570, ~: 27576) LibRLPTest:testRLPEncodeBytes() (gas: 382226) -LibRLPTest:testRLPEncodeBytesDifferential(bytes32) (runs: 299, μ: 459461, ~: 652902) -LibRLPTest:testRLPEncodeList() (gas: 746242) -LibRLPTest:testRLPEncodeList2() (gas: 822824) -LibRLPTest:testRLPEncodeListDifferential(bytes,uint256) (runs: 299, μ: 713819, ~: 665865) -LibRLPTest:testRLPEncodeUint() (gas: 1471535) -LibRLPTest:testRLPEncodeUint(uint256) (runs: 299, μ: 187389, ~: 25238) -LibRLPTest:testRLPEncodeUintDifferential(uint256) (runs: 299, μ: 405042, ~: 27345) -LibRLPTest:testRLPMemory(bytes32) (runs: 299, μ: 490840, ~: 653508) -LibRLPTest:testRLPPUint256() (gas: 365221) -LibRLPTest:testSmallLog256Equivalence(uint256) (runs: 299, μ: 23642, ~: 23689) -LibRLPTest:test__codesize() (gas: 14888) +LibRLPTest:testRLPEncodeBytesDifferential(bytes32) (runs: 299, μ: 410210, ~: 648521) +LibRLPTest:testRLPEncodeList() (gas: 742271) +LibRLPTest:testRLPEncodeList2() (gas: 818622) +LibRLPTest:testRLPEncodeListDifferential(bytes,uint256) (runs: 299, μ: 686538, ~: 661505) +LibRLPTest:testRLPEncodeUint() (gas: 1304532) +LibRLPTest:testRLPEncodeUint(uint256) (runs: 299, μ: 183869, ~: 25217) +LibRLPTest:testRLPEncodeUintDifferential(uint256) (runs: 299, μ: 427942, ~: 27489) +LibRLPTest:testRLPMemory(bytes32) (runs: 299, μ: 449222, ~: 648847) +LibRLPTest:testRLPPUint256() (gas: 364901) +LibRLPTest:testSmallLog256Equivalence(uint256) (runs: 299, μ: 23647, ~: 23689) +LibRLPTest:test__codesize() (gas: 14839) LibSortTest:testCopy(uint256) (runs: 299, μ: 138416, ~: 26968) LibSortTest:testInsertionSortAddressesDifferential(uint256) (runs: 299, μ: 73253, ~: 25190) LibSortTest:testInsertionSortInts() (gas: 112151) @@ -924,17 +925,17 @@ LibZipTest:testFlzCompressDecompress() (gas: 1250953) LibZipTest:testFlzCompressDecompress(bytes) (runs: 299, μ: 762658, ~: 671356) LibZipTest:testFlzCompressDecompress2() (gas: 760133) LibZipTest:test__codesize() (gas: 20369) -LifebuoyTest:testLifebuoyCreateDeployment(address,address,uint256) (runs: 299, μ: 4618186, ~: 4613846) -LifebuoyTest:testLifebuoyOwnedCloneRescuePermissions(bytes32) (runs: 299, μ: 941483, ~: 941344) -LifebuoyTest:testLifebuoyOwnedRescuePermissions(bytes32) (runs: 299, μ: 945539, ~: 938554) -LifebuoyTest:testLifebuoyRescuePermissions(bytes32) (runs: 299, μ: 928653, ~: 935789) +LifebuoyTest:testLifebuoyCreateDeployment(address,address,uint256) (runs: 299, μ: 3278409, ~: 4598970) +LifebuoyTest:testLifebuoyOwnedCloneRescuePermissions(bytes32) (runs: 299, μ: 941424, ~: 941319) +LifebuoyTest:testLifebuoyOwnedRescuePermissions(bytes32) (runs: 299, μ: 946934, ~: 938716) +LifebuoyTest:testLifebuoyRescuePermissions(bytes32) (runs: 299, μ: 929861, ~: 935934) LifebuoyTest:testLockEverything() (gas: 662008) LifebuoyTest:testLockRescue() (gas: 687529) LifebuoyTest:testLockRescueETH() (gas: 699031) -LifebuoyTest:testRescueERC20(uint256) (runs: 299, μ: 655263, ~: 657104) -LifebuoyTest:testRescueERC721(bytes32) (runs: 299, μ: 651562, ~: 651708) -LifebuoyTest:testRescueETH(uint256) (runs: 299, μ: 664144, ~: 664830) -LifebuoyTest:test__codesize() (gas: 31171) +LifebuoyTest:testRescueERC20(uint256) (runs: 299, μ: 655667, ~: 657326) +LifebuoyTest:testRescueERC721(bytes32) (runs: 299, μ: 651579, ~: 651790) +LifebuoyTest:testRescueETH(uint256) (runs: 299, μ: 664114, ~: 664835) +LifebuoyTest:test__codesize() (gas: 31001) MerkleProofLibTest:testEmptyCalldataHelpers() (gas: 985) MerkleProofLibTest:testVerifyMultiProof(bool,bool,bool,bool,bytes32) (runs: 299, μ: 747632, ~: 622800) MerkleProofLibTest:testVerifyMultiProofForHeightOneTree(bool,bool,bool,bool,bool,bool[]) (runs: 299, μ: 37580, ~: 37202) @@ -1243,7 +1244,7 @@ UpgradeableBeaconTest:testUpgradeableSolidityBeaconOnlyOwnerFunctions() (gas: 26 UpgradeableBeaconTest:testUpgradeableYulBeaconOnlyFnSelectorNotRecognised() (gas: 172796) UpgradeableBeaconTest:testUpgradeableYulBeaconOnlyOwnerFunctions() (gas: 198398) UpgradeableBeaconTest:test__codesize() (gas: 8808) -WETHInvariants:invariantTotalSupplyEqualsBalance() (runs: 10, calls: 150, reverts: 78) +WETHInvariants:invariantTotalSupplyEqualsBalance() (runs: 10, calls: 150, reverts: 77) WETHInvariants:test__codesize() (gas: 5178) WETHTest:testDeposit() (gas: 62272) WETHTest:testDeposit(uint256) (runs: 299, μ: 61545, ~: 62566) diff --git a/src/utils/LibRLP.sol b/src/utils/LibRLP.sol index d89d048996..3ef3c00732 100644 --- a/src/utils/LibRLP.sol +++ b/src/utils/LibRLP.sol @@ -94,6 +94,8 @@ library LibRLP { // - addresses are treated like byte strings of length 20, agnostic of leading zero bytes. // - uint256s are converted to byte strings, stripped of leading zero bytes, and encoded. // - bools are converted to uint256s (`b ? 1 : 0`), then encoded with the uint256. + // - For bytes1 to bytes32, you must manually convert them to bytes memory + // with `abi.encodePacked(x)` before encoding. /// @dev Returns a new empty list. function l() internal pure returns (List memory result) {} @@ -125,13 +127,10 @@ library LibRLP { /// @dev Appends `x` to `list`. Returns `list` for function chaining. function p(List memory list, uint256 x) internal pure returns (List memory result) { + result._data = x << 48; + _updateTail(list, result); /// @solidity memory-safe-assembly assembly { - mstore(result, shl(48, x)) - let v := or(shr(mload(list), result), mload(list)) - let tail := shr(40, v) - mstore(list, xor(shl(40, xor(tail, result)), v)) // Update the tail. - mstore(tail, or(mload(tail), result)) // Make the previous tail point to `result`. // If `x` is too big, we cannot pack it inline with the node. // We'll have to allocate a new slot for `x` and store the pointer to it in the node. if shr(208, x) { @@ -140,8 +139,8 @@ library LibRLP { mstore(0x40, add(m, 0x20)) mstore(result, shl(40, or(1, shl(8, m)))) } - result := list } + result = list; } /// @dev Appends `x` to `list`. Returns `list` for function chaining. @@ -149,12 +148,9 @@ library LibRLP { /// @solidity memory-safe-assembly assembly { mstore(result, shl(40, or(4, shl(8, x)))) - let v := or(shr(mload(list), result), mload(list)) - let tail := shr(40, v) - mstore(list, xor(shl(40, xor(tail, result)), v)) // Update the tail. - mstore(tail, or(mload(tail), result)) // Make the previous tail point to `result`. - result := list } + _updateTail(list, result); + result = list; } /// @dev Appends `x` to `list`. Returns `list` for function chaining. @@ -162,12 +158,9 @@ library LibRLP { /// @solidity memory-safe-assembly assembly { mstore(result, shl(48, iszero(iszero(x)))) - let v := or(shr(mload(list), result), mload(list)) - let tail := shr(40, v) - mstore(list, xor(shl(40, xor(tail, result)), v)) // Update the tail. - mstore(tail, or(mload(tail), result)) // Make the previous tail point to `result`. - result := list } + _updateTail(list, result); + result = list; } /// @dev Appends `x` to `list`. Returns `list` for function chaining. @@ -175,12 +168,9 @@ library LibRLP { /// @solidity memory-safe-assembly assembly { mstore(result, shl(40, or(2, shl(8, x)))) - let v := or(shr(mload(list), result), mload(list)) - let tail := shr(40, v) - mstore(list, xor(shl(40, xor(tail, result)), v)) // Update the tail. - mstore(tail, or(mload(tail), result)) // Make the previous tail point to `result`. - result := list } + _updateTail(list, result); + result = list; } /// @dev Appends `x` to `list`. Returns `list` for function chaining. @@ -188,12 +178,9 @@ library LibRLP { /// @solidity memory-safe-assembly assembly { mstore(result, shl(40, or(3, shl(8, x)))) - let v := or(shr(mload(list), result), mload(list)) - let tail := shr(40, v) - mstore(list, xor(shl(40, xor(tail, result)), v)) // Update the tail. - mstore(tail, or(mload(tail), result)) // Make the previous tail point to `result`. - result := list } + _updateTail(list, result); + result = list; } /// @dev Returns the RLP encoding of `list`. @@ -377,4 +364,19 @@ library LibRLP { } } } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PRIVATE HELPERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Updates the tail in `list`. + function _updateTail(List memory list, List memory result) private pure { + /// @solidity memory-safe-assembly + assembly { + let v := or(shr(mload(list), result), mload(list)) + let tail := shr(40, v) + mstore(list, xor(shl(40, xor(tail, result)), v)) // Update the tail. + mstore(tail, or(mload(tail), result)) // Make the previous tail point to `result`. + } + } } diff --git a/test/LibRLP.t.sol b/test/LibRLP.t.sol index 657b09979a..0a61e5e1de 100644 --- a/test/LibRLP.t.sol +++ b/test/LibRLP.t.sol @@ -246,6 +246,15 @@ contract LibRLPTest is SoladyTest { assertEq(LibRLP.encode(s), abi.encodePacked(hex"b9fffe", s)); } + function testRLPEncodeAddressViaList(address a0, address a1) public { + _maybeBzztMemory(); + bytes memory computed = LibRLP.l(_brutalized(a0)).p(_brutalized(a1)).encode(); + _checkMemory(computed); + _maybeBzztMemory(); + bytes memory expected = LibRLP.l(abi.encodePacked(a0)).p(abi.encodePacked(a1)).encode(); + assertEq(computed, expected); + } + function testRLPEncodeListDifferential(bytes memory x0, uint256 x1) public { _maybeBzztMemory(); LibRLP.List memory list = LibRLP.l(x0).p(x1).p(x1).p(x0); @@ -286,7 +295,7 @@ contract LibRLPTest is SoladyTest { function testRLPEncodeAddressDifferential(address x) public { _maybeBzztMemory(); - bytes memory computed = LibRLP.encode(x); + bytes memory computed = LibRLP.encode(_brutalized(x)); _checkAndMaybeBzztMemory(computed); bytes memory computed2 = _encode(x); _checkAndMaybeBzztMemory(computed2); diff --git a/test/Lifebuoy.t.sol b/test/Lifebuoy.t.sol index b9b8f59f7a..314fb55650 100644 --- a/test/Lifebuoy.t.sol +++ b/test/Lifebuoy.t.sol @@ -38,11 +38,16 @@ contract LifebuoyTest is SoladyTest { } function _deployViaCreate(address deployer, bytes memory initcode) internal returns (address) { - (bool success, bytes memory result) = deployer.call(type(MockERC721).creationCode); + (bool success, bytes memory result) = deployer.call(initcode); assertTrue(success); return abi.decode(result, (address)); } + function _testLifebuoyCreateDeployment(address deployer, bytes memory initcode) internal { + address expected = LibRLP.computeAddress(deployer, vm.getNonce(deployer)); + assertEq(_deployViaCreate(deployer, initcode), expected); + } + function testLifebuoyCreateDeployment(address deployer, address owner, uint256 r) public { while (deployer.code.length != 0 || uint160(deployer) < 0xffffffffff) { deployer = _randomNonZeroAddress(); @@ -51,23 +56,17 @@ contract LifebuoyTest is SoladyTest { for (uint256 i; i != 3; ++i) { r = r >> 32; if (r & 31 == 0) { - address expected = LibRLP.computeAddress(deployer, vm.getNonce(deployer)); - address deployed = _deployViaCreate(deployer, type(MockERC721).creationCode); - assertEq(deployed, expected); + _testLifebuoyCreateDeployment(deployer, type(MockERC721).creationCode); continue; } r = r >> 8; if (r & 1 == 0) { - address expected = LibRLP.computeAddress(deployer, vm.getNonce(deployer)); bytes memory initcode = type(MockLifebuoyOwned).creationCode; - initcode = abi.encodePacked(initcode, owner); - address deployed = _deployViaCreate(deployer, initcode); - assertEq(deployed, expected); + initcode = abi.encodePacked(initcode, abi.encode(owner)); + _testLifebuoyCreateDeployment(deployer, initcode); continue; } - address expected = LibRLP.computeAddress(deployer, vm.getNonce(deployer)); - address deployed = _deployViaCreate(deployer, type(MockLifebuoy).creationCode); - assertEq(deployed, expected); + _testLifebuoyCreateDeployment(deployer, type(MockLifebuoy).creationCode); } }