From 649b2d27c2b6f88eb87a9c36cd9425dac089e228 Mon Sep 17 00:00:00 2001 From: dk1a Date: Tue, 15 Aug 2023 17:00:27 +0300 Subject: [PATCH] update comments, build --- .../src/codegen/tables/NumberList.sol | 40 +++- .../src/codegen/tables/Dynamics1.sol | 171 ++++++++++++++---- .../src/codegen/tables/Dynamics2.sol | 107 ++++++++--- .../src/codegen/tables/Singleton.sol | 107 ++++++++--- .../store/src/codegen/tables/Callbacks.sol | 20 +- packages/store/src/codegen/tables/Hooks.sol | 20 +- packages/store/src/codegen/tables/Mixed.sol | 40 +++- .../src/codegen/tables/StoreMetadata.sol | 40 +++- packages/store/ts/codegen/field.ts | 10 +- packages/world/gas-report.json | 4 +- .../src/modules/core/tables/SystemHooks.sol | 28 ++- .../keysintable/tables/KeysInTable.sol | 171 ++++++++++++++---- .../keyswithvalue/tables/KeysWithValue.sol | 28 ++- packages/world/test/tables/AddressArray.sol | 28 ++- 14 files changed, 626 insertions(+), 188 deletions(-) diff --git a/e2e/packages/contracts/src/codegen/tables/NumberList.sol b/e2e/packages/contracts/src/codegen/tables/NumberList.sol index afff8cc4a4..fe99301d82 100644 --- a/e2e/packages/contracts/src/codegen/tables/NumberList.sol +++ b/e2e/packages/contracts/src/codegen/tables/NumberList.sol @@ -114,20 +114,30 @@ library NumberList { } } - /** Get an item of value (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of value + * (unchecked, returns invalid data if index overflows) + */ function getItem(uint256 _index) internal view returns (uint32) { bytes32[] memory _keyTuple = new bytes32[](0); - bytes memory _blob = StoreSwitch.getFieldSlice(_tableId, _keyTuple, 0, getSchema(), _index * 4, (_index + 1) * 4); - return (uint32(Bytes.slice4(_blob, 0))); + unchecked { + bytes memory _blob = StoreSwitch.getFieldSlice(_tableId, _keyTuple, 0, getSchema(), _index * 4, (_index + 1) * 4); + return (uint32(Bytes.slice4(_blob, 0))); + } } - /** Get an item of value (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of value (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItem(IStore _store, uint256 _index) internal view returns (uint32) { bytes32[] memory _keyTuple = new bytes32[](0); - bytes memory _blob = _store.getFieldSlice(_tableId, _keyTuple, 0, getSchema(), _index * 4, (_index + 1) * 4); - return (uint32(Bytes.slice4(_blob, 0))); + unchecked { + bytes memory _blob = _store.getFieldSlice(_tableId, _keyTuple, 0, getSchema(), _index * 4, (_index + 1) * 4); + return (uint32(Bytes.slice4(_blob, 0))); + } } /** Push an element to value */ @@ -158,18 +168,28 @@ library NumberList { _store.popFromField(_tableId, _keyTuple, 0, 4); } - /** Update an element of value at `_index` */ + /** + * Update an element of value at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function update(uint256 _index, uint32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](0); - StoreSwitch.updateInField(_tableId, _keyTuple, 0, _index * 4, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 0, _index * 4, abi.encodePacked((_element))); + } } - /** Update an element of value (using the specified store) at `_index` */ + /** + * Update an element of value (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function update(IStore _store, uint256 _index, uint32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](0); - _store.updateInField(_tableId, _keyTuple, 0, _index * 4, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 0, _index * 4, abi.encodePacked((_element))); + } } /** Tightly pack full data using this table's schema */ diff --git a/packages/cli/contracts/src/codegen/tables/Dynamics1.sol b/packages/cli/contracts/src/codegen/tables/Dynamics1.sol index eca9179513..19c20c4149 100644 --- a/packages/cli/contracts/src/codegen/tables/Dynamics1.sol +++ b/packages/cli/contracts/src/codegen/tables/Dynamics1.sol @@ -137,7 +137,10 @@ library Dynamics1 { } } - /** Get an item of staticB32 (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of staticB32 + * (unchecked, returns invalid data if index overflows) + */ function getItemStaticB32(bytes32 key, uint256 _index) internal view returns (bytes32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -155,7 +158,10 @@ library Dynamics1 { } } - /** Get an item of staticB32 (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of staticB32 (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemStaticB32(IStore _store, bytes32 key, uint256 _index) internal view returns (bytes32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -198,20 +204,30 @@ library Dynamics1 { _store.popFromField(_tableId, _keyTuple, 0, 32); } - /** Update an element of staticB32 at `_index` */ + /** + * Update an element of staticB32 at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateStaticB32(bytes32 key, uint256 _index, bytes32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - StoreSwitch.updateInField(_tableId, _keyTuple, 0, _index * 32, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 0, _index * 32, abi.encodePacked((_element))); + } } - /** Update an element of staticB32 (using the specified store) at `_index` */ + /** + * Update an element of staticB32 (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateStaticB32(IStore _store, bytes32 key, uint256 _index, bytes32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - _store.updateInField(_tableId, _keyTuple, 0, _index * 32, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 0, _index * 32, abi.encodePacked((_element))); + } } /** Get staticI32 */ @@ -270,7 +286,10 @@ library Dynamics1 { } } - /** Get an item of staticI32 (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of staticI32 + * (unchecked, returns invalid data if index overflows) + */ function getItemStaticI32(bytes32 key, uint256 _index) internal view returns (int32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -281,7 +300,10 @@ library Dynamics1 { } } - /** Get an item of staticI32 (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of staticI32 (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemStaticI32(IStore _store, bytes32 key, uint256 _index) internal view returns (int32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -324,20 +346,30 @@ library Dynamics1 { _store.popFromField(_tableId, _keyTuple, 1, 4); } - /** Update an element of staticI32 at `_index` */ + /** + * Update an element of staticI32 at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateStaticI32(bytes32 key, uint256 _index, int32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - StoreSwitch.updateInField(_tableId, _keyTuple, 1, _index * 4, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 1, _index * 4, abi.encodePacked((_element))); + } } - /** Update an element of staticI32 (using the specified store) at `_index` */ + /** + * Update an element of staticI32 (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateStaticI32(IStore _store, bytes32 key, uint256 _index, int32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - _store.updateInField(_tableId, _keyTuple, 1, _index * 4, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 1, _index * 4, abi.encodePacked((_element))); + } } /** Get staticU128 */ @@ -396,7 +428,10 @@ library Dynamics1 { } } - /** Get an item of staticU128 (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of staticU128 + * (unchecked, returns invalid data if index overflows) + */ function getItemStaticU128(bytes32 key, uint256 _index) internal view returns (uint128) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -414,7 +449,10 @@ library Dynamics1 { } } - /** Get an item of staticU128 (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of staticU128 (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemStaticU128(IStore _store, bytes32 key, uint256 _index) internal view returns (uint128) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -457,20 +495,30 @@ library Dynamics1 { _store.popFromField(_tableId, _keyTuple, 2, 16); } - /** Update an element of staticU128 at `_index` */ + /** + * Update an element of staticU128 at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateStaticU128(bytes32 key, uint256 _index, uint128 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - StoreSwitch.updateInField(_tableId, _keyTuple, 2, _index * 16, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 2, _index * 16, abi.encodePacked((_element))); + } } - /** Update an element of staticU128 (using the specified store) at `_index` */ + /** + * Update an element of staticU128 (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateStaticU128(IStore _store, bytes32 key, uint256 _index, uint128 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - _store.updateInField(_tableId, _keyTuple, 2, _index * 16, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 2, _index * 16, abi.encodePacked((_element))); + } } /** Get staticAddrs */ @@ -529,7 +577,10 @@ library Dynamics1 { } } - /** Get an item of staticAddrs (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of staticAddrs + * (unchecked, returns invalid data if index overflows) + */ function getItemStaticAddrs(bytes32 key, uint256 _index) internal view returns (address) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -547,7 +598,10 @@ library Dynamics1 { } } - /** Get an item of staticAddrs (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of staticAddrs (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemStaticAddrs(IStore _store, bytes32 key, uint256 _index) internal view returns (address) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -590,20 +644,30 @@ library Dynamics1 { _store.popFromField(_tableId, _keyTuple, 3, 20); } - /** Update an element of staticAddrs at `_index` */ + /** + * Update an element of staticAddrs at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateStaticAddrs(bytes32 key, uint256 _index, address _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - StoreSwitch.updateInField(_tableId, _keyTuple, 3, _index * 20, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 3, _index * 20, abi.encodePacked((_element))); + } } - /** Update an element of staticAddrs (using the specified store) at `_index` */ + /** + * Update an element of staticAddrs (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateStaticAddrs(IStore _store, bytes32 key, uint256 _index, address _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - _store.updateInField(_tableId, _keyTuple, 3, _index * 20, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 3, _index * 20, abi.encodePacked((_element))); + } } /** Get staticBools */ @@ -662,7 +726,10 @@ library Dynamics1 { } } - /** Get an item of staticBools (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of staticBools + * (unchecked, returns invalid data if index overflows) + */ function getItemStaticBools(bytes32 key, uint256 _index) internal view returns (bool) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -673,7 +740,10 @@ library Dynamics1 { } } - /** Get an item of staticBools (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of staticBools (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemStaticBools(IStore _store, bytes32 key, uint256 _index) internal view returns (bool) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -716,20 +786,30 @@ library Dynamics1 { _store.popFromField(_tableId, _keyTuple, 4, 1); } - /** Update an element of staticBools at `_index` */ + /** + * Update an element of staticBools at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateStaticBools(bytes32 key, uint256 _index, bool _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - StoreSwitch.updateInField(_tableId, _keyTuple, 4, _index * 1, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 4, _index * 1, abi.encodePacked((_element))); + } } - /** Update an element of staticBools (using the specified store) at `_index` */ + /** + * Update an element of staticBools (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateStaticBools(IStore _store, bytes32 key, uint256 _index, bool _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - _store.updateInField(_tableId, _keyTuple, 4, _index * 1, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 4, _index * 1, abi.encodePacked((_element))); + } } /** Get the full data */ @@ -795,35 +875,46 @@ library Dynamics1 { set(_store, key, _table.staticB32, _table.staticI32, _table.staticU128, _table.staticAddrs, _table.staticBools); } - /** Decode the tightly packed blob using this table's schema */ + /** + * Decode the tightly packed blob using this table's schema. + * Undefined behaviour for invalid blobs. + */ function decode(bytes memory _blob) internal pure returns (Dynamics1Data memory _table) { // 0 is the total byte length of static data PackedCounter _encodedLengths = PackedCounter.wrap(Bytes.slice32(_blob, 0)); // Store trims the blob if dynamic fields are all empty if (_blob.length > 0) { - uint256 _start; // skip static data length + dynamic lengths word - uint256 _end = 32; - - _start = _end; - _end += _encodedLengths.atIndex(0); + uint256 _start = 32; + uint256 _end; + unchecked { + _end = 32 + _encodedLengths.atIndex(0); + } _table.staticB32 = toStaticArray_bytes32_1(SliceLib.getSubslice(_blob, _start, _end).decodeArray_bytes32()); _start = _end; - _end += _encodedLengths.atIndex(1); + unchecked { + _end += _encodedLengths.atIndex(1); + } _table.staticI32 = toStaticArray_int32_2(SliceLib.getSubslice(_blob, _start, _end).decodeArray_int32()); _start = _end; - _end += _encodedLengths.atIndex(2); + unchecked { + _end += _encodedLengths.atIndex(2); + } _table.staticU128 = toStaticArray_uint128_3(SliceLib.getSubslice(_blob, _start, _end).decodeArray_uint128()); _start = _end; - _end += _encodedLengths.atIndex(3); + unchecked { + _end += _encodedLengths.atIndex(3); + } _table.staticAddrs = toStaticArray_address_4(SliceLib.getSubslice(_blob, _start, _end).decodeArray_address()); _start = _end; - _end += _encodedLengths.atIndex(4); + unchecked { + _end += _encodedLengths.atIndex(4); + } _table.staticBools = toStaticArray_bool_5(SliceLib.getSubslice(_blob, _start, _end).decodeArray_bool()); } } diff --git a/packages/cli/contracts/src/codegen/tables/Dynamics2.sol b/packages/cli/contracts/src/codegen/tables/Dynamics2.sol index 681ec7196c..2de0e96b8b 100644 --- a/packages/cli/contracts/src/codegen/tables/Dynamics2.sol +++ b/packages/cli/contracts/src/codegen/tables/Dynamics2.sol @@ -131,7 +131,10 @@ library Dynamics2 { } } - /** Get an item of u64 (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of u64 + * (unchecked, returns invalid data if index overflows) + */ function getItemU64(bytes32 key, uint256 _index) internal view returns (uint64) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -142,7 +145,10 @@ library Dynamics2 { } } - /** Get an item of u64 (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of u64 (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemU64(IStore _store, bytes32 key, uint256 _index) internal view returns (uint64) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -185,20 +191,30 @@ library Dynamics2 { _store.popFromField(_tableId, _keyTuple, 0, 8); } - /** Update an element of u64 at `_index` */ + /** + * Update an element of u64 at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateU64(bytes32 key, uint256 _index, uint64 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - StoreSwitch.updateInField(_tableId, _keyTuple, 0, _index * 8, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 0, _index * 8, abi.encodePacked((_element))); + } } - /** Update an element of u64 (using the specified store) at `_index` */ + /** + * Update an element of u64 (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateU64(IStore _store, bytes32 key, uint256 _index, uint64 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - _store.updateInField(_tableId, _keyTuple, 0, _index * 8, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 0, _index * 8, abi.encodePacked((_element))); + } } /** Get str */ @@ -257,7 +273,10 @@ library Dynamics2 { } } - /** Get an item of str (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of str + * (unchecked, returns invalid data if index overflows) + */ function getItemStr(bytes32 key, uint256 _index) internal view returns (string memory) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -268,7 +287,10 @@ library Dynamics2 { } } - /** Get an item of str (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of str (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemStr(IStore _store, bytes32 key, uint256 _index) internal view returns (string memory) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -311,20 +333,30 @@ library Dynamics2 { _store.popFromField(_tableId, _keyTuple, 1, 1); } - /** Update a slice of str at `_index` */ + /** + * Update a slice of str at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateStr(bytes32 key, uint256 _index, string memory _slice) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - StoreSwitch.updateInField(_tableId, _keyTuple, 1, _index * 1, bytes((_slice))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 1, _index * 1, bytes((_slice))); + } } - /** Update a slice of str (using the specified store) at `_index` */ + /** + * Update a slice of str (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateStr(IStore _store, bytes32 key, uint256 _index, string memory _slice) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - _store.updateInField(_tableId, _keyTuple, 1, _index * 1, bytes((_slice))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 1, _index * 1, bytes((_slice))); + } } /** Get b */ @@ -383,7 +415,10 @@ library Dynamics2 { } } - /** Get an item of b (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of b + * (unchecked, returns invalid data if index overflows) + */ function getItemB(bytes32 key, uint256 _index) internal view returns (bytes memory) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -394,7 +429,10 @@ library Dynamics2 { } } - /** Get an item of b (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of b (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemB(IStore _store, bytes32 key, uint256 _index) internal view returns (bytes memory) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -437,20 +475,30 @@ library Dynamics2 { _store.popFromField(_tableId, _keyTuple, 2, 1); } - /** Update a slice of b at `_index` */ + /** + * Update a slice of b at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateB(bytes32 key, uint256 _index, bytes memory _slice) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - StoreSwitch.updateInField(_tableId, _keyTuple, 2, _index * 1, bytes((_slice))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 2, _index * 1, bytes((_slice))); + } } - /** Update a slice of b (using the specified store) at `_index` */ + /** + * Update a slice of b (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateB(IStore _store, bytes32 key, uint256 _index, bytes memory _slice) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - _store.updateInField(_tableId, _keyTuple, 2, _index * 1, bytes((_slice))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 2, _index * 1, bytes((_slice))); + } } /** Get the full data */ @@ -501,27 +549,34 @@ library Dynamics2 { set(_store, key, _table.u64, _table.str, _table.b); } - /** Decode the tightly packed blob using this table's schema */ + /** + * Decode the tightly packed blob using this table's schema. + * Undefined behaviour for invalid blobs. + */ function decode(bytes memory _blob) internal pure returns (Dynamics2Data memory _table) { // 0 is the total byte length of static data PackedCounter _encodedLengths = PackedCounter.wrap(Bytes.slice32(_blob, 0)); // Store trims the blob if dynamic fields are all empty if (_blob.length > 0) { - uint256 _start; // skip static data length + dynamic lengths word - uint256 _end = 32; - - _start = _end; - _end += _encodedLengths.atIndex(0); + uint256 _start = 32; + uint256 _end; + unchecked { + _end = 32 + _encodedLengths.atIndex(0); + } _table.u64 = (SliceLib.getSubslice(_blob, _start, _end).decodeArray_uint64()); _start = _end; - _end += _encodedLengths.atIndex(1); + unchecked { + _end += _encodedLengths.atIndex(1); + } _table.str = (string(SliceLib.getSubslice(_blob, _start, _end).toBytes())); _start = _end; - _end += _encodedLengths.atIndex(2); + unchecked { + _end += _encodedLengths.atIndex(2); + } _table.b = (bytes(SliceLib.getSubslice(_blob, _start, _end).toBytes())); } } diff --git a/packages/cli/contracts/src/codegen/tables/Singleton.sol b/packages/cli/contracts/src/codegen/tables/Singleton.sol index 12da04a33b..30fac036d9 100644 --- a/packages/cli/contracts/src/codegen/tables/Singleton.sol +++ b/packages/cli/contracts/src/codegen/tables/Singleton.sol @@ -150,7 +150,10 @@ library Singleton { } } - /** Get an item of v2 (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of v2 + * (unchecked, returns invalid data if index overflows) + */ function getItemV2(uint256 _index) internal view returns (uint32) { bytes32[] memory _keyTuple = new bytes32[](0); @@ -160,7 +163,10 @@ library Singleton { } } - /** Get an item of v2 (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of v2 (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemV2(IStore _store, uint256 _index) internal view returns (uint32) { bytes32[] memory _keyTuple = new bytes32[](0); @@ -198,18 +204,28 @@ library Singleton { _store.popFromField(_tableId, _keyTuple, 1, 4); } - /** Update an element of v2 at `_index` */ + /** + * Update an element of v2 at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateV2(uint256 _index, uint32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](0); - StoreSwitch.updateInField(_tableId, _keyTuple, 1, _index * 4, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 1, _index * 4, abi.encodePacked((_element))); + } } - /** Update an element of v2 (using the specified store) at `_index` */ + /** + * Update an element of v2 (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateV2(IStore _store, uint256 _index, uint32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](0); - _store.updateInField(_tableId, _keyTuple, 1, _index * 4, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 1, _index * 4, abi.encodePacked((_element))); + } } /** Get v3 */ @@ -262,7 +278,10 @@ library Singleton { } } - /** Get an item of v3 (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of v3 + * (unchecked, returns invalid data if index overflows) + */ function getItemV3(uint256 _index) internal view returns (uint32) { bytes32[] memory _keyTuple = new bytes32[](0); @@ -272,7 +291,10 @@ library Singleton { } } - /** Get an item of v3 (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of v3 (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemV3(IStore _store, uint256 _index) internal view returns (uint32) { bytes32[] memory _keyTuple = new bytes32[](0); @@ -310,18 +332,28 @@ library Singleton { _store.popFromField(_tableId, _keyTuple, 2, 4); } - /** Update an element of v3 at `_index` */ + /** + * Update an element of v3 at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateV3(uint256 _index, uint32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](0); - StoreSwitch.updateInField(_tableId, _keyTuple, 2, _index * 4, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 2, _index * 4, abi.encodePacked((_element))); + } } - /** Update an element of v3 (using the specified store) at `_index` */ + /** + * Update an element of v3 (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateV3(IStore _store, uint256 _index, uint32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](0); - _store.updateInField(_tableId, _keyTuple, 2, _index * 4, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 2, _index * 4, abi.encodePacked((_element))); + } } /** Get v4 */ @@ -374,7 +406,10 @@ library Singleton { } } - /** Get an item of v4 (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of v4 + * (unchecked, returns invalid data if index overflows) + */ function getItemV4(uint256 _index) internal view returns (uint32) { bytes32[] memory _keyTuple = new bytes32[](0); @@ -384,7 +419,10 @@ library Singleton { } } - /** Get an item of v4 (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of v4 (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemV4(IStore _store, uint256 _index) internal view returns (uint32) { bytes32[] memory _keyTuple = new bytes32[](0); @@ -422,18 +460,28 @@ library Singleton { _store.popFromField(_tableId, _keyTuple, 3, 4); } - /** Update an element of v4 at `_index` */ + /** + * Update an element of v4 at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateV4(uint256 _index, uint32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](0); - StoreSwitch.updateInField(_tableId, _keyTuple, 3, _index * 4, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 3, _index * 4, abi.encodePacked((_element))); + } } - /** Update an element of v4 (using the specified store) at `_index` */ + /** + * Update an element of v4 (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateV4(IStore _store, uint256 _index, uint32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](0); - _store.updateInField(_tableId, _keyTuple, 3, _index * 4, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 3, _index * 4, abi.encodePacked((_element))); + } } /** Get the full data */ @@ -472,7 +520,10 @@ library Singleton { _store.setRecord(_tableId, _keyTuple, _data); } - /** Decode the tightly packed blob using this table's schema */ + /** + * Decode the tightly packed blob using this table's schema. + * Undefined behaviour for invalid blobs. + */ function decode( bytes memory _blob ) internal pure returns (int256 v1, uint32[2] memory v2, uint32[2] memory v3, uint32[1] memory v4) { @@ -483,20 +534,24 @@ library Singleton { // Store trims the blob if dynamic fields are all empty if (_blob.length > 32) { - uint256 _start; // skip static data length + dynamic lengths word - uint256 _end = 64; - - _start = _end; - _end += _encodedLengths.atIndex(0); + uint256 _start = 64; + uint256 _end; + unchecked { + _end = 64 + _encodedLengths.atIndex(0); + } v2 = toStaticArray_uint32_2(SliceLib.getSubslice(_blob, _start, _end).decodeArray_uint32()); _start = _end; - _end += _encodedLengths.atIndex(1); + unchecked { + _end += _encodedLengths.atIndex(1); + } v3 = toStaticArray_uint32_2(SliceLib.getSubslice(_blob, _start, _end).decodeArray_uint32()); _start = _end; - _end += _encodedLengths.atIndex(2); + unchecked { + _end += _encodedLengths.atIndex(2); + } v4 = toStaticArray_uint32_1(SliceLib.getSubslice(_blob, _start, _end).decodeArray_uint32()); } } diff --git a/packages/store/src/codegen/tables/Callbacks.sol b/packages/store/src/codegen/tables/Callbacks.sol index 1ffc7e4f81..e3983aded6 100644 --- a/packages/store/src/codegen/tables/Callbacks.sol +++ b/packages/store/src/codegen/tables/Callbacks.sol @@ -121,7 +121,10 @@ library Callbacks { } } - /** Get an item of value (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of value + * (unchecked, returns invalid data if index overflows) + */ function getItem(bytes32 key, uint256 _index) internal view returns (bytes24) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -139,7 +142,10 @@ library Callbacks { } } - /** Get an item of value (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of value (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItem(IStore _store, bytes32 key, uint256 _index) internal view returns (bytes24) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -182,7 +188,10 @@ library Callbacks { _store.popFromField(_tableId, _keyTuple, 0, 24); } - /** Update an element of value at `_index` */ + /** + * Update an element of value at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function update(bytes32 key, uint256 _index, bytes24 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -192,7 +201,10 @@ library Callbacks { } } - /** Update an element of value (using the specified store) at `_index` */ + /** + * Update an element of value (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function update(IStore _store, bytes32 key, uint256 _index, bytes24 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; diff --git a/packages/store/src/codegen/tables/Hooks.sol b/packages/store/src/codegen/tables/Hooks.sol index 806df82776..4708636baa 100644 --- a/packages/store/src/codegen/tables/Hooks.sol +++ b/packages/store/src/codegen/tables/Hooks.sol @@ -121,7 +121,10 @@ library Hooks { } } - /** Get an item of value (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of value + * (unchecked, returns invalid data if index overflows) + */ function getItem(bytes32 key, uint256 _index) internal view returns (address) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -139,7 +142,10 @@ library Hooks { } } - /** Get an item of value (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of value (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItem(IStore _store, bytes32 key, uint256 _index) internal view returns (address) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -182,7 +188,10 @@ library Hooks { _store.popFromField(_tableId, _keyTuple, 0, 20); } - /** Update an element of value at `_index` */ + /** + * Update an element of value at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function update(bytes32 key, uint256 _index, address _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -192,7 +201,10 @@ library Hooks { } } - /** Update an element of value (using the specified store) at `_index` */ + /** + * Update an element of value (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function update(IStore _store, bytes32 key, uint256 _index, address _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; diff --git a/packages/store/src/codegen/tables/Mixed.sol b/packages/store/src/codegen/tables/Mixed.sol index d7f5651d29..23ce59dbc2 100644 --- a/packages/store/src/codegen/tables/Mixed.sol +++ b/packages/store/src/codegen/tables/Mixed.sol @@ -202,7 +202,10 @@ library Mixed { } } - /** Get an item of a32 (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of a32 + * (unchecked, returns invalid data if index overflows) + */ function getItemA32(bytes32 key, uint256 _index) internal view returns (uint32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -213,7 +216,10 @@ library Mixed { } } - /** Get an item of a32 (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of a32 (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemA32(IStore _store, bytes32 key, uint256 _index) internal view returns (uint32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -256,7 +262,10 @@ library Mixed { _store.popFromField(_tableId, _keyTuple, 2, 4); } - /** Update an element of a32 at `_index` */ + /** + * Update an element of a32 at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateA32(bytes32 key, uint256 _index, uint32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -266,7 +275,10 @@ library Mixed { } } - /** Update an element of a32 (using the specified store) at `_index` */ + /** + * Update an element of a32 (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateA32(IStore _store, bytes32 key, uint256 _index, uint32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -332,7 +344,10 @@ library Mixed { } } - /** Get an item of s (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of s + * (unchecked, returns invalid data if index overflows) + */ function getItemS(bytes32 key, uint256 _index) internal view returns (string memory) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -343,7 +358,10 @@ library Mixed { } } - /** Get an item of s (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of s (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemS(IStore _store, bytes32 key, uint256 _index) internal view returns (string memory) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -386,7 +404,10 @@ library Mixed { _store.popFromField(_tableId, _keyTuple, 3, 1); } - /** Update a slice of s at `_index` */ + /** + * Update a slice of s at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateS(bytes32 key, uint256 _index, string memory _slice) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -396,7 +417,10 @@ library Mixed { } } - /** Update a slice of s (using the specified store) at `_index` */ + /** + * Update a slice of s (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateS(IStore _store, bytes32 key, uint256 _index, string memory _slice) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; diff --git a/packages/store/src/codegen/tables/StoreMetadata.sol b/packages/store/src/codegen/tables/StoreMetadata.sol index e39d33988b..02012dce67 100644 --- a/packages/store/src/codegen/tables/StoreMetadata.sol +++ b/packages/store/src/codegen/tables/StoreMetadata.sol @@ -128,7 +128,10 @@ library StoreMetadata { } } - /** Get an item of tableName (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of tableName + * (unchecked, returns invalid data if index overflows) + */ function getItemTableName(bytes32 tableId, uint256 _index) internal view returns (string memory) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = tableId; @@ -139,7 +142,10 @@ library StoreMetadata { } } - /** Get an item of tableName (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of tableName (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemTableName(IStore _store, bytes32 tableId, uint256 _index) internal view returns (string memory) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = tableId; @@ -182,7 +188,10 @@ library StoreMetadata { _store.popFromField(_tableId, _keyTuple, 0, 1); } - /** Update a slice of tableName at `_index` */ + /** + * Update a slice of tableName at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateTableName(bytes32 tableId, uint256 _index, string memory _slice) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = tableId; @@ -192,7 +201,10 @@ library StoreMetadata { } } - /** Update a slice of tableName (using the specified store) at `_index` */ + /** + * Update a slice of tableName (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateTableName(IStore _store, bytes32 tableId, uint256 _index, string memory _slice) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = tableId; @@ -261,7 +273,10 @@ library StoreMetadata { } } - /** Get an item of abiEncodedFieldNames (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of abiEncodedFieldNames + * (unchecked, returns invalid data if index overflows) + */ function getItemAbiEncodedFieldNames(bytes32 tableId, uint256 _index) internal view returns (bytes memory) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = tableId; @@ -272,7 +287,10 @@ library StoreMetadata { } } - /** Get an item of abiEncodedFieldNames (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of abiEncodedFieldNames (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemAbiEncodedFieldNames( IStore _store, bytes32 tableId, @@ -319,7 +337,10 @@ library StoreMetadata { _store.popFromField(_tableId, _keyTuple, 1, 1); } - /** Update a slice of abiEncodedFieldNames at `_index` */ + /** + * Update a slice of abiEncodedFieldNames at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateAbiEncodedFieldNames(bytes32 tableId, uint256 _index, bytes memory _slice) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = tableId; @@ -329,7 +350,10 @@ library StoreMetadata { } } - /** Update a slice of abiEncodedFieldNames (using the specified store) at `_index` */ + /** + * Update a slice of abiEncodedFieldNames (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateAbiEncodedFieldNames(IStore _store, bytes32 tableId, uint256 _index, bytes memory _slice) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = tableId; diff --git a/packages/store/ts/codegen/field.ts b/packages/store/ts/codegen/field.ts index ae06464048..7b3c5a5758 100644 --- a/packages/store/ts/codegen/field.ts +++ b/packages/store/ts/codegen/field.ts @@ -71,7 +71,10 @@ export function renderFieldMethods(options: RenderTableOptions) { result += renderWithStore( storeArgument, (_typedStore, _store, _commentSuffix) => ` - /** Get an item of ${field.name}${_commentSuffix} (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of ${field.name}${_commentSuffix} + * (unchecked, returns invalid data if index overflows) + */ function getItem${field.methodNameSuffix}(${renderArguments([ _typedStore, _typedTableId, @@ -128,7 +131,10 @@ export function renderFieldMethods(options: RenderTableOptions) { result += renderWithStore( storeArgument, (_typedStore, _store, _commentSuffix) => ` - /** Update ${portionData.title} of ${field.name}${_commentSuffix} at \`_index\` */ + /** + * Update ${portionData.title} of ${field.name}${_commentSuffix} at \`_index\` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function update${field.methodNameSuffix}(${renderArguments([ _typedStore, _typedTableId, diff --git a/packages/world/gas-report.json b/packages/world/gas-report.json index 0416375d8e..9926b8903a 100644 --- a/packages/world/gas-report.json +++ b/packages/world/gas-report.json @@ -39,7 +39,7 @@ "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookCompositeGas", "name": "delete a composite record on a table with keysInTableModule installed", - "gasUsed": 259604 + "gasUsed": 259406 }, { "file": "test/KeysInTableModule.t.sol", @@ -57,7 +57,7 @@ "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookGas", "name": "delete a record on a table with keysInTableModule installed", - "gasUsed": 136250 + "gasUsed": 136184 }, { "file": "test/KeysWithValueModule.t.sol", diff --git a/packages/world/src/modules/core/tables/SystemHooks.sol b/packages/world/src/modules/core/tables/SystemHooks.sol index d95f039550..e0aa0f43e0 100644 --- a/packages/world/src/modules/core/tables/SystemHooks.sol +++ b/packages/world/src/modules/core/tables/SystemHooks.sol @@ -121,7 +121,10 @@ library SystemHooks { } } - /** Get an item of value (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of value + * (unchecked, returns invalid data if index overflows) + */ function getItem(bytes32 resourceSelector, uint256 _index) internal view returns (address) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = resourceSelector; @@ -139,7 +142,10 @@ library SystemHooks { } } - /** Get an item of value (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of value (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItem(IStore _store, bytes32 resourceSelector, uint256 _index) internal view returns (address) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = resourceSelector; @@ -182,20 +188,30 @@ library SystemHooks { _store.popFromField(_tableId, _keyTuple, 0, 20); } - /** Update an element of value at `_index` */ + /** + * Update an element of value at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function update(bytes32 resourceSelector, uint256 _index, address _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = resourceSelector; - StoreSwitch.updateInField(_tableId, _keyTuple, 0, _index * 20, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 0, _index * 20, abi.encodePacked((_element))); + } } - /** Update an element of value (using the specified store) at `_index` */ + /** + * Update an element of value (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function update(IStore _store, bytes32 resourceSelector, uint256 _index, address _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = resourceSelector; - _store.updateInField(_tableId, _keyTuple, 0, _index * 20, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 0, _index * 20, abi.encodePacked((_element))); + } } /** Tightly pack full data using this table's schema */ diff --git a/packages/world/src/modules/keysintable/tables/KeysInTable.sol b/packages/world/src/modules/keysintable/tables/KeysInTable.sol index af67199af0..dde965f55e 100644 --- a/packages/world/src/modules/keysintable/tables/KeysInTable.sol +++ b/packages/world/src/modules/keysintable/tables/KeysInTable.sol @@ -137,7 +137,10 @@ library KeysInTable { } } - /** Get an item of keys0 (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of keys0 + * (unchecked, returns invalid data if index overflows) + */ function getItemKeys0(bytes32 sourceTable, uint256 _index) internal view returns (bytes32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; @@ -155,7 +158,10 @@ library KeysInTable { } } - /** Get an item of keys0 (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of keys0 (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemKeys0(IStore _store, bytes32 sourceTable, uint256 _index) internal view returns (bytes32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; @@ -198,20 +204,30 @@ library KeysInTable { _store.popFromField(_tableId, _keyTuple, 0, 32); } - /** Update an element of keys0 at `_index` */ + /** + * Update an element of keys0 at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateKeys0(bytes32 sourceTable, uint256 _index, bytes32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; - StoreSwitch.updateInField(_tableId, _keyTuple, 0, _index * 32, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 0, _index * 32, abi.encodePacked((_element))); + } } - /** Update an element of keys0 (using the specified store) at `_index` */ + /** + * Update an element of keys0 (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateKeys0(IStore _store, bytes32 sourceTable, uint256 _index, bytes32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; - _store.updateInField(_tableId, _keyTuple, 0, _index * 32, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 0, _index * 32, abi.encodePacked((_element))); + } } /** Get keys1 */ @@ -270,7 +286,10 @@ library KeysInTable { } } - /** Get an item of keys1 (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of keys1 + * (unchecked, returns invalid data if index overflows) + */ function getItemKeys1(bytes32 sourceTable, uint256 _index) internal view returns (bytes32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; @@ -288,7 +307,10 @@ library KeysInTable { } } - /** Get an item of keys1 (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of keys1 (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemKeys1(IStore _store, bytes32 sourceTable, uint256 _index) internal view returns (bytes32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; @@ -331,20 +353,30 @@ library KeysInTable { _store.popFromField(_tableId, _keyTuple, 1, 32); } - /** Update an element of keys1 at `_index` */ + /** + * Update an element of keys1 at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateKeys1(bytes32 sourceTable, uint256 _index, bytes32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; - StoreSwitch.updateInField(_tableId, _keyTuple, 1, _index * 32, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 1, _index * 32, abi.encodePacked((_element))); + } } - /** Update an element of keys1 (using the specified store) at `_index` */ + /** + * Update an element of keys1 (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateKeys1(IStore _store, bytes32 sourceTable, uint256 _index, bytes32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; - _store.updateInField(_tableId, _keyTuple, 1, _index * 32, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 1, _index * 32, abi.encodePacked((_element))); + } } /** Get keys2 */ @@ -403,7 +435,10 @@ library KeysInTable { } } - /** Get an item of keys2 (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of keys2 + * (unchecked, returns invalid data if index overflows) + */ function getItemKeys2(bytes32 sourceTable, uint256 _index) internal view returns (bytes32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; @@ -421,7 +456,10 @@ library KeysInTable { } } - /** Get an item of keys2 (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of keys2 (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemKeys2(IStore _store, bytes32 sourceTable, uint256 _index) internal view returns (bytes32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; @@ -464,20 +502,30 @@ library KeysInTable { _store.popFromField(_tableId, _keyTuple, 2, 32); } - /** Update an element of keys2 at `_index` */ + /** + * Update an element of keys2 at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateKeys2(bytes32 sourceTable, uint256 _index, bytes32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; - StoreSwitch.updateInField(_tableId, _keyTuple, 2, _index * 32, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 2, _index * 32, abi.encodePacked((_element))); + } } - /** Update an element of keys2 (using the specified store) at `_index` */ + /** + * Update an element of keys2 (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateKeys2(IStore _store, bytes32 sourceTable, uint256 _index, bytes32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; - _store.updateInField(_tableId, _keyTuple, 2, _index * 32, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 2, _index * 32, abi.encodePacked((_element))); + } } /** Get keys3 */ @@ -536,7 +584,10 @@ library KeysInTable { } } - /** Get an item of keys3 (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of keys3 + * (unchecked, returns invalid data if index overflows) + */ function getItemKeys3(bytes32 sourceTable, uint256 _index) internal view returns (bytes32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; @@ -554,7 +605,10 @@ library KeysInTable { } } - /** Get an item of keys3 (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of keys3 (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemKeys3(IStore _store, bytes32 sourceTable, uint256 _index) internal view returns (bytes32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; @@ -597,20 +651,30 @@ library KeysInTable { _store.popFromField(_tableId, _keyTuple, 3, 32); } - /** Update an element of keys3 at `_index` */ + /** + * Update an element of keys3 at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateKeys3(bytes32 sourceTable, uint256 _index, bytes32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; - StoreSwitch.updateInField(_tableId, _keyTuple, 3, _index * 32, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 3, _index * 32, abi.encodePacked((_element))); + } } - /** Update an element of keys3 (using the specified store) at `_index` */ + /** + * Update an element of keys3 (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateKeys3(IStore _store, bytes32 sourceTable, uint256 _index, bytes32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; - _store.updateInField(_tableId, _keyTuple, 3, _index * 32, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 3, _index * 32, abi.encodePacked((_element))); + } } /** Get keys4 */ @@ -669,7 +733,10 @@ library KeysInTable { } } - /** Get an item of keys4 (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of keys4 + * (unchecked, returns invalid data if index overflows) + */ function getItemKeys4(bytes32 sourceTable, uint256 _index) internal view returns (bytes32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; @@ -687,7 +754,10 @@ library KeysInTable { } } - /** Get an item of keys4 (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of keys4 (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItemKeys4(IStore _store, bytes32 sourceTable, uint256 _index) internal view returns (bytes32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; @@ -730,20 +800,30 @@ library KeysInTable { _store.popFromField(_tableId, _keyTuple, 4, 32); } - /** Update an element of keys4 at `_index` */ + /** + * Update an element of keys4 at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateKeys4(bytes32 sourceTable, uint256 _index, bytes32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; - StoreSwitch.updateInField(_tableId, _keyTuple, 4, _index * 32, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 4, _index * 32, abi.encodePacked((_element))); + } } - /** Update an element of keys4 (using the specified store) at `_index` */ + /** + * Update an element of keys4 (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function updateKeys4(IStore _store, bytes32 sourceTable, uint256 _index, bytes32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = sourceTable; - _store.updateInField(_tableId, _keyTuple, 4, _index * 32, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 4, _index * 32, abi.encodePacked((_element))); + } } /** Get the full data */ @@ -809,35 +889,46 @@ library KeysInTable { set(_store, sourceTable, _table.keys0, _table.keys1, _table.keys2, _table.keys3, _table.keys4); } - /** Decode the tightly packed blob using this table's schema */ + /** + * Decode the tightly packed blob using this table's schema. + * Undefined behaviour for invalid blobs. + */ function decode(bytes memory _blob) internal pure returns (KeysInTableData memory _table) { // 0 is the total byte length of static data PackedCounter _encodedLengths = PackedCounter.wrap(Bytes.slice32(_blob, 0)); // Store trims the blob if dynamic fields are all empty if (_blob.length > 0) { - uint256 _start; // skip static data length + dynamic lengths word - uint256 _end = 32; - - _start = _end; - _end += _encodedLengths.atIndex(0); + uint256 _start = 32; + uint256 _end; + unchecked { + _end = 32 + _encodedLengths.atIndex(0); + } _table.keys0 = (SliceLib.getSubslice(_blob, _start, _end).decodeArray_bytes32()); _start = _end; - _end += _encodedLengths.atIndex(1); + unchecked { + _end += _encodedLengths.atIndex(1); + } _table.keys1 = (SliceLib.getSubslice(_blob, _start, _end).decodeArray_bytes32()); _start = _end; - _end += _encodedLengths.atIndex(2); + unchecked { + _end += _encodedLengths.atIndex(2); + } _table.keys2 = (SliceLib.getSubslice(_blob, _start, _end).decodeArray_bytes32()); _start = _end; - _end += _encodedLengths.atIndex(3); + unchecked { + _end += _encodedLengths.atIndex(3); + } _table.keys3 = (SliceLib.getSubslice(_blob, _start, _end).decodeArray_bytes32()); _start = _end; - _end += _encodedLengths.atIndex(4); + unchecked { + _end += _encodedLengths.atIndex(4); + } _table.keys4 = (SliceLib.getSubslice(_blob, _start, _end).decodeArray_bytes32()); } } diff --git a/packages/world/src/modules/keyswithvalue/tables/KeysWithValue.sol b/packages/world/src/modules/keyswithvalue/tables/KeysWithValue.sol index 9c063f31c5..7195986076 100644 --- a/packages/world/src/modules/keyswithvalue/tables/KeysWithValue.sol +++ b/packages/world/src/modules/keyswithvalue/tables/KeysWithValue.sol @@ -122,7 +122,10 @@ library KeysWithValue { } } - /** Get an item of keysWithValue (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of keysWithValue + * (unchecked, returns invalid data if index overflows) + */ function getItem(bytes32 _tableId, bytes32 valueHash, uint256 _index) internal view returns (bytes32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = valueHash; @@ -140,7 +143,10 @@ library KeysWithValue { } } - /** Get an item of keysWithValue (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of keysWithValue (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItem(IStore _store, bytes32 _tableId, bytes32 valueHash, uint256 _index) internal view returns (bytes32) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = valueHash; @@ -183,20 +189,30 @@ library KeysWithValue { _store.popFromField(_tableId, _keyTuple, 0, 32); } - /** Update an element of keysWithValue at `_index` */ + /** + * Update an element of keysWithValue at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function update(bytes32 _tableId, bytes32 valueHash, uint256 _index, bytes32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = valueHash; - StoreSwitch.updateInField(_tableId, _keyTuple, 0, _index * 32, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 0, _index * 32, abi.encodePacked((_element))); + } } - /** Update an element of keysWithValue (using the specified store) at `_index` */ + /** + * Update an element of keysWithValue (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function update(IStore _store, bytes32 _tableId, bytes32 valueHash, uint256 _index, bytes32 _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = valueHash; - _store.updateInField(_tableId, _keyTuple, 0, _index * 32, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 0, _index * 32, abi.encodePacked((_element))); + } } /** Tightly pack full data using this table's schema */ diff --git a/packages/world/test/tables/AddressArray.sol b/packages/world/test/tables/AddressArray.sol index e11bb9f6b7..c338531100 100644 --- a/packages/world/test/tables/AddressArray.sol +++ b/packages/world/test/tables/AddressArray.sol @@ -118,7 +118,10 @@ library AddressArray { } } - /** Get an item of value (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of value + * (unchecked, returns invalid data if index overflows) + */ function getItem(bytes32 _tableId, bytes32 key, uint256 _index) internal view returns (address) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -136,7 +139,10 @@ library AddressArray { } } - /** Get an item of value (using the specified store) (unchecked, returns invalid data if index overflows) */ + /** + * Get an item of value (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ function getItem(IStore _store, bytes32 _tableId, bytes32 key, uint256 _index) internal view returns (address) { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; @@ -179,20 +185,30 @@ library AddressArray { _store.popFromField(_tableId, _keyTuple, 0, 20); } - /** Update an element of value at `_index` */ + /** + * Update an element of value at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function update(bytes32 _tableId, bytes32 key, uint256 _index, address _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - StoreSwitch.updateInField(_tableId, _keyTuple, 0, _index * 20, abi.encodePacked((_element))); + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 0, _index * 20, abi.encodePacked((_element))); + } } - /** Update an element of value (using the specified store) at `_index` */ + /** + * Update an element of value (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ function update(IStore _store, bytes32 _tableId, bytes32 key, uint256 _index, address _element) internal { bytes32[] memory _keyTuple = new bytes32[](1); _keyTuple[0] = key; - _store.updateInField(_tableId, _keyTuple, 0, _index * 20, abi.encodePacked((_element))); + unchecked { + _store.updateInField(_tableId, _keyTuple, 0, _index * 20, abi.encodePacked((_element))); + } } /** Tightly pack full data using this table's schema */