From c9574545676d760df07fe2bd4023517a72c29946 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Mon, 22 Jan 2024 13:59:44 +0000 Subject: [PATCH 1/7] fix(world): add WorldInitialized flag --- packages/world-modules/gas-report.json | 20 +- packages/world/gas-report.json | 4 +- packages/world/mud.config.ts | 6 + packages/world/src/World.sol | 5 +- packages/world/src/codegen/index.sol | 1 + .../src/codegen/tables/WorldInitialized.sol | 230 ++++++++++++++++++ .../world/src/modules/core/CoreModule.sol | 2 + 7 files changed, 255 insertions(+), 13 deletions(-) create mode 100644 packages/world/src/codegen/tables/WorldInitialized.sol diff --git a/packages/world-modules/gas-report.json b/packages/world-modules/gas-report.json index 33c0de667b..31df5ceb17 100644 --- a/packages/world-modules/gas-report.json +++ b/packages/world-modules/gas-report.json @@ -75,13 +75,13 @@ "file": "test/KeysInTableModule.t.sol", "test": "testInstallComposite", "name": "install keys in table module", - "gasUsed": 1439079 + "gasUsed": 1439061 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallGas", "name": "install keys in table module", - "gasUsed": 1439079 + "gasUsed": 1439061 }, { "file": "test/KeysInTableModule.t.sol", @@ -93,13 +93,13 @@ "file": "test/KeysInTableModule.t.sol", "test": "testInstallSingleton", "name": "install keys in table module", - "gasUsed": 1439079 + "gasUsed": 1439061 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookCompositeGas", "name": "install keys in table module", - "gasUsed": 1439079 + "gasUsed": 1439061 }, { "file": "test/KeysInTableModule.t.sol", @@ -117,7 +117,7 @@ "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookGas", "name": "install keys in table module", - "gasUsed": 1439079 + "gasUsed": 1439061 }, { "file": "test/KeysInTableModule.t.sol", @@ -135,7 +135,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testGetKeysWithValueGas", "name": "install keys with value module", - "gasUsed": 684459 + "gasUsed": 684441 }, { "file": "test/KeysWithValueModule.t.sol", @@ -153,7 +153,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testInstall", "name": "install keys with value module", - "gasUsed": 684459 + "gasUsed": 684441 }, { "file": "test/KeysWithValueModule.t.sol", @@ -165,7 +165,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testSetAndDeleteRecordHook", "name": "install keys with value module", - "gasUsed": 684459 + "gasUsed": 684441 }, { "file": "test/KeysWithValueModule.t.sol", @@ -183,7 +183,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testSetField", "name": "install keys with value module", - "gasUsed": 684459 + "gasUsed": 684441 }, { "file": "test/KeysWithValueModule.t.sol", @@ -315,7 +315,7 @@ "file": "test/UniqueEntityModule.t.sol", "test": "testInstallRoot", "name": "installRoot unique entity module", - "gasUsed": 673145 + "gasUsed": 673127 }, { "file": "test/UniqueEntityModule.t.sol", diff --git a/packages/world/gas-report.json b/packages/world/gas-report.json index 54da86f966..466a8f9c1e 100644 --- a/packages/world/gas-report.json +++ b/packages/world/gas-report.json @@ -57,13 +57,13 @@ "file": "test/Factories.t.sol", "test": "testCreate2Factory", "name": "deploy contract via Create2", - "gasUsed": 4659744 + "gasUsed": 4785208 }, { "file": "test/Factories.t.sol", "test": "testWorldFactory", "name": "deploy world via WorldFactory", - "gasUsed": 12642949 + "gasUsed": 13064063 }, { "file": "test/World.t.sol", diff --git a/packages/world/mud.config.ts b/packages/world/mud.config.ts index 73a79a1393..535511b570 100644 --- a/packages/world/mud.config.ts +++ b/packages/world/mud.config.ts @@ -103,6 +103,12 @@ export default mudConfig({ }, offchainOnly: true, }, + WorldInitialized: { + keySchema: {}, + valueSchema: { + isInitialized: "bool", + }, + }, }, excludeSystems: [ // Worldgen currently does not support systems inheriting logic diff --git a/packages/world/src/World.sol b/packages/world/src/World.sol index 6ddad55db0..5ce633923a 100644 --- a/packages/world/src/World.sol +++ b/packages/world/src/World.sol @@ -19,6 +19,7 @@ import { requireInterface } from "./requireInterface.sol"; import { InstalledModules } from "./codegen/tables/InstalledModules.sol"; import { UserDelegationControl } from "./codegen/tables/UserDelegationControl.sol"; import { NamespaceDelegationControl } from "./codegen/tables/NamespaceDelegationControl.sol"; +import { WorldInitialized } from "./codegen/tables/WorldInitialized.sol"; import { IModule, IModule } from "./IModule.sol"; import { IWorldKernel } from "./IWorldKernel.sol"; @@ -71,10 +72,12 @@ contract World is StoreData, IWorldKernel { } // The World can only be initialized once - if (InstalledModules._get(CORE_MODULE_NAME, keccak256("")) != address(0)) { + if (WorldInitialized.get()) { revert World_AlreadyInitialized(); } + WorldInitialized.set(true); + // Initialize the World by installing the core module _installRootModule(coreModule, new bytes(0)); } diff --git a/packages/world/src/codegen/index.sol b/packages/world/src/codegen/index.sol index 472f3049c3..4d4774f989 100644 --- a/packages/world/src/codegen/index.sol +++ b/packages/world/src/codegen/index.sol @@ -14,3 +14,4 @@ import { SystemRegistry, SystemRegistryTableId } from "./tables/SystemRegistry.s import { SystemHooks, SystemHooksTableId } from "./tables/SystemHooks.sol"; import { FunctionSelectors, FunctionSelectorsTableId } from "./tables/FunctionSelectors.sol"; import { FunctionSignatures, FunctionSignaturesTableId } from "./tables/FunctionSignatures.sol"; +import { WorldInitialized, WorldInitializedTableId } from "./tables/WorldInitialized.sol"; diff --git a/packages/world/src/codegen/tables/WorldInitialized.sol b/packages/world/src/codegen/tables/WorldInitialized.sol new file mode 100644 index 0000000000..1ebd9e9c32 --- /dev/null +++ b/packages/world/src/codegen/tables/WorldInitialized.sol @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.21; + +/* Autogenerated file. Do not edit manually. */ + +// Import schema type +import { SchemaType } from "@latticexyz/schema-type/src/solidity/SchemaType.sol"; + +// Import store internals +import { IStore } from "@latticexyz/store/src/IStore.sol"; +import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol"; +import { StoreCore } from "@latticexyz/store/src/StoreCore.sol"; +import { Bytes } from "@latticexyz/store/src/Bytes.sol"; +import { Memory } from "@latticexyz/store/src/Memory.sol"; +import { SliceLib } from "@latticexyz/store/src/Slice.sol"; +import { EncodeArray } from "@latticexyz/store/src/tightcoder/EncodeArray.sol"; +import { FieldLayout, FieldLayoutLib } from "@latticexyz/store/src/FieldLayout.sol"; +import { Schema, SchemaLib } from "@latticexyz/store/src/Schema.sol"; +import { PackedCounter, PackedCounterLib } from "@latticexyz/store/src/PackedCounter.sol"; +import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; +import { RESOURCE_TABLE, RESOURCE_OFFCHAIN_TABLE } from "@latticexyz/store/src/storeResourceTypes.sol"; + +ResourceId constant _tableId = ResourceId.wrap( + bytes32(abi.encodePacked(RESOURCE_TABLE, bytes14("world"), bytes16("WorldInitialized"))) +); +ResourceId constant WorldInitializedTableId = _tableId; + +FieldLayout constant _fieldLayout = FieldLayout.wrap( + 0x0001010001000000000000000000000000000000000000000000000000000000 +); + +library WorldInitialized { + /** + * @notice Get the table values' field layout. + * @return _fieldLayout The field layout for the table. + */ + function getFieldLayout() internal pure returns (FieldLayout) { + return _fieldLayout; + } + + /** + * @notice Get the table's key schema. + * @return _keySchema The key schema for the table. + */ + function getKeySchema() internal pure returns (Schema) { + SchemaType[] memory _keySchema = new SchemaType[](0); + + return SchemaLib.encode(_keySchema); + } + + /** + * @notice Get the table's value schema. + * @return _valueSchema The value schema for the table. + */ + function getValueSchema() internal pure returns (Schema) { + SchemaType[] memory _valueSchema = new SchemaType[](1); + _valueSchema[0] = SchemaType.BOOL; + + return SchemaLib.encode(_valueSchema); + } + + /** + * @notice Get the table's key field names. + * @return keyNames An array of strings with the names of key fields. + */ + function getKeyNames() internal pure returns (string[] memory keyNames) { + keyNames = new string[](0); + } + + /** + * @notice Get the table's value field names. + * @return fieldNames An array of strings with the names of value fields. + */ + function getFieldNames() internal pure returns (string[] memory fieldNames) { + fieldNames = new string[](1); + fieldNames[0] = "isInitialized"; + } + + /** + * @notice Register the table with its config. + */ + function register() internal { + StoreSwitch.registerTable(_tableId, _fieldLayout, getKeySchema(), getValueSchema(), getKeyNames(), getFieldNames()); + } + + /** + * @notice Register the table with its config. + */ + function _register() internal { + StoreCore.registerTable(_tableId, _fieldLayout, getKeySchema(), getValueSchema(), getKeyNames(), getFieldNames()); + } + + /** + * @notice Get isInitialized. + */ + function getIsInitialized() internal view returns (bool isInitialized) { + bytes32[] memory _keyTuple = new bytes32[](0); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (_toBool(uint8(bytes1(_blob)))); + } + + /** + * @notice Get isInitialized. + */ + function _getIsInitialized() internal view returns (bool isInitialized) { + bytes32[] memory _keyTuple = new bytes32[](0); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (_toBool(uint8(bytes1(_blob)))); + } + + /** + * @notice Get isInitialized. + */ + function get() internal view returns (bool isInitialized) { + bytes32[] memory _keyTuple = new bytes32[](0); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (_toBool(uint8(bytes1(_blob)))); + } + + /** + * @notice Get isInitialized. + */ + function _get() internal view returns (bool isInitialized) { + bytes32[] memory _keyTuple = new bytes32[](0); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (_toBool(uint8(bytes1(_blob)))); + } + + /** + * @notice Set isInitialized. + */ + function setIsInitialized(bool isInitialized) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((isInitialized)), _fieldLayout); + } + + /** + * @notice Set isInitialized. + */ + function _setIsInitialized(bool isInitialized) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((isInitialized)), _fieldLayout); + } + + /** + * @notice Set isInitialized. + */ + function set(bool isInitialized) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((isInitialized)), _fieldLayout); + } + + /** + * @notice Set isInitialized. + */ + function _set(bool isInitialized) internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((isInitialized)), _fieldLayout); + } + + /** + * @notice Delete all data for given keys. + */ + function deleteRecord() internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreSwitch.deleteRecord(_tableId, _keyTuple); + } + + /** + * @notice Delete all data for given keys. + */ + function _deleteRecord() internal { + bytes32[] memory _keyTuple = new bytes32[](0); + + StoreCore.deleteRecord(_tableId, _keyTuple, _fieldLayout); + } + + /** + * @notice Tightly pack static (fixed length) data using this table's schema. + * @return The static data, encoded into a sequence of bytes. + */ + function encodeStatic(bool isInitialized) internal pure returns (bytes memory) { + return abi.encodePacked(isInitialized); + } + + /** + * @notice Encode all of a record's fields. + * @return The static (fixed length) data, encoded into a sequence of bytes. + * @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(bool isInitialized) internal pure returns (bytes memory, PackedCounter, bytes memory) { + bytes memory _staticData = encodeStatic(isInitialized); + + PackedCounter _encodedLengths; + bytes memory _dynamicData; + + return (_staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Encode keys as a bytes32 array using this table's field layout. + */ + function encodeKeyTuple() internal pure returns (bytes32[] memory) { + bytes32[] memory _keyTuple = new bytes32[](0); + + return _keyTuple; + } +} + +/** + * @notice Cast a value to a bool. + * @dev Boolean values are encoded as uint8 (1 = true, 0 = false), but Solidity doesn't allow casting between uint8 and bool. + * @param value The uint8 value to convert. + * @return result The boolean value. + */ +function _toBool(uint8 value) pure returns (bool result) { + assembly { + result := value + } +} diff --git a/packages/world/src/modules/core/CoreModule.sol b/packages/world/src/modules/core/CoreModule.sol index 0637cd92f2..b6776cb4a7 100644 --- a/packages/world/src/modules/core/CoreModule.sol +++ b/packages/world/src/modules/core/CoreModule.sol @@ -28,6 +28,7 @@ import { FunctionSelectors } from "../../codegen/tables/FunctionSelectors.sol"; import { FunctionSignatures } from "../../codegen/tables/FunctionSignatures.sol"; import { SystemHooks } from "../../codegen/tables/SystemHooks.sol"; import { SystemRegistry } from "../../codegen/tables/SystemRegistry.sol"; +import { WorldInitialized } from "../../codegen/tables/WorldInitialized.sol"; import { Balances } from "../../codegen/tables/Balances.sol"; import { WorldRegistrationSystem } from "./implementations/WorldRegistrationSystem.sol"; @@ -99,6 +100,7 @@ contract CoreModule is Module { FunctionSignatures.register(); SystemHooks.register(); SystemRegistry.register(); + WorldInitialized.register(); ResourceIds._setExists(ROOT_NAMESPACE_ID, true); NamespaceOwner._set(ROOT_NAMESPACE_ID, _msgSender()); From 849c1016f103746a2ba6713532626c9e6378132a Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Mon, 22 Jan 2024 14:01:13 +0000 Subject: [PATCH 2/7] changeset --- .changeset/neat-tools-check.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/neat-tools-check.md diff --git a/.changeset/neat-tools-check.md b/.changeset/neat-tools-check.md new file mode 100644 index 0000000000..15a22d255a --- /dev/null +++ b/.changeset/neat-tools-check.md @@ -0,0 +1,5 @@ +--- +"@latticexyz/world": patch +--- + +Added a table that tracks whether the world has already been initialized. From c2e1391ffec3001a9a6ecae54e52f5ed3def9ea2 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Mon, 22 Jan 2024 18:51:15 +0000 Subject: [PATCH 3/7] refactor: store core module address --- packages/store-sync/package.json | 4 +- packages/world-modules/gas-report.json | 62 +++++++------- packages/world/gas-report.json | 32 ++++---- packages/world/mud.config.ts | 4 +- packages/world/src/World.sol | 6 +- packages/world/src/codegen/index.sol | 2 +- ...dInitialized.sol => CoreModuleAddress.sol} | 80 ++++++++----------- .../world/src/modules/core/CoreModule.sol | 4 +- 8 files changed, 91 insertions(+), 103 deletions(-) rename packages/world/src/codegen/tables/{WorldInitialized.sol => CoreModuleAddress.sol} (73%) diff --git a/packages/store-sync/package.json b/packages/store-sync/package.json index e8600fce4d..9bd6d018d5 100644 --- a/packages/store-sync/package.json +++ b/packages/store-sync/package.json @@ -55,7 +55,7 @@ "dev": "tsup --watch", "lint": "eslint .", "test": "DATABASE_URL=http://127.0.0.1:5432/postgres vitest", - "test:ci": "vitest --run" + "test:ci": "vitest --run recs" }, "dependencies": { "@latticexyz/block-logs-stream": "workspace:*", @@ -89,4 +89,4 @@ "access": "public" }, "gitHead": "914a1e0ae4a573d685841ca2ea921435057deb8f" -} +} \ No newline at end of file diff --git a/packages/world-modules/gas-report.json b/packages/world-modules/gas-report.json index 31df5ceb17..0752af8aee 100644 --- a/packages/world-modules/gas-report.json +++ b/packages/world-modules/gas-report.json @@ -3,85 +3,85 @@ "file": "test/ERC20.t.sol", "test": "testApprove", "name": "approve", - "gasUsed": 114348 + "gasUsed": 114354 }, { "file": "test/ERC20.t.sol", "test": "testBurn", "name": "burn", - "gasUsed": 75910 + "gasUsed": 75916 }, { "file": "test/ERC20.t.sol", "test": "testMint", "name": "mint", - "gasUsed": 161749 + "gasUsed": 161755 }, { "file": "test/ERC20.t.sol", "test": "testTransfer", "name": "transfer", - "gasUsed": 92995 + "gasUsed": 93001 }, { "file": "test/ERC20.t.sol", "test": "testTransferFrom", "name": "transferFrom", - "gasUsed": 130331 + "gasUsed": 130337 }, { "file": "test/ERC721.t.sol", "test": "testApproveAllGas", "name": "setApprovalForAll", - "gasUsed": 113972 + "gasUsed": 113978 }, { "file": "test/ERC721.t.sol", "test": "testApproveGas", "name": "approve", - "gasUsed": 87981 + "gasUsed": 87987 }, { "file": "test/ERC721.t.sol", "test": "testBurnGas", "name": "burn", - "gasUsed": 101910 + "gasUsed": 101916 }, { "file": "test/ERC721.t.sol", "test": "testMintGas", "name": "mint", - "gasUsed": 169480 + "gasUsed": 169486 }, { "file": "test/ERC721.t.sol", "test": "testSafeMintToEOAGas", "name": "safeMint", - "gasUsed": 169751 + "gasUsed": 169757 }, { "file": "test/ERC721.t.sol", "test": "testSafeTransferFromToEOAGas", "name": "safeTransferFrom", - "gasUsed": 143744 + "gasUsed": 143750 }, { "file": "test/ERC721.t.sol", "test": "testTransferFromGas", "name": "transferFrom", - "gasUsed": 136901 + "gasUsed": 136907 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallComposite", "name": "install keys in table module", - "gasUsed": 1439061 + "gasUsed": 1439094 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallGas", "name": "install keys in table module", - "gasUsed": 1439061 + "gasUsed": 1439094 }, { "file": "test/KeysInTableModule.t.sol", @@ -93,13 +93,13 @@ "file": "test/KeysInTableModule.t.sol", "test": "testInstallSingleton", "name": "install keys in table module", - "gasUsed": 1439061 + "gasUsed": 1439094 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookCompositeGas", "name": "install keys in table module", - "gasUsed": 1439061 + "gasUsed": 1439094 }, { "file": "test/KeysInTableModule.t.sol", @@ -117,7 +117,7 @@ "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookGas", "name": "install keys in table module", - "gasUsed": 1439061 + "gasUsed": 1439094 }, { "file": "test/KeysInTableModule.t.sol", @@ -135,7 +135,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testGetKeysWithValueGas", "name": "install keys with value module", - "gasUsed": 684441 + "gasUsed": 684471 }, { "file": "test/KeysWithValueModule.t.sol", @@ -153,7 +153,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testInstall", "name": "install keys with value module", - "gasUsed": 684441 + "gasUsed": 684471 }, { "file": "test/KeysWithValueModule.t.sol", @@ -165,7 +165,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testSetAndDeleteRecordHook", "name": "install keys with value module", - "gasUsed": 684441 + "gasUsed": 684471 }, { "file": "test/KeysWithValueModule.t.sol", @@ -183,7 +183,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testSetField", "name": "install keys with value module", - "gasUsed": 684441 + "gasUsed": 684471 }, { "file": "test/KeysWithValueModule.t.sol", @@ -267,60 +267,60 @@ "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromCallboundDelegation", "name": "register a callbound delegation", - "gasUsed": 118198 + "gasUsed": 118201 }, { "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromCallboundDelegation", "name": "call a system via a callbound delegation", - "gasUsed": 36679 + "gasUsed": 36685 }, { "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromSystemDelegation", "name": "register a systembound delegation", - "gasUsed": 115751 + "gasUsed": 115754 }, { "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromSystemDelegation", "name": "call a system via a systembound delegation", - "gasUsed": 33851 + "gasUsed": 33857 }, { "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromTimeboundDelegation", "name": "register a timebound delegation", - "gasUsed": 112674 + "gasUsed": 112677 }, { "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromTimeboundDelegation", "name": "call a system via a timebound delegation", - "gasUsed": 26797 + "gasUsed": 26803 }, { "file": "test/UniqueEntityModule.t.sol", "test": "testInstall", "name": "install unique entity module", - "gasUsed": 704219 + "gasUsed": 704234 }, { "file": "test/UniqueEntityModule.t.sol", "test": "testInstall", "name": "get a unique entity nonce (non-root module)", - "gasUsed": 50365 + "gasUsed": 50368 }, { "file": "test/UniqueEntityModule.t.sol", "test": "testInstallRoot", "name": "installRoot unique entity module", - "gasUsed": 673127 + "gasUsed": 673154 }, { "file": "test/UniqueEntityModule.t.sol", "test": "testInstallRoot", "name": "get a unique entity nonce (root module)", - "gasUsed": 50368 + "gasUsed": 50371 } ] diff --git a/packages/world/gas-report.json b/packages/world/gas-report.json index 466a8f9c1e..0696169fed 100644 --- a/packages/world/gas-report.json +++ b/packages/world/gas-report.json @@ -45,49 +45,49 @@ "file": "test/BatchCall.t.sol", "test": "testBatchCallFromReturnData", "name": "call systems with batchCallFrom", - "gasUsed": 52611 + "gasUsed": 52620 }, { "file": "test/BatchCall.t.sol", "test": "testBatchCallReturnData", "name": "call systems with batchCall", - "gasUsed": 51457 + "gasUsed": 51466 }, { "file": "test/Factories.t.sol", "test": "testCreate2Factory", "name": "deploy contract via Create2", - "gasUsed": 4785208 + "gasUsed": 4759984 }, { "file": "test/Factories.t.sol", "test": "testWorldFactory", "name": "deploy world via WorldFactory", - "gasUsed": 13064063 + "gasUsed": 13039359 }, { "file": "test/World.t.sol", "test": "testCall", "name": "call a system via the World", - "gasUsed": 12361 + "gasUsed": 12364 }, { "file": "test/World.t.sol", "test": "testCallFromNamespaceDelegation", "name": "call a system via a namespace fallback delegation", - "gasUsed": 26131 + "gasUsed": 26137 }, { "file": "test/World.t.sol", "test": "testCallFromUnlimitedDelegation", "name": "register an unlimited delegation", - "gasUsed": 47607 + "gasUsed": 47610 }, { "file": "test/World.t.sol", "test": "testCallFromUnlimitedDelegation", "name": "call a system via an unlimited delegation", - "gasUsed": 12797 + "gasUsed": 12800 }, { "file": "test/World.t.sol", @@ -105,37 +105,37 @@ "file": "test/World.t.sol", "test": "testRegisterFunctionSelector", "name": "Register a function selector", - "gasUsed": 84542 + "gasUsed": 84545 }, { "file": "test/World.t.sol", "test": "testRegisterNamespace", "name": "Register a new namespace", - "gasUsed": 120969 + "gasUsed": 120972 }, { "file": "test/World.t.sol", "test": "testRegisterRootFunctionSelector", "name": "Register a root function selector", - "gasUsed": 80445 + "gasUsed": 80448 }, { "file": "test/World.t.sol", "test": "testRegisterSystem", "name": "register a system", - "gasUsed": 164363 + "gasUsed": 164366 }, { "file": "test/World.t.sol", "test": "testRegisterTable", "name": "Register a new table in the namespace", - "gasUsed": 536881 + "gasUsed": 536884 }, { "file": "test/World.t.sol", "test": "testRenounceNamespace", "name": "Renounce namespace ownership", - "gasUsed": 36773 + "gasUsed": 36776 }, { "file": "test/World.t.sol", @@ -153,13 +153,13 @@ "file": "test/World.t.sol", "test": "testUnregisterNamespaceDelegation", "name": "unregister a namespace delegation", - "gasUsed": 28360 + "gasUsed": 28363 }, { "file": "test/World.t.sol", "test": "testUnregisterUnlimitedDelegation", "name": "unregister an unlimited delegation", - "gasUsed": 26255 + "gasUsed": 26258 }, { "file": "test/WorldDynamicUpdate.t.sol", diff --git a/packages/world/mud.config.ts b/packages/world/mud.config.ts index 535511b570..e6c3380dcd 100644 --- a/packages/world/mud.config.ts +++ b/packages/world/mud.config.ts @@ -103,10 +103,10 @@ export default mudConfig({ }, offchainOnly: true, }, - WorldInitialized: { + CoreModuleAddress: { keySchema: {}, valueSchema: { - isInitialized: "bool", + coreModuleAddress: "address", }, }, }, diff --git a/packages/world/src/World.sol b/packages/world/src/World.sol index 5ce633923a..920a9f9c28 100644 --- a/packages/world/src/World.sol +++ b/packages/world/src/World.sol @@ -19,7 +19,7 @@ import { requireInterface } from "./requireInterface.sol"; import { InstalledModules } from "./codegen/tables/InstalledModules.sol"; import { UserDelegationControl } from "./codegen/tables/UserDelegationControl.sol"; import { NamespaceDelegationControl } from "./codegen/tables/NamespaceDelegationControl.sol"; -import { WorldInitialized } from "./codegen/tables/WorldInitialized.sol"; +import { CoreModuleAddress } from "./codegen/tables/CoreModuleAddress.sol"; import { IModule, IModule } from "./IModule.sol"; import { IWorldKernel } from "./IWorldKernel.sol"; @@ -72,11 +72,11 @@ contract World is StoreData, IWorldKernel { } // The World can only be initialized once - if (WorldInitialized.get()) { + if (CoreModuleAddress.get() != address(0)) { revert World_AlreadyInitialized(); } - WorldInitialized.set(true); + CoreModuleAddress.set(address(coreModule)); // Initialize the World by installing the core module _installRootModule(coreModule, new bytes(0)); diff --git a/packages/world/src/codegen/index.sol b/packages/world/src/codegen/index.sol index 4d4774f989..65059df63f 100644 --- a/packages/world/src/codegen/index.sol +++ b/packages/world/src/codegen/index.sol @@ -14,4 +14,4 @@ import { SystemRegistry, SystemRegistryTableId } from "./tables/SystemRegistry.s import { SystemHooks, SystemHooksTableId } from "./tables/SystemHooks.sol"; import { FunctionSelectors, FunctionSelectorsTableId } from "./tables/FunctionSelectors.sol"; import { FunctionSignatures, FunctionSignaturesTableId } from "./tables/FunctionSignatures.sol"; -import { WorldInitialized, WorldInitializedTableId } from "./tables/WorldInitialized.sol"; +import { CoreModuleAddress, CoreModuleAddressTableId } from "./tables/CoreModuleAddress.sol"; diff --git a/packages/world/src/codegen/tables/WorldInitialized.sol b/packages/world/src/codegen/tables/CoreModuleAddress.sol similarity index 73% rename from packages/world/src/codegen/tables/WorldInitialized.sol rename to packages/world/src/codegen/tables/CoreModuleAddress.sol index 1ebd9e9c32..6f2b2d0432 100644 --- a/packages/world/src/codegen/tables/WorldInitialized.sol +++ b/packages/world/src/codegen/tables/CoreModuleAddress.sol @@ -21,15 +21,15 @@ import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; import { RESOURCE_TABLE, RESOURCE_OFFCHAIN_TABLE } from "@latticexyz/store/src/storeResourceTypes.sol"; ResourceId constant _tableId = ResourceId.wrap( - bytes32(abi.encodePacked(RESOURCE_TABLE, bytes14("world"), bytes16("WorldInitialized"))) + bytes32(abi.encodePacked(RESOURCE_TABLE, bytes14("world"), bytes16("CoreModuleAddres"))) ); -ResourceId constant WorldInitializedTableId = _tableId; +ResourceId constant CoreModuleAddressTableId = _tableId; FieldLayout constant _fieldLayout = FieldLayout.wrap( - 0x0001010001000000000000000000000000000000000000000000000000000000 + 0x0014010014000000000000000000000000000000000000000000000000000000 ); -library WorldInitialized { +library CoreModuleAddress { /** * @notice Get the table values' field layout. * @return _fieldLayout The field layout for the table. @@ -54,7 +54,7 @@ library WorldInitialized { */ function getValueSchema() internal pure returns (Schema) { SchemaType[] memory _valueSchema = new SchemaType[](1); - _valueSchema[0] = SchemaType.BOOL; + _valueSchema[0] = SchemaType.ADDRESS; return SchemaLib.encode(_valueSchema); } @@ -73,7 +73,7 @@ library WorldInitialized { */ function getFieldNames() internal pure returns (string[] memory fieldNames) { fieldNames = new string[](1); - fieldNames[0] = "isInitialized"; + fieldNames[0] = "coreModuleAddress"; } /** @@ -91,79 +91,79 @@ library WorldInitialized { } /** - * @notice Get isInitialized. + * @notice Get coreModuleAddress. */ - function getIsInitialized() internal view returns (bool isInitialized) { + function getCoreModuleAddress() internal view returns (address coreModuleAddress) { bytes32[] memory _keyTuple = new bytes32[](0); bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); - return (_toBool(uint8(bytes1(_blob)))); + return (address(bytes20(_blob))); } /** - * @notice Get isInitialized. + * @notice Get coreModuleAddress. */ - function _getIsInitialized() internal view returns (bool isInitialized) { + function _getCoreModuleAddress() internal view returns (address coreModuleAddress) { bytes32[] memory _keyTuple = new bytes32[](0); bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); - return (_toBool(uint8(bytes1(_blob)))); + return (address(bytes20(_blob))); } /** - * @notice Get isInitialized. + * @notice Get coreModuleAddress. */ - function get() internal view returns (bool isInitialized) { + function get() internal view returns (address coreModuleAddress) { bytes32[] memory _keyTuple = new bytes32[](0); bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); - return (_toBool(uint8(bytes1(_blob)))); + return (address(bytes20(_blob))); } /** - * @notice Get isInitialized. + * @notice Get coreModuleAddress. */ - function _get() internal view returns (bool isInitialized) { + function _get() internal view returns (address coreModuleAddress) { bytes32[] memory _keyTuple = new bytes32[](0); bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); - return (_toBool(uint8(bytes1(_blob)))); + return (address(bytes20(_blob))); } /** - * @notice Set isInitialized. + * @notice Set coreModuleAddress. */ - function setIsInitialized(bool isInitialized) internal { + function setCoreModuleAddress(address coreModuleAddress) internal { bytes32[] memory _keyTuple = new bytes32[](0); - StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((isInitialized)), _fieldLayout); + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((coreModuleAddress)), _fieldLayout); } /** - * @notice Set isInitialized. + * @notice Set coreModuleAddress. */ - function _setIsInitialized(bool isInitialized) internal { + function _setCoreModuleAddress(address coreModuleAddress) internal { bytes32[] memory _keyTuple = new bytes32[](0); - StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((isInitialized)), _fieldLayout); + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((coreModuleAddress)), _fieldLayout); } /** - * @notice Set isInitialized. + * @notice Set coreModuleAddress. */ - function set(bool isInitialized) internal { + function set(address coreModuleAddress) internal { bytes32[] memory _keyTuple = new bytes32[](0); - StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((isInitialized)), _fieldLayout); + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((coreModuleAddress)), _fieldLayout); } /** - * @notice Set isInitialized. + * @notice Set coreModuleAddress. */ - function _set(bool isInitialized) internal { + function _set(address coreModuleAddress) internal { bytes32[] memory _keyTuple = new bytes32[](0); - StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((isInitialized)), _fieldLayout); + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((coreModuleAddress)), _fieldLayout); } /** @@ -188,8 +188,8 @@ library WorldInitialized { * @notice Tightly pack static (fixed length) data using this table's schema. * @return The static data, encoded into a sequence of bytes. */ - function encodeStatic(bool isInitialized) internal pure returns (bytes memory) { - return abi.encodePacked(isInitialized); + function encodeStatic(address coreModuleAddress) internal pure returns (bytes memory) { + return abi.encodePacked(coreModuleAddress); } /** @@ -198,8 +198,8 @@ library WorldInitialized { * @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(bool isInitialized) internal pure returns (bytes memory, PackedCounter, bytes memory) { - bytes memory _staticData = encodeStatic(isInitialized); + function encode(address coreModuleAddress) internal pure returns (bytes memory, PackedCounter, bytes memory) { + bytes memory _staticData = encodeStatic(coreModuleAddress); PackedCounter _encodedLengths; bytes memory _dynamicData; @@ -216,15 +216,3 @@ library WorldInitialized { return _keyTuple; } } - -/** - * @notice Cast a value to a bool. - * @dev Boolean values are encoded as uint8 (1 = true, 0 = false), but Solidity doesn't allow casting between uint8 and bool. - * @param value The uint8 value to convert. - * @return result The boolean value. - */ -function _toBool(uint8 value) pure returns (bool result) { - assembly { - result := value - } -} diff --git a/packages/world/src/modules/core/CoreModule.sol b/packages/world/src/modules/core/CoreModule.sol index b6776cb4a7..3cef4271b7 100644 --- a/packages/world/src/modules/core/CoreModule.sol +++ b/packages/world/src/modules/core/CoreModule.sol @@ -28,7 +28,7 @@ import { FunctionSelectors } from "../../codegen/tables/FunctionSelectors.sol"; import { FunctionSignatures } from "../../codegen/tables/FunctionSignatures.sol"; import { SystemHooks } from "../../codegen/tables/SystemHooks.sol"; import { SystemRegistry } from "../../codegen/tables/SystemRegistry.sol"; -import { WorldInitialized } from "../../codegen/tables/WorldInitialized.sol"; +import { CoreModuleAddress } from "../../codegen/tables/CoreModuleAddress.sol"; import { Balances } from "../../codegen/tables/Balances.sol"; import { WorldRegistrationSystem } from "./implementations/WorldRegistrationSystem.sol"; @@ -100,7 +100,7 @@ contract CoreModule is Module { FunctionSignatures.register(); SystemHooks.register(); SystemRegistry.register(); - WorldInitialized.register(); + CoreModuleAddress.register(); ResourceIds._setExists(ROOT_NAMESPACE_ID, true); NamespaceOwner._set(ROOT_NAMESPACE_ID, _msgSender()); From 09468eb2fcec28309819a4b40c84640776a517de Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Mon, 22 Jan 2024 18:51:54 +0000 Subject: [PATCH 4/7] remove unused file --- packages/store-sync/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/store-sync/package.json b/packages/store-sync/package.json index 9bd6d018d5..e8600fce4d 100644 --- a/packages/store-sync/package.json +++ b/packages/store-sync/package.json @@ -55,7 +55,7 @@ "dev": "tsup --watch", "lint": "eslint .", "test": "DATABASE_URL=http://127.0.0.1:5432/postgres vitest", - "test:ci": "vitest --run recs" + "test:ci": "vitest --run" }, "dependencies": { "@latticexyz/block-logs-stream": "workspace:*", @@ -89,4 +89,4 @@ "access": "public" }, "gitHead": "914a1e0ae4a573d685841ca2ea921435057deb8f" -} \ No newline at end of file +} From 3ee5eb366c2774272728b198db7867fb22453323 Mon Sep 17 00:00:00 2001 From: yonada Date: Mon, 22 Jan 2024 19:07:43 +0000 Subject: [PATCH 5/7] refactor: rename field Co-authored-by: alvarius --- packages/world/mud.config.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/world/mud.config.ts b/packages/world/mud.config.ts index e6c3380dcd..ed898154b7 100644 --- a/packages/world/mud.config.ts +++ b/packages/world/mud.config.ts @@ -105,9 +105,7 @@ export default mudConfig({ }, CoreModuleAddress: { keySchema: {}, - valueSchema: { - coreModuleAddress: "address", - }, + valueSchema: "address", }, }, excludeSystems: [ From 62fbdd360de016373069a108ea4ce9a9d3c87dcb Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Mon, 22 Jan 2024 19:08:44 +0000 Subject: [PATCH 6/7] chore: build --- .../src/codegen/tables/CoreModuleAddress.sol | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/world/src/codegen/tables/CoreModuleAddress.sol b/packages/world/src/codegen/tables/CoreModuleAddress.sol index 6f2b2d0432..0933c2c60c 100644 --- a/packages/world/src/codegen/tables/CoreModuleAddress.sol +++ b/packages/world/src/codegen/tables/CoreModuleAddress.sol @@ -73,7 +73,7 @@ library CoreModuleAddress { */ function getFieldNames() internal pure returns (string[] memory fieldNames) { fieldNames = new string[](1); - fieldNames[0] = "coreModuleAddress"; + fieldNames[0] = "value"; } /** @@ -91,9 +91,9 @@ library CoreModuleAddress { } /** - * @notice Get coreModuleAddress. + * @notice Get value. */ - function getCoreModuleAddress() internal view returns (address coreModuleAddress) { + function getValue() internal view returns (address value) { bytes32[] memory _keyTuple = new bytes32[](0); bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); @@ -101,9 +101,9 @@ library CoreModuleAddress { } /** - * @notice Get coreModuleAddress. + * @notice Get value. */ - function _getCoreModuleAddress() internal view returns (address coreModuleAddress) { + function _getValue() internal view returns (address value) { bytes32[] memory _keyTuple = new bytes32[](0); bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); @@ -111,9 +111,9 @@ library CoreModuleAddress { } /** - * @notice Get coreModuleAddress. + * @notice Get value. */ - function get() internal view returns (address coreModuleAddress) { + function get() internal view returns (address value) { bytes32[] memory _keyTuple = new bytes32[](0); bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); @@ -121,9 +121,9 @@ library CoreModuleAddress { } /** - * @notice Get coreModuleAddress. + * @notice Get value. */ - function _get() internal view returns (address coreModuleAddress) { + function _get() internal view returns (address value) { bytes32[] memory _keyTuple = new bytes32[](0); bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); @@ -131,39 +131,39 @@ library CoreModuleAddress { } /** - * @notice Set coreModuleAddress. + * @notice Set value. */ - function setCoreModuleAddress(address coreModuleAddress) internal { + function setValue(address value) internal { bytes32[] memory _keyTuple = new bytes32[](0); - StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((coreModuleAddress)), _fieldLayout); + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((value)), _fieldLayout); } /** - * @notice Set coreModuleAddress. + * @notice Set value. */ - function _setCoreModuleAddress(address coreModuleAddress) internal { + function _setValue(address value) internal { bytes32[] memory _keyTuple = new bytes32[](0); - StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((coreModuleAddress)), _fieldLayout); + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((value)), _fieldLayout); } /** - * @notice Set coreModuleAddress. + * @notice Set value. */ - function set(address coreModuleAddress) internal { + function set(address value) internal { bytes32[] memory _keyTuple = new bytes32[](0); - StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((coreModuleAddress)), _fieldLayout); + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((value)), _fieldLayout); } /** - * @notice Set coreModuleAddress. + * @notice Set value. */ - function _set(address coreModuleAddress) internal { + function _set(address value) internal { bytes32[] memory _keyTuple = new bytes32[](0); - StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((coreModuleAddress)), _fieldLayout); + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((value)), _fieldLayout); } /** @@ -188,8 +188,8 @@ library CoreModuleAddress { * @notice Tightly pack static (fixed length) data using this table's schema. * @return The static data, encoded into a sequence of bytes. */ - function encodeStatic(address coreModuleAddress) internal pure returns (bytes memory) { - return abi.encodePacked(coreModuleAddress); + function encodeStatic(address value) internal pure returns (bytes memory) { + return abi.encodePacked(value); } /** @@ -198,8 +198,8 @@ library CoreModuleAddress { * @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(address coreModuleAddress) internal pure returns (bytes memory, PackedCounter, bytes memory) { - bytes memory _staticData = encodeStatic(coreModuleAddress); + function encode(address value) internal pure returns (bytes memory, PackedCounter, bytes memory) { + bytes memory _staticData = encodeStatic(value); PackedCounter _encodedLengths; bytes memory _dynamicData; From 78336aaf9b1058b3769933aabb13f11870868df7 Mon Sep 17 00:00:00 2001 From: yonada Date: Mon, 22 Jan 2024 19:09:08 +0000 Subject: [PATCH 7/7] chore: update changeset Co-authored-by: alvarius --- .changeset/neat-tools-check.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/neat-tools-check.md b/.changeset/neat-tools-check.md index 15a22d255a..f8d4fa1924 100644 --- a/.changeset/neat-tools-check.md +++ b/.changeset/neat-tools-check.md @@ -2,4 +2,4 @@ "@latticexyz/world": patch --- -Added a table that tracks whether the world has already been initialized. +Added a table to track the `CoreModule` address the world was initialised with.