From 16cbe5c3b8c2735a0ef8d6a6ea9263072d3fcd15 Mon Sep 17 00:00:00 2001 From: Vectorized Date: Mon, 13 May 2024 12:30:03 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20DynamicBufferLib=20push=20singles?= =?UTF-8?q?=20(#931)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gas-snapshot | 72 ++-- src/utils/DynamicBufferLib.sol | 757 ++++++++++++++++++++++++++++++++- test/DynamicBufferLib.t.sol | 136 ++++++ 3 files changed, 927 insertions(+), 38 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 11e459100..e29e034ba 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -63,16 +63,18 @@ DateTimeLibTest:testWeekday() (gas: 682) DateTimeLibTest:test__codesize() (gas: 19094) DeploylessPredeployQueryerTest:testPredeployQueryer(bytes32) (runs: 271, μ: 227343, ~: 218488) DeploylessPredeployQueryerTest:test__codesize() (gas: 6702) -DynamicBufferLibTest:testClear(uint256) (runs: 271, μ: 34490, ~: 34534) -DynamicBufferLibTest:testDynamicBuffer(bytes[],uint256) (runs: 271, μ: 901374, ~: 796089) -DynamicBufferLibTest:testDynamicBuffer(uint256) (runs: 271, μ: 806480, ~: 684407) -DynamicBufferLibTest:testDynamicBufferChaining() (gas: 12499) -DynamicBufferLibTest:testDynamicBufferReserveFromEmpty() (gas: 2736) -DynamicBufferLibTest:testDynamicBufferReserveFromEmpty2() (gas: 2423) -DynamicBufferLibTest:testDynamicBufferReserveFromEmpty3(bytes,uint256) (runs: 271, μ: 3172, ~: 2122) -DynamicBufferLibTest:testJoinWithConcat() (gas: 31407) -DynamicBufferLibTest:testJoinWithDynamicBuffer() (gas: 10764) -DynamicBufferLibTest:test__codesize() (gas: 9852) +DynamicBufferLibTest:testClear(uint256) (runs: 271, μ: 34512, ~: 34562) +DynamicBufferLibTest:testDynamicBuffer(bytes[],uint256) (runs: 271, μ: 941671, ~: 793328) +DynamicBufferLibTest:testDynamicBuffer(uint256) (runs: 271, μ: 814549, ~: 678271) +DynamicBufferLibTest:testDynamicBufferChaining() (gas: 12661) +DynamicBufferLibTest:testDynamicBufferPushSingles(uint256,uint256,uint256) (runs: 271, μ: 375615, ~: 42703) +DynamicBufferLibTest:testDynamicBufferPushSinglesReinterpretCast() (gas: 21959) +DynamicBufferLibTest:testDynamicBufferReserveFromEmpty() (gas: 2754) +DynamicBufferLibTest:testDynamicBufferReserveFromEmpty2() (gas: 2463) +DynamicBufferLibTest:testDynamicBufferReserveFromEmpty3(bytes,uint256) (runs: 271, μ: 2997, ~: 2150) +DynamicBufferLibTest:testJoinWithConcat() (gas: 31429) +DynamicBufferLibTest:testJoinWithDynamicBuffer() (gas: 10830) +DynamicBufferLibTest:test__codesize() (gas: 12754) ECDSATest:testBytes32ToEthSignedMessageHash() (gas: 381) ECDSATest:testBytesToEthSignedMessageHash() (gas: 11587935) ECDSATest:testBytesToEthSignedMessageHashEmpty() (gas: 578) @@ -192,7 +194,7 @@ ERC1967FactoryTest:testUpgradeAndCallWithRevert() (gas: 265645) ERC1967FactoryTest:testUpgradeUnauthorized() (gas: 270340) ERC1967FactoryTest:testUpgradeWithCorruptedProxy() (gas: 263130) ERC1967FactoryTest:test__codesize() (gas: 32000) -ERC20Invariants:invariantBalanceSum() (runs: 256, calls: 3840, reverts: 2302) +ERC20Invariants:invariantBalanceSum() (runs: 256, calls: 3840, reverts: 2311) ERC20Invariants:test__codesize() (gas: 7534) ERC20Test:testApprove() (gas: 35730) ERC20Test:testApprove(address,uint256) (runs: 271, μ: 31107, ~: 31181) @@ -241,7 +243,7 @@ ERC4337Test:testDisableInitializerForImplementation() (gas: 1320597) ERC4337Test:testETHReceived() (gas: 16584) ERC4337Test:testExecute() (gas: 382808) ERC4337Test:testExecuteBatch() (gas: 692731) -ERC4337Test:testExecuteBatch(uint256) (runs: 271, μ: 545941, ~: 669068) +ERC4337Test:testExecuteBatch(uint256) (runs: 271, μ: 543668, ~: 669058) ERC4337Test:testInitializer() (gas: 285472) ERC4337Test:testIsValidSignature() (gas: 119651) ERC4337Test:testIsValidSignaturePersonalSign() (gas: 102966) @@ -274,21 +276,21 @@ ERC4626Test:testWithdrawZero() (gas: 51874) ERC4626Test:test__codesize() (gas: 37202) ERC6551Test:testBaseFeeMini() (gas: 39514) ERC6551Test:testCdFallback() (gas: 894982) -ERC6551Test:testDeployERC6551(uint256) (runs: 271, μ: 170655, ~: 168891) +ERC6551Test:testDeployERC6551(uint256) (runs: 271, μ: 170603, ~: 168890) ERC6551Test:testDeployERC6551Proxy() (gas: 80395) ERC6551Test:testExecute() (gas: 506735) ERC6551Test:testExecuteBatch() (gas: 816151) -ERC6551Test:testExecuteBatch(uint256) (runs: 271, μ: 621149, ~: 482768) +ERC6551Test:testExecuteBatch(uint256) (runs: 271, μ: 623234, ~: 592342) ERC6551Test:testInitializeERC6551ProxyImplementation() (gas: 189914) ERC6551Test:testIsValidSigner(address) (runs: 271, μ: 167492, ~: 167474) ERC6551Test:testOnERC1155BatchReceived() (gas: 1697916) ERC6551Test:testOnERC1155Received() (gas: 1695271) ERC6551Test:testOnERC721Received() (gas: 1738609) ERC6551Test:testOnERC721ReceivedCycles() (gas: 1727948) -ERC6551Test:testOnERC721ReceivedCyclesWithDifferentChainIds(uint256) (runs: 271, μ: 450390, ~: 455363) -ERC6551Test:testOwnerWorksWithChainIdChange(uint256,uint256) (runs: 271, μ: 1363684, ~: 1363678) +ERC6551Test:testOnERC721ReceivedCyclesWithDifferentChainIds(uint256) (runs: 271, μ: 450366, ~: 455356) +ERC6551Test:testOwnerWorksWithChainIdChange(uint256,uint256) (runs: 271, μ: 1363685, ~: 1363678) ERC6551Test:testSupportsInterface() (gas: 169450) -ERC6551Test:testUpdateState(uint256) (runs: 271, μ: 235184, ~: 235124) +ERC6551Test:testUpdateState(uint256) (runs: 271, μ: 235185, ~: 235126) ERC6551Test:testUpgrade() (gas: 248420) ERC6551Test:test__codesize() (gas: 51483) ERC6909Test:testApprove() (gas: 36868) @@ -867,19 +869,19 @@ LibStringTest:testToStringZeroBrutalized() (gas: 546679) LibStringTest:testToStringZeroRightPadded(uint256) (runs: 271, μ: 591359, ~: 547409) LibStringTest:test__codesize() (gas: 40904) LibZipTest:testCdCompress() (gas: 126842) -LibZipTest:testCdCompressDecompress(bytes) (runs: 271, μ: 748538, ~: 656042) -LibZipTest:testCdCompressDecompress(uint256) (runs: 271, μ: 799143, ~: 671488) +LibZipTest:testCdCompressDecompress(bytes) (runs: 271, μ: 749724, ~: 656502) +LibZipTest:testCdCompressDecompress(uint256) (runs: 271, μ: 786119, ~: 671836) LibZipTest:testCdDecompressOnInvalidInput() (gas: 1397) LibZipTest:testCdFallback() (gas: 5647022) -LibZipTest:testCdFallback(bytes,uint256) (runs: 271, μ: 1157343, ~: 1058090) +LibZipTest:testCdFallback(bytes,uint256) (runs: 271, μ: 1163535, ~: 1059172) LibZipTest:testCdFallbackDecompressor(bytes) (runs: 271, μ: 121400, ~: 117715) -LibZipTest:testCdFallbackDecompressor(uint256) (runs: 271, μ: 173696, ~: 159949) +LibZipTest:testCdFallbackDecompressor(uint256) (runs: 271, μ: 171434, ~: 159867) LibZipTest:testCdFallbackMaskTrick(uint256,uint256) (runs: 271, μ: 590, ~: 585) -LibZipTest:testDecompressWontRevert(bytes) (runs: 271, μ: 736437, ~: 634466) -LibZipTest:testFlzCompressDecompress() (gas: 1250087) -LibZipTest:testFlzCompressDecompress(bytes) (runs: 271, μ: 801847, ~: 674713) -LibZipTest:testFlzCompressDecompress2() (gas: 759122) -LibZipTest:test__codesize() (gas: 20352) +LibZipTest:testDecompressWontRevert(bytes) (runs: 271, μ: 738141, ~: 634927) +LibZipTest:testFlzCompressDecompress() (gas: 1250287) +LibZipTest:testFlzCompressDecompress(bytes) (runs: 271, μ: 802148, ~: 675173) +LibZipTest:testFlzCompressDecompress2() (gas: 759322) +LibZipTest:test__codesize() (gas: 20356) MerkleProofLibTest:testEmptyCalldataHelpers() (gas: 985) MerkleProofLibTest:testVerifyMultiProof(bool,bool,bool,bool,bytes32) (runs: 271, μ: 740107, ~: 642851) MerkleProofLibTest:testVerifyMultiProofForHeightOneTree(bool,bool,bool,bool,bool,bool[]) (runs: 271, μ: 37178, ~: 38010) @@ -1064,7 +1066,7 @@ SafeCastLibTest:testSafeCastUint256ToIntBench() (gas: 330222) SafeCastLibTest:testSafeCastUint256ToUintBench() (gas: 326262) SafeCastLibTest:testSafeCastUintToUint(uint256,uint256) (runs: 271, μ: 19336, ~: 24926) SafeCastLibTest:test__codesize() (gas: 23270) -SafeTransferLibTest:testApproveWithGarbageReverts(address,uint256) (runs: 271, μ: 109744, ~: 123540) +SafeTransferLibTest:testApproveWithGarbageReverts(address,uint256) (runs: 271, μ: 109928, ~: 123668) SafeTransferLibTest:testApproveWithMissingReturn() (gas: 32065) SafeTransferLibTest:testApproveWithMissingReturn(address,uint256) (runs: 271, μ: 32211, ~: 32285) SafeTransferLibTest:testApproveWithNonContract() (gas: 3012) @@ -1088,7 +1090,7 @@ SafeTransferLibTest:testApproveWithStandardERC20(address,uint256) (runs: 271, μ SafeTransferLibTest:testBalanceOfStandardERC20() (gas: 7852) SafeTransferLibTest:testBalanceOfStandardERC20(address,uint256) (runs: 271, μ: 40449, ~: 40719) SafeTransferLibTest:testForceTransferETHToGriever() (gas: 1511565) -SafeTransferLibTest:testForceTransferETHToGriever(uint256,uint256) (runs: 271, μ: 538375, ~: 570885) +SafeTransferLibTest:testForceTransferETHToGriever(uint256,uint256) (runs: 271, μ: 538014, ~: 570885) SafeTransferLibTest:testPermit2() (gas: 89497) SafeTransferLibTest:testPermit2InvalidAmount(uint256) (runs: 271, μ: 102472, ~: 102494) SafeTransferLibTest:testPermit2OnDAI() (gas: 89519) @@ -1096,7 +1098,7 @@ SafeTransferLibTest:testPermit2TransferFromInvalidAmount(uint256) (runs: 271, μ SafeTransferLibTest:testSimplePermit2AndPermit2TransferFrom() (gas: 1102105) SafeTransferLibTest:testSimplePermit2AndPermit2TransferFromGas() (gas: 137347) SafeTransferLibTest:testTransferAllETH() (gas: 34621) -SafeTransferLibTest:testTransferAllETH(address) (runs: 271, μ: 34671, ~: 35034) +SafeTransferLibTest:testTransferAllETH(address) (runs: 271, μ: 34789, ~: 35034) SafeTransferLibTest:testTransferAllETHToContractWithoutFallbackReverts() (gas: 10846) SafeTransferLibTest:testTransferAllETHToContractWithoutFallbackReverts(uint256) (runs: 271, μ: 10869, ~: 10869) SafeTransferLibTest:testTransferAllFromWithStandardERC20() (gas: 33319) @@ -1124,23 +1126,23 @@ SafeTransferLibTest:testTransferFromWithRevertingReverts() (gas: 527143) SafeTransferLibTest:testTransferFromWithRevertingReverts(address,address,uint256) (runs: 271, μ: 655176, ~: 527301) SafeTransferLibTest:testTransferFromWithStandardERC20() (gas: 566534) SafeTransferLibTest:testTransferFromWithStandardERC20(address,address,uint256) (runs: 271, μ: 682809, ~: 566572) -SafeTransferLibTest:testTransferWithGarbageReverts(address,uint256) (runs: 271, μ: 748750, ~: 648388) +SafeTransferLibTest:testTransferWithGarbageReverts(address,uint256) (runs: 271, μ: 748566, ~: 648388) SafeTransferLibTest:testTransferWithMissingReturn() (gas: 554420) -SafeTransferLibTest:testTransferWithMissingReturn(address,uint256) (runs: 271, μ: 675337, ~: 554767) +SafeTransferLibTest:testTransferWithMissingReturn(address,uint256) (runs: 271, μ: 675336, ~: 554767) SafeTransferLibTest:testTransferWithNonContract() (gas: 3010) SafeTransferLibTest:testTransferWithNonContract(address,address,uint256) (runs: 271, μ: 3622, ~: 3634) -SafeTransferLibTest:testTransferWithNonGarbage(address,uint256) (runs: 271, μ: 739212, ~: 624046) +SafeTransferLibTest:testTransferWithNonGarbage(address,uint256) (runs: 271, μ: 739367, ~: 624046) SafeTransferLibTest:testTransferWithReturnsFalseReverts() (gas: 530949) SafeTransferLibTest:testTransferWithReturnsFalseReverts(address,uint256) (runs: 271, μ: 688395, ~: 531206) SafeTransferLibTest:testTransferWithReturnsTooLittleReverts() (gas: 531136) SafeTransferLibTest:testTransferWithReturnsTooLittleReverts(address,uint256) (runs: 271, μ: 683335, ~: 531152) SafeTransferLibTest:testTransferWithReturnsTooMuch() (gas: 554821) -SafeTransferLibTest:testTransferWithReturnsTooMuch(address,uint256) (runs: 271, μ: 635227, ~: 555224) +SafeTransferLibTest:testTransferWithReturnsTooMuch(address,uint256) (runs: 271, μ: 632419, ~: 555224) SafeTransferLibTest:testTransferWithReturnsTwoReverts(address,uint256) (runs: 271, μ: 676551, ~: 531163) SafeTransferLibTest:testTransferWithRevertingReverts() (gas: 530843) -SafeTransferLibTest:testTransferWithRevertingReverts(address,uint256) (runs: 271, μ: 730501, ~: 531121) +SafeTransferLibTest:testTransferWithRevertingReverts(address,uint256) (runs: 271, μ: 730501, ~: 531142) SafeTransferLibTest:testTransferWithStandardERC20() (gas: 555088) -SafeTransferLibTest:testTransferWithStandardERC20(address,uint256) (runs: 271, μ: 621450, ~: 555059) +SafeTransferLibTest:testTransferWithStandardERC20(address,uint256) (runs: 271, μ: 629241, ~: 555059) SafeTransferLibTest:testTrySafeTransferFrom(address,address,uint256) (runs: 271, μ: 109073, ~: 111573) SafeTransferLibTest:testTryTransferAllETH() (gas: 148698) SafeTransferLibTest:testTryTransferETH() (gas: 148701) diff --git a/src/utils/DynamicBufferLib.sol b/src/utils/DynamicBufferLib.sol index b8b94d2ca..3c0814523 100644 --- a/src/utils/DynamicBufferLib.sol +++ b/src/utils/DynamicBufferLib.sol @@ -35,7 +35,7 @@ library DynamicBufferLib { bytes memory data; /// @solidity memory-safe-assembly assembly { - data := 0x00 + data := 0x01 mstore(data, sub(i, n)) } result = p(result, data); @@ -116,8 +116,8 @@ library DynamicBufferLib { break } // If it's a reserve operation, set the variables to skip the appending. - if iszero(data) { - mstore(data, data) + if eq(data, 0x01) { + mstore(data, 0x00) newBufDataLen := bufDataLen } // Copy `data` one word at a time, backwards. @@ -212,6 +212,737 @@ library DynamicBufferLib { result = p(p(p(p(p(p(p(buffer, data0), data1), data2), data3), data4), data5), data6); } + /// @dev Appends `abi.encodePacked(bool(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBool(DynamicBuffer memory buffer, bool data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + uint256 casted; + /// @solidity memory-safe-assembly + assembly { + casted := iszero(iszero(data)) + } + result = p(buffer, _single(casted, 1)); + } + + /// @dev Appends `abi.encodePacked(address(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pAddress(DynamicBuffer memory buffer, address data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(uint256(uint160(data)), 20)); + } + + /// @dev Appends `abi.encodePacked(uint8(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint8(DynamicBuffer memory buffer, uint8 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 1)); + } + + /// @dev Appends `abi.encodePacked(uint16(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint16(DynamicBuffer memory buffer, uint16 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 2)); + } + + /// @dev Appends `abi.encodePacked(uint24(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint24(DynamicBuffer memory buffer, uint24 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 3)); + } + + /// @dev Appends `abi.encodePacked(uint32(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint32(DynamicBuffer memory buffer, uint32 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 4)); + } + + /// @dev Appends `abi.encodePacked(uint40(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint40(DynamicBuffer memory buffer, uint40 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 5)); + } + + /// @dev Appends `abi.encodePacked(uint48(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint48(DynamicBuffer memory buffer, uint48 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 6)); + } + + /// @dev Appends `abi.encodePacked(uint56(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint56(DynamicBuffer memory buffer, uint56 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 7)); + } + + /// @dev Appends `abi.encodePacked(uint64(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint64(DynamicBuffer memory buffer, uint64 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 8)); + } + + /// @dev Appends `abi.encodePacked(uint72(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint72(DynamicBuffer memory buffer, uint72 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 9)); + } + + /// @dev Appends `abi.encodePacked(uint80(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint80(DynamicBuffer memory buffer, uint80 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 10)); + } + + /// @dev Appends `abi.encodePacked(uint88(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint88(DynamicBuffer memory buffer, uint88 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 11)); + } + + /// @dev Appends `abi.encodePacked(uint96(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint96(DynamicBuffer memory buffer, uint96 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 12)); + } + + /// @dev Appends `abi.encodePacked(uint104(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint104(DynamicBuffer memory buffer, uint104 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 13)); + } + + /// @dev Appends `abi.encodePacked(uint112(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint112(DynamicBuffer memory buffer, uint112 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 14)); + } + + /// @dev Appends `abi.encodePacked(uint120(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint120(DynamicBuffer memory buffer, uint120 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 15)); + } + + /// @dev Appends `abi.encodePacked(uint128(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint128(DynamicBuffer memory buffer, uint128 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 16)); + } + + /// @dev Appends `abi.encodePacked(uint136(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint136(DynamicBuffer memory buffer, uint136 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 17)); + } + + /// @dev Appends `abi.encodePacked(uint144(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint144(DynamicBuffer memory buffer, uint144 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 18)); + } + + /// @dev Appends `abi.encodePacked(uint152(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint152(DynamicBuffer memory buffer, uint152 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 19)); + } + + /// @dev Appends `abi.encodePacked(uint160(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint160(DynamicBuffer memory buffer, uint160 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 20)); + } + + /// @dev Appends `abi.encodePacked(uint168(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint168(DynamicBuffer memory buffer, uint168 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 21)); + } + + /// @dev Appends `abi.encodePacked(uint176(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint176(DynamicBuffer memory buffer, uint176 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 22)); + } + + /// @dev Appends `abi.encodePacked(uint184(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint184(DynamicBuffer memory buffer, uint184 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 23)); + } + + /// @dev Appends `abi.encodePacked(uint192(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint192(DynamicBuffer memory buffer, uint192 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 24)); + } + + /// @dev Appends `abi.encodePacked(uint200(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint200(DynamicBuffer memory buffer, uint200 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 25)); + } + + /// @dev Appends `abi.encodePacked(uint208(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint208(DynamicBuffer memory buffer, uint208 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 26)); + } + + /// @dev Appends `abi.encodePacked(uint216(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint216(DynamicBuffer memory buffer, uint216 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 27)); + } + + /// @dev Appends `abi.encodePacked(uint224(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint224(DynamicBuffer memory buffer, uint224 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 28)); + } + + /// @dev Appends `abi.encodePacked(uint232(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint232(DynamicBuffer memory buffer, uint232 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 29)); + } + + /// @dev Appends `abi.encodePacked(uint240(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint240(DynamicBuffer memory buffer, uint240 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 30)); + } + + /// @dev Appends `abi.encodePacked(uint248(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint248(DynamicBuffer memory buffer, uint248 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 31)); + } + + /// @dev Appends `abi.encodePacked(uint256(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pUint256(DynamicBuffer memory buffer, uint256 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(data, 32)); + } + + /// @dev Appends `abi.encodePacked(bytes1(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes1(DynamicBuffer memory buffer, bytes1 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 1)); + } + + /// @dev Appends `abi.encodePacked(bytes2(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes2(DynamicBuffer memory buffer, bytes2 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 2)); + } + + /// @dev Appends `abi.encodePacked(bytes3(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes3(DynamicBuffer memory buffer, bytes3 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 3)); + } + + /// @dev Appends `abi.encodePacked(bytes4(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes4(DynamicBuffer memory buffer, bytes4 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 4)); + } + + /// @dev Appends `abi.encodePacked(bytes5(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes5(DynamicBuffer memory buffer, bytes5 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 5)); + } + + /// @dev Appends `abi.encodePacked(bytes6(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes6(DynamicBuffer memory buffer, bytes6 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 6)); + } + + /// @dev Appends `abi.encodePacked(bytes7(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes7(DynamicBuffer memory buffer, bytes7 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 7)); + } + + /// @dev Appends `abi.encodePacked(bytes8(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes8(DynamicBuffer memory buffer, bytes8 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 8)); + } + + /// @dev Appends `abi.encodePacked(bytes9(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes9(DynamicBuffer memory buffer, bytes9 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 9)); + } + + /// @dev Appends `abi.encodePacked(bytes10(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes10(DynamicBuffer memory buffer, bytes10 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 10)); + } + + /// @dev Appends `abi.encodePacked(bytes11(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes11(DynamicBuffer memory buffer, bytes11 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 11)); + } + + /// @dev Appends `abi.encodePacked(bytes12(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes12(DynamicBuffer memory buffer, bytes12 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 12)); + } + + /// @dev Appends `abi.encodePacked(bytes13(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes13(DynamicBuffer memory buffer, bytes13 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 13)); + } + + /// @dev Appends `abi.encodePacked(bytes14(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes14(DynamicBuffer memory buffer, bytes14 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 14)); + } + + /// @dev Appends `abi.encodePacked(bytes15(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes15(DynamicBuffer memory buffer, bytes15 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 15)); + } + + /// @dev Appends `abi.encodePacked(bytes16(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes16(DynamicBuffer memory buffer, bytes16 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 16)); + } + + /// @dev Appends `abi.encodePacked(bytes17(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes17(DynamicBuffer memory buffer, bytes17 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 17)); + } + + /// @dev Appends `abi.encodePacked(bytes18(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes18(DynamicBuffer memory buffer, bytes18 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 18)); + } + + /// @dev Appends `abi.encodePacked(bytes19(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes19(DynamicBuffer memory buffer, bytes19 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 19)); + } + + /// @dev Appends `abi.encodePacked(bytes20(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes20(DynamicBuffer memory buffer, bytes20 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 20)); + } + + /// @dev Appends `abi.encodePacked(bytes21(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes21(DynamicBuffer memory buffer, bytes21 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 21)); + } + + /// @dev Appends `abi.encodePacked(bytes22(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes22(DynamicBuffer memory buffer, bytes22 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 22)); + } + + /// @dev Appends `abi.encodePacked(bytes23(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes23(DynamicBuffer memory buffer, bytes23 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 23)); + } + + /// @dev Appends `abi.encodePacked(bytes24(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes24(DynamicBuffer memory buffer, bytes24 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 24)); + } + + /// @dev Appends `abi.encodePacked(bytes25(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes25(DynamicBuffer memory buffer, bytes25 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 25)); + } + + /// @dev Appends `abi.encodePacked(bytes26(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes26(DynamicBuffer memory buffer, bytes26 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 26)); + } + + /// @dev Appends `abi.encodePacked(bytes27(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes27(DynamicBuffer memory buffer, bytes27 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 27)); + } + + /// @dev Appends `abi.encodePacked(bytes28(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes28(DynamicBuffer memory buffer, bytes28 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 28)); + } + + /// @dev Appends `abi.encodePacked(bytes29(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes29(DynamicBuffer memory buffer, bytes29 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 29)); + } + + /// @dev Appends `abi.encodePacked(bytes30(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes30(DynamicBuffer memory buffer, bytes30 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 30)); + } + + /// @dev Appends `abi.encodePacked(bytes31(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes31(DynamicBuffer memory buffer, bytes31 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 31)); + } + + /// @dev Appends `abi.encodePacked(bytes32(data))` to buffer. + /// Returns the same buffer, so that it can be used for function chaining. + function pBytes32(DynamicBuffer memory buffer, bytes32 data) + internal + pure + returns (DynamicBuffer memory result) + { + _deallocate(result); + result = p(buffer, _single(bytes32(data), 32)); + } + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ @@ -223,4 +954,24 @@ library DynamicBufferLib { mstore(0x40, result) // Deallocate, as we have already allocated. } } + + /// @dev Returns a temporary bytes string of length `n` for `data`. + function _single(uint256 data, uint256 n) private pure returns (bytes memory result) { + /// @solidity memory-safe-assembly + assembly { + result := 0x00 + mstore(n, data) + mstore(result, n) + } + } + + /// @dev Returns a temporary bytes string of length `n` for `data`. + function _single(bytes32 data, uint256 n) private pure returns (bytes memory result) { + /// @solidity memory-safe-assembly + assembly { + result := 0x00 + mstore(0x20, data) + mstore(result, n) + } + } } diff --git a/test/DynamicBufferLib.t.sol b/test/DynamicBufferLib.t.sol index 281553f35..8cae624b8 100644 --- a/test/DynamicBufferLib.t.sol +++ b/test/DynamicBufferLib.t.sol @@ -7,6 +7,142 @@ import {DynamicBufferLib} from "../src/utils/DynamicBufferLib.sol"; contract DynamicBufferLibTest is SoladyTest { using DynamicBufferLib for DynamicBufferLib.DynamicBuffer; + function testDynamicBufferPushSingles(uint256 x, uint256 y, uint256 z) public { + if (_random() % 32 == 0) _brutalizeMemory(); + DynamicBufferLib.DynamicBuffer memory buffer; + if (_random() % 4 == 0) { + if (_random() % 2 == 0) { + DynamicBufferLib.DynamicBuffer memory newBuffer; + buffer = newBuffer; + } + buffer.pUint256(x); + assertEq(buffer.data, abi.encodePacked(uint256(x))); + buffer.pUint256(y).pUint256(z); + assertEq(buffer.data, abi.encodePacked(uint256(x), uint256(y), uint256(z))); + } + if (_random() % 32 == 0) _brutalizeMemory(); + if (_random() % 4 == 0) { + if (_random() % 2 == 0) { + DynamicBufferLib.DynamicBuffer memory newBuffer; + buffer = newBuffer; + } else { + buffer.clear(); + } + buffer.pUint32(uint32(x)); + assertEq(buffer.data, abi.encodePacked(uint32(x))); + buffer.pUint32(uint32(y)).pUint32(uint32(z)); + assertEq(buffer.data, abi.encodePacked(uint32(x), uint32(y), uint32(z))); + } + if (_random() % 32 == 0) _brutalizeMemory(); + if (_random() % 4 == 0) { + if (_random() % 2 == 0) { + DynamicBufferLib.DynamicBuffer memory newBuffer; + buffer = newBuffer; + } else { + buffer.clear(); + } + buffer.pUint8(uint8(x)); + assertEq(buffer.data, abi.encodePacked(uint8(x))); + buffer.pUint8(uint8(y)).pUint8(uint8(z)); + assertEq(buffer.data, abi.encodePacked(uint8(x), uint8(y), uint8(z))); + } + if (_random() % 32 == 0) _brutalizeMemory(); + if (_random() % 4 == 0) { + if (_random() % 2 == 0) { + DynamicBufferLib.DynamicBuffer memory newBuffer; + buffer = newBuffer; + } else { + buffer.clear(); + } + buffer.pBytes32(bytes32(x)); + assertEq(buffer.data, abi.encodePacked(bytes32(x))); + buffer.pBytes32(bytes32(y)).pBytes32(bytes32(z)); + assertEq(buffer.data, abi.encodePacked(bytes32(x), bytes32(y), bytes32(z))); + } + if (_random() % 32 == 0) _brutalizeMemory(); + if (_random() % 4 == 0) { + if (_random() % 2 == 0) { + DynamicBufferLib.DynamicBuffer memory newBuffer; + buffer = newBuffer; + } else { + buffer.clear(); + } + buffer.pBytes3(bytes3(bytes32(x))); + assertEq(buffer.data, abi.encodePacked(bytes3(bytes32(x)))); + buffer.pBytes3(bytes3(bytes32(y))).pBytes3(bytes3(bytes32(z))); + assertEq( + buffer.data, + abi.encodePacked(bytes3(bytes32(x)), bytes3(bytes32(y)), bytes3(bytes32(z))) + ); + } + if (_random() % 32 == 0) _brutalizeMemory(); + if (_random() % 4 == 0) { + if (_random() % 2 == 0) { + DynamicBufferLib.DynamicBuffer memory newBuffer; + buffer = newBuffer; + } else { + buffer.clear(); + } + buffer.pBytes1(bytes1(bytes32(x))); + assertEq(buffer.data, abi.encodePacked(bytes1(bytes32(x)))); + buffer.pBytes1(bytes1(bytes32(y))).pBytes1(bytes1(bytes32(z))); + assertEq( + buffer.data, + abi.encodePacked(bytes1(bytes32(x)), bytes1(bytes32(y)), bytes1(bytes32(z))) + ); + } + if (_random() % 32 == 0) _brutalizeMemory(); + if (_random() % 4 == 0) { + if (_random() % 2 == 0) { + DynamicBufferLib.DynamicBuffer memory newBuffer; + buffer = newBuffer; + } else { + buffer.clear(); + } + buffer.pBool(x % 2 == 0); + assertEq(buffer.data, abi.encodePacked(x % 2 == 0)); + buffer.pBool(y % 2 == 0).pBool(z % 2 == 0); + assertEq(buffer.data, abi.encodePacked(x % 2 == 0, y % 2 == 0, z % 2 == 0)); + } + if (_random() % 32 == 0) _brutalizeMemory(); + if (_random() % 4 == 0) { + if (_random() % 2 == 0) { + DynamicBufferLib.DynamicBuffer memory newBuffer; + buffer = newBuffer; + } else { + buffer.clear(); + } + buffer.pAddress(address(uint160(x))); + assertEq(buffer.data, abi.encodePacked(address(uint160(x)))); + buffer.pAddress(address(uint160(y))).pAddress(address(uint160(z))); + assertEq( + buffer.data, + abi.encodePacked(address(uint160(x)), address(uint160(y)), address(uint160(z))) + ); + } + } + + function testDynamicBufferPushSinglesReinterpretCast() public { + uint256 n = 32; + DynamicBufferLib.DynamicBuffer memory buffer; + uint256[] memory expected = new uint256[](n); + unchecked { + for (uint256 i; i != n; ++i) { + uint256 v = (i << 128) | 1; + buffer.pUint256(v); + expected[i] = v; + } + } + uint256[] memory computed; + /// @solidity memory-safe-assembly + assembly { + computed := mload(buffer) + let nBytes := mload(computed) + mstore(computed, shr(5, nBytes)) + } + assertEq(computed, expected); + } + function testClear(uint256) public { DynamicBufferLib.DynamicBuffer memory buffer; bytes memory b0 = _generateRandomBytes(128, _random());