From 6c05c3ba54cf0d42a78d539ed17985dbe236f056 Mon Sep 17 00:00:00 2001 From: dk1a Date: Wed, 12 Jul 2023 14:55:16 +0300 Subject: [PATCH 1/2] test(store): clean up Utils, add tests --- packages/store/abi/Utils.sol/Utils.abi.json | 1 - packages/store/src/Memory.sol | 4 +- packages/store/src/Storage.sol | 10 ++--- packages/store/src/StoreCore.sol | 1 - packages/store/src/Utils.sol | 38 ++++++++----------- packages/store/test/Storage.t.sol | 1 - packages/store/test/StoreCore.t.sol | 1 - packages/store/test/StoreCoreGas.t.sol | 1 - packages/store/test/Utils.t.sol | 35 +++++++++++++++++ .../world/abi/src/Utils.sol/Utils.abi.json | 1 - 10 files changed, 58 insertions(+), 35 deletions(-) delete mode 100644 packages/store/abi/Utils.sol/Utils.abi.json create mode 100644 packages/store/test/Utils.t.sol delete mode 100644 packages/world/abi/src/Utils.sol/Utils.abi.json diff --git a/packages/store/abi/Utils.sol/Utils.abi.json b/packages/store/abi/Utils.sol/Utils.abi.json deleted file mode 100644 index 0637a088a0..0000000000 --- a/packages/store/abi/Utils.sol/Utils.abi.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/packages/store/src/Memory.sol b/packages/store/src/Memory.sol index 493aeba861..6619fce0c4 100644 --- a/packages/store/src/Memory.sol +++ b/packages/store/src/Memory.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.0; -import { Utils } from "./Utils.sol"; +import { leftMask } from "./Utils.sol"; library Memory { function load(uint256 memoryPointer) internal pure returns (bytes32 data) { @@ -49,7 +49,7 @@ library Memory { ) } } else { - uint256 mask = Utils.leftMask(length); + uint256 mask = leftMask(length); assembly { mstore( toPointer, diff --git a/packages/store/src/Storage.sol b/packages/store/src/Storage.sol index 52eb366459..403de0490a 100644 --- a/packages/store/src/Storage.sol +++ b/packages/store/src/Storage.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.0; -import { Utils } from "./Utils.sol"; +import { leftMask } from "./Utils.sol"; /** * TODO Probably not fully optimized @@ -45,7 +45,7 @@ library Storage { wordRemainder = 32 - offset; } - uint256 mask = Utils.leftMask(length); + uint256 mask = leftMask(length); /// @solidity memory-safe-assembly assembly { // Load data from memory and offset it to match storage @@ -91,7 +91,7 @@ library Storage { // For the last partial word, apply a mask to the end if (length > 0) { - uint256 mask = Utils.leftMask(length); + uint256 mask = leftMask(length); /// @solidity memory-safe-assembly assembly { sstore( @@ -151,7 +151,7 @@ library Storage { wordRemainder = 32 - offset; } - uint256 mask = Utils.leftMask(wordRemainder); + uint256 mask = leftMask(wordRemainder); /// @solidity memory-safe-assembly assembly { // Load data from storage and offset it to match memory @@ -195,7 +195,7 @@ library Storage { // For the last partial word, apply a mask to the end if (length > 0) { - uint256 mask = Utils.leftMask(length); + uint256 mask = leftMask(length); /// @solidity memory-safe-assembly assembly { mstore( diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index b30613d1d9..84edd3c7fc 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -11,7 +11,6 @@ import { Slice, SliceLib } from "./Slice.sol"; import { StoreMetadata, Hooks, HooksTableId } from "./codegen/Tables.sol"; import { IStoreErrors } from "./IStoreErrors.sol"; import { IStoreHook } from "./IStore.sol"; -import { Utils } from "./Utils.sol"; import { TableId } from "./TableId.sol"; library StoreCore { diff --git a/packages/store/src/Utils.sol b/packages/store/src/Utils.sol index 14c95abd14..85eefd1544 100644 --- a/packages/store/src/Utils.sol +++ b/packages/store/src/Utils.sol @@ -1,27 +1,21 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.0; -library Utils { - function divCeil(uint256 a, uint256 b) internal pure returns (uint256) { - return a / b + (a % b == 0 ? 0 : 1); - } - - /** - * Adapted from https://github.com/dk1a/solidity-stringutils/blob/main/src/utils/mem.sol#L149-L167 - * @dev Left-aligned byte mask (e.g. for partial mload/mstore). - * For byteLength >= 32 returns type(uint256).max - * - * length 0: 0x000000...000000 - * length 1: 0xff0000...000000 - * length 2: 0xffff00...000000 - * ... - * length 30: 0xffffff...ff0000 - * length 31: 0xffffff...ffff00 - * length 32+: 0xffffff...ffffff - */ - function leftMask(uint256 byteLength) internal pure returns (uint256) { - unchecked { - return ~(type(uint256).max >> (byteLength * 8)); - } +/** + * Adapted from https://github.com/dk1a/solidity-stringutils/blob/main/src/utils/mem.sol#L149-L167 + * @dev Left-aligned byte mask (e.g. for partial mload/mstore). + * For byteLength >= 32 returns type(uint256).max + * + * length 0: 0x000000...000000 + * length 1: 0xff0000...000000 + * length 2: 0xffff00...000000 + * ... + * length 30: 0xffffff...ff0000 + * length 31: 0xffffff...ffff00 + * length 32+: 0xffffff...ffffff + */ +function leftMask(uint256 byteLength) pure returns (uint256) { + unchecked { + return ~(type(uint256).max >> (byteLength * 8)); } } diff --git a/packages/store/test/Storage.t.sol b/packages/store/test/Storage.t.sol index a85d9b98ad..fe8be775ed 100644 --- a/packages/store/test/Storage.t.sol +++ b/packages/store/test/Storage.t.sol @@ -4,7 +4,6 @@ pragma solidity >=0.8.0; import { Test } from "forge-std/Test.sol"; import { GasReporter } from "@latticexyz/gas-report/src/GasReporter.sol"; import { Storage } from "../src/Storage.sol"; -import { Utils } from "../src/Utils.sol"; import { Bytes } from "../src/Bytes.sol"; contract StorageTest is Test, GasReporter { diff --git a/packages/store/test/StoreCore.t.sol b/packages/store/test/StoreCore.t.sol index 682c9f26bb..95d440813c 100644 --- a/packages/store/test/StoreCore.t.sol +++ b/packages/store/test/StoreCore.t.sol @@ -4,7 +4,6 @@ pragma solidity >=0.8.0; import "forge-std/Test.sol"; import { SchemaType } from "@latticexyz/schema-type/src/solidity/SchemaType.sol"; import { StoreCore, StoreCoreInternal } from "../src/StoreCore.sol"; -import { Utils } from "../src/Utils.sol"; import { Bytes } from "../src/Bytes.sol"; import { TableId } from "../src/TableId.sol"; import { SliceLib } from "../src/Slice.sol"; diff --git a/packages/store/test/StoreCoreGas.t.sol b/packages/store/test/StoreCoreGas.t.sol index e7f222d7cc..2ac1348de8 100644 --- a/packages/store/test/StoreCoreGas.t.sol +++ b/packages/store/test/StoreCoreGas.t.sol @@ -5,7 +5,6 @@ import { Test } from "forge-std/Test.sol"; import { GasReporter } from "@latticexyz/gas-report/src/GasReporter.sol"; import { SchemaType } from "@latticexyz/schema-type/src/solidity/SchemaType.sol"; import { StoreCore, StoreCoreInternal } from "../src/StoreCore.sol"; -import { Utils } from "../src/Utils.sol"; import { Bytes } from "../src/Bytes.sol"; import { SliceLib } from "../src/Slice.sol"; import { EncodeArray } from "../src/tightcoder/EncodeArray.sol"; diff --git a/packages/store/test/Utils.t.sol b/packages/store/test/Utils.t.sol new file mode 100644 index 0000000000..21e981862c --- /dev/null +++ b/packages/store/test/Utils.t.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { Test } from "forge-std/Test.sol"; +import { GasReporter } from "@latticexyz/gas-report/src/GasReporter.sol"; +import { leftMask } from "../src/Utils.sol"; + +contract UtilsTest is Test, GasReporter { + function testLeftMask() public { + bytes32 mask; + assertEq(leftMask(0), uint256(mask)); + bytes32 highByte = hex"ff"; + for (uint256 i = 1; i <= 32; i++) { + mask |= highByte; + highByte >>= 8; + assertEq(leftMask(i), uint256(mask)); + } + } + + function testFuzzLeftMaskOver32(uint256 byteLength) public { + // for values >32 the mask must always be type(uint256).max + vm.assume(byteLength > 32); + assertEq(leftMask(byteLength), type(uint256).max); + } + + function testLeftMaskOver32() public { + // manually test for overflow issues + for (uint256 i; i < 100; i++) { + assertEq(leftMask(type(uint256).max - i), type(uint256).max); + } + for (uint256 i; i < 100; i++) { + assertEq(leftMask((type(uint256).max >> 8) + 50 - i), type(uint256).max); + } + } +} diff --git a/packages/world/abi/src/Utils.sol/Utils.abi.json b/packages/world/abi/src/Utils.sol/Utils.abi.json deleted file mode 100644 index 0637a088a0..0000000000 --- a/packages/world/abi/src/Utils.sol/Utils.abi.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file From a1d228714e9eeadd75d842d0f80f3477bc215538 Mon Sep 17 00:00:00 2001 From: dk1a Date: Wed, 12 Jul 2023 17:10:32 +0300 Subject: [PATCH 2/2] rebuild --- packages/world/abi/{world/src => }/Utils.sol/Utils.abi.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/world/abi/{world/src => }/Utils.sol/Utils.abi.json (100%) diff --git a/packages/world/abi/world/src/Utils.sol/Utils.abi.json b/packages/world/abi/Utils.sol/Utils.abi.json similarity index 100% rename from packages/world/abi/world/src/Utils.sol/Utils.abi.json rename to packages/world/abi/Utils.sol/Utils.abi.json