diff --git a/packages/cli/src/render-solidity/renderTable.ts b/packages/cli/src/render-solidity/renderTable.ts index 9231c48cc6..deaaeb3881 100644 --- a/packages/cli/src/render-solidity/renderTable.ts +++ b/packages/cli/src/render-solidity/renderTable.ts @@ -4,7 +4,16 @@ import { renderRecordMethods } from "./record.js"; import { RenderTableOptions } from "./types.js"; export function renderTable(options: RenderTableOptions) { - const { imports, libraryName, structName, staticResourceData, storeImportPath, fields, withRecordMethods } = options; + const { + imports, + libraryName, + structName, + staticResourceData, + storeImportPath, + fields, + withRecordMethods, + primaryKeys, + } = options; const { _typedTableId, _typedKeyArgs, _primaryKeysDefinition } = renderCommonData(options); @@ -60,6 +69,13 @@ library ${libraryName} { return SchemaLib.encode(_schema); } + function getKeySchema() internal pure returns (Schema) { + SchemaType[] memory _schema = new SchemaType[](${primaryKeys.length}); + ${renderList(primaryKeys, ({ enumName }, index) => `_schema[${index}] = SchemaType.${enumName};`)} + + return SchemaLib.encode(_schema); + } + /** Get the table's metadata */ function getMetadata() internal pure returns (string memory, string[] memory) { string[] memory _fieldNames = new string[](${fields.length}); @@ -69,7 +85,7 @@ library ${libraryName} { /** Register the table's schema */ function registerSchema(${_typedTableId}) internal { - StoreSwitch.registerSchema(_tableId, getSchema()); + StoreSwitch.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata */ @@ -84,7 +100,7 @@ ${ : ` /** Register the table's schema for the specified store */ function registerSchema(${renderArguments([_typedTableId, "IStore _store"])}) internal { - _store.registerSchema(_tableId, getSchema()); + _store.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata for the specified store */ diff --git a/packages/cli/src/utils/deploy-v2.ts b/packages/cli/src/utils/deploy-v2.ts index 3d404c8d26..34f6af81aa 100644 --- a/packages/cli/src/utils/deploy-v2.ts +++ b/packages/cli/src/utils/deploy-v2.ts @@ -71,7 +71,7 @@ export async function deploy(mudConfig: MUDConfig, deployConfig: DeployConfig): // Register tables promises.push( - ...Object.entries(mudConfig.tables).map(async ([tableName, { fileSelector, schema }]) => { + ...Object.entries(mudConfig.tables).map(async ([tableName, { fileSelector, schema, primaryKeys }]) => { console.log(chalk.blue(`Registering table ${tableName} at ${namespace}/${fileSelector}`)); // Register table @@ -79,10 +79,15 @@ export async function deploy(mudConfig: MUDConfig, deployConfig: DeployConfig): return resolveSchemaOrUserTypeSimple(schemaOrUserType, mudConfig.userTypes); }); + const keyTypes = Object.values(primaryKeys).map((schemaOrUserType) => { + return resolveSchemaOrUserTypeSimple(schemaOrUserType, mudConfig.userTypes); + }); + await fastTxExecute(WorldContract, "registerTable", [ toBytes16(namespace), toBytes16(fileSelector), encodeSchema(schemaTypes), + encodeSchema(keyTypes), ]); // Register table metadata diff --git a/packages/store/gas-report.txt b/packages/store/gas-report.txt index db0934e124..6d8f0cbfb7 100644 --- a/packages/store/gas-report.txt +++ b/packages/store/gas-report.txt @@ -14,9 +14,9 @@ (test/Gas.t.sol) | pass abi encoded bytes to external contract [someContract.doSomethingWithBytes(abiEncoded)]: 6554 (test/Gas.t.sol) | pass custom encoded bytes to external contract [someContract.doSomethingWithBytes(customEncoded)]: 1381 (test/Mixed.t.sol) | store Mixed struct in storage (native solidity) [testMixed = mixed]: 92050 -(test/Mixed.t.sol) | register Mixed schema [Mixed.registerSchema()]: 35823 -(test/Mixed.t.sol) | set record in Mixed [Mixed.set({ key: key, u32: 1, u128: 2, a32: a32, s: s })]: 111978 -(test/Mixed.t.sol) | get record from Mixed [MixedData memory mixed = Mixed.get(key)]: 13395 +(test/Mixed.t.sol) | register Mixed schema [Mixed.registerSchema()]: 61103 +(test/Mixed.t.sol) | set record in Mixed [Mixed.set({ key: key, u32: 1, u128: 2, a32: a32, s: s })]: 111931 +(test/Mixed.t.sol) | get record from Mixed [MixedData memory mixed = Mixed.get(key)]: 13374 (test/PackedCounter.t.sol) | get value at index of PackedCounter [packedCounter.atIndex(3)]: 261 (test/PackedCounter.t.sol) | set value at index of PackedCounter [packedCounter = packedCounter.setAtIndex(2, 5)]: 799 (test/PackedCounter.t.sol) | pack uint16 array into PackedCounter [PackedCounter packedCounter = PackedCounterLib.pack(counters)]: 2152 @@ -44,48 +44,49 @@ (test/Storage.t.sol) | store 1 storage slot [Storage.store({ storagePointer: storagePointer, data: originalDataFirstSlot })]: 22509 (test/Storage.t.sol) | store 34 bytes over 3 storage slots (with offset and safeTrail)) [Storage.store({ storagePointer: storagePointer, offset: 31, data: data1 })]: 23164 (test/Storage.t.sol) | load 34 bytes over 3 storage slots (with offset and safeTrail)) [bytes memory data = Storage.load({ storagePointer: storagePointer, length: 34, offset: 31 })]: 1104 -(test/StoreCore.t.sol) | access non-existing record [bytes memory data1 = StoreCore.getRecord(table, key)]: 7326 -(test/StoreCore.t.sol) | access static field of non-existing record [bytes memory data2 = StoreCore.getField(table, key, 0)]: 2990 -(test/StoreCore.t.sol) | access dynamic field of non-existing record [bytes memory data3 = StoreCore.getField(table, key, 1)]: 3605 -(test/StoreCore.t.sol) | delete record (complex data, 3 slots) [StoreCore.deleteRecord(table, key)]: 10992 -(test/StoreCore.t.sol) | Check for existence of table (existent) [StoreCore.hasTable(table)]: 1120 -(test/StoreCore.t.sol) | check for existence of table (non-existent) [StoreCore.hasTable(table2)]: 3144 -(test/StoreCore.t.sol) | register subscriber [StoreCore.registerStoreHook(table, subscriber)]: 67345 -(test/StoreCore.t.sol) | set record on table with subscriber [StoreCore.setRecord(table, key, data)]: 73830 -(test/StoreCore.t.sol) | set static field on table with subscriber [StoreCore.setField(table, key, 0, data)]: 29585 -(test/StoreCore.t.sol) | delete record on table with subscriber [StoreCore.deleteRecord(table, key)]: 24432 -(test/StoreCore.t.sol) | register subscriber [StoreCore.registerStoreHook(table, subscriber)]: 67345 -(test/StoreCore.t.sol) | set (dynamic) record on table with subscriber [StoreCore.setRecord(table, key, data)]: 167237 -(test/StoreCore.t.sol) | set (dynamic) field on table with subscriber [StoreCore.setField(table, key, 1, arrayDataBytes)]: 32628 -(test/StoreCore.t.sol) | delete (dynamic) record on table with subscriber [StoreCore.deleteRecord(table, key)]: 25910 -(test/StoreCore.t.sol) | push to field (1 slot, 1 uint32 item) [StoreCore.pushToField(table, key, 1, secondDataToPush)]: 16952 -(test/StoreCore.t.sol) | push to field (2 slots, 10 uint32 items) [StoreCore.pushToField(table, key, 2, thirdDataToPush)]: 39673 -(test/StoreCore.t.sol) | StoreCore: register schema [StoreCore.registerSchema(table, schema)]: 30539 -(test/StoreCore.t.sol) | StoreCore: get schema (warm) [Schema loadedSchema = StoreCore.getSchema(table)]: 1148 -(test/StoreCore.t.sol) | set complex record with dynamic data (4 slots) [StoreCore.setRecord(table, key, data)]: 107606 -(test/StoreCore.t.sol) | get complex record with dynamic data (4 slots) [bytes memory loadedData = StoreCore.getRecord(table, key)]: 6458 +(test/StoreCore.t.sol) | access non-existing record [bytes memory data1 = StoreCore.getRecord(table, key)]: 7322 +(test/StoreCore.t.sol) | access static field of non-existing record [bytes memory data2 = StoreCore.getField(table, key, 0)]: 2991 +(test/StoreCore.t.sol) | access dynamic field of non-existing record [bytes memory data3 = StoreCore.getField(table, key, 1)]: 3604 +(test/StoreCore.t.sol) | delete record (complex data, 3 slots) [StoreCore.deleteRecord(table, key)]: 10970 +(test/StoreCore.t.sol) | Check for existence of table (existent) [StoreCore.hasTable(table)]: 1117 +(test/StoreCore.t.sol) | check for existence of table (non-existent) [StoreCore.hasTable(table2)]: 3143 +(test/StoreCore.t.sol) | register subscriber [StoreCore.registerStoreHook(table, subscriber)]: 67279 +(test/StoreCore.t.sol) | set record on table with subscriber [StoreCore.setRecord(table, key, data)]: 73742 +(test/StoreCore.t.sol) | set static field on table with subscriber [StoreCore.setField(table, key, 0, data)]: 29511 +(test/StoreCore.t.sol) | delete record on table with subscriber [StoreCore.deleteRecord(table, key)]: 24365 +(test/StoreCore.t.sol) | register subscriber [StoreCore.registerStoreHook(table, subscriber)]: 67279 +(test/StoreCore.t.sol) | set (dynamic) record on table with subscriber [StoreCore.setRecord(table, key, data)]: 167149 +(test/StoreCore.t.sol) | set (dynamic) field on table with subscriber [StoreCore.setField(table, key, 1, arrayDataBytes)]: 32562 +(test/StoreCore.t.sol) | delete (dynamic) record on table with subscriber [StoreCore.deleteRecord(table, key)]: 25845 +(test/StoreCore.t.sol) | push to field (1 slot, 1 uint32 item) [StoreCore.pushToField(table, key, 1, secondDataToPush)]: 16930 +(test/StoreCore.t.sol) | push to field (2 slots, 10 uint32 items) [StoreCore.pushToField(table, key, 2, thirdDataToPush)]: 39652 +(test/StoreCore.t.sol) | StoreCore: register schema [StoreCore.registerSchema(table, schema, keySchema)]: 54796 +(test/StoreCore.t.sol) | StoreCore: get schema (warm) [Schema loadedSchema = StoreCore.getSchema(table)]: 1145 +(test/StoreCore.t.sol) | StoreCore: get key schema (warm) [Schema loadedKeySchema = StoreCore.getKeySchema(table)]: 1213 +(test/StoreCore.t.sol) | set complex record with dynamic data (4 slots) [StoreCore.setRecord(table, key, data)]: 107585 +(test/StoreCore.t.sol) | get complex record with dynamic data (4 slots) [bytes memory loadedData = StoreCore.getRecord(table, key)]: 6459 (test/StoreCore.t.sol) | compare: Set complex record with dynamic data using native solidity [testStruct = _testStruct]: 116842 (test/StoreCore.t.sol) | compare: Set complex record with dynamic data using abi.encode [testMapping[1234] = abi.encode(_testStruct)]: 267376 -(test/StoreCore.t.sol) | set dynamic length of dynamic index 0 [StoreCoreInternal._setDynamicDataLengthAtIndex(table, key, 0, 10)]: 23602 +(test/StoreCore.t.sol) | set dynamic length of dynamic index 0 [StoreCoreInternal._setDynamicDataLengthAtIndex(table, key, 0, 10)]: 23600 (test/StoreCore.t.sol) | set dynamic length of dynamic index 1 [StoreCoreInternal._setDynamicDataLengthAtIndex(table, key, 1, 99)]: 1719 -(test/StoreCore.t.sol) | reduce dynamic length of dynamic index 0 [StoreCoreInternal._setDynamicDataLengthAtIndex(table, key, 0, 5)]: 1707 -(test/StoreCore.t.sol) | set static field (1 slot) [StoreCore.setField(table, key, 0, abi.encodePacked(firstDataBytes))]: 38017 +(test/StoreCore.t.sol) | reduce dynamic length of dynamic index 0 [StoreCoreInternal._setDynamicDataLengthAtIndex(table, key, 0, 5)]: 1708 +(test/StoreCore.t.sol) | set static field (1 slot) [StoreCore.setField(table, key, 0, abi.encodePacked(firstDataBytes))]: 37994 (test/StoreCore.t.sol) | get static field (1 slot) [bytes memory loadedData = StoreCore.getField(table, key, 0)]: 2996 -(test/StoreCore.t.sol) | set static field (overlap 2 slot) [StoreCore.setField(table, key, 1, abi.encodePacked(secondDataBytes))]: 33030 +(test/StoreCore.t.sol) | set static field (overlap 2 slot) [StoreCore.setField(table, key, 1, abi.encodePacked(secondDataBytes))]: 33008 (test/StoreCore.t.sol) | get static field (overlap 2 slot) [loadedData = StoreCore.getField(table, key, 1)]: 3884 -(test/StoreCore.t.sol) | set dynamic field (1 slot, first dynamic field) [StoreCore.setField(table, key, 2, thirdDataBytes)]: 55332 +(test/StoreCore.t.sol) | set dynamic field (1 slot, first dynamic field) [StoreCore.setField(table, key, 2, thirdDataBytes)]: 55311 (test/StoreCore.t.sol) | get dynamic field (1 slot, first dynamic field) [loadedData = StoreCore.getField(table, key, 2)]: 3836 -(test/StoreCore.t.sol) | set dynamic field (1 slot, second dynamic field) [StoreCore.setField(table, key, 3, fourthDataBytes)]: 35472 -(test/StoreCore.t.sol) | get dynamic field (1 slot, second dynamic field) [loadedData = StoreCore.getField(table, key, 3)]: 3855 -(test/StoreCore.t.sol) | set static record (1 slot) [StoreCore.setRecord(table, key, data)]: 37297 +(test/StoreCore.t.sol) | set dynamic field (1 slot, second dynamic field) [StoreCore.setField(table, key, 3, fourthDataBytes)]: 35450 +(test/StoreCore.t.sol) | get dynamic field (1 slot, second dynamic field) [loadedData = StoreCore.getField(table, key, 3)]: 3856 +(test/StoreCore.t.sol) | set static record (1 slot) [StoreCore.setRecord(table, key, data)]: 37275 (test/StoreCore.t.sol) | get static record (1 slot) [bytes memory loadedData = StoreCore.getRecord(table, key, schema)]: 1335 -(test/StoreCore.t.sol) | set static record (2 slots) [StoreCore.setRecord(table, key, data)]: 59861 +(test/StoreCore.t.sol) | set static record (2 slots) [StoreCore.setRecord(table, key, data)]: 59840 (test/StoreCore.t.sol) | get static record (2 slots) [bytes memory loadedData = StoreCore.getRecord(table, key, schema)]: 1580 -(test/StoreCore.t.sol) | StoreCore: set table metadata [StoreCore.setMetadata(table, tableName, fieldNames)]: 251689 -(test/StoreMetadata.t.sol) | set record in StoreMetadataTable [StoreMetadata.set({ tableId: tableId, tableName: tableName, abiEncodedFieldNames: abi.encode(fieldNames) })]: 250156 -(test/StoreMetadata.t.sol) | get record from StoreMetadataTable [StoreMetadataData memory metadata = StoreMetadata.get(tableId)]: 12132 -(test/StoreSwitch.t.sol) | check if delegatecall [isDelegate = StoreSwitch.isDelegateCall()]: 693 +(test/StoreCore.t.sol) | StoreCore: set table metadata [StoreCore.setMetadata(table, tableName, fieldNames)]: 251645 +(test/StoreMetadata.t.sol) | set record in StoreMetadataTable [StoreMetadata.set({ tableId: tableId, tableName: tableName, abiEncodedFieldNames: abi.encode(fieldNames) })]: 250112 +(test/StoreMetadata.t.sol) | get record from StoreMetadataTable [StoreMetadataData memory metadata = StoreMetadata.get(tableId)]: 12110 +(test/StoreSwitch.t.sol) | check if delegatecall [isDelegate = StoreSwitch.isDelegateCall()]: 671 (test/StoreSwitch.t.sol) | check if delegatecall [isDelegate = StoreSwitch.isDelegateCall()]: 627 -(test/Vector2.t.sol) | register Vector2 schema [Vector2.registerSchema()]: 32600 -(test/Vector2.t.sol) | set Vector2 record [Vector2.set({ key: key, x: 1, y: 2 })]: 38541 -(test/Vector2.t.sol) | get Vector2 record [Vector2Data memory vector = Vector2.get(key)]: 5063 \ No newline at end of file +(test/Vector2.t.sol) | register Vector2 schema [Vector2.registerSchema()]: 57901 +(test/Vector2.t.sol) | set Vector2 record [Vector2.set({ key: key, x: 1, y: 2 })]: 38539 +(test/Vector2.t.sol) | get Vector2 record [Vector2Data memory vector = Vector2.get(key)]: 5064 \ No newline at end of file diff --git a/packages/store/src/IStore.sol b/packages/store/src/IStore.sol index bf47ae908e..ca1aa3da79 100644 --- a/packages/store/src/IStore.sol +++ b/packages/store/src/IStore.sol @@ -8,10 +8,12 @@ interface IStore { event StoreSetField(uint256 table, bytes32[] key, uint8 schemaIndex, bytes data); event StoreDeleteRecord(uint256 table, bytes32[] key); - function registerSchema(uint256 table, Schema schema) external; + function registerSchema(uint256 table, Schema schema, Schema keySchema) external; function getSchema(uint256 table) external view returns (Schema schema); + function getKeySchema(uint256 table) external view returns (Schema schema); + function setMetadata(uint256 table, string calldata tableName, string[] calldata fieldNames) external; // Set full record (including full dynamic data) diff --git a/packages/store/src/Store.sol b/packages/store/src/Store.sol index 29f067f3ae..77204939c8 100644 --- a/packages/store/src/Store.sol +++ b/packages/store/src/Store.sol @@ -14,6 +14,10 @@ abstract contract Store is IStore { schema = StoreCore.getSchema(table); } + function getKeySchema(uint256 table) public view virtual returns (Schema schema) { + schema = StoreCore.getKeySchema(table); + } + // Get full record (static and dynamic data, load schema from storage) function getRecord(uint256 table, bytes32[] calldata key) public view virtual returns (bytes memory data) { data = StoreCore.getRecord(table, key); diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index a688ccf189..e94c40ec7e 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -40,7 +40,11 @@ library StoreCore { */ function initialize() internal { // Register internal schema table - registerSchema(StoreCoreInternal.SCHEMA_TABLE, SchemaLib.encode(SchemaType.BYTES32)); + registerSchema( + StoreCoreInternal.SCHEMA_TABLE, + SchemaLib.encode(SchemaType.BYTES32, SchemaType.BYTES32), // The Schema table's valueSchema is { valueSchema: BYTES32, keySchema: BYTES32 } + SchemaLib.encode(SchemaType.UINT256) // The Schema table's keySchema is { tableId: UINT256 } + ); // Register other internal tables // @@ -70,6 +74,16 @@ library StoreCore { } } + /** + * Get the key schema for the given tableId + */ + function getKeySchema(uint256 tableId) internal view returns (Schema keySchema) { + keySchema = StoreCoreInternal._getKeySchema(tableId); + if (keySchema.isEmpty()) { + revert StoreCore_TableNotFound(tableId, tableId.toString()); + } + } + /** * Check if a table with the given tableId exists */ @@ -80,9 +94,10 @@ library StoreCore { /** * Register a new tableId schema */ - function registerSchema(uint256 tableId, Schema schema) internal { + function registerSchema(uint256 tableId, Schema valueSchema, Schema keySchema) internal { // Verify the schema is valid - schema.validate(); + valueSchema.validate(); + keySchema.validate(); // Verify the schema doesn't exist yet if (hasTable(tableId)) { @@ -90,7 +105,7 @@ library StoreCore { } // Register the schema - StoreCoreInternal._registerSchemaUnchecked(tableId, schema); + StoreCoreInternal._registerSchemaUnchecked(tableId, valueSchema, keySchema); } /** @@ -372,17 +387,25 @@ library StoreCoreInternal { return Schema.wrap(Storage.load({ storagePointer: location })); } + function _getKeySchema(uint256 tableId) internal view returns (Schema) { + bytes32[] memory key = new bytes32[](1); + key[0] = bytes32(tableId); + uint256 location = StoreCoreInternal._getStaticDataLocation(SCHEMA_TABLE, key); + return Schema.wrap(Storage.load({ storagePointer: location + 0x20 })); + } + /** * Register a new tableId schema without validity checks */ - function _registerSchemaUnchecked(uint256 tableId, Schema schema) internal { + function _registerSchemaUnchecked(uint256 tableId, Schema valueSchema, Schema keySchema) internal { bytes32[] memory key = new bytes32[](1); key[0] = bytes32(tableId); uint256 location = _getStaticDataLocation(SCHEMA_TABLE, key); - Storage.store({ storagePointer: location, data: schema.unwrap() }); + Storage.store({ storagePointer: location, data: valueSchema.unwrap() }); + Storage.store({ storagePointer: location + 0x20, data: keySchema.unwrap() }); // Emit an event to notify indexers - emit StoreCore.StoreSetRecord(SCHEMA_TABLE, key, abi.encodePacked(schema.unwrap())); + emit StoreCore.StoreSetRecord(SCHEMA_TABLE, key, abi.encodePacked(valueSchema.unwrap(), keySchema.unwrap())); } /************************************************************************ diff --git a/packages/store/src/StoreSwitch.sol b/packages/store/src/StoreSwitch.sol index 38180990fb..499bf25d15 100644 --- a/packages/store/src/StoreSwitch.sol +++ b/packages/store/src/StoreSwitch.sol @@ -34,11 +34,11 @@ library StoreSwitch { } } - function registerSchema(uint256 table, Schema schema) internal { + function registerSchema(uint256 table, Schema schema, Schema keySchema) internal { if (isDelegateCall()) { - StoreCore.registerSchema(table, schema); + StoreCore.registerSchema(table, schema, keySchema); } else { - IStore(msg.sender).registerSchema(table, schema); + IStore(msg.sender).registerSchema(table, schema, keySchema); } } diff --git a/packages/store/src/StoreView.sol b/packages/store/src/StoreView.sol index b3025b4c55..6cd019635c 100644 --- a/packages/store/src/StoreView.sol +++ b/packages/store/src/StoreView.sol @@ -13,7 +13,7 @@ contract StoreView is Store { /** * Not implemented in StoreView */ - function registerSchema(uint256, Schema) public virtual { + function registerSchema(uint256, Schema, Schema) public virtual { revert StoreView_NotImplemented(); } diff --git a/packages/store/src/tables/Callbacks.sol b/packages/store/src/tables/Callbacks.sol index 3c2a628209..1be96b55ec 100644 --- a/packages/store/src/tables/Callbacks.sol +++ b/packages/store/src/tables/Callbacks.sol @@ -28,6 +28,13 @@ library Callbacks { return SchemaLib.encode(_schema); } + function getKeySchema() internal pure returns (Schema) { + SchemaType[] memory _schema = new SchemaType[](1); + _schema[0] = SchemaType.BYTES32; + + return SchemaLib.encode(_schema); + } + /** Get the table's metadata */ function getMetadata() internal pure returns (string memory, string[] memory) { string[] memory _fieldNames = new string[](1); @@ -37,7 +44,7 @@ library Callbacks { /** Register the table's schema */ function registerSchema() internal { - StoreSwitch.registerSchema(_tableId, getSchema()); + StoreSwitch.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata */ diff --git a/packages/store/src/tables/Hooks.sol b/packages/store/src/tables/Hooks.sol index b88c54902b..3dba10bb14 100644 --- a/packages/store/src/tables/Hooks.sol +++ b/packages/store/src/tables/Hooks.sol @@ -28,6 +28,13 @@ library Hooks { return SchemaLib.encode(_schema); } + function getKeySchema() internal pure returns (Schema) { + SchemaType[] memory _schema = new SchemaType[](1); + _schema[0] = SchemaType.BYTES32; + + return SchemaLib.encode(_schema); + } + /** Get the table's metadata */ function getMetadata() internal pure returns (string memory, string[] memory) { string[] memory _fieldNames = new string[](1); @@ -37,7 +44,7 @@ library Hooks { /** Register the table's schema */ function registerSchema() internal { - StoreSwitch.registerSchema(_tableId, getSchema()); + StoreSwitch.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata */ diff --git a/packages/store/src/tables/Mixed.sol b/packages/store/src/tables/Mixed.sol index 751a5c8566..51a4bbad51 100644 --- a/packages/store/src/tables/Mixed.sol +++ b/packages/store/src/tables/Mixed.sol @@ -38,6 +38,13 @@ library Mixed { return SchemaLib.encode(_schema); } + function getKeySchema() internal pure returns (Schema) { + SchemaType[] memory _schema = new SchemaType[](1); + _schema[0] = SchemaType.BYTES32; + + return SchemaLib.encode(_schema); + } + /** Get the table's metadata */ function getMetadata() internal pure returns (string memory, string[] memory) { string[] memory _fieldNames = new string[](4); @@ -50,7 +57,7 @@ library Mixed { /** Register the table's schema */ function registerSchema() internal { - StoreSwitch.registerSchema(_tableId, getSchema()); + StoreSwitch.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata */ diff --git a/packages/store/src/tables/StoreMetadata.sol b/packages/store/src/tables/StoreMetadata.sol index 0f81f45c69..52fc526a7f 100644 --- a/packages/store/src/tables/StoreMetadata.sol +++ b/packages/store/src/tables/StoreMetadata.sol @@ -34,6 +34,13 @@ library StoreMetadata { return SchemaLib.encode(_schema); } + function getKeySchema() internal pure returns (Schema) { + SchemaType[] memory _schema = new SchemaType[](1); + _schema[0] = SchemaType.UINT256; + + return SchemaLib.encode(_schema); + } + /** Get the table's metadata */ function getMetadata() internal pure returns (string memory, string[] memory) { string[] memory _fieldNames = new string[](2); @@ -44,7 +51,7 @@ library StoreMetadata { /** Register the table's schema */ function registerSchema() internal { - StoreSwitch.registerSchema(_tableId, getSchema()); + StoreSwitch.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata */ @@ -55,7 +62,7 @@ library StoreMetadata { /** Register the table's schema for the specified store */ function registerSchema(IStore _store) internal { - _store.registerSchema(_tableId, getSchema()); + _store.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata for the specified store */ diff --git a/packages/store/src/tables/Vector2.sol b/packages/store/src/tables/Vector2.sol index 3ac4da2cd8..6a3e8ff48a 100644 --- a/packages/store/src/tables/Vector2.sol +++ b/packages/store/src/tables/Vector2.sol @@ -34,6 +34,13 @@ library Vector2 { return SchemaLib.encode(_schema); } + function getKeySchema() internal pure returns (Schema) { + SchemaType[] memory _schema = new SchemaType[](1); + _schema[0] = SchemaType.BYTES32; + + return SchemaLib.encode(_schema); + } + /** Get the table's metadata */ function getMetadata() internal pure returns (string memory, string[] memory) { string[] memory _fieldNames = new string[](2); @@ -44,7 +51,7 @@ library Vector2 { /** Register the table's schema */ function registerSchema() internal { - StoreSwitch.registerSchema(_tableId, getSchema()); + StoreSwitch.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata */ diff --git a/packages/store/test/StoreCore.t.sol b/packages/store/test/StoreCore.t.sol index 82052b59a2..146e9798df 100644 --- a/packages/store/test/StoreCore.t.sol +++ b/packages/store/test/StoreCore.t.sol @@ -24,6 +24,7 @@ struct TestStruct { contract StoreCoreTest is Test, StoreView { TestStruct private testStruct; mapping(uint256 => bytes) private testMapping; + Schema defaultKeySchema = SchemaLib.encode(SchemaType.BYTES32); // Expose an external setRecord function for testing purposes of indexers (see testHooks) function setRecord(uint256 table, bytes32[] calldata key, bytes calldata data) public override { @@ -51,12 +52,13 @@ contract StoreCoreTest is Test, StoreView { } // Expose an external registerSchema function for testing purposes of indexers (see testHooks) - function registerSchema(uint256 table, Schema schema) public override { - StoreCore.registerSchema(table, schema); + function registerSchema(uint256 table, Schema schema, Schema keySchema) public override { + StoreCore.registerSchema(table, schema, keySchema); } function testRegisterAndGetSchema() public { Schema schema = SchemaLib.encode(SchemaType.UINT8, SchemaType.UINT16, SchemaType.UINT8, SchemaType.UINT16); + Schema keySchema = SchemaLib.encode(SchemaType.UINT8, SchemaType.UINT16); uint256 table = uint256(keccak256("some.table")); @@ -64,26 +66,34 @@ contract StoreCoreTest is Test, StoreView { bytes32[] memory key = new bytes32[](1); key[0] = bytes32(table); vm.expectEmit(true, true, true, true); - emit StoreSetRecord(StoreCoreInternal.SCHEMA_TABLE, key, abi.encodePacked(schema.unwrap())); + emit StoreSetRecord(StoreCoreInternal.SCHEMA_TABLE, key, abi.encodePacked(schema.unwrap(), keySchema.unwrap())); // !gasreport StoreCore: register schema - StoreCore.registerSchema(table, schema); + StoreCore.registerSchema(table, schema, keySchema); // !gasreport StoreCore: get schema (warm) Schema loadedSchema = StoreCore.getSchema(table); - assertEq(schema.unwrap(), loadedSchema.unwrap()); + assertEq(loadedSchema.unwrap(), schema.unwrap()); + + // !gasreport StoreCore: get key schema (warm) + Schema loadedKeySchema = StoreCore.getKeySchema(table); + assertEq(loadedKeySchema.unwrap(), keySchema.unwrap()); } function testFailRegisterInvalidSchema() public { - StoreCore.registerSchema(uint256(keccak256("table")), Schema.wrap(keccak256("random bytes as schema"))); + StoreCore.registerSchema( + uint256(keccak256("table")), + Schema.wrap(keccak256("random bytes as schema")), + Schema.wrap(keccak256("random bytes as key schema")) + ); } function testHasSchema() public { Schema schema = SchemaLib.encode(SchemaType.UINT8, SchemaType.UINT16, SchemaType.UINT8, SchemaType.UINT16); uint256 table = uint256(keccak256("some.table")); uint256 table2 = uint256(keccak256("other.table")); - StoreCore.registerSchema(table, schema); + StoreCore.registerSchema(table, schema, defaultKeySchema); // !gasreport Check for existence of table (existent) StoreCore.hasTable(table); @@ -98,13 +108,14 @@ contract StoreCoreTest is Test, StoreView { function testSetMetadata() public { uint256 table = uint256(keccak256("some.table")); Schema schema = SchemaLib.encode(SchemaType.UINT8, SchemaType.UINT16); + Schema keySchema = SchemaLib.encode(SchemaType.UINT8, SchemaType.UINT16, SchemaType.UINT8, SchemaType.UINT16); string memory tableName = "someTable"; string[] memory fieldNames = new string[](2); fieldNames[0] = "field1"; fieldNames[1] = "field2"; // Register table - StoreCore.registerSchema(table, schema); + StoreCore.registerSchema(table, schema, keySchema); // !gasreport StoreCore: set table metadata StoreCore.setMetadata(table, tableName, fieldNames); @@ -119,13 +130,14 @@ contract StoreCoreTest is Test, StoreView { function testlSetMetadataRevert() public { uint256 table = uint256(keccak256("some.table")); Schema schema = SchemaLib.encode(SchemaType.UINT8); + Schema keySchema = SchemaLib.encode(SchemaType.UINT8, SchemaType.UINT16, SchemaType.UINT8, SchemaType.UINT16); string memory tableName = "someTable"; string[] memory fieldNames = new string[](2); fieldNames[0] = "field1"; fieldNames[1] = "field2"; // Register table - StoreCore.registerSchema(table, schema); + StoreCore.registerSchema(table, schema, keySchema); vm.expectRevert(abi.encodeWithSelector(StoreCore.StoreCore_InvalidFieldNamesLength.selector, 1, 2)); StoreCore.setMetadata(table, tableName, fieldNames); @@ -143,7 +155,7 @@ contract StoreCoreTest is Test, StoreView { ); // Register schema - StoreCore.registerSchema(table, schema); + StoreCore.registerSchema(table, schema, defaultKeySchema); // Create some key bytes32[] memory key = new bytes32[](1); @@ -182,7 +194,7 @@ contract StoreCoreTest is Test, StoreView { Schema schema = SchemaLib.encode(SchemaType.UINT8, SchemaType.UINT16, SchemaType.UINT8, SchemaType.UINT16); uint256 table = uint256(keccak256("some.table")); - StoreCore.registerSchema(table, schema); + StoreCore.registerSchema(table, schema, defaultKeySchema); // Set data bytes memory data = abi.encodePacked(bytes1(0x01), bytes2(0x0203), bytes1(0x04), bytes2(0x0506)); @@ -208,7 +220,7 @@ contract StoreCoreTest is Test, StoreView { // Register table's schema Schema schema = SchemaLib.encode(SchemaType.UINT8, SchemaType.UINT16, SchemaType.UINT8, SchemaType.UINT16); uint256 table = uint256(keccak256("some.table")); - StoreCore.registerSchema(table, schema); + StoreCore.registerSchema(table, schema, defaultKeySchema); // Set data bytes memory data = abi.encodePacked(bytes1(0x01), bytes2(0x0203), bytes1(0x04)); @@ -224,7 +236,7 @@ contract StoreCoreTest is Test, StoreView { // Register table's schema Schema schema = SchemaLib.encode(SchemaType.UINT128, SchemaType.UINT256); uint256 table = uint256(keccak256("some.table")); - StoreCore.registerSchema(table, schema); + StoreCore.registerSchema(table, schema, defaultKeySchema); // Set data bytes memory data = abi.encodePacked( @@ -255,7 +267,7 @@ contract StoreCoreTest is Test, StoreView { { // Register table's schema Schema schema = SchemaLib.encode(SchemaType.UINT128, SchemaType.UINT32_ARRAY, SchemaType.UINT32_ARRAY); - StoreCore.registerSchema(table, schema); + StoreCore.registerSchema(table, schema, defaultKeySchema); } bytes16 firstDataBytes = bytes16(0x0102030405060708090a0b0c0d0e0f10); @@ -339,7 +351,7 @@ contract StoreCoreTest is Test, StoreView { SchemaType.UINT32_ARRAY, SchemaType.UINT32_ARRAY ); - StoreCore.registerSchema(table, schema); + StoreCore.registerSchema(table, schema, defaultKeySchema); } bytes16 firstDataBytes = bytes16(0x0102030405060708090a0b0c0d0e0f10); @@ -477,7 +489,7 @@ contract StoreCoreTest is Test, StoreView { // Register table's schema Schema schema = SchemaLib.encode(SchemaType.UINT128, SchemaType.UINT32_ARRAY, SchemaType.UINT32_ARRAY); - StoreCore.registerSchema(table, schema); + StoreCore.registerSchema(table, schema, defaultKeySchema); bytes16 firstDataBytes = bytes16(0x0102030405060708090a0b0c0d0e0f10); @@ -546,7 +558,7 @@ contract StoreCoreTest is Test, StoreView { { // Register table's schema Schema schema = SchemaLib.encode(SchemaType.UINT256, SchemaType.UINT32_ARRAY, SchemaType.UINT32_ARRAY); - StoreCore.registerSchema(table, schema); + StoreCore.registerSchema(table, schema, defaultKeySchema); } // Create key @@ -649,7 +661,7 @@ contract StoreCoreTest is Test, StoreView { uint256 table = uint256(keccak256("some.table")); Schema schema = SchemaLib.encode(SchemaType.UINT32, SchemaType.UINT32_ARRAY); - StoreCore.registerSchema(table, schema); + StoreCore.registerSchema(table, schema, defaultKeySchema); // Create key bytes32[] memory key = new bytes32[](1); @@ -675,10 +687,10 @@ contract StoreCoreTest is Test, StoreView { // Register table's schema Schema schema = SchemaLib.encode(SchemaType.UINT128); - StoreCore.registerSchema(table, schema); + StoreCore.registerSchema(table, schema, defaultKeySchema); // Create subscriber - MirrorSubscriber subscriber = new MirrorSubscriber(table, schema); + MirrorSubscriber subscriber = new MirrorSubscriber(table, schema, defaultKeySchema); // !gasreport register subscriber StoreCore.registerStoreHook(table, subscriber); @@ -716,10 +728,10 @@ contract StoreCoreTest is Test, StoreView { // Register table's schema Schema schema = SchemaLib.encode(SchemaType.UINT128, SchemaType.UINT32_ARRAY); - StoreCore.registerSchema(table, schema); + StoreCore.registerSchema(table, schema, defaultKeySchema); // Create subscriber - MirrorSubscriber subscriber = new MirrorSubscriber(table, schema); + MirrorSubscriber subscriber = new MirrorSubscriber(table, schema, defaultKeySchema); // !gasreport register subscriber StoreCore.registerStoreHook(table, subscriber); @@ -766,8 +778,8 @@ uint256 constant indexerTableId = uint256(keccak256("indexer.table")); contract MirrorSubscriber is IStoreHook { uint256 _table; - constructor(uint256 table, Schema schema) { - IStore(msg.sender).registerSchema(indexerTableId, schema); + constructor(uint256 table, Schema schema, Schema keySchema) { + IStore(msg.sender).registerSchema(indexerTableId, schema, keySchema); _table = table; } diff --git a/packages/world/src/World.sol b/packages/world/src/World.sol index 460d45126e..5deaae0b4c 100644 --- a/packages/world/src/World.sol +++ b/packages/world/src/World.sol @@ -82,7 +82,8 @@ contract World is Store { function registerTable( bytes16 namespace, bytes16 file, - Schema schema + Schema valueSchema, + Schema keySchema ) public virtual returns (bytes32 resourceSelector) { resourceSelector = ResourceSelector.from(namespace, file); @@ -102,17 +103,17 @@ contract World is Store { // Store the table resource type ResourceType.set(resourceSelector, Resource.TABLE); - // Register the table's schema - StoreCore.registerSchema(resourceSelector.toTableId(), schema); + // Register the table's valueSchema and keySchema + StoreCore.registerSchema(resourceSelector.toTableId(), valueSchema, keySchema); } /** * Register the given schema for the given table id. * This overload exists to conform with the IStore interface. */ - function registerSchema(uint256 tableId, Schema schema) public virtual override { + function registerSchema(uint256 tableId, Schema valueSchema, Schema keySchema) public virtual override { bytes32 tableSelector = ResourceSelector.from(tableId); - registerTable(tableSelector.getNamespace(), tableSelector.getFile(), schema); + registerTable(tableSelector.getNamespace(), tableSelector.getFile(), valueSchema, keySchema); } /** diff --git a/packages/world/src/tables/AddressArray.sol b/packages/world/src/tables/AddressArray.sol index 9e2536e45e..befaa04db3 100644 --- a/packages/world/src/tables/AddressArray.sol +++ b/packages/world/src/tables/AddressArray.sol @@ -25,6 +25,13 @@ library AddressArray { return SchemaLib.encode(_schema); } + function getKeySchema() internal pure returns (Schema) { + SchemaType[] memory _schema = new SchemaType[](1); + _schema[0] = SchemaType.BYTES32; + + return SchemaLib.encode(_schema); + } + /** Get the table's metadata */ function getMetadata() internal pure returns (string memory, string[] memory) { string[] memory _fieldNames = new string[](1); @@ -34,7 +41,7 @@ library AddressArray { /** Register the table's schema */ function registerSchema(uint256 _tableId) internal { - StoreSwitch.registerSchema(_tableId, getSchema()); + StoreSwitch.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata */ @@ -45,7 +52,7 @@ library AddressArray { /** Register the table's schema for the specified store */ function registerSchema(uint256 _tableId, IStore _store) internal { - _store.registerSchema(_tableId, getSchema()); + _store.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata for the specified store */ diff --git a/packages/world/src/tables/Bool.sol b/packages/world/src/tables/Bool.sol index d9d161cda3..31310c6759 100644 --- a/packages/world/src/tables/Bool.sol +++ b/packages/world/src/tables/Bool.sol @@ -23,14 +23,20 @@ library Bool { return SchemaLib.encode(_schema); } + function getKeySchema() internal pure returns (Schema) { + SchemaType[] memory _schema = new SchemaType[](0); + + return SchemaLib.encode(_schema); + } + /** Register the table's schema */ function registerSchema(uint256 _tableId) internal { - StoreSwitch.registerSchema(_tableId, getSchema()); + StoreSwitch.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Register the table's schema for the specified store */ function registerSchema(uint256 _tableId, IStore _store) internal { - _store.registerSchema(_tableId, getSchema()); + _store.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Get value */ diff --git a/packages/world/src/tables/NamespaceOwner.sol b/packages/world/src/tables/NamespaceOwner.sol index 475284c0ef..01048369c8 100644 --- a/packages/world/src/tables/NamespaceOwner.sol +++ b/packages/world/src/tables/NamespaceOwner.sol @@ -28,6 +28,13 @@ library NamespaceOwner { return SchemaLib.encode(_schema); } + function getKeySchema() internal pure returns (Schema) { + SchemaType[] memory _schema = new SchemaType[](1); + _schema[0] = SchemaType.BYTES16; + + return SchemaLib.encode(_schema); + } + /** Get the table's metadata */ function getMetadata() internal pure returns (string memory, string[] memory) { string[] memory _fieldNames = new string[](1); @@ -37,7 +44,7 @@ library NamespaceOwner { /** Register the table's schema */ function registerSchema() internal { - StoreSwitch.registerSchema(_tableId, getSchema()); + StoreSwitch.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata */ @@ -48,7 +55,7 @@ library NamespaceOwner { /** Register the table's schema for the specified store */ function registerSchema(IStore _store) internal { - _store.registerSchema(_tableId, getSchema()); + _store.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata for the specified store */ diff --git a/packages/world/src/tables/ResourceAccess.sol b/packages/world/src/tables/ResourceAccess.sol index 5ea4d3a2cd..bcd2c85456 100644 --- a/packages/world/src/tables/ResourceAccess.sol +++ b/packages/world/src/tables/ResourceAccess.sol @@ -28,6 +28,14 @@ library ResourceAccess { return SchemaLib.encode(_schema); } + function getKeySchema() internal pure returns (Schema) { + SchemaType[] memory _schema = new SchemaType[](2); + _schema[0] = SchemaType.BYTES32; + _schema[1] = SchemaType.ADDRESS; + + return SchemaLib.encode(_schema); + } + /** Get the table's metadata */ function getMetadata() internal pure returns (string memory, string[] memory) { string[] memory _fieldNames = new string[](1); @@ -37,7 +45,7 @@ library ResourceAccess { /** Register the table's schema */ function registerSchema() internal { - StoreSwitch.registerSchema(_tableId, getSchema()); + StoreSwitch.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata */ @@ -48,7 +56,7 @@ library ResourceAccess { /** Register the table's schema for the specified store */ function registerSchema(IStore _store) internal { - _store.registerSchema(_tableId, getSchema()); + _store.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata for the specified store */ diff --git a/packages/world/src/tables/ResourceType.sol b/packages/world/src/tables/ResourceType.sol index 84265f51b3..bf5f0b1486 100644 --- a/packages/world/src/tables/ResourceType.sol +++ b/packages/world/src/tables/ResourceType.sol @@ -31,6 +31,13 @@ library ResourceType { return SchemaLib.encode(_schema); } + function getKeySchema() internal pure returns (Schema) { + SchemaType[] memory _schema = new SchemaType[](1); + _schema[0] = SchemaType.BYTES32; + + return SchemaLib.encode(_schema); + } + /** Get the table's metadata */ function getMetadata() internal pure returns (string memory, string[] memory) { string[] memory _fieldNames = new string[](1); @@ -40,7 +47,7 @@ library ResourceType { /** Register the table's schema */ function registerSchema() internal { - StoreSwitch.registerSchema(_tableId, getSchema()); + StoreSwitch.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata */ diff --git a/packages/world/src/tables/SystemRegistry.sol b/packages/world/src/tables/SystemRegistry.sol index 6ace9bfebc..5bd5d88279 100644 --- a/packages/world/src/tables/SystemRegistry.sol +++ b/packages/world/src/tables/SystemRegistry.sol @@ -28,6 +28,13 @@ library SystemRegistry { return SchemaLib.encode(_schema); } + function getKeySchema() internal pure returns (Schema) { + SchemaType[] memory _schema = new SchemaType[](1); + _schema[0] = SchemaType.ADDRESS; + + return SchemaLib.encode(_schema); + } + /** Get the table's metadata */ function getMetadata() internal pure returns (string memory, string[] memory) { string[] memory _fieldNames = new string[](1); @@ -37,7 +44,7 @@ library SystemRegistry { /** Register the table's schema */ function registerSchema() internal { - StoreSwitch.registerSchema(_tableId, getSchema()); + StoreSwitch.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata */ diff --git a/packages/world/src/tables/Systems.sol b/packages/world/src/tables/Systems.sol index 663c29c86e..9014dec711 100644 --- a/packages/world/src/tables/Systems.sol +++ b/packages/world/src/tables/Systems.sol @@ -29,6 +29,13 @@ library Systems { return SchemaLib.encode(_schema); } + function getKeySchema() internal pure returns (Schema) { + SchemaType[] memory _schema = new SchemaType[](1); + _schema[0] = SchemaType.BYTES32; + + return SchemaLib.encode(_schema); + } + /** Get the table's metadata */ function getMetadata() internal pure returns (string memory, string[] memory) { string[] memory _fieldNames = new string[](2); @@ -39,7 +46,7 @@ library Systems { /** Register the table's schema */ function registerSchema() internal { - StoreSwitch.registerSchema(_tableId, getSchema()); + StoreSwitch.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata */ @@ -50,7 +57,7 @@ library Systems { /** Register the table's schema for the specified store */ function registerSchema(IStore _store) internal { - _store.registerSchema(_tableId, getSchema()); + _store.registerSchema(_tableId, getSchema(), getKeySchema()); } /** Set the table's metadata for the specified store */ diff --git a/packages/world/src/test/tables/AddressArray.sol b/packages/world/src/test/tables/AddressArray.sol deleted file mode 100644 index 66e4bc184a..0000000000 --- a/packages/world/src/test/tables/AddressArray.sol +++ /dev/null @@ -1,103 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.0; - -/* 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 { SliceLib } from "@latticexyz/store/src/Slice.sol"; -import { EncodeArray } from "@latticexyz/store/src/tightcoder/EncodeArray.sol"; -import { Schema, SchemaLib } from "@latticexyz/store/src/Schema.sol"; -import { PackedCounter, PackedCounterLib } from "@latticexyz/store/src/PackedCounter.sol"; - -uint256 constant _tableId = uint256(keccak256("/AddressArray")); -uint256 constant AddressArrayTableId = _tableId; - -library AddressArray { - /** Get the table's schema */ - function getSchema() internal pure returns (Schema) { - SchemaType[] memory _schema = new SchemaType[](1); - _schema[0] = SchemaType.ADDRESS_ARRAY; - - return SchemaLib.encode(_schema); - } - - /** Get the table's metadata */ - function getMetadata() internal pure returns (string memory, string[] memory) { - string[] memory _fieldNames = new string[](1); - _fieldNames[0] = "value"; - return ("AddressArray", _fieldNames); - } - - /** Register the table's schema */ - function registerSchema() internal { - StoreSwitch.registerSchema(_tableId, getSchema()); - } - - /** Set the table's metadata */ - function setMetadata() internal { - (string memory _tableName, string[] memory _fieldNames) = getMetadata(); - StoreSwitch.setMetadata(_tableId, _tableName, _fieldNames); - } - - /** Register the table's schema for the specified store */ - function registerSchema(IStore _store) internal { - _store.registerSchema(_tableId, getSchema()); - } - - /** Set the table's metadata for the specified store */ - function setMetadata(IStore _store) internal { - (string memory _tableName, string[] memory _fieldNames) = getMetadata(); - _store.setMetadata(_tableId, _tableName, _fieldNames); - } - - /** Get value */ - function get(bytes32 key) internal view returns (address[] memory value) { - bytes32[] memory _primaryKeys = new bytes32[](1); - _primaryKeys[0] = bytes32((key)); - - bytes memory _blob = StoreSwitch.getField(_tableId, _primaryKeys, 0); - return (SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_address()); - } - - /** Get value from the specified store */ - function get(IStore _store, bytes32 key) internal view returns (address[] memory value) { - bytes32[] memory _primaryKeys = new bytes32[](1); - _primaryKeys[0] = bytes32((key)); - - bytes memory _blob = _store.getField(_tableId, _primaryKeys, 0); - return (SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_address()); - } - - /** Set value */ - function set(bytes32 key, address[] memory value) internal { - bytes32[] memory _primaryKeys = new bytes32[](1); - _primaryKeys[0] = bytes32((key)); - - StoreSwitch.setField(_tableId, _primaryKeys, 0, EncodeArray.encode((value))); - } - - /** Push an element to value */ - function push(bytes32 key, address _element) internal { - bytes32[] memory _primaryKeys = new bytes32[](1); - _primaryKeys[0] = bytes32((key)); - - bytes memory _blob = StoreSwitch.getField(_tableId, _primaryKeys, 0); - bytes memory _newBlob = abi.encodePacked(_blob, abi.encodePacked((_element))); - StoreSwitch.setField(_tableId, _primaryKeys, 0, _newBlob); - } - - /* Delete all data for given keys */ - function deleteRecord(bytes32 key) internal { - bytes32[] memory _primaryKeys = new bytes32[](1); - _primaryKeys[0] = bytes32((key)); - - StoreSwitch.deleteRecord(_tableId, _primaryKeys); - } -} diff --git a/packages/world/test/World.t.sol b/packages/world/test/World.t.sol index 3dca5d9ae3..151012dda0 100644 --- a/packages/world/test/World.t.sol +++ b/packages/world/test/World.t.sol @@ -97,6 +97,7 @@ contract WorldTest is Test { event HookCalled(bytes data); event WorldTestSystemLog(string log); + Schema defaultKeySchema = SchemaLib.encode(SchemaType.BYTES32); World world; bytes32 key; @@ -153,7 +154,7 @@ contract WorldTest is Test { bytes16 table = "testTable"; // Register a new table in the namespace - bytes32 tableSelector = world.registerTable(namespace, table, schema); + bytes32 tableSelector = world.registerTable(namespace, table, schema, defaultKeySchema); // Expect the namespace to be created and owned by the caller assertEq(NamespaceOwner.get(world, namespace), address(this)); @@ -163,11 +164,11 @@ contract WorldTest is Test { // Expect an error when registering an existing table vm.expectRevert(abi.encodeWithSelector(World.ResourceExists.selector, tableSelector.toString())); - world.registerTable(namespace, table, schema); + world.registerTable(namespace, table, schema, defaultKeySchema); // Expect an error when registering a table in a namespace that is not owned by the caller _expectAccessDenied(address(0x01), namespace, ""); - world.registerTable(namespace, "otherTable", schema); + world.registerTable(namespace, "otherTable", schema, defaultKeySchema); } function testSetMetadata() public { @@ -187,7 +188,7 @@ contract WorldTest is Test { world.setMetadata("invalid", "invalid", tableName, fieldNames); // Register a table - world.registerTable(namespace, file, schema); + world.registerTable(namespace, file, schema, defaultKeySchema); // Set metadata world.setMetadata(namespace, file, tableName, fieldNames); @@ -256,7 +257,7 @@ contract WorldTest is Test { function testDuplicateSelectors() public { // Register a new table - bytes32 resourceSelector = world.registerTable("namespace", "file", Bool.getSchema()); + bytes32 resourceSelector = world.registerTable("namespace", "file", Bool.getSchema(), defaultKeySchema); // Deploy a new system System system = new System(); @@ -270,7 +271,7 @@ contract WorldTest is Test { // Expect an error when trying to register a table at the same selector vm.expectRevert(abi.encodeWithSelector(World.ResourceExists.selector, resourceSelector.toString())); - world.registerTable("namespace2", "file", Bool.getSchema()); + world.registerTable("namespace2", "file", Bool.getSchema(), defaultKeySchema); } function testGrantAccess() public { @@ -283,7 +284,7 @@ contract WorldTest is Test { function testSetRecord() public { // Register a new table - bytes32 resourceSelector = world.registerTable("testSetRecord", "testTable", Bool.getSchema()); + bytes32 resourceSelector = world.registerTable("testSetRecord", "testTable", Bool.getSchema(), defaultKeySchema); uint256 tableId = uint256(resourceSelector); // Write data to the table @@ -299,7 +300,7 @@ contract WorldTest is Test { function testSetField() public { // Register a new table - bytes32 resourceSelector = world.registerTable("testSetField", "testTable", Bool.getSchema()); + bytes32 resourceSelector = world.registerTable("testSetField", "testTable", Bool.getSchema(), defaultKeySchema); uint256 tableId = uint256(resourceSelector); // Write data to the table via its namespace @@ -328,7 +329,7 @@ contract WorldTest is Test { bytes16 file = "testTable"; // Register a new table - bytes32 resourceSelector = world.registerTable(namespace, file, AddressArray.getSchema()); + bytes32 resourceSelector = world.registerTable(namespace, file, AddressArray.getSchema(), defaultKeySchema); uint256 tableId = uint256(resourceSelector); // Create data @@ -364,7 +365,7 @@ contract WorldTest is Test { function testDeleteRecord() public { // Register a new table - bytes32 resourceSelector = world.registerTable("testDeleteRecord", "testTable", Bool.getSchema()); + bytes32 resourceSelector = world.registerTable("testDeleteRecord", "testTable", Bool.getSchema(), defaultKeySchema); uint256 tableId = uint256(resourceSelector); // Write data to the table via the namespace and expect it to be written @@ -465,7 +466,7 @@ contract WorldTest is Test { function testRegisterTableHook() public { // Register a new table - bytes32 resourceSelector = world.registerTable("", "testTable", Bool.getSchema()); + bytes32 resourceSelector = world.registerTable("", "testTable", Bool.getSchema(), defaultKeySchema); uint256 tableId = uint256(resourceSelector); // Register a new hook @@ -487,7 +488,7 @@ contract WorldTest is Test { function testWriteRootSystem() public { // Register a new table - bytes32 resourceSelector = world.registerTable("namespace", "testTable", Bool.getSchema()); + bytes32 resourceSelector = world.registerTable("namespace", "testTable", Bool.getSchema(), defaultKeySchema); uint256 tableId = uint256(resourceSelector); // Register a new system @@ -507,7 +508,7 @@ contract WorldTest is Test { function testWriteAutonomousSystem() public { // Register a new table - uint256 tableId = uint256(world.registerTable("namespace", "testTable", Bool.getSchema())); + uint256 tableId = uint256(world.registerTable("namespace", "testTable", Bool.getSchema(), defaultKeySchema)); // Register a new system WorldTestSystem system = new WorldTestSystem();