diff --git a/e2e/packages/contracts/mud.config.ts b/e2e/packages/contracts/mud.config.ts index 23841e30aa..8ef93cf956 100644 --- a/e2e/packages/contracts/mud.config.ts +++ b/e2e/packages/contracts/mud.config.ts @@ -49,7 +49,7 @@ export default mudConfig({ }, StaticArray: { keySchema: {}, - valueSchema: "uint256[2]", + valueSchema: "uint256[3]", }, }, }); diff --git a/e2e/packages/contracts/src/codegen/tables/StaticArray.sol b/e2e/packages/contracts/src/codegen/tables/StaticArray.sol index 99d6b62320..b1d4c52261 100644 --- a/e2e/packages/contracts/src/codegen/tables/StaticArray.sol +++ b/e2e/packages/contracts/src/codegen/tables/StaticArray.sol @@ -62,105 +62,105 @@ library StaticArray { /** * @notice Get value. */ - function getValue() internal view returns (uint256[2] memory value) { + function getValue() internal view returns (uint256[3] memory value) { bytes32[] memory _keyTuple = new bytes32[](0); bytes memory _blob = StoreSwitch.getDynamicField(_tableId, _keyTuple, 0); - return toStaticArray_uint256_2(SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_uint256()); + return toStaticArray_uint256_3(SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_uint256()); } /** * @notice Get value. */ - function _getValue() internal view returns (uint256[2] memory value) { + function _getValue() internal view returns (uint256[3] memory value) { bytes32[] memory _keyTuple = new bytes32[](0); bytes memory _blob = StoreCore.getDynamicField(_tableId, _keyTuple, 0); - return toStaticArray_uint256_2(SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_uint256()); + return toStaticArray_uint256_3(SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_uint256()); } /** * @notice Get value. */ - function get() internal view returns (uint256[2] memory value) { + function get() internal view returns (uint256[3] memory value) { bytes32[] memory _keyTuple = new bytes32[](0); bytes memory _blob = StoreSwitch.getDynamicField(_tableId, _keyTuple, 0); - return toStaticArray_uint256_2(SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_uint256()); + return toStaticArray_uint256_3(SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_uint256()); } /** * @notice Get value. */ - function _get() internal view returns (uint256[2] memory value) { + function _get() internal view returns (uint256[3] memory value) { bytes32[] memory _keyTuple = new bytes32[](0); bytes memory _blob = StoreCore.getDynamicField(_tableId, _keyTuple, 0); - return toStaticArray_uint256_2(SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_uint256()); + return toStaticArray_uint256_3(SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_uint256()); } /** * @notice Set value. */ - function setValue(uint256[2] memory value) internal { + function setValue(uint256[3] memory value) internal { bytes32[] memory _keyTuple = new bytes32[](0); - StoreSwitch.setDynamicField(_tableId, _keyTuple, 0, EncodeArray.encode(fromStaticArray_uint256_2(value))); + StoreSwitch.setDynamicField(_tableId, _keyTuple, 0, EncodeArray.encode(fromStaticArray_uint256_3(value))); } /** * @notice Set value. */ - function _setValue(uint256[2] memory value) internal { + function _setValue(uint256[3] memory value) internal { bytes32[] memory _keyTuple = new bytes32[](0); - StoreCore.setDynamicField(_tableId, _keyTuple, 0, EncodeArray.encode(fromStaticArray_uint256_2(value))); + StoreCore.setDynamicField(_tableId, _keyTuple, 0, EncodeArray.encode(fromStaticArray_uint256_3(value))); } /** * @notice Set value. */ - function set(uint256[2] memory value) internal { + function set(uint256[3] memory value) internal { bytes32[] memory _keyTuple = new bytes32[](0); - StoreSwitch.setDynamicField(_tableId, _keyTuple, 0, EncodeArray.encode(fromStaticArray_uint256_2(value))); + StoreSwitch.setDynamicField(_tableId, _keyTuple, 0, EncodeArray.encode(fromStaticArray_uint256_3(value))); } /** * @notice Set value. */ - function _set(uint256[2] memory value) internal { + function _set(uint256[3] memory value) internal { bytes32[] memory _keyTuple = new bytes32[](0); - StoreCore.setDynamicField(_tableId, _keyTuple, 0, EncodeArray.encode(fromStaticArray_uint256_2(value))); + StoreCore.setDynamicField(_tableId, _keyTuple, 0, EncodeArray.encode(fromStaticArray_uint256_3(value))); } /** * @notice Get the length of value. */ function lengthValue() internal pure returns (uint256) { - return 2; + return 3; } /** * @notice Get the length of value. */ function _lengthValue() internal pure returns (uint256) { - return 2; + return 3; } /** * @notice Get the length of value. */ function length() internal pure returns (uint256) { - return 2; + return 3; } /** * @notice Get the length of value. */ function _length() internal pure returns (uint256) { - return 2; + return 3; } /** @@ -285,7 +285,7 @@ library StaticArray { * @notice Tightly pack dynamic data lengths using this table's schema. * @return _encodedLengths The lengths of the dynamic fields (packed into a single bytes32 value). */ - function encodeLengths(uint256[2] memory value) internal pure returns (PackedCounter _encodedLengths) { + function encodeLengths(uint256[3] memory value) internal pure returns (PackedCounter _encodedLengths) { // Lengths are effectively checked during copy by 2**40 bytes exceeding gas limits unchecked { _encodedLengths = PackedCounterLib.pack(value.length * 32); @@ -296,8 +296,8 @@ library StaticArray { * @notice Tightly pack dynamic (variable length) data using this table's schema. * @return The dynamic data, encoded into a sequence of bytes. */ - function encodeDynamic(uint256[2] memory value) internal pure returns (bytes memory) { - return abi.encodePacked(EncodeArray.encode(fromStaticArray_uint256_2(value))); + function encodeDynamic(uint256[3] memory value) internal pure returns (bytes memory) { + return abi.encodePacked(EncodeArray.encode(fromStaticArray_uint256_3(value))); } /** @@ -306,7 +306,7 @@ library StaticArray { * @return The lengths of the dynamic fields (packed into a single bytes32 value). * @return The dynamic (variable length) data, encoded into a sequence of bytes. */ - function encode(uint256[2] memory value) internal pure returns (bytes memory, PackedCounter, bytes memory) { + function encode(uint256[3] memory value) internal pure returns (bytes memory, PackedCounter, bytes memory) { bytes memory _staticData; PackedCounter _encodedLengths = encodeLengths(value); bytes memory _dynamicData = encodeDynamic(value); @@ -333,8 +333,8 @@ library StaticArray { * @param _value The dynamic array to cast. * @return _result The static array. */ -function toStaticArray_uint256_2(uint256[] memory _value) pure returns (uint256[2] memory _result) { - if (_value.length < 2) { +function toStaticArray_uint256_3(uint256[] memory _value) pure returns (uint256[3] memory _result) { + if (_value.length < 3) { // return an uninitialized array if the length is smaller than the fixed length to avoid memory corruption return _result; } else { @@ -352,13 +352,13 @@ function toStaticArray_uint256_2(uint256[] memory _value) pure returns (uint256[ * @param _value The static array to copy. * @return _result The dynamic array. */ -function fromStaticArray_uint256_2(uint256[2] memory _value) pure returns (uint256[] memory _result) { - _result = new uint256[](2); +function fromStaticArray_uint256_3(uint256[3] memory _value) pure returns (uint256[] memory _result) { + _result = new uint256[](3); uint256 fromPointer; uint256 toPointer; assembly { fromPointer := _value toPointer := add(_result, 0x20) } - Memory.copy(fromPointer, toPointer, 64); + Memory.copy(fromPointer, toPointer, 96); } diff --git a/e2e/packages/contracts/test/StaticArray.t.sol b/e2e/packages/contracts/test/StaticArray.t.sol index 94e3723aeb..2d770b2aab 100644 --- a/e2e/packages/contracts/test/StaticArray.t.sol +++ b/e2e/packages/contracts/test/StaticArray.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.24; import { MudTest } from "@latticexyz/world/test/MudTest.t.sol"; -import { toStaticArray_uint256_2 } from "../src/codegen/tables/StaticArray.sol"; +import { toStaticArray_uint256_3 } from "../src/codegen/tables/StaticArray.sol"; contract StaticArrayTest is MudTest { uint256 internal memoryCorruptionCheck = uint256(keccak256("memoryCorruptionCheck")); @@ -12,32 +12,42 @@ contract StaticArrayTest is MudTest { * Test that the data is correctly copied when the dynamic and static arrays are the same length */ function testMemoryCorruptionSameLength() public { - uint256[] memory data = new uint256[](2); + uint256[] memory data = new uint256[](3); data[0] = 1; data[1] = 2; + data[2] = memoryCorruptionCheck; - uint256[2] memory result = toStaticArray_uint256_2(data); + uint256[3] memory result = toStaticArray_uint256_3(data); assertEq(result[0], 1); assertEq(result[1], 2); + + uint256 memoryAfterResult; + assembly { + memoryAfterResult := mload(add(result, 0x40)) + mstore(0x40, add(mload(0x40), 0x40)) + } + assertEq(memoryAfterResult, memoryCorruptionCheck); } /* * Test that the data is correctly copied when the dynamic array is longer */ function testMemoryCorruptionLongerDynamic() public { - uint256[] memory data = new uint256[](3); + uint256[] memory data = new uint256[](4); data[0] = 1; data[1] = 2; - data[2] = memoryCorruptionCheck; + data[2] = 3; + data[3] = memoryCorruptionCheck; - uint256[2] memory result = toStaticArray_uint256_2(data); + uint256[3] memory result = toStaticArray_uint256_3(data); assertEq(result[0], 1); assertEq(result[1], 2); + assertEq(result[2], 3); uint256 memoryAfterResult; assembly { - memoryAfterResult := mload(add(result, 0x40)) - mstore(0x40, add(mload(0x40), 0x20)) + memoryAfterResult := mload(add(result, 0x60)) + mstore(0x40, add(mload(0x40), 0x30)) } assertEq(memoryAfterResult, memoryCorruptionCheck); } @@ -46,11 +56,18 @@ contract StaticArrayTest is MudTest { * Test that an uninitialized array is returned when the dynamic array is shorter */ function testMemoryCorruptionShorterDynamic() public { - uint256[] memory data = new uint256[](1); + uint256[] memory data = new uint256[](2); data[0] = 1; + data[1] = memoryCorruptionCheck; - uint256[2] memory result = toStaticArray_uint256_2(data); + uint256[3] memory result = toStaticArray_uint256_3(data); assertEq(result[0], 0); - assertEq(result[1], 0); + + uint256 memoryAfterResult; + assembly { + memoryAfterResult := mload(add(result, 0x20)) + mstore(0x40, add(mload(0x40), 0x20)) + } + assertNotEq(memoryAfterResult, memoryCorruptionCheck); } }