From ed404b7d840db755f7513d4a7d32b85eaa3dd058 Mon Sep 17 00:00:00 2001 From: yonada Date: Thu, 25 Apr 2024 18:54:09 +0100 Subject: [PATCH] fix(store): enforce unique table names across types (#2736) Co-authored-by: Kevin Ingersoll --- .changeset/strong-lobsters-shake.md | 5 + docs/pages/store/reference/misc.mdx | 22 +++- docs/pages/world/reference/misc.mdx | 2 +- packages/cli/src/deploy/common.ts | 4 +- packages/store/gas-report.json | 26 ++--- packages/store/src/ResourceId.sol | 9 ++ packages/store/src/StoreCore.sol | 10 +- packages/store/src/version.sol | 2 +- .../store/ts/protocol-snapshots/2.0.2.snap | 57 ++++++++++ packages/store/ts/protocolVersions.ts | 2 + packages/world-modules/gas-report.json | 24 ++--- packages/world/gas-report.json | 8 +- packages/world/src/version.sol | 2 +- .../world/ts/protocol-snapshots/2.0.2.snap | 102 ++++++++++++++++++ packages/world/ts/protocolVersions.ts | 2 + 15 files changed, 238 insertions(+), 39 deletions(-) create mode 100644 .changeset/strong-lobsters-shake.md create mode 100644 packages/store/ts/protocol-snapshots/2.0.2.snap create mode 100644 packages/world/ts/protocol-snapshots/2.0.2.snap diff --git a/.changeset/strong-lobsters-shake.md b/.changeset/strong-lobsters-shake.md new file mode 100644 index 0000000000..3f657a2adb --- /dev/null +++ b/.changeset/strong-lobsters-shake.md @@ -0,0 +1,5 @@ +--- +"@latticexyz/store": patch +--- + +Added a check to `registerTable` that prevents registering both an offchain and onchain table with the same name, making it easier to use human-readable names in indexers. diff --git a/docs/pages/store/reference/misc.mdx b/docs/pages/store/reference/misc.mdx index c50a76c213..abae9a77b9 100644 --- a/docs/pages/store/reference/misc.mdx +++ b/docs/pages/store/reference/misc.mdx @@ -1850,6 +1850,26 @@ function getType(ResourceId resourceId) internal pure returns (bytes2); | -------- | -------- | ------------------------------------- | | `` | `bytes2` | The extracted 2-byte type identifier. | +#### getResourceName + +Get the name from a resource ID. + +```solidity +function getResourceName(ResourceId resourceId) internal pure returns (bytes30); +``` + +**Parameters** + +| Name | Type | Description | +| ------------ | ------------ | ---------------- | +| `resourceId` | `ResourceId` | The resource ID. | + +**Returns** + +| Name | Type | Description | +| -------- | --------- | --------------- | +| `` | `bytes30` | A 30-byte name. | + ## ResourceIdLib [Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/ResourceId.sol) @@ -2688,5 +2708,5 @@ Contains a constant representing the version of the Store protocol. _Identifier for the current Store protocol version._ ```solidity -bytes32 constant STORE_VERSION = "2.0.1"; +bytes32 constant STORE_VERSION = "2.0.2"; ``` diff --git a/docs/pages/world/reference/misc.mdx b/docs/pages/world/reference/misc.mdx index f243fec51a..be7eea5f25 100644 --- a/docs/pages/world/reference/misc.mdx +++ b/docs/pages/world/reference/misc.mdx @@ -104,5 +104,5 @@ Contains a constant representing the version of the World protocol. _Identifier for the current World protocol version._ ```solidity -bytes32 constant WORLD_VERSION = "2.0.1"; +bytes32 constant WORLD_VERSION = "2.0.2"; ``` diff --git a/packages/cli/src/deploy/common.ts b/packages/cli/src/deploy/common.ts index a13035cc6e..da4a2f29c1 100644 --- a/packages/cli/src/deploy/common.ts +++ b/packages/cli/src/deploy/common.ts @@ -25,8 +25,8 @@ export const worldDeployEvents = [helloStoreEvent, helloWorldEvent] as const; export const worldAbi = [...IBaseWorldAbi, ...IModuleAbi] as const; // Ideally, this should be an append-only list. Before adding more versions here, be sure to add backwards-compatible support for old Store/World versions. -export const supportedStoreVersions = ["2.0.0", "2.0.1"]; -export const supportedWorldVersions = ["2.0.0", "2.0.1"]; +export const supportedStoreVersions = ["2.0.0", "2.0.1", "2.0.2"]; +export const supportedWorldVersions = ["2.0.0", "2.0.1", "2.0.2"]; // TODO: extend this to include factory+deployer address? so we can reuse the deployer for a world? export type WorldDeploy = { diff --git a/packages/store/gas-report.json b/packages/store/gas-report.json index e4ba19f8c0..b3b2ab23e7 100644 --- a/packages/store/gas-report.json +++ b/packages/store/gas-report.json @@ -357,7 +357,7 @@ "file": "test/KeyEncoding.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "register KeyEncoding table", - "gasUsed": 717787 + "gasUsed": 721008 }, { "file": "test/Mixed.t.sol", @@ -669,7 +669,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testAccessEmptyData", "name": "access length of dynamic field of non-existing record", - "gasUsed": 1158 + "gasUsed": 1159 }, { "file": "test/StoreCoreGas.t.sol", @@ -771,13 +771,13 @@ "file": "test/StoreCoreGas.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "StoreCore: register table", - "gasUsed": 647841 + "gasUsed": 651056 }, { "file": "test/StoreCoreGas.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "StoreCore: get field layout (warm)", - "gasUsed": 508 + "gasUsed": 509 }, { "file": "test/StoreCoreGas.t.sol", @@ -795,13 +795,13 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetDynamicData", "name": "set complex record with dynamic data (4 slots)", - "gasUsed": 101866 + "gasUsed": 101867 }, { "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetDynamicData", "name": "get complex record with dynamic data (4 slots)", - "gasUsed": 4235 + "gasUsed": 4234 }, { "file": "test/StoreCoreGas.t.sol", @@ -813,7 +813,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetDynamicData", "name": "compare: Set complex record with dynamic data using abi.encode", - "gasUsed": 267534 + "gasUsed": 267535 }, { "file": "test/StoreCoreGas.t.sol", @@ -825,13 +825,13 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetDynamicDataLength", "name": "set dynamic length of dynamic index 1", - "gasUsed": 967 + "gasUsed": 968 }, { "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetDynamicDataLength", "name": "reduce dynamic length of dynamic index 0", - "gasUsed": 957 + "gasUsed": 958 }, { "file": "test/StoreCoreGas.t.sol", @@ -873,7 +873,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetField", "name": "set dynamic field (1 slot, second dynamic field)", - "gasUsed": 32246 + "gasUsed": 32247 }, { "file": "test/StoreCoreGas.t.sol", @@ -891,13 +891,13 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetStaticData", "name": "get static record (1 slot)", - "gasUsed": 1551 + "gasUsed": 1552 }, { "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetStaticDataSpanningWords", "name": "set static record (2 slots)", - "gasUsed": 54649 + "gasUsed": 54650 }, { "file": "test/StoreCoreGas.t.sol", @@ -1113,7 +1113,7 @@ "file": "test/Vector2.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "register Vector2 field layout", - "gasUsed": 443849 + "gasUsed": 447063 }, { "file": "test/Vector2.t.sol", diff --git a/packages/store/src/ResourceId.sol b/packages/store/src/ResourceId.sol index f0905e1305..03cf8c7c0a 100644 --- a/packages/store/src/ResourceId.sol +++ b/packages/store/src/ResourceId.sol @@ -45,4 +45,13 @@ library ResourceIdInstance { function getType(ResourceId resourceId) internal pure returns (bytes2) { return bytes2(ResourceId.unwrap(resourceId)); } + + /** + * @notice Get the name from a resource ID. + * @param resourceId The resource ID. + * @return A 30-byte name. + */ + function getResourceName(ResourceId resourceId) internal pure returns (bytes30) { + return bytes30(ResourceId.unwrap(resourceId) << (TYPE_BITS)); + } } diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index ddd38a60b1..696bb399f6 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -15,7 +15,7 @@ import { IStoreHook } from "./IStoreHook.sol"; import { StoreSwitch } from "./StoreSwitch.sol"; import { Hook, HookLib } from "./Hook.sol"; import { BEFORE_SET_RECORD, AFTER_SET_RECORD, BEFORE_SPLICE_STATIC_DATA, AFTER_SPLICE_STATIC_DATA, BEFORE_SPLICE_DYNAMIC_DATA, AFTER_SPLICE_DYNAMIC_DATA, BEFORE_DELETE_RECORD, AFTER_DELETE_RECORD } from "./storeHookTypes.sol"; -import { ResourceId } from "./ResourceId.sol"; +import { ResourceId, ResourceIdLib } from "./ResourceId.sol"; import { RESOURCE_TABLE, RESOURCE_OFFCHAIN_TABLE } from "./storeResourceTypes.sol"; import { IStoreEvents } from "./IStoreEvents.sol"; @@ -160,7 +160,7 @@ library StoreCore { string[] memory keyNames, string[] memory fieldNames ) internal { - // Verify the table ID is of type RESOURCE_TABLE + // Verify the table ID is of type RESOURCE_TABLE or RESOURCE_OFFCHAIN_TABLE if (tableId.getType() != RESOURCE_TABLE && tableId.getType() != RESOURCE_OFFCHAIN_TABLE) { revert IStoreErrors.Store_InvalidResourceType(RESOURCE_TABLE, tableId, string(abi.encodePacked(tableId))); } @@ -209,8 +209,10 @@ library StoreCore { } } - // Verify there is no resource with this ID yet - if (ResourceIds._getExists(tableId)) { + // Verify that there is no table or offchain table with the same name + ResourceId onchainTableId = ResourceIdLib.encode(RESOURCE_TABLE, tableId.getResourceName()); + ResourceId offchainTableId = ResourceIdLib.encode(RESOURCE_OFFCHAIN_TABLE, tableId.getResourceName()); + if (ResourceIds._getExists(onchainTableId) || ResourceIds._getExists(offchainTableId)) { revert IStoreErrors.Store_TableAlreadyExists(tableId, string(abi.encodePacked(tableId))); } diff --git a/packages/store/src/version.sol b/packages/store/src/version.sol index 3e0a984e7a..3f0b1abcc6 100644 --- a/packages/store/src/version.sol +++ b/packages/store/src/version.sol @@ -8,4 +8,4 @@ pragma solidity >=0.8.24; */ /// @dev Identifier for the current Store protocol version. -bytes32 constant STORE_VERSION = "2.0.1"; +bytes32 constant STORE_VERSION = "2.0.2"; diff --git a/packages/store/ts/protocol-snapshots/2.0.2.snap b/packages/store/ts/protocol-snapshots/2.0.2.snap new file mode 100644 index 0000000000..21c6ecc745 --- /dev/null +++ b/packages/store/ts/protocol-snapshots/2.0.2.snap @@ -0,0 +1,57 @@ +[ + "error EncodedLengths_InvalidLength(uint256 length)", + "error FieldLayout_Empty()", + "error FieldLayout_InvalidStaticDataLength(uint256 staticDataLength, uint256 computedStaticDataLength)", + "error FieldLayout_StaticLengthDoesNotFitInAWord(uint256 index)", + "error FieldLayout_StaticLengthIsNotZero(uint256 index)", + "error FieldLayout_StaticLengthIsZero(uint256 index)", + "error FieldLayout_TooManyDynamicFields(uint256 numFields, uint256 maxFields)", + "error FieldLayout_TooManyFields(uint256 numFields, uint256 maxFields)", + "error Schema_InvalidLength(uint256 length)", + "error Schema_StaticTypeAfterDynamicType()", + "error Slice_OutOfBounds(bytes data, uint256 start, uint256 end)", + "error Store_IndexOutOfBounds(uint256 length, uint256 accessedIndex)", + "error Store_InvalidBounds(uint256 start, uint256 end)", + "error Store_InvalidFieldNamesLength(uint256 expected, uint256 received)", + "error Store_InvalidKeyNamesLength(uint256 expected, uint256 received)", + "error Store_InvalidResourceType(bytes2 expected, bytes32 resourceId, string resourceIdString)", + "error Store_InvalidSplice(uint40 startWithinField, uint40 deleteCount, uint40 fieldLength)", + "error Store_InvalidStaticDataLength(uint256 expected, uint256 received)", + "error Store_InvalidValueSchemaDynamicLength(uint256 expected, uint256 received)", + "error Store_InvalidValueSchemaLength(uint256 expected, uint256 received)", + "error Store_InvalidValueSchemaStaticLength(uint256 expected, uint256 received)", + "error Store_TableAlreadyExists(bytes32 tableId, string tableIdString)", + "error Store_TableNotFound(bytes32 tableId, string tableIdString)", + "event HelloStore(bytes32 indexed storeVersion)", + "event Store_DeleteRecord(bytes32 indexed tableId, bytes32[] keyTuple)", + "event Store_SetRecord(bytes32 indexed tableId, bytes32[] keyTuple, bytes staticData, bytes32 encodedLengths, bytes dynamicData)", + "event Store_SpliceDynamicData(bytes32 indexed tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, uint48 start, uint40 deleteCount, bytes32 encodedLengths, bytes data)", + "event Store_SpliceStaticData(bytes32 indexed tableId, bytes32[] keyTuple, uint48 start, bytes data)", + "function deleteRecord(bytes32 tableId, bytes32[] keyTuple)", + "function getDynamicField(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex) view returns (bytes)", + "function getDynamicFieldLength(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex) view returns (uint256)", + "function getDynamicFieldSlice(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, uint256 start, uint256 end) view returns (bytes data)", + "function getField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes32 fieldLayout) view returns (bytes data)", + "function getField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex) view returns (bytes data)", + "function getFieldLayout(bytes32 tableId) view returns (bytes32 fieldLayout)", + "function getFieldLength(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes32 fieldLayout) view returns (uint256)", + "function getFieldLength(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex) view returns (uint256)", + "function getKeySchema(bytes32 tableId) view returns (bytes32 keySchema)", + "function getRecord(bytes32 tableId, bytes32[] keyTuple, bytes32 fieldLayout) view returns (bytes staticData, bytes32 encodedLengths, bytes dynamicData)", + "function getRecord(bytes32 tableId, bytes32[] keyTuple) view returns (bytes staticData, bytes32 encodedLengths, bytes dynamicData)", + "function getStaticField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes32 fieldLayout) view returns (bytes32)", + "function getValueSchema(bytes32 tableId) view returns (bytes32 valueSchema)", + "function popFromDynamicField(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, uint256 byteLengthToPop)", + "function pushToDynamicField(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, bytes dataToPush)", + "function registerStoreHook(bytes32 tableId, address hookAddress, uint8 enabledHooksBitmap)", + "function registerTable(bytes32 tableId, bytes32 fieldLayout, bytes32 keySchema, bytes32 valueSchema, string[] keyNames, string[] fieldNames)", + "function setDynamicField(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, bytes data)", + "function setField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes data, bytes32 fieldLayout)", + "function setField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes data)", + "function setRecord(bytes32 tableId, bytes32[] keyTuple, bytes staticData, bytes32 encodedLengths, bytes dynamicData)", + "function setStaticField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes data, bytes32 fieldLayout)", + "function spliceDynamicData(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, uint40 startWithinField, uint40 deleteCount, bytes data)", + "function spliceStaticData(bytes32 tableId, bytes32[] keyTuple, uint48 start, bytes data)", + "function storeVersion() view returns (bytes32 version)", + "function unregisterStoreHook(bytes32 tableId, address hookAddress)", +] \ No newline at end of file diff --git a/packages/store/ts/protocolVersions.ts b/packages/store/ts/protocolVersions.ts index f99100a48a..b91dcbbbc2 100644 --- a/packages/store/ts/protocolVersions.ts +++ b/packages/store/ts/protocolVersions.ts @@ -1,5 +1,7 @@ // History of protocol versions and a short description of what changed in each. export const protocolVersions = { + "2.0.2": + "Patched `StoreCore.registerTable` to prevent registering both an offchain and onchain table with the same name.", "2.0.1": "Patched `StoreRead.getDynamicFieldLength` to use the correct method to read the dynamic field length.", "2.0.0": "Initial v2 release. See mud.dev/changelog for the full list of changes from v1.", }; diff --git a/packages/world-modules/gas-report.json b/packages/world-modules/gas-report.json index fbcb13e891..cc113365fe 100644 --- a/packages/world-modules/gas-report.json +++ b/packages/world-modules/gas-report.json @@ -3,7 +3,7 @@ "file": "test/CallWithSignatureModule.t.sol", "test": "testInstallRoot", "name": "install delegation module", - "gasUsed": 687912 + "gasUsed": 691133 }, { "file": "test/CallWithSignatureModule.t.sol", @@ -87,13 +87,13 @@ "file": "test/KeysInTableModule.t.sol", "test": "testInstallComposite", "name": "install keys in table module", - "gasUsed": 1456815 + "gasUsed": 1463317 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallGas", "name": "install keys in table module", - "gasUsed": 1456815 + "gasUsed": 1463317 }, { "file": "test/KeysInTableModule.t.sol", @@ -105,13 +105,13 @@ "file": "test/KeysInTableModule.t.sol", "test": "testInstallSingleton", "name": "install keys in table module", - "gasUsed": 1456815 + "gasUsed": 1463317 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookCompositeGas", "name": "install keys in table module", - "gasUsed": 1456815 + "gasUsed": 1463317 }, { "file": "test/KeysInTableModule.t.sol", @@ -129,7 +129,7 @@ "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookGas", "name": "install keys in table module", - "gasUsed": 1456815 + "gasUsed": 1463317 }, { "file": "test/KeysInTableModule.t.sol", @@ -147,7 +147,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testGetKeysWithValueGas", "name": "install keys with value module", - "gasUsed": 715762 + "gasUsed": 719012 }, { "file": "test/KeysWithValueModule.t.sol", @@ -165,7 +165,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testInstall", "name": "install keys with value module", - "gasUsed": 715762 + "gasUsed": 719012 }, { "file": "test/KeysWithValueModule.t.sol", @@ -177,7 +177,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testSetAndDeleteRecordHook", "name": "install keys with value module", - "gasUsed": 715762 + "gasUsed": 719012 }, { "file": "test/KeysWithValueModule.t.sol", @@ -195,7 +195,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testSetField", "name": "install keys with value module", - "gasUsed": 715762 + "gasUsed": 719012 }, { "file": "test/KeysWithValueModule.t.sol", @@ -315,7 +315,7 @@ "file": "test/UniqueEntityModule.t.sol", "test": "testInstall", "name": "install unique entity module", - "gasUsed": 715495 + "gasUsed": 718745 }, { "file": "test/UniqueEntityModule.t.sol", @@ -327,7 +327,7 @@ "file": "test/UniqueEntityModule.t.sol", "test": "testInstallRoot", "name": "installRoot unique entity module", - "gasUsed": 685964 + "gasUsed": 689190 }, { "file": "test/UniqueEntityModule.t.sol", diff --git a/packages/world/gas-report.json b/packages/world/gas-report.json index 131e2971f3..d2da0ab8d7 100644 --- a/packages/world/gas-report.json +++ b/packages/world/gas-report.json @@ -63,7 +63,7 @@ "file": "test/Factories.t.sol", "test": "testWorldFactoryGas", "name": "deploy world via WorldFactory", - "gasUsed": 12805251 + "gasUsed": 12847807 }, { "file": "test/World.t.sol", @@ -129,7 +129,7 @@ "file": "test/World.t.sol", "test": "testRegisterTable", "name": "Register a new table in the namespace", - "gasUsed": 569676 + "gasUsed": 572927 }, { "file": "test/World.t.sol", @@ -249,7 +249,7 @@ "file": "test/WorldProxy.t.sol", "test": "testRegisterTable", "name": "Register a new table in the namespace", - "gasUsed": 574686 + "gasUsed": 577937 }, { "file": "test/WorldProxy.t.sol", @@ -285,7 +285,7 @@ "file": "test/WorldProxyFactory.t.sol", "test": "testWorldProxyFactoryGas", "name": "deploy world via WorldProxyFactory", - "gasUsed": 9100791 + "gasUsed": 9143347 }, { "file": "test/WorldProxyFactory.t.sol", diff --git a/packages/world/src/version.sol b/packages/world/src/version.sol index 15315b6673..c09c418bc9 100644 --- a/packages/world/src/version.sol +++ b/packages/world/src/version.sol @@ -8,4 +8,4 @@ pragma solidity >=0.8.24; */ /// @dev Identifier for the current World protocol version. -bytes32 constant WORLD_VERSION = "2.0.1"; +bytes32 constant WORLD_VERSION = "2.0.2"; diff --git a/packages/world/ts/protocol-snapshots/2.0.2.snap b/packages/world/ts/protocol-snapshots/2.0.2.snap new file mode 100644 index 0000000000..aed3400889 --- /dev/null +++ b/packages/world/ts/protocol-snapshots/2.0.2.snap @@ -0,0 +1,102 @@ +[ + "error EncodedLengths_InvalidLength(uint256 length)", + "error FieldLayout_Empty()", + "error FieldLayout_InvalidStaticDataLength(uint256 staticDataLength, uint256 computedStaticDataLength)", + "error FieldLayout_StaticLengthDoesNotFitInAWord(uint256 index)", + "error FieldLayout_StaticLengthIsNotZero(uint256 index)", + "error FieldLayout_StaticLengthIsZero(uint256 index)", + "error FieldLayout_TooManyDynamicFields(uint256 numFields, uint256 maxFields)", + "error FieldLayout_TooManyFields(uint256 numFields, uint256 maxFields)", + "error Module_AlreadyInstalled()", + "error Module_MissingDependency(address dependency)", + "error Module_NonRootInstallNotSupported()", + "error Module_RootInstallNotSupported()", + "error Schema_InvalidLength(uint256 length)", + "error Schema_StaticTypeAfterDynamicType()", + "error Slice_OutOfBounds(bytes data, uint256 start, uint256 end)", + "error Store_IndexOutOfBounds(uint256 length, uint256 accessedIndex)", + "error Store_InvalidBounds(uint256 start, uint256 end)", + "error Store_InvalidFieldNamesLength(uint256 expected, uint256 received)", + "error Store_InvalidKeyNamesLength(uint256 expected, uint256 received)", + "error Store_InvalidResourceType(bytes2 expected, bytes32 resourceId, string resourceIdString)", + "error Store_InvalidSplice(uint40 startWithinField, uint40 deleteCount, uint40 fieldLength)", + "error Store_InvalidStaticDataLength(uint256 expected, uint256 received)", + "error Store_InvalidValueSchemaDynamicLength(uint256 expected, uint256 received)", + "error Store_InvalidValueSchemaLength(uint256 expected, uint256 received)", + "error Store_InvalidValueSchemaStaticLength(uint256 expected, uint256 received)", + "error Store_TableAlreadyExists(bytes32 tableId, string tableIdString)", + "error Store_TableNotFound(bytes32 tableId, string tableIdString)", + "error World_AccessDenied(string resource, address caller)", + "error World_AlreadyInitialized()", + "error World_CallbackNotAllowed(bytes4 functionSelector)", + "error World_DelegationNotFound(address delegator, address delegatee)", + "error World_FunctionSelectorAlreadyExists(bytes4 functionSelector)", + "error World_FunctionSelectorNotFound(bytes4 functionSelector)", + "error World_InsufficientBalance(uint256 balance, uint256 amount)", + "error World_InterfaceNotSupported(address contractAddress, bytes4 interfaceId)", + "error World_InvalidNamespace(bytes14 namespace)", + "error World_InvalidResourceId(bytes32 resourceId, string resourceIdString)", + "error World_InvalidResourceType(bytes2 expected, bytes32 resourceId, string resourceIdString)", + "error World_ResourceAlreadyExists(bytes32 resourceId, string resourceIdString)", + "error World_ResourceNotFound(bytes32 resourceId, string resourceIdString)", + "error World_SystemAlreadyExists(address system)", + "error World_UnlimitedDelegationNotAllowed()", + "event HelloStore(bytes32 indexed storeVersion)", + "event HelloWorld(bytes32 indexed worldVersion)", + "event Store_DeleteRecord(bytes32 indexed tableId, bytes32[] keyTuple)", + "event Store_SetRecord(bytes32 indexed tableId, bytes32[] keyTuple, bytes staticData, bytes32 encodedLengths, bytes dynamicData)", + "event Store_SpliceDynamicData(bytes32 indexed tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, uint48 start, uint40 deleteCount, bytes32 encodedLengths, bytes data)", + "event Store_SpliceStaticData(bytes32 indexed tableId, bytes32[] keyTuple, uint48 start, bytes data)", + "function batchCall((bytes32 systemId, bytes callData)[] systemCalls) returns (bytes[] returnDatas)", + "function batchCallFrom((address from, bytes32 systemId, bytes callData)[] systemCalls) returns (bytes[] returnDatas)", + "function call(bytes32 systemId, bytes callData) payable returns (bytes)", + "function callFrom(address delegator, bytes32 systemId, bytes callData) payable returns (bytes)", + "function creator() view returns (address)", + "function deleteRecord(bytes32 tableId, bytes32[] keyTuple)", + "function getDynamicField(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex) view returns (bytes)", + "function getDynamicFieldLength(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex) view returns (uint256)", + "function getDynamicFieldSlice(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, uint256 start, uint256 end) view returns (bytes data)", + "function getField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes32 fieldLayout) view returns (bytes data)", + "function getField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex) view returns (bytes data)", + "function getFieldLayout(bytes32 tableId) view returns (bytes32 fieldLayout)", + "function getFieldLength(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes32 fieldLayout) view returns (uint256)", + "function getFieldLength(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex) view returns (uint256)", + "function getKeySchema(bytes32 tableId) view returns (bytes32 keySchema)", + "function getRecord(bytes32 tableId, bytes32[] keyTuple, bytes32 fieldLayout) view returns (bytes staticData, bytes32 encodedLengths, bytes dynamicData)", + "function getRecord(bytes32 tableId, bytes32[] keyTuple) view returns (bytes staticData, bytes32 encodedLengths, bytes dynamicData)", + "function getStaticField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes32 fieldLayout) view returns (bytes32)", + "function getValueSchema(bytes32 tableId) view returns (bytes32 valueSchema)", + "function grantAccess(bytes32 resourceId, address grantee)", + "function initialize(address initModule)", + "function installModule(address module, bytes encodedArgs)", + "function installRootModule(address module, bytes encodedArgs)", + "function popFromDynamicField(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, uint256 byteLengthToPop)", + "function pushToDynamicField(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, bytes dataToPush)", + "function registerDelegation(address delegatee, bytes32 delegationControlId, bytes initCallData)", + "function registerFunctionSelector(bytes32 systemId, string systemFunctionSignature) returns (bytes4 worldFunctionSelector)", + "function registerNamespace(bytes32 namespaceId)", + "function registerNamespaceDelegation(bytes32 namespaceId, bytes32 delegationControlId, bytes initCallData)", + "function registerRootFunctionSelector(bytes32 systemId, string worldFunctionSignature, string systemFunctionSignature) returns (bytes4 worldFunctionSelector)", + "function registerStoreHook(bytes32 tableId, address hookAddress, uint8 enabledHooksBitmap)", + "function registerSystem(bytes32 systemId, address system, bool publicAccess)", + "function registerSystemHook(bytes32 systemId, address hookAddress, uint8 enabledHooksBitmap)", + "function registerTable(bytes32 tableId, bytes32 fieldLayout, bytes32 keySchema, bytes32 valueSchema, string[] keyNames, string[] fieldNames)", + "function renounceOwnership(bytes32 namespaceId)", + "function revokeAccess(bytes32 resourceId, address grantee)", + "function setDynamicField(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, bytes data)", + "function setField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes data, bytes32 fieldLayout)", + "function setField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes data)", + "function setRecord(bytes32 tableId, bytes32[] keyTuple, bytes staticData, bytes32 encodedLengths, bytes dynamicData)", + "function setStaticField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes data, bytes32 fieldLayout)", + "function spliceDynamicData(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, uint40 startWithinField, uint40 deleteCount, bytes data)", + "function spliceStaticData(bytes32 tableId, bytes32[] keyTuple, uint48 start, bytes data)", + "function storeVersion() view returns (bytes32 version)", + "function transferBalanceToAddress(bytes32 fromNamespaceId, address toAddress, uint256 amount)", + "function transferBalanceToNamespace(bytes32 fromNamespaceId, bytes32 toNamespaceId, uint256 amount)", + "function transferOwnership(bytes32 namespaceId, address newOwner)", + "function unregisterDelegation(address delegatee)", + "function unregisterNamespaceDelegation(bytes32 namespaceId)", + "function unregisterStoreHook(bytes32 tableId, address hookAddress)", + "function unregisterSystemHook(bytes32 systemId, address hookAddress)", + "function worldVersion() view returns (bytes32)", +] \ No newline at end of file diff --git a/packages/world/ts/protocolVersions.ts b/packages/world/ts/protocolVersions.ts index f99100a48a..b91dcbbbc2 100644 --- a/packages/world/ts/protocolVersions.ts +++ b/packages/world/ts/protocolVersions.ts @@ -1,5 +1,7 @@ // History of protocol versions and a short description of what changed in each. export const protocolVersions = { + "2.0.2": + "Patched `StoreCore.registerTable` to prevent registering both an offchain and onchain table with the same name.", "2.0.1": "Patched `StoreRead.getDynamicFieldLength` to use the correct method to read the dynamic field length.", "2.0.0": "Initial v2 release. See mud.dev/changelog for the full list of changes from v1.", };