From 3b3541dbef8f3423ef27a735bc48cec57339b4da Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Tue, 5 Dec 2023 15:07:51 +0000 Subject: [PATCH 01/21] fix(store): emit event after calling beforeSetRecord hook --- packages/store/gas-report.json | 22 +++++++++--------- packages/store/src/StoreCore.sol | 16 ++++++------- packages/world-modules/gas-report.json | 32 +++++++++++++------------- packages/world/gas-report.json | 10 ++++---- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/packages/store/gas-report.json b/packages/store/gas-report.json index 9f4e108ac7..3212b9e24b 100644 --- a/packages/store/gas-report.json +++ b/packages/store/gas-report.json @@ -369,7 +369,7 @@ "file": "test/KeyEncoding.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "register KeyEncoding table", - "gasUsed": 719017 + "gasUsed": 719033 }, { "file": "test/Mixed.t.sol", @@ -393,7 +393,7 @@ "file": "test/Mixed.t.sol", "test": "testSetGetDeleteExternal", "name": "set record in Mixed (external, cold)", - "gasUsed": 108527 + "gasUsed": 108528 }, { "file": "test/Mixed.t.sol", @@ -411,7 +411,7 @@ "file": "test/Mixed.t.sol", "test": "testSetGetDeleteInternal", "name": "set record in Mixed (internal, cold)", - "gasUsed": 103281 + "gasUsed": 103282 }, { "file": "test/Mixed.t.sol", @@ -753,7 +753,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testHooks", "name": "set record on table with subscriber", - "gasUsed": 72296 + "gasUsed": 72320 }, { "file": "test/StoreCoreGas.t.sol", @@ -777,7 +777,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testHooksDynamicData", "name": "set (dynamic) record on table with subscriber", - "gasUsed": 165451 + "gasUsed": 165460 }, { "file": "test/StoreCoreGas.t.sol", @@ -807,7 +807,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "StoreCore: register table", - "gasUsed": 640899 + "gasUsed": 640903 }, { "file": "test/StoreCoreGas.t.sol", @@ -831,7 +831,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetDynamicData", "name": "set complex record with dynamic data (4 slots)", - "gasUsed": 102512 + "gasUsed": 102513 }, { "file": "test/StoreCoreGas.t.sol", @@ -921,7 +921,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetStaticData", "name": "set static record (1 slot)", - "gasUsed": 32756 + "gasUsed": 32782 }, { "file": "test/StoreCoreGas.t.sol", @@ -933,7 +933,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetStaticDataSpanningWords", "name": "set static record (2 slots)", - "gasUsed": 55260 + "gasUsed": 55289 }, { "file": "test/StoreCoreGas.t.sol", @@ -1143,13 +1143,13 @@ "file": "test/Vector2.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "register Vector2 field layout", - "gasUsed": 442403 + "gasUsed": 442404 }, { "file": "test/Vector2.t.sol", "test": "testSetAndGet", "name": "set Vector2 record", - "gasUsed": 33658 + "gasUsed": 33684 }, { "file": "test/Vector2.t.sol", diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index 7697618970..e5144483c4 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -298,14 +298,6 @@ library StoreCore { bytes memory dynamicData, FieldLayout fieldLayout ) internal { - // Emit event to notify indexers - emit Store_SetRecord(tableId, keyTuple, staticData, encodedLengths, dynamicData); - - // Early return if the table is an offchain table - if (tableId.getType() != RESOURCE_TABLE) { - return; - } - // Call onBeforeSetRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) bytes21[] memory hooks = StoreHooks._get(tableId); for (uint256 i; i < hooks.length; i++) { @@ -322,6 +314,14 @@ library StoreCore { } } + // Emit event to notify indexers + emit Store_SetRecord(tableId, keyTuple, staticData, encodedLengths, dynamicData); + + // Early return if the table is an offchain table + if (tableId.getType() != RESOURCE_TABLE) { + return; + } + // Store the static data at the static data location uint256 staticDataLocation = StoreCoreInternal._getStaticDataLocation(tableId, keyTuple); uint256 memoryPointer = Memory.dataPointer(staticData); diff --git a/packages/world-modules/gas-report.json b/packages/world-modules/gas-report.json index b9e5dddb20..c8f49a12cd 100644 --- a/packages/world-modules/gas-report.json +++ b/packages/world-modules/gas-report.json @@ -75,37 +75,37 @@ "file": "test/KeysInTableModule.t.sol", "test": "testInstallComposite", "name": "install keys in table module", - "gasUsed": 1409435 + "gasUsed": 1409440 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallGas", "name": "install keys in table module", - "gasUsed": 1409435 + "gasUsed": 1409440 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallGas", "name": "set a record on a table with keysInTableModule installed", - "gasUsed": 158814 + "gasUsed": 158838 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallSingleton", "name": "install keys in table module", - "gasUsed": 1409435 + "gasUsed": 1409440 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookCompositeGas", "name": "install keys in table module", - "gasUsed": 1409435 + "gasUsed": 1409440 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookCompositeGas", "name": "change a composite record on a table with keysInTableModule installed", - "gasUsed": 22497 + "gasUsed": 22498 }, { "file": "test/KeysInTableModule.t.sol", @@ -117,13 +117,13 @@ "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookGas", "name": "install keys in table module", - "gasUsed": 1409435 + "gasUsed": 1409440 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookGas", "name": "change a record on a table with keysInTableModule installed", - "gasUsed": 21219 + "gasUsed": 21220 }, { "file": "test/KeysInTableModule.t.sol", @@ -135,7 +135,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testGetKeysWithValueGas", "name": "install keys with value module", - "gasUsed": 650708 + "gasUsed": 650709 }, { "file": "test/KeysWithValueModule.t.sol", @@ -153,25 +153,25 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testInstall", "name": "install keys with value module", - "gasUsed": 650708 + "gasUsed": 650709 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testInstall", "name": "set a record on a table with KeysWithValueModule installed", - "gasUsed": 135405 + "gasUsed": 135406 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testSetAndDeleteRecordHook", "name": "install keys with value module", - "gasUsed": 650708 + "gasUsed": 650709 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testSetAndDeleteRecordHook", "name": "change a record on a table with KeysWithValueModule installed", - "gasUsed": 103789 + "gasUsed": 103790 }, { "file": "test/KeysWithValueModule.t.sol", @@ -183,7 +183,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testSetField", "name": "install keys with value module", - "gasUsed": 650708 + "gasUsed": 650709 }, { "file": "test/KeysWithValueModule.t.sol", @@ -303,7 +303,7 @@ "file": "test/UniqueEntityModule.t.sol", "test": "testInstall", "name": "install unique entity module", - "gasUsed": 678996 + "gasUsed": 683359 }, { "file": "test/UniqueEntityModule.t.sol", @@ -315,7 +315,7 @@ "file": "test/UniqueEntityModule.t.sol", "test": "testInstallRoot", "name": "installRoot unique entity module", - "gasUsed": 644433 + "gasUsed": 648796 }, { "file": "test/UniqueEntityModule.t.sol", diff --git a/packages/world/gas-report.json b/packages/world/gas-report.json index 007eafe3d9..8458e38e30 100644 --- a/packages/world/gas-report.json +++ b/packages/world/gas-report.json @@ -93,7 +93,7 @@ "file": "test/World.t.sol", "test": "testRegisterFunctionSelector", "name": "Register a function selector", - "gasUsed": 83149 + "gasUsed": 87510 }, { "file": "test/World.t.sol", @@ -105,19 +105,19 @@ "file": "test/World.t.sol", "test": "testRegisterRootFunctionSelector", "name": "Register a root function selector", - "gasUsed": 80433 + "gasUsed": 84795 }, { "file": "test/World.t.sol", "test": "testRegisterSystem", "name": "register a system", - "gasUsed": 162594 + "gasUsed": 162595 }, { "file": "test/World.t.sol", "test": "testRegisterTable", "name": "Register a new table in the namespace", - "gasUsed": 637367 + "gasUsed": 637368 }, { "file": "test/World.t.sol", @@ -129,7 +129,7 @@ "file": "test/World.t.sol", "test": "testSetRecord", "name": "Write data to the table", - "gasUsed": 39039 + "gasUsed": 39062 }, { "file": "test/WorldDynamicUpdate.t.sol", From 54317e439ef36166c03cc3e36419abda418ea913 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Tue, 5 Dec 2023 15:15:51 +0000 Subject: [PATCH 02/21] fix: move splice events --- packages/store/src/StoreCore.sol | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index e5144483c4..84de069931 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -389,14 +389,6 @@ library StoreCore { function spliceStaticData(ResourceId tableId, bytes32[] memory keyTuple, uint48 start, bytes memory data) internal { uint256 location = StoreCoreInternal._getStaticDataLocation(tableId, keyTuple); - // Emit event to notify offchain indexers - emit StoreCore.Store_SpliceStaticData({ tableId: tableId, keyTuple: keyTuple, start: start, data: data }); - - // Early return if the table is an offchain table - if (tableId.getType() != RESOURCE_TABLE) { - return; - } - // Call onBeforeSpliceStaticData hooks (before actually modifying the state, so observers have access to the previous state if needed) bytes21[] memory hooks = StoreHooks._get(tableId); for (uint256 i; i < hooks.length; i++) { @@ -411,6 +403,14 @@ library StoreCore { } } + // Emit event to notify offchain indexers + emit StoreCore.Store_SpliceStaticData({ tableId: tableId, keyTuple: keyTuple, start: start, data: data }); + + // Early return if the table is an offchain table + if (tableId.getType() != RESOURCE_TABLE) { + return; + } + // Store the provided value in storage Storage.store({ storagePointer: location, offset: start, data: data }); From 93d3b9959702ec1572f5768dd6dcd7ad377e0176 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Tue, 5 Dec 2023 15:22:56 +0000 Subject: [PATCH 03/21] chore: docs, gas --- docs/pages/store/reference/store-core.mdx | 37 -------------- docs/pages/store/reference/store.mdx | 43 ---------------- packages/store/gas-report.json | 12 ++--- packages/world-modules/gas-report.json | 62 +++++++++++------------ packages/world/gas-report.json | 10 ++-- 5 files changed, 42 insertions(+), 122 deletions(-) diff --git a/docs/pages/store/reference/store-core.mdx b/docs/pages/store/reference/store-core.mdx index 421cbdc3dd..bb9c8ba2db 100644 --- a/docs/pages/store/reference/store-core.mdx +++ b/docs/pages/store/reference/store-core.mdx @@ -774,16 +774,6 @@ event Store_SetRecord( ); ``` -**Parameters** - -| Name | Type | Description | -| ---------------- | --------------- | ------------------------------------------------------- | -| `tableId` | `ResourceId` | The ID of the table where the record is set. | -| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | -| `staticData` | `bytes` | The static data of the record. | -| `encodedLengths` | `PackedCounter` | The encoded lengths of the dynamic data of the record. | -| `dynamicData` | `bytes` | The dynamic data of the record. | - ### Store_SpliceStaticData Emitted when static data in the store is spliced. @@ -795,15 +785,6 @@ so the total length of the data remains the same and no data is shifted._ event Store_SpliceStaticData(ResourceId indexed tableId, bytes32[] keyTuple, uint48 start, bytes data); ``` -**Parameters** - -| Name | Type | Description | -| ---------- | ------------ | --------------------------------------------------------------------- | -| `tableId` | `ResourceId` | The ID of the table where the data is spliced. | -| `keyTuple` | `bytes32[]` | An array representing the key for the record. | -| `start` | `uint48` | The start position in bytes for the splice operation. | -| `data` | `bytes` | The data to write to the static data of the record at the start byte. | - ### Store_SpliceDynamicData Emitted when dynamic data in the store is spliced. @@ -819,17 +800,6 @@ event Store_SpliceDynamicData( ); ``` -**Parameters** - -| Name | Type | Description | -| ---------------- | --------------- | ------------------------------------------------------------------------- | -| `tableId` | `ResourceId` | The ID of the table where the data is spliced. | -| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | -| `start` | `uint48` | The start position in bytes for the splice operation. | -| `deleteCount` | `uint40` | The number of bytes to delete in the splice operation. | -| `encodedLengths` | `PackedCounter` | The encoded lengths of the dynamic data of the record. | -| `data` | `bytes` | The data to insert into the dynamic data of the record at the start byte. | - ### Store_DeleteRecord Emitted when a record is deleted from the store. @@ -837,10 +807,3 @@ Emitted when a record is deleted from the store. ```solidity event Store_DeleteRecord(ResourceId indexed tableId, bytes32[] keyTuple); ``` - -**Parameters** - -| Name | Type | Description | -| ---------- | ------------ | ------------------------------------------------------- | -| `tableId` | `ResourceId` | The ID of the table where the record is deleted. | -| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | diff --git a/docs/pages/store/reference/store.mdx b/docs/pages/store/reference/store.mdx index 71551f45df..7f6b1db8ab 100644 --- a/docs/pages/store/reference/store.mdx +++ b/docs/pages/store/reference/store.mdx @@ -23,16 +23,6 @@ event Store_SetRecord( ); ``` -**Parameters** - -| Name | Type | Description | -| ---------------- | --------------- | ------------------------------------------------------- | -| `tableId` | `ResourceId` | The ID of the table where the record is set. | -| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | -| `staticData` | `bytes` | The static data of the record. | -| `encodedLengths` | `PackedCounter` | The encoded lengths of the dynamic data of the record. | -| `dynamicData` | `bytes` | The dynamic data of the record. | - ### Store_SpliceStaticData Emitted when static data in the store is spliced. @@ -44,15 +34,6 @@ so the total length of the data remains the same and no data is shifted._ event Store_SpliceStaticData(ResourceId indexed tableId, bytes32[] keyTuple, uint48 start, bytes data); ``` -**Parameters** - -| Name | Type | Description | -| ---------- | ------------ | --------------------------------------------------------------------- | -| `tableId` | `ResourceId` | The ID of the table where the data is spliced. | -| `keyTuple` | `bytes32[]` | An array representing the key for the record. | -| `start` | `uint48` | The start position in bytes for the splice operation. | -| `data` | `bytes` | The data to write to the static data of the record at the start byte. | - ### Store_SpliceDynamicData Emitted when dynamic data in the store is spliced. @@ -68,17 +49,6 @@ event Store_SpliceDynamicData( ); ``` -**Parameters** - -| Name | Type | Description | -| ---------------- | --------------- | ------------------------------------------------------------------------- | -| `tableId` | `ResourceId` | The ID of the table where the data is spliced. | -| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | -| `start` | `uint48` | The start position in bytes for the splice operation. | -| `deleteCount` | `uint40` | The number of bytes to delete in the splice operation. | -| `encodedLengths` | `PackedCounter` | The encoded lengths of the dynamic data of the record. | -| `data` | `bytes` | The data to insert into the dynamic data of the record at the start byte. | - ### Store_DeleteRecord Emitted when a record is deleted from the store. @@ -87,13 +57,6 @@ Emitted when a record is deleted from the store. event Store_DeleteRecord(ResourceId indexed tableId, bytes32[] keyTuple); ``` -**Parameters** - -| Name | Type | Description | -| ---------- | ------------ | ------------------------------------------------------- | -| `tableId` | `ResourceId` | The ID of the table where the record is deleted. | -| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | - ## IStoreErrors [Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/IStoreErrors.sol) @@ -191,12 +154,6 @@ Emitted when the store is initialized. event HelloStore(bytes32 indexed storeVersion); ``` -**Parameters** - -| Name | Type | Description | -| -------------- | --------- | ---------------------------------- | -| `storeVersion` | `bytes32` | The version of the Store contract. | - ## IStoreRead [Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/IStoreRead.sol) diff --git a/packages/store/gas-report.json b/packages/store/gas-report.json index 3212b9e24b..b7c5359edf 100644 --- a/packages/store/gas-report.json +++ b/packages/store/gas-report.json @@ -369,7 +369,7 @@ "file": "test/KeyEncoding.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "register KeyEncoding table", - "gasUsed": 719033 + "gasUsed": 719047 }, { "file": "test/Mixed.t.sol", @@ -759,7 +759,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testHooks", "name": "set static field on table with subscriber", - "gasUsed": 19761 + "gasUsed": 19785 }, { "file": "test/StoreCoreGas.t.sol", @@ -807,7 +807,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "StoreCore: register table", - "gasUsed": 640903 + "gasUsed": 640929 }, { "file": "test/StoreCoreGas.t.sol", @@ -873,7 +873,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetField", "name": "set static field (1 slot)", - "gasUsed": 31209 + "gasUsed": 31237 }, { "file": "test/StoreCoreGas.t.sol", @@ -885,7 +885,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetField", "name": "set static field (overlap 2 slot)", - "gasUsed": 29862 + "gasUsed": 29893 }, { "file": "test/StoreCoreGas.t.sol", @@ -1143,7 +1143,7 @@ "file": "test/Vector2.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "register Vector2 field layout", - "gasUsed": 442404 + "gasUsed": 442432 }, { "file": "test/Vector2.t.sol", diff --git a/packages/world-modules/gas-report.json b/packages/world-modules/gas-report.json index c8f49a12cd..5957105b19 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": 114329 + "gasUsed": 114357 }, { "file": "test/ERC20.t.sol", "test": "testBurn", "name": "burn", - "gasUsed": 75866 + "gasUsed": 75913 }, { "file": "test/ERC20.t.sol", "test": "testMint", "name": "mint", - "gasUsed": 161705 + "gasUsed": 161752 }, { "file": "test/ERC20.t.sol", "test": "testTransfer", "name": "transfer", - "gasUsed": 92948 + "gasUsed": 92998 }, { "file": "test/ERC20.t.sol", "test": "testTransferFrom", "name": "transferFrom", - "gasUsed": 130250 + "gasUsed": 130328 }, { "file": "test/ERC721.t.sol", "test": "testApproveAllGas", "name": "setApprovalForAll", - "gasUsed": 113956 + "gasUsed": 113984 }, { "file": "test/ERC721.t.sol", "test": "testApproveGas", "name": "approve", - "gasUsed": 87965 + "gasUsed": 87990 }, { "file": "test/ERC721.t.sol", "test": "testBurnGas", "name": "burn", - "gasUsed": 101835 + "gasUsed": 101910 }, { "file": "test/ERC721.t.sol", "test": "testMintGas", "name": "mint", - "gasUsed": 169433 + "gasUsed": 169483 }, { "file": "test/ERC721.t.sol", "test": "testSafeMintToEOAGas", "name": "safeMint", - "gasUsed": 169704 + "gasUsed": 169754 }, { "file": "test/ERC721.t.sol", "test": "testSafeTransferFromToEOAGas", "name": "safeTransferFrom", - "gasUsed": 143638 + "gasUsed": 143738 }, { "file": "test/ERC721.t.sol", "test": "testTransferFromGas", "name": "transferFrom", - "gasUsed": 136798 + "gasUsed": 136898 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallComposite", "name": "install keys in table module", - "gasUsed": 1409440 + "gasUsed": 1409578 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallGas", "name": "install keys in table module", - "gasUsed": 1409440 + "gasUsed": 1409578 }, { "file": "test/KeysInTableModule.t.sol", @@ -93,13 +93,13 @@ "file": "test/KeysInTableModule.t.sol", "test": "testInstallSingleton", "name": "install keys in table module", - "gasUsed": 1409440 + "gasUsed": 1409578 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookCompositeGas", "name": "install keys in table module", - "gasUsed": 1409440 + "gasUsed": 1409578 }, { "file": "test/KeysInTableModule.t.sol", @@ -111,13 +111,13 @@ "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookCompositeGas", "name": "delete a composite record on a table with keysInTableModule installed", - "gasUsed": 155729 + "gasUsed": 155758 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookGas", "name": "install keys in table module", - "gasUsed": 1409440 + "gasUsed": 1409578 }, { "file": "test/KeysInTableModule.t.sol", @@ -129,13 +129,13 @@ "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookGas", "name": "delete a record on a table with keysInTableModule installed", - "gasUsed": 84971 + "gasUsed": 85000 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testGetKeysWithValueGas", "name": "install keys with value module", - "gasUsed": 650709 + "gasUsed": 650824 }, { "file": "test/KeysWithValueModule.t.sol", @@ -153,7 +153,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testInstall", "name": "install keys with value module", - "gasUsed": 650709 + "gasUsed": 650824 }, { "file": "test/KeysWithValueModule.t.sol", @@ -165,7 +165,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testSetAndDeleteRecordHook", "name": "install keys with value module", - "gasUsed": 650709 + "gasUsed": 650824 }, { "file": "test/KeysWithValueModule.t.sol", @@ -183,7 +183,7 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testSetField", "name": "install keys with value module", - "gasUsed": 650709 + "gasUsed": 650824 }, { "file": "test/KeysWithValueModule.t.sol", @@ -267,7 +267,7 @@ "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromCallboundDelegation", "name": "register a callbound delegation", - "gasUsed": 117426 + "gasUsed": 117460 }, { "file": "test/StandardDelegationsModule.t.sol", @@ -279,19 +279,19 @@ "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromSystemDelegation", "name": "register a systembound delegation", - "gasUsed": 114982 + "gasUsed": 115013 }, { "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromSystemDelegation", "name": "call a system via a systembound delegation", - "gasUsed": 33831 + "gasUsed": 33860 }, { "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromTimeboundDelegation", "name": "register a timebound delegation", - "gasUsed": 111920 + "gasUsed": 111948 }, { "file": "test/StandardDelegationsModule.t.sol", @@ -303,24 +303,24 @@ "file": "test/UniqueEntityModule.t.sol", "test": "testInstall", "name": "install unique entity module", - "gasUsed": 683359 + "gasUsed": 683477 }, { "file": "test/UniqueEntityModule.t.sol", "test": "testInstall", "name": "get a unique entity nonce (non-root module)", - "gasUsed": 51026 + "gasUsed": 51048 }, { "file": "test/UniqueEntityModule.t.sol", "test": "testInstallRoot", "name": "installRoot unique entity module", - "gasUsed": 648796 + "gasUsed": 648858 }, { "file": "test/UniqueEntityModule.t.sol", "test": "testInstallRoot", "name": "get a unique entity nonce (root module)", - "gasUsed": 51026 + "gasUsed": 51048 } ] diff --git a/packages/world/gas-report.json b/packages/world/gas-report.json index 8458e38e30..18be74b5cf 100644 --- a/packages/world/gas-report.json +++ b/packages/world/gas-report.json @@ -69,7 +69,7 @@ "file": "test/World.t.sol", "test": "testCallFromUnlimitedDelegation", "name": "register an unlimited delegation", - "gasUsed": 47623 + "gasUsed": 47642 }, { "file": "test/World.t.sol", @@ -99,7 +99,7 @@ "file": "test/World.t.sol", "test": "testRegisterNamespace", "name": "Register a new namespace", - "gasUsed": 120887 + "gasUsed": 120917 }, { "file": "test/World.t.sol", @@ -111,19 +111,19 @@ "file": "test/World.t.sol", "test": "testRegisterSystem", "name": "register a system", - "gasUsed": 162595 + "gasUsed": 162627 }, { "file": "test/World.t.sol", "test": "testRegisterTable", "name": "Register a new table in the namespace", - "gasUsed": 637368 + "gasUsed": 637426 }, { "file": "test/World.t.sol", "test": "testSetField", "name": "Write data to a table field", - "gasUsed": 36881 + "gasUsed": 36903 }, { "file": "test/World.t.sol", From ab426ef9253906367edcc019ea7973862fd0c3fb Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Tue, 5 Dec 2023 15:25:25 +0000 Subject: [PATCH 04/21] fix: rearrange _spliceDynamicData --- packages/store/gas-report.json | 48 +++++++++++++------------- packages/store/src/StoreCore.sol | 34 +++++++++--------- packages/world-modules/gas-report.json | 32 ++++++++--------- packages/world/gas-report.json | 10 +++--- 4 files changed, 62 insertions(+), 62 deletions(-) diff --git a/packages/store/gas-report.json b/packages/store/gas-report.json index b7c5359edf..28165ff88e 100644 --- a/packages/store/gas-report.json +++ b/packages/store/gas-report.json @@ -63,7 +63,7 @@ "file": "test/Callbacks.t.sol", "test": "testSetAndGet", "name": "Callbacks: set field", - "gasUsed": 56241 + "gasUsed": 56256 }, { "file": "test/Callbacks.t.sol", @@ -75,7 +75,7 @@ "file": "test/Callbacks.t.sol", "test": "testSetAndGet", "name": "Callbacks: push 1 element", - "gasUsed": 32499 + "gasUsed": 32515 }, { "file": "test/FieldLayout.t.sol", @@ -669,25 +669,25 @@ "file": "test/StoreCoreDynamic.t.sol", "test": "testPopFromSecondField", "name": "pop from field (cold, 1 slot, 1 uint32 item)", - "gasUsed": 18017 + "gasUsed": 18026 }, { "file": "test/StoreCoreDynamic.t.sol", "test": "testPopFromSecondField", "name": "pop from field (warm, 1 slot, 1 uint32 item)", - "gasUsed": 12024 + "gasUsed": 12034 }, { "file": "test/StoreCoreDynamic.t.sol", "test": "testPopFromThirdField", "name": "pop from field (cold, 2 slots, 10 uint32 items)", - "gasUsed": 15785 + "gasUsed": 15795 }, { "file": "test/StoreCoreDynamic.t.sol", "test": "testPopFromThirdField", "name": "pop from field (warm, 2 slots, 10 uint32 items)", - "gasUsed": 11792 + "gasUsed": 11803 }, { "file": "test/StoreCoreGas.t.sol", @@ -783,7 +783,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testHooksDynamicData", "name": "set (dynamic) field on table with subscriber", - "gasUsed": 24439 + "gasUsed": 24461 }, { "file": "test/StoreCoreGas.t.sol", @@ -795,13 +795,13 @@ "file": "test/StoreCoreGas.t.sol", "test": "testPushToDynamicField", "name": "push to field (1 slot, 1 uint32 item)", - "gasUsed": 9444 + "gasUsed": 9460 }, { "file": "test/StoreCoreGas.t.sol", "test": "testPushToDynamicField", "name": "push to field (2 slots, 10 uint32 items)", - "gasUsed": 32114 + "gasUsed": 32135 }, { "file": "test/StoreCoreGas.t.sol", @@ -897,7 +897,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetField", "name": "set dynamic field (1 slot, first dynamic field)", - "gasUsed": 53930 + "gasUsed": 53946 }, { "file": "test/StoreCoreGas.t.sol", @@ -909,7 +909,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetField", "name": "set dynamic field (1 slot, second dynamic field)", - "gasUsed": 32153 + "gasUsed": 32171 }, { "file": "test/StoreCoreGas.t.sol", @@ -945,13 +945,13 @@ "file": "test/StoreCoreGas.t.sol", "test": "testUpdateInDynamicField", "name": "update in field (1 slot, 1 uint32 item)", - "gasUsed": 8792 + "gasUsed": 8820 }, { "file": "test/StoreCoreGas.t.sol", "test": "testUpdateInDynamicField", "name": "push to field (2 slots, 6 uint64 items)", - "gasUsed": 9238 + "gasUsed": 9267 }, { "file": "test/StoreHook.t.sol", @@ -981,13 +981,13 @@ "file": "test/StoreHooks.t.sol", "test": "testOneSlot", "name": "StoreHooks: set field with one elements (cold)", - "gasUsed": 58247 + "gasUsed": 58260 }, { "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: set field (cold)", - "gasUsed": 58247 + "gasUsed": 58260 }, { "file": "test/StoreHooks.t.sol", @@ -999,25 +999,25 @@ "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: push 1 element (cold)", - "gasUsed": 12597 + "gasUsed": 12611 }, { "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: pop 1 element (warm)", - "gasUsed": 9931 + "gasUsed": 9943 }, { "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: push 1 element (warm)", - "gasUsed": 10614 + "gasUsed": 10631 }, { "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: update 1 element (warm)", - "gasUsed": 29840 + "gasUsed": 29871 }, { "file": "test/StoreHooks.t.sol", @@ -1029,19 +1029,19 @@ "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: set field (warm)", - "gasUsed": 30392 + "gasUsed": 30412 }, { "file": "test/StoreHooks.t.sol", "test": "testThreeSlots", "name": "StoreHooks: set field with three elements (cold)", - "gasUsed": 80935 + "gasUsed": 80951 }, { "file": "test/StoreHooks.t.sol", "test": "testTwoSlots", "name": "StoreHooks: set field with two elements (cold)", - "gasUsed": 80847 + "gasUsed": 80863 }, { "file": "test/StoreHooksColdLoad.t.sol", @@ -1071,13 +1071,13 @@ "file": "test/StoreHooksColdLoad.t.sol", "test": "testPop", "name": "StoreHooks: pop 1 element (cold)", - "gasUsed": 18366 + "gasUsed": 18375 }, { "file": "test/StoreHooksColdLoad.t.sol", "test": "testUpdate", "name": "StoreHooks: update 1 element (cold)", - "gasUsed": 20295 + "gasUsed": 20318 }, { "file": "test/StoreSwitch.t.sol", diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index 84de069931..9fe87fa7a4 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -989,6 +989,23 @@ library StoreCoreInternal { // Update the encoded length PackedCounter updatedEncodedLengths = previousEncodedLengths.setAtIndex(dynamicFieldIndex, updatedFieldLength); + // Call onBeforeSpliceDynamicData hooks (before actually modifying the state, so observers have access to the previous state if needed) + bytes21[] memory hooks = StoreHooks._get(tableId); + for (uint256 i; i < hooks.length; i++) { + Hook hook = Hook.wrap(hooks[i]); + if (hook.isEnabled(BEFORE_SPLICE_DYNAMIC_DATA)) { + IStoreHook(hook.getAddress()).onBeforeSpliceDynamicData({ + tableId: tableId, + keyTuple: keyTuple, + dynamicFieldIndex: dynamicFieldIndex, + startWithinField: startWithinField, + deleteCount: deleteCount, + encodedLengths: updatedEncodedLengths, + data: data + }); + } + } + { // Compute start index for the splice uint256 start = startWithinField; @@ -1010,23 +1027,6 @@ library StoreCoreInternal { }); } - // Call onBeforeSpliceDynamicData hooks (before actually modifying the state, so observers have access to the previous state if needed) - bytes21[] memory hooks = StoreHooks._get(tableId); - for (uint256 i; i < hooks.length; i++) { - Hook hook = Hook.wrap(hooks[i]); - if (hook.isEnabled(BEFORE_SPLICE_DYNAMIC_DATA)) { - IStoreHook(hook.getAddress()).onBeforeSpliceDynamicData({ - tableId: tableId, - keyTuple: keyTuple, - dynamicFieldIndex: dynamicFieldIndex, - startWithinField: startWithinField, - deleteCount: deleteCount, - encodedLengths: updatedEncodedLengths, - data: data - }); - } - } - // Store the updated encoded lengths in storage if (previousFieldLength != updatedFieldLength) { uint256 dynamicSchemaLengthSlot = _getDynamicDataLengthLocation(tableId, keyTuple); diff --git a/packages/world-modules/gas-report.json b/packages/world-modules/gas-report.json index 5957105b19..c654540d98 100644 --- a/packages/world-modules/gas-report.json +++ b/packages/world-modules/gas-report.json @@ -75,31 +75,31 @@ "file": "test/KeysInTableModule.t.sol", "test": "testInstallComposite", "name": "install keys in table module", - "gasUsed": 1409578 + "gasUsed": 1409591 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallGas", "name": "install keys in table module", - "gasUsed": 1409578 + "gasUsed": 1409591 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallGas", "name": "set a record on a table with keysInTableModule installed", - "gasUsed": 158838 + "gasUsed": 158851 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallSingleton", "name": "install keys in table module", - "gasUsed": 1409578 + "gasUsed": 1409591 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookCompositeGas", "name": "install keys in table module", - "gasUsed": 1409578 + "gasUsed": 1409591 }, { "file": "test/KeysInTableModule.t.sol", @@ -111,13 +111,13 @@ "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookCompositeGas", "name": "delete a composite record on a table with keysInTableModule installed", - "gasUsed": 155758 + "gasUsed": 155854 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookGas", "name": "install keys in table module", - "gasUsed": 1409578 + "gasUsed": 1409591 }, { "file": "test/KeysInTableModule.t.sol", @@ -129,13 +129,13 @@ "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookGas", "name": "delete a record on a table with keysInTableModule installed", - "gasUsed": 85000 + "gasUsed": 85032 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testGetKeysWithValueGas", "name": "install keys with value module", - "gasUsed": 650824 + "gasUsed": 650837 }, { "file": "test/KeysWithValueModule.t.sol", @@ -153,25 +153,25 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testInstall", "name": "install keys with value module", - "gasUsed": 650824 + "gasUsed": 650837 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testInstall", "name": "set a record on a table with KeysWithValueModule installed", - "gasUsed": 135406 + "gasUsed": 135419 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testSetAndDeleteRecordHook", "name": "install keys with value module", - "gasUsed": 650824 + "gasUsed": 650837 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testSetAndDeleteRecordHook", "name": "change a record on a table with KeysWithValueModule installed", - "gasUsed": 103790 + "gasUsed": 103816 }, { "file": "test/KeysWithValueModule.t.sol", @@ -183,19 +183,19 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testSetField", "name": "install keys with value module", - "gasUsed": 650824 + "gasUsed": 650837 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testSetField", "name": "set a field on a table with KeysWithValueModule installed", - "gasUsed": 146626 + "gasUsed": 146639 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testSetField", "name": "change a field on a table with KeysWithValueModule installed", - "gasUsed": 111385 + "gasUsed": 111398 }, { "file": "test/query.t.sol", diff --git a/packages/world/gas-report.json b/packages/world/gas-report.json index 18be74b5cf..37eaa9a211 100644 --- a/packages/world/gas-report.json +++ b/packages/world/gas-report.json @@ -87,7 +87,7 @@ "file": "test/World.t.sol", "test": "testPushToDynamicField", "name": "Push data to the table", - "gasUsed": 85811 + "gasUsed": 85827 }, { "file": "test/World.t.sol", @@ -135,25 +135,25 @@ "file": "test/WorldDynamicUpdate.t.sol", "test": "testPopFromDynamicField", "name": "pop 1 address (cold)", - "gasUsed": 25602 + "gasUsed": 25612 }, { "file": "test/WorldDynamicUpdate.t.sol", "test": "testPopFromDynamicField", "name": "pop 1 address (warm)", - "gasUsed": 12748 + "gasUsed": 12758 }, { "file": "test/WorldDynamicUpdate.t.sol", "test": "testSpliceDynamicData", "name": "update in field 1 item (cold)", - "gasUsed": 25953 + "gasUsed": 25975 }, { "file": "test/WorldDynamicUpdate.t.sol", "test": "testSpliceDynamicData", "name": "update in field 1 item (warm)", - "gasUsed": 13154 + "gasUsed": 13176 }, { "file": "test/WorldResourceId.t.sol", From 15c2f5d2cb86e28fb750ca2ae9c258d9b288e40b Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 5 Jan 2024 11:10:44 +0000 Subject: [PATCH 05/21] chore: do not change docs --- docs/pages/store/reference/store-core.mdx | 37 +++++++++++++++++++ docs/pages/store/reference/store.mdx | 43 +++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/docs/pages/store/reference/store-core.mdx b/docs/pages/store/reference/store-core.mdx index bb9c8ba2db..421cbdc3dd 100644 --- a/docs/pages/store/reference/store-core.mdx +++ b/docs/pages/store/reference/store-core.mdx @@ -774,6 +774,16 @@ event Store_SetRecord( ); ``` +**Parameters** + +| Name | Type | Description | +| ---------------- | --------------- | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table where the record is set. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `staticData` | `bytes` | The static data of the record. | +| `encodedLengths` | `PackedCounter` | The encoded lengths of the dynamic data of the record. | +| `dynamicData` | `bytes` | The dynamic data of the record. | + ### Store_SpliceStaticData Emitted when static data in the store is spliced. @@ -785,6 +795,15 @@ so the total length of the data remains the same and no data is shifted._ event Store_SpliceStaticData(ResourceId indexed tableId, bytes32[] keyTuple, uint48 start, bytes data); ``` +**Parameters** + +| Name | Type | Description | +| ---------- | ------------ | --------------------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table where the data is spliced. | +| `keyTuple` | `bytes32[]` | An array representing the key for the record. | +| `start` | `uint48` | The start position in bytes for the splice operation. | +| `data` | `bytes` | The data to write to the static data of the record at the start byte. | + ### Store_SpliceDynamicData Emitted when dynamic data in the store is spliced. @@ -800,6 +819,17 @@ event Store_SpliceDynamicData( ); ``` +**Parameters** + +| Name | Type | Description | +| ---------------- | --------------- | ------------------------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table where the data is spliced. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `start` | `uint48` | The start position in bytes for the splice operation. | +| `deleteCount` | `uint40` | The number of bytes to delete in the splice operation. | +| `encodedLengths` | `PackedCounter` | The encoded lengths of the dynamic data of the record. | +| `data` | `bytes` | The data to insert into the dynamic data of the record at the start byte. | + ### Store_DeleteRecord Emitted when a record is deleted from the store. @@ -807,3 +837,10 @@ Emitted when a record is deleted from the store. ```solidity event Store_DeleteRecord(ResourceId indexed tableId, bytes32[] keyTuple); ``` + +**Parameters** + +| Name | Type | Description | +| ---------- | ------------ | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table where the record is deleted. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | diff --git a/docs/pages/store/reference/store.mdx b/docs/pages/store/reference/store.mdx index 7f6b1db8ab..71551f45df 100644 --- a/docs/pages/store/reference/store.mdx +++ b/docs/pages/store/reference/store.mdx @@ -23,6 +23,16 @@ event Store_SetRecord( ); ``` +**Parameters** + +| Name | Type | Description | +| ---------------- | --------------- | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table where the record is set. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `staticData` | `bytes` | The static data of the record. | +| `encodedLengths` | `PackedCounter` | The encoded lengths of the dynamic data of the record. | +| `dynamicData` | `bytes` | The dynamic data of the record. | + ### Store_SpliceStaticData Emitted when static data in the store is spliced. @@ -34,6 +44,15 @@ so the total length of the data remains the same and no data is shifted._ event Store_SpliceStaticData(ResourceId indexed tableId, bytes32[] keyTuple, uint48 start, bytes data); ``` +**Parameters** + +| Name | Type | Description | +| ---------- | ------------ | --------------------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table where the data is spliced. | +| `keyTuple` | `bytes32[]` | An array representing the key for the record. | +| `start` | `uint48` | The start position in bytes for the splice operation. | +| `data` | `bytes` | The data to write to the static data of the record at the start byte. | + ### Store_SpliceDynamicData Emitted when dynamic data in the store is spliced. @@ -49,6 +68,17 @@ event Store_SpliceDynamicData( ); ``` +**Parameters** + +| Name | Type | Description | +| ---------------- | --------------- | ------------------------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table where the data is spliced. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `start` | `uint48` | The start position in bytes for the splice operation. | +| `deleteCount` | `uint40` | The number of bytes to delete in the splice operation. | +| `encodedLengths` | `PackedCounter` | The encoded lengths of the dynamic data of the record. | +| `data` | `bytes` | The data to insert into the dynamic data of the record at the start byte. | + ### Store_DeleteRecord Emitted when a record is deleted from the store. @@ -57,6 +87,13 @@ Emitted when a record is deleted from the store. event Store_DeleteRecord(ResourceId indexed tableId, bytes32[] keyTuple); ``` +**Parameters** + +| Name | Type | Description | +| ---------- | ------------ | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table where the record is deleted. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | + ## IStoreErrors [Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/IStoreErrors.sol) @@ -154,6 +191,12 @@ Emitted when the store is initialized. event HelloStore(bytes32 indexed storeVersion); ``` +**Parameters** + +| Name | Type | Description | +| -------------- | --------- | ---------------------------------- | +| `storeVersion` | `bytes32` | The version of the Store contract. | + ## IStoreRead [Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/IStoreRead.sol) From 0d5ee29cccf1e11a27b84ffa7af0af73bcc09163 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 5 Jan 2024 11:13:06 +0000 Subject: [PATCH 06/21] fix: emit delete record event after hook --- packages/store/src/StoreCore.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index ba20f690c7..2e3aa74b01 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -583,9 +583,6 @@ library StoreCore { * @param fieldLayout The field layout for the record. */ function deleteRecord(ResourceId tableId, bytes32[] memory keyTuple, FieldLayout fieldLayout) internal { - // Emit event to notify indexers - emit Store_DeleteRecord(tableId, keyTuple); - // Early return if the table is an offchain table if (tableId.getType() != RESOURCE_TABLE) { return; @@ -600,6 +597,9 @@ library StoreCore { } } + // Emit event to notify indexers + emit Store_DeleteRecord(tableId, keyTuple); + // Delete static data uint256 staticDataLocation = StoreCoreInternal._getStaticDataLocation(tableId, keyTuple); Storage.store({ storagePointer: staticDataLocation, offset: 0, data: new bytes(fieldLayout.staticDataLength()) }); From e26a209d363c508d9e54fa751991899e394d6de4 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 5 Jan 2024 11:22:03 +0000 Subject: [PATCH 07/21] chore: changeset --- .changeset/beige-ads-melt.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/beige-ads-melt.md diff --git a/.changeset/beige-ads-melt.md b/.changeset/beige-ads-melt.md new file mode 100644 index 0000000000..4cb3da3d5c --- /dev/null +++ b/.changeset/beige-ads-melt.md @@ -0,0 +1,5 @@ +--- +"@latticexyz/store": patch +--- + +Fixes the functions in `StoreCore` to emit a storage event after calling the `beforeSetRecord` hook, ensuring that storage events are emitted in the same order that values are set on-chain. From 8526b26a3dc202690c219ebd8aab844216b468a6 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 5 Jan 2024 11:25:13 +0000 Subject: [PATCH 08/21] fix: do not change encoded lengths --- packages/store/src/StoreCore.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index 2e3aa74b01..166f124c7d 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -1049,7 +1049,7 @@ library StoreCoreInternal { dynamicFieldIndex: dynamicFieldIndex, startWithinField: startWithinField, deleteCount: deleteCount, - encodedLengths: previousEncodedLengths, + encodedLengths: updatedEncodedLengths, data: data }); } From 90dd47d08e5968126d5ca7320fa6db9112f16584 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 5 Jan 2024 11:26:32 +0000 Subject: [PATCH 09/21] fix: update correct lengths --- packages/store/src/StoreCore.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index 166f124c7d..06fe92d81b 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -1000,7 +1000,7 @@ library StoreCoreInternal { dynamicFieldIndex: dynamicFieldIndex, startWithinField: startWithinField, deleteCount: deleteCount, - encodedLengths: updatedEncodedLengths, + encodedLengths: previousEncodedLengths, data: data }); } From 9cb4a3c08b78370110fd0bad050b9d349e2e0706 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 12 Jan 2024 11:03:52 +0000 Subject: [PATCH 10/21] fix: proper early return for offchain tables --- packages/store/src/StoreCore.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index 4051e920a7..84bd7020f4 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -583,11 +583,6 @@ library StoreCore { * @param fieldLayout The field layout for the record. */ function deleteRecord(ResourceId tableId, bytes32[] memory keyTuple, FieldLayout fieldLayout) internal { - // Early return if the table is an offchain table - if (tableId.getType() != RESOURCE_TABLE) { - return; - } - // Call onBeforeDeleteRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) bytes21[] memory hooks = StoreHooks._get(tableId); for (uint256 i; i < hooks.length; i++) { @@ -600,6 +595,11 @@ library StoreCore { // Emit event to notify indexers emit Store_DeleteRecord(tableId, keyTuple); + // Early return if the table is an offchain table + if (tableId.getType() != RESOURCE_TABLE) { + return; + } + // Delete static data uint256 staticDataLocation = StoreCoreInternal._getStaticDataLocation(tableId, keyTuple); Storage.store({ storagePointer: staticDataLocation, offset: 0, data: new bytes(fieldLayout.staticDataLength()) }); From 2a84f6ad02dda9cbb4bfa8c86c0f6f9c61f3cb58 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 12 Jan 2024 12:19:17 +0000 Subject: [PATCH 11/21] test: ensure that events are emitted for offchain table sets --- packages/store/test/StoreCore.t.sol | 30 ++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/store/test/StoreCore.t.sol b/packages/store/test/StoreCore.t.sol index 7638fac612..b4b7de0d12 100644 --- a/packages/store/test/StoreCore.t.sol +++ b/packages/store/test/StoreCore.t.sol @@ -17,7 +17,7 @@ import { StoreSwitch } from "../src/StoreSwitch.sol"; import { IStoreHook } from "../src/IStoreHook.sol"; import { Tables, ResourceIds, TablesTableId } from "../src/codegen/index.sol"; import { ResourceId, ResourceIdLib, ResourceIdInstance } from "../src/ResourceId.sol"; -import { RESOURCE_TABLE } from "../src/storeResourceTypes.sol"; +import { RESOURCE_TABLE, RESOURCE_OFFCHAIN_TABLE } from "../src/storeResourceTypes.sol"; import { FieldLayoutEncodeHelper } from "./FieldLayoutEncodeHelper.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, ALL, BEFORE_ALL, AFTER_ALL } from "../src/storeHookTypes.sol"; import { SchemaEncodeHelper } from "./SchemaEncodeHelper.sol"; @@ -44,6 +44,7 @@ contract StoreCoreTest is Test, StoreMock { string[] defaultKeyNames = new string[](1); ResourceId _tableId = ResourceIdLib.encode({ typeId: RESOURCE_TABLE, name: "some table" }); ResourceId _tableId2 = ResourceIdLib.encode({ typeId: RESOURCE_TABLE, name: "some other table" }); + ResourceId _tableId3 = ResourceIdLib.encode({ typeId: RESOURCE_OFFCHAIN_TABLE, name: "some table" }); function testGetStaticDataLocation() public { ResourceId tableId = _tableId; @@ -1318,4 +1319,31 @@ contract StoreCoreTest is Test, StoreMock { assertEq(loadedData.encodedLengths.unwrap(), bytes32(0)); assertEq(loadedData.dynamicData, ""); } + + function testSetDataOffchainTable() public { + ResourceId tableId = _tableId3; + + // Register offchain table + FieldLayout fieldLayout = FieldLayoutEncodeHelper.encode(1, 2, 1, 2, 0); + Schema valueSchema = SchemaEncodeHelper.encode( + SchemaType.UINT8, + SchemaType.UINT16, + SchemaType.UINT8, + SchemaType.UINT16 + ); + + IStore(this).registerTable(tableId, fieldLayout, defaultKeySchema, valueSchema, new string[](1), new string[](4)); + + // Set data + bytes memory staticData = abi.encodePacked(bytes1(0x01), bytes2(0x0203), bytes1(0x04), bytes2(0x0506)); + + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = "some key"; + + // Expect a Store_SetRecord event to be emitted + vm.expectEmit(true, true, true, true); + emit Store_SetRecord(tableId, keyTuple, staticData, PackedCounter.wrap(bytes32(0)), new bytes(0)); + + IStore(this).setRecord(tableId, keyTuple, staticData, PackedCounter.wrap(bytes32(0)), new bytes(0)); + } } From d05b85e65b1a6447b974501ebc98c805f1d8bc5f Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 12 Jan 2024 12:21:35 +0000 Subject: [PATCH 12/21] test: check for deleted offchain tables --- packages/store/test/StoreCore.t.sol | 57 +++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/packages/store/test/StoreCore.t.sol b/packages/store/test/StoreCore.t.sol index b4b7de0d12..6dbc3a9d40 100644 --- a/packages/store/test/StoreCore.t.sol +++ b/packages/store/test/StoreCore.t.sol @@ -1346,4 +1346,61 @@ contract StoreCoreTest is Test, StoreMock { IStore(this).setRecord(tableId, keyTuple, staticData, PackedCounter.wrap(bytes32(0)), new bytes(0)); } + + function testDeleteDataOffchainTable() public { + ResourceId tableId = _tableId3; + + // Register table + FieldLayout fieldLayout = FieldLayoutEncodeHelper.encode(16, 2); + { + Schema valueSchema = SchemaEncodeHelper.encode( + SchemaType.UINT128, + SchemaType.UINT32_ARRAY, + SchemaType.UINT32_ARRAY + ); + IStore(this).registerTable(tableId, fieldLayout, defaultKeySchema, valueSchema, new string[](1), new string[](3)); + } + + bytes16 firstDataBytes = bytes16(0x0102030405060708090a0b0c0d0e0f10); + + bytes memory secondDataBytes; + { + uint32[] memory secondData = new uint32[](2); + secondData[0] = 0x11121314; + secondData[1] = 0x15161718; + secondDataBytes = EncodeArray.encode(secondData); + } + + bytes memory thirdDataBytes; + { + uint32[] memory thirdData = new uint32[](3); + thirdData[0] = 0x191a1b1c; + thirdData[1] = 0x1d1e1f20; + thirdData[2] = 0x21222324; + thirdDataBytes = EncodeArray.encode(thirdData); + } + + PackedCounter encodedDynamicLength; + { + encodedDynamicLength = PackedCounterLib.pack(uint40(secondDataBytes.length), uint40(thirdDataBytes.length)); + } + + // Concat data + bytes memory staticData = abi.encodePacked(firstDataBytes); + bytes memory dynamicData = abi.encodePacked(secondDataBytes, thirdDataBytes); + + // Create keyTuple + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = bytes32("some key"); + + // Set data + IStore(this).setRecord(tableId, keyTuple, staticData, encodedDynamicLength, dynamicData); + + // Expect a Store_DeleteRecord event to be emitted + vm.expectEmit(true, true, true, true); + emit Store_DeleteRecord(tableId, keyTuple); + + // Delete data + IStore(this).deleteRecord(tableId, keyTuple); + } } From 3d50fb311204020c467cffdf11c716f04e90c285 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 12 Jan 2024 13:11:43 +0000 Subject: [PATCH 13/21] feat: disable before hooks for offchain tables --- packages/store/gas-report.json | 98 ++++++++++++++++---------------- packages/store/src/StoreCore.sol | 60 ++++++++++--------- 2 files changed, 82 insertions(+), 76 deletions(-) diff --git a/packages/store/gas-report.json b/packages/store/gas-report.json index bac9764588..b8e4e0b181 100644 --- a/packages/store/gas-report.json +++ b/packages/store/gas-report.json @@ -63,7 +63,7 @@ "file": "test/Callbacks.t.sol", "test": "testSetAndGet", "name": "Callbacks: set field", - "gasUsed": 56271 + "gasUsed": 56286 }, { "file": "test/Callbacks.t.sol", @@ -75,7 +75,7 @@ "file": "test/Callbacks.t.sol", "test": "testSetAndGet", "name": "Callbacks: push 1 element", - "gasUsed": 32530 + "gasUsed": 32545 }, { "file": "test/FieldLayout.t.sol", @@ -369,7 +369,7 @@ "file": "test/KeyEncoding.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "register KeyEncoding table", - "gasUsed": 719062 + "gasUsed": 719207 }, { "file": "test/Mixed.t.sol", @@ -381,19 +381,19 @@ "file": "test/Mixed.t.sol", "test": "testDeleteExternalCold", "name": "delete record from Mixed (external, cold)", - "gasUsed": 24372 + "gasUsed": 24437 }, { "file": "test/Mixed.t.sol", "test": "testDeleteInternalCold", "name": "delete record from Mixed (internal, cold)", - "gasUsed": 19168 + "gasUsed": 19233 }, { "file": "test/Mixed.t.sol", "test": "testSetGetDeleteExternal", "name": "set record in Mixed (external, cold)", - "gasUsed": 108528 + "gasUsed": 108593 }, { "file": "test/Mixed.t.sol", @@ -405,13 +405,13 @@ "file": "test/Mixed.t.sol", "test": "testSetGetDeleteExternal", "name": "delete record from Mixed (external, warm)", - "gasUsed": 8688 + "gasUsed": 8753 }, { "file": "test/Mixed.t.sol", "test": "testSetGetDeleteInternal", "name": "set record in Mixed (internal, cold)", - "gasUsed": 103282 + "gasUsed": 103347 }, { "file": "test/Mixed.t.sol", @@ -423,7 +423,7 @@ "file": "test/Mixed.t.sol", "test": "testSetGetDeleteInternal", "name": "delete record from Mixed (internal, warm)", - "gasUsed": 7481 + "gasUsed": 7546 }, { "file": "test/PackedCounter.t.sol", @@ -669,25 +669,25 @@ "file": "test/StoreCoreDynamic.t.sol", "test": "testPopFromSecondField", "name": "pop from field (cold, 1 slot, 1 uint32 item)", - "gasUsed": 18041 + "gasUsed": 18056 }, { "file": "test/StoreCoreDynamic.t.sol", "test": "testPopFromSecondField", "name": "pop from field (warm, 1 slot, 1 uint32 item)", - "gasUsed": 12049 + "gasUsed": 12064 }, { "file": "test/StoreCoreDynamic.t.sol", "test": "testPopFromThirdField", "name": "pop from field (cold, 2 slots, 10 uint32 items)", - "gasUsed": 15810 + "gasUsed": 15825 }, { "file": "test/StoreCoreDynamic.t.sol", "test": "testPopFromThirdField", "name": "pop from field (warm, 2 slots, 10 uint32 items)", - "gasUsed": 11818 + "gasUsed": 11833 }, { "file": "test/StoreCoreGas.t.sol", @@ -717,7 +717,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testDeleteData", "name": "delete record (complex data, 3 slots)", - "gasUsed": 8015 + "gasUsed": 8080 }, { "file": "test/StoreCoreGas.t.sol", @@ -747,67 +747,67 @@ "file": "test/StoreCoreGas.t.sol", "test": "testHooks", "name": "register subscriber", - "gasUsed": 57954 + "gasUsed": 57984 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooks", "name": "set record on table with subscriber", - "gasUsed": 72320 + "gasUsed": 72450 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooks", "name": "set static field on table with subscriber", - "gasUsed": 19815 + "gasUsed": 19945 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooks", "name": "delete record on table with subscriber", - "gasUsed": 18617 + "gasUsed": 18747 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooksDynamicData", "name": "register subscriber", - "gasUsed": 57954 + "gasUsed": 57984 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooksDynamicData", "name": "set (dynamic) record on table with subscriber", - "gasUsed": 165460 + "gasUsed": 165590 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooksDynamicData", "name": "set (dynamic) field on table with subscriber", - "gasUsed": 24491 + "gasUsed": 24521 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooksDynamicData", "name": "delete (dynamic) record on table with subscriber", - "gasUsed": 20283 + "gasUsed": 20413 }, { "file": "test/StoreCoreGas.t.sol", "test": "testPushToDynamicField", "name": "push to field (1 slot, 1 uint32 item)", - "gasUsed": 9475 + "gasUsed": 9490 }, { "file": "test/StoreCoreGas.t.sol", "test": "testPushToDynamicField", "name": "push to field (2 slots, 10 uint32 items)", - "gasUsed": 32150 + "gasUsed": 32165 }, { "file": "test/StoreCoreGas.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "StoreCore: register table", - "gasUsed": 640944 + "gasUsed": 641089 }, { "file": "test/StoreCoreGas.t.sol", @@ -831,7 +831,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetDynamicData", "name": "set complex record with dynamic data (4 slots)", - "gasUsed": 102513 + "gasUsed": 102578 }, { "file": "test/StoreCoreGas.t.sol", @@ -873,7 +873,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetField", "name": "set static field (1 slot)", - "gasUsed": 31252 + "gasUsed": 31317 }, { "file": "test/StoreCoreGas.t.sol", @@ -885,7 +885,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetField", "name": "set static field (overlap 2 slot)", - "gasUsed": 29908 + "gasUsed": 29973 }, { "file": "test/StoreCoreGas.t.sol", @@ -897,7 +897,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetField", "name": "set dynamic field (1 slot, first dynamic field)", - "gasUsed": 53961 + "gasUsed": 53976 }, { "file": "test/StoreCoreGas.t.sol", @@ -909,7 +909,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetField", "name": "set dynamic field (1 slot, second dynamic field)", - "gasUsed": 32186 + "gasUsed": 32201 }, { "file": "test/StoreCoreGas.t.sol", @@ -921,7 +921,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetStaticData", "name": "set static record (1 slot)", - "gasUsed": 32782 + "gasUsed": 32847 }, { "file": "test/StoreCoreGas.t.sol", @@ -933,7 +933,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetStaticDataSpanningWords", "name": "set static record (2 slots)", - "gasUsed": 55289 + "gasUsed": 55354 }, { "file": "test/StoreCoreGas.t.sol", @@ -945,13 +945,13 @@ "file": "test/StoreCoreGas.t.sol", "test": "testUpdateInDynamicField", "name": "update in field (1 slot, 1 uint32 item)", - "gasUsed": 8835 + "gasUsed": 8850 }, { "file": "test/StoreCoreGas.t.sol", "test": "testUpdateInDynamicField", "name": "push to field (2 slots, 6 uint64 items)", - "gasUsed": 9282 + "gasUsed": 9297 }, { "file": "test/StoreHook.t.sol", @@ -981,13 +981,13 @@ "file": "test/StoreHooks.t.sol", "test": "testOneSlot", "name": "StoreHooks: set field with one elements (cold)", - "gasUsed": 58275 + "gasUsed": 58290 }, { "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: set field (cold)", - "gasUsed": 58275 + "gasUsed": 58290 }, { "file": "test/StoreHooks.t.sol", @@ -999,55 +999,55 @@ "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: push 1 element (cold)", - "gasUsed": 12626 + "gasUsed": 12641 }, { "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: pop 1 element (warm)", - "gasUsed": 9958 + "gasUsed": 9973 }, { "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: push 1 element (warm)", - "gasUsed": 10646 + "gasUsed": 10661 }, { "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: update 1 element (warm)", - "gasUsed": 29886 + "gasUsed": 29901 }, { "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: delete record (warm)", - "gasUsed": 10425 + "gasUsed": 10490 }, { "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: set field (warm)", - "gasUsed": 30427 + "gasUsed": 30442 }, { "file": "test/StoreHooks.t.sol", "test": "testThreeSlots", "name": "StoreHooks: set field with three elements (cold)", - "gasUsed": 80966 + "gasUsed": 80981 }, { "file": "test/StoreHooks.t.sol", "test": "testTwoSlots", "name": "StoreHooks: set field with two elements (cold)", - "gasUsed": 80878 + "gasUsed": 80893 }, { "file": "test/StoreHooksColdLoad.t.sol", "test": "testDelete", "name": "StoreHooks: delete record (cold)", - "gasUsed": 19283 + "gasUsed": 19348 }, { "file": "test/StoreHooksColdLoad.t.sol", @@ -1071,13 +1071,13 @@ "file": "test/StoreHooksColdLoad.t.sol", "test": "testPop", "name": "StoreHooks: pop 1 element (cold)", - "gasUsed": 18390 + "gasUsed": 18405 }, { "file": "test/StoreHooksColdLoad.t.sol", "test": "testUpdate", "name": "StoreHooks: update 1 element (cold)", - "gasUsed": 20333 + "gasUsed": 20348 }, { "file": "test/StoreSwitch.t.sol", @@ -1143,13 +1143,13 @@ "file": "test/Vector2.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "register Vector2 field layout", - "gasUsed": 442447 + "gasUsed": 442592 }, { "file": "test/Vector2.t.sol", "test": "testSetAndGet", "name": "set Vector2 record", - "gasUsed": 33684 + "gasUsed": 33749 }, { "file": "test/Vector2.t.sol", diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index 84bd7020f4..6e916c016b 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -298,19 +298,21 @@ library StoreCore { bytes memory dynamicData, FieldLayout fieldLayout ) internal { - // Call onBeforeSetRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) bytes21[] memory hooks = StoreHooks._get(tableId); - for (uint256 i; i < hooks.length; i++) { - Hook hook = Hook.wrap(hooks[i]); - if (hook.isEnabled(BEFORE_SET_RECORD)) { - IStoreHook(hook.getAddress()).onBeforeSetRecord( - tableId, - keyTuple, - staticData, - encodedLengths, - dynamicData, - fieldLayout - ); + if (tableId.getType() == RESOURCE_TABLE) { + // Call onBeforeSetRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) + for (uint256 i; i < hooks.length; i++) { + Hook hook = Hook.wrap(hooks[i]); + if (hook.isEnabled(BEFORE_SET_RECORD)) { + IStoreHook(hook.getAddress()).onBeforeSetRecord( + tableId, + keyTuple, + staticData, + encodedLengths, + dynamicData, + fieldLayout + ); + } } } @@ -389,17 +391,19 @@ library StoreCore { function spliceStaticData(ResourceId tableId, bytes32[] memory keyTuple, uint48 start, bytes memory data) internal { uint256 location = StoreCoreInternal._getStaticDataLocation(tableId, keyTuple); - // Call onBeforeSpliceStaticData hooks (before actually modifying the state, so observers have access to the previous state if needed) bytes21[] memory hooks = StoreHooks._get(tableId); - for (uint256 i; i < hooks.length; i++) { - Hook hook = Hook.wrap(hooks[i]); - if (hook.isEnabled(BEFORE_SPLICE_STATIC_DATA)) { - IStoreHook(hook.getAddress()).onBeforeSpliceStaticData({ - tableId: tableId, - keyTuple: keyTuple, - start: start, - data: data - }); + if (tableId.getType() == RESOURCE_TABLE) { + // Call onBeforeSpliceStaticData hooks (before actually modifying the state, so observers have access to the previous state if needed) + for (uint256 i; i < hooks.length; i++) { + Hook hook = Hook.wrap(hooks[i]); + if (hook.isEnabled(BEFORE_SPLICE_STATIC_DATA)) { + IStoreHook(hook.getAddress()).onBeforeSpliceStaticData({ + tableId: tableId, + keyTuple: keyTuple, + start: start, + data: data + }); + } } } @@ -583,12 +587,14 @@ library StoreCore { * @param fieldLayout The field layout for the record. */ function deleteRecord(ResourceId tableId, bytes32[] memory keyTuple, FieldLayout fieldLayout) internal { - // Call onBeforeDeleteRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) bytes21[] memory hooks = StoreHooks._get(tableId); - for (uint256 i; i < hooks.length; i++) { - Hook hook = Hook.wrap(hooks[i]); - if (hook.isEnabled(BEFORE_DELETE_RECORD)) { - IStoreHook(hook.getAddress()).onBeforeDeleteRecord(tableId, keyTuple, fieldLayout); + if (tableId.getType() == RESOURCE_TABLE) { + // Call onBeforeDeleteRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) + for (uint256 i; i < hooks.length; i++) { + Hook hook = Hook.wrap(hooks[i]); + if (hook.isEnabled(BEFORE_DELETE_RECORD)) { + IStoreHook(hook.getAddress()).onBeforeDeleteRecord(tableId, keyTuple, fieldLayout); + } } } From 568aaf0ab6c507c6b098bb4332add98f9bc43386 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 12 Jan 2024 13:21:05 +0000 Subject: [PATCH 14/21] chore: gas tests --- packages/store/gas-report.json | 24 +++++-- packages/store/test/StoreCore.t.sol | 2 +- packages/store/test/StoreCoreGas.t.sol | 91 +++++++++++++++++++++++++- 3 files changed, 109 insertions(+), 8 deletions(-) diff --git a/packages/store/gas-report.json b/packages/store/gas-report.json index b8e4e0b181..cc891b16bf 100644 --- a/packages/store/gas-report.json +++ b/packages/store/gas-report.json @@ -719,6 +719,12 @@ "name": "delete record (complex data, 3 slots)", "gasUsed": 8080 }, + { + "file": "test/StoreCoreGas.t.sol", + "test": "testDeleteDataOffchainTable", + "name": "StoreCore: delete record in offchain table", + "gasUsed": 7047 + }, { "file": "test/StoreCoreGas.t.sol", "test": "testGetStaticDataLocation", @@ -753,19 +759,19 @@ "file": "test/StoreCoreGas.t.sol", "test": "testHooks", "name": "set record on table with subscriber", - "gasUsed": 72450 + "gasUsed": 72515 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooks", "name": "set static field on table with subscriber", - "gasUsed": 19945 + "gasUsed": 19967 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooks", "name": "delete record on table with subscriber", - "gasUsed": 18747 + "gasUsed": 18725 }, { "file": "test/StoreCoreGas.t.sol", @@ -777,19 +783,19 @@ "file": "test/StoreCoreGas.t.sol", "test": "testHooksDynamicData", "name": "set (dynamic) record on table with subscriber", - "gasUsed": 165590 + "gasUsed": 165655 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooksDynamicData", "name": "set (dynamic) field on table with subscriber", - "gasUsed": 24521 + "gasUsed": 24476 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooksDynamicData", "name": "delete (dynamic) record on table with subscriber", - "gasUsed": 20413 + "gasUsed": 20391 }, { "file": "test/StoreCoreGas.t.sol", @@ -941,6 +947,12 @@ "name": "get static record (2 slots)", "gasUsed": 1740 }, + { + "file": "test/StoreCoreGas.t.sol", + "test": "testSetDataOffchainTable", + "name": "StoreCore: set record in offchain table", + "gasUsed": 12453 + }, { "file": "test/StoreCoreGas.t.sol", "test": "testUpdateInDynamicField", diff --git a/packages/store/test/StoreCore.t.sol b/packages/store/test/StoreCore.t.sol index 6dbc3a9d40..15a3983363 100644 --- a/packages/store/test/StoreCore.t.sol +++ b/packages/store/test/StoreCore.t.sol @@ -44,7 +44,7 @@ contract StoreCoreTest is Test, StoreMock { string[] defaultKeyNames = new string[](1); ResourceId _tableId = ResourceIdLib.encode({ typeId: RESOURCE_TABLE, name: "some table" }); ResourceId _tableId2 = ResourceIdLib.encode({ typeId: RESOURCE_TABLE, name: "some other table" }); - ResourceId _tableId3 = ResourceIdLib.encode({ typeId: RESOURCE_OFFCHAIN_TABLE, name: "some table" }); + ResourceId _tableId3 = ResourceIdLib.encode({ typeId: RESOURCE_OFFCHAIN_TABLE, name: "some offchain table" }); function testGetStaticDataLocation() public { ResourceId tableId = _tableId; diff --git a/packages/store/test/StoreCoreGas.t.sol b/packages/store/test/StoreCoreGas.t.sol index 3b65a03fc2..67962c21b1 100644 --- a/packages/store/test/StoreCoreGas.t.sol +++ b/packages/store/test/StoreCoreGas.t.sol @@ -16,7 +16,7 @@ import { IStoreErrors } from "../src/IStoreErrors.sol"; import { IStore } from "../src/IStore.sol"; import { ResourceId, ResourceIdLib } from "../src/ResourceId.sol"; import { ResourceIds } from "../src/codegen/tables/ResourceIds.sol"; -import { RESOURCE_TABLE } from "../src/storeResourceTypes.sol"; +import { RESOURCE_TABLE, RESOURCE_OFFCHAIN_TABLE } from "../src/storeResourceTypes.sol"; import { FieldLayoutEncodeHelper } from "./FieldLayoutEncodeHelper.sol"; import { SchemaEncodeHelper } from "./SchemaEncodeHelper.sol"; import { StoreMock } from "./StoreMock.sol"; @@ -37,6 +37,7 @@ contract StoreCoreGasTest is Test, GasReporter, StoreMock { Schema defaultKeySchema = SchemaEncodeHelper.encode(SchemaType.BYTES32); ResourceId _tableId = ResourceIdLib.encode({ typeId: RESOURCE_TABLE, name: "some table" }); ResourceId _tableId2 = ResourceIdLib.encode({ typeId: RESOURCE_TABLE, name: "some other table" }); + ResourceId _tableId3 = ResourceIdLib.encode({ typeId: RESOURCE_OFFCHAIN_TABLE, name: "some offchain table" }); function testGetStaticDataLocation() public { ResourceId tableId = _tableId; @@ -724,4 +725,92 @@ contract StoreCoreGasTest is Test, GasReporter, StoreMock { StoreCore.deleteRecord(tableId, keyTuple); endGasReport(); } + + function testSetDataOffchainTable() public { + ResourceId tableId = _tableId3; + + // Register offchain table + FieldLayout fieldLayout = FieldLayoutEncodeHelper.encode(1, 2, 1, 2, 0); + Schema valueSchema = SchemaEncodeHelper.encode( + SchemaType.UINT8, + SchemaType.UINT16, + SchemaType.UINT8, + SchemaType.UINT16 + ); + + IStore(this).registerTable(tableId, fieldLayout, defaultKeySchema, valueSchema, new string[](1), new string[](4)); + + // Set data + bytes memory staticData = abi.encodePacked(bytes1(0x01), bytes2(0x0203), bytes1(0x04), bytes2(0x0506)); + + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = "some key"; + + // Expect a Store_SetRecord event to be emitted + vm.expectEmit(true, true, true, true); + emit Store_SetRecord(tableId, keyTuple, staticData, PackedCounter.wrap(bytes32(0)), new bytes(0)); + + startGasReport("StoreCore: set record in offchain table"); + IStore(this).setRecord(tableId, keyTuple, staticData, PackedCounter.wrap(bytes32(0)), new bytes(0)); + endGasReport(); + } + + function testDeleteDataOffchainTable() public { + ResourceId tableId = _tableId3; + + // Register table + FieldLayout fieldLayout = FieldLayoutEncodeHelper.encode(16, 2); + { + Schema valueSchema = SchemaEncodeHelper.encode( + SchemaType.UINT128, + SchemaType.UINT32_ARRAY, + SchemaType.UINT32_ARRAY + ); + IStore(this).registerTable(tableId, fieldLayout, defaultKeySchema, valueSchema, new string[](1), new string[](3)); + } + + bytes16 firstDataBytes = bytes16(0x0102030405060708090a0b0c0d0e0f10); + + bytes memory secondDataBytes; + { + uint32[] memory secondData = new uint32[](2); + secondData[0] = 0x11121314; + secondData[1] = 0x15161718; + secondDataBytes = EncodeArray.encode(secondData); + } + + bytes memory thirdDataBytes; + { + uint32[] memory thirdData = new uint32[](3); + thirdData[0] = 0x191a1b1c; + thirdData[1] = 0x1d1e1f20; + thirdData[2] = 0x21222324; + thirdDataBytes = EncodeArray.encode(thirdData); + } + + PackedCounter encodedDynamicLength; + { + encodedDynamicLength = PackedCounterLib.pack(uint40(secondDataBytes.length), uint40(thirdDataBytes.length)); + } + + // Concat data + bytes memory staticData = abi.encodePacked(firstDataBytes); + bytes memory dynamicData = abi.encodePacked(secondDataBytes, thirdDataBytes); + + // Create keyTuple + bytes32[] memory keyTuple = new bytes32[](1); + keyTuple[0] = bytes32("some key"); + + // Set data + IStore(this).setRecord(tableId, keyTuple, staticData, encodedDynamicLength, dynamicData); + + // Expect a Store_DeleteRecord event to be emitted + vm.expectEmit(true, true, true, true); + emit Store_DeleteRecord(tableId, keyTuple); + + // Delete data + startGasReport("StoreCore: delete record in offchain table"); + IStore(this).deleteRecord(tableId, keyTuple); + endGasReport(); + } } From 2cbc51a93f66200b75f0396c07c989c0fabd9074 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 12 Jan 2024 13:28:04 +0000 Subject: [PATCH 15/21] refactor: use boolean --- packages/store/gas-report.json | 24 ++++++++++++------------ packages/store/src/StoreCore.sol | 17 +++++++++++------ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/packages/store/gas-report.json b/packages/store/gas-report.json index cc891b16bf..8932530f46 100644 --- a/packages/store/gas-report.json +++ b/packages/store/gas-report.json @@ -369,7 +369,7 @@ "file": "test/KeyEncoding.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "register KeyEncoding table", - "gasUsed": 719207 + "gasUsed": 719182 }, { "file": "test/Mixed.t.sol", @@ -393,7 +393,7 @@ "file": "test/Mixed.t.sol", "test": "testSetGetDeleteExternal", "name": "set record in Mixed (external, cold)", - "gasUsed": 108593 + "gasUsed": 108568 }, { "file": "test/Mixed.t.sol", @@ -411,7 +411,7 @@ "file": "test/Mixed.t.sol", "test": "testSetGetDeleteInternal", "name": "set record in Mixed (internal, cold)", - "gasUsed": 103347 + "gasUsed": 103322 }, { "file": "test/Mixed.t.sol", @@ -759,7 +759,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testHooks", "name": "set record on table with subscriber", - "gasUsed": 72515 + "gasUsed": 72465 }, { "file": "test/StoreCoreGas.t.sol", @@ -783,7 +783,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testHooksDynamicData", "name": "set (dynamic) record on table with subscriber", - "gasUsed": 165655 + "gasUsed": 165605 }, { "file": "test/StoreCoreGas.t.sol", @@ -813,7 +813,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "StoreCore: register table", - "gasUsed": 641089 + "gasUsed": 641064 }, { "file": "test/StoreCoreGas.t.sol", @@ -837,7 +837,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetDynamicData", "name": "set complex record with dynamic data (4 slots)", - "gasUsed": 102578 + "gasUsed": 102553 }, { "file": "test/StoreCoreGas.t.sol", @@ -927,7 +927,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetStaticData", "name": "set static record (1 slot)", - "gasUsed": 32847 + "gasUsed": 32822 }, { "file": "test/StoreCoreGas.t.sol", @@ -939,7 +939,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetStaticDataSpanningWords", "name": "set static record (2 slots)", - "gasUsed": 55354 + "gasUsed": 55329 }, { "file": "test/StoreCoreGas.t.sol", @@ -951,7 +951,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetDataOffchainTable", "name": "StoreCore: set record in offchain table", - "gasUsed": 12453 + "gasUsed": 12428 }, { "file": "test/StoreCoreGas.t.sol", @@ -1155,13 +1155,13 @@ "file": "test/Vector2.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "register Vector2 field layout", - "gasUsed": 442592 + "gasUsed": 442567 }, { "file": "test/Vector2.t.sol", "test": "testSetAndGet", "name": "set Vector2 record", - "gasUsed": 33749 + "gasUsed": 33724 }, { "file": "test/Vector2.t.sol", diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index 6e916c016b..10be8db3ae 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -298,8 +298,10 @@ library StoreCore { bytes memory dynamicData, FieldLayout fieldLayout ) internal { + bool isTable = tableId.getType() == RESOURCE_TABLE; + bytes21[] memory hooks = StoreHooks._get(tableId); - if (tableId.getType() == RESOURCE_TABLE) { + if (isTable) { // Call onBeforeSetRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) for (uint256 i; i < hooks.length; i++) { Hook hook = Hook.wrap(hooks[i]); @@ -320,7 +322,7 @@ library StoreCore { emit Store_SetRecord(tableId, keyTuple, staticData, encodedLengths, dynamicData); // Early return if the table is an offchain table - if (tableId.getType() != RESOURCE_TABLE) { + if (!isTable) { return; } @@ -389,10 +391,11 @@ library StoreCore { * @param data The data to write to the static data of the record at the start byte. */ function spliceStaticData(ResourceId tableId, bytes32[] memory keyTuple, uint48 start, bytes memory data) internal { + bool isTable = tableId.getType() == RESOURCE_TABLE; uint256 location = StoreCoreInternal._getStaticDataLocation(tableId, keyTuple); bytes21[] memory hooks = StoreHooks._get(tableId); - if (tableId.getType() == RESOURCE_TABLE) { + if (isTable) { // Call onBeforeSpliceStaticData hooks (before actually modifying the state, so observers have access to the previous state if needed) for (uint256 i; i < hooks.length; i++) { Hook hook = Hook.wrap(hooks[i]); @@ -411,7 +414,7 @@ library StoreCore { emit StoreCore.Store_SpliceStaticData({ tableId: tableId, keyTuple: keyTuple, start: start, data: data }); // Early return if the table is an offchain table - if (tableId.getType() != RESOURCE_TABLE) { + if (!isTable) { return; } @@ -587,8 +590,10 @@ library StoreCore { * @param fieldLayout The field layout for the record. */ function deleteRecord(ResourceId tableId, bytes32[] memory keyTuple, FieldLayout fieldLayout) internal { + bool isTable = tableId.getType() == RESOURCE_TABLE; + bytes21[] memory hooks = StoreHooks._get(tableId); - if (tableId.getType() == RESOURCE_TABLE) { + if (isTable) { // Call onBeforeDeleteRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) for (uint256 i; i < hooks.length; i++) { Hook hook = Hook.wrap(hooks[i]); @@ -602,7 +607,7 @@ library StoreCore { emit Store_DeleteRecord(tableId, keyTuple); // Early return if the table is an offchain table - if (tableId.getType() != RESOURCE_TABLE) { + if (!isTable) { return; } From b4c2a40bc64fcbdfa08f7a777d0c8e05c8c7fac9 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 12 Jan 2024 13:36:46 +0000 Subject: [PATCH 16/21] perf: remove offchain check for before hooks --- packages/store/gas-report.json | 102 +++++++++++++++---------------- packages/store/src/StoreCore.sol | 71 +++++++++------------ 2 files changed, 81 insertions(+), 92 deletions(-) diff --git a/packages/store/gas-report.json b/packages/store/gas-report.json index 8932530f46..d6c458ad90 100644 --- a/packages/store/gas-report.json +++ b/packages/store/gas-report.json @@ -63,7 +63,7 @@ "file": "test/Callbacks.t.sol", "test": "testSetAndGet", "name": "Callbacks: set field", - "gasUsed": 56286 + "gasUsed": 56271 }, { "file": "test/Callbacks.t.sol", @@ -75,7 +75,7 @@ "file": "test/Callbacks.t.sol", "test": "testSetAndGet", "name": "Callbacks: push 1 element", - "gasUsed": 32545 + "gasUsed": 32530 }, { "file": "test/FieldLayout.t.sol", @@ -369,7 +369,7 @@ "file": "test/KeyEncoding.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "register KeyEncoding table", - "gasUsed": 719182 + "gasUsed": 719062 }, { "file": "test/Mixed.t.sol", @@ -381,19 +381,19 @@ "file": "test/Mixed.t.sol", "test": "testDeleteExternalCold", "name": "delete record from Mixed (external, cold)", - "gasUsed": 24437 + "gasUsed": 24372 }, { "file": "test/Mixed.t.sol", "test": "testDeleteInternalCold", "name": "delete record from Mixed (internal, cold)", - "gasUsed": 19233 + "gasUsed": 19168 }, { "file": "test/Mixed.t.sol", "test": "testSetGetDeleteExternal", "name": "set record in Mixed (external, cold)", - "gasUsed": 108568 + "gasUsed": 108528 }, { "file": "test/Mixed.t.sol", @@ -405,13 +405,13 @@ "file": "test/Mixed.t.sol", "test": "testSetGetDeleteExternal", "name": "delete record from Mixed (external, warm)", - "gasUsed": 8753 + "gasUsed": 8688 }, { "file": "test/Mixed.t.sol", "test": "testSetGetDeleteInternal", "name": "set record in Mixed (internal, cold)", - "gasUsed": 103322 + "gasUsed": 103282 }, { "file": "test/Mixed.t.sol", @@ -423,7 +423,7 @@ "file": "test/Mixed.t.sol", "test": "testSetGetDeleteInternal", "name": "delete record from Mixed (internal, warm)", - "gasUsed": 7546 + "gasUsed": 7481 }, { "file": "test/PackedCounter.t.sol", @@ -669,25 +669,25 @@ "file": "test/StoreCoreDynamic.t.sol", "test": "testPopFromSecondField", "name": "pop from field (cold, 1 slot, 1 uint32 item)", - "gasUsed": 18056 + "gasUsed": 18041 }, { "file": "test/StoreCoreDynamic.t.sol", "test": "testPopFromSecondField", "name": "pop from field (warm, 1 slot, 1 uint32 item)", - "gasUsed": 12064 + "gasUsed": 12049 }, { "file": "test/StoreCoreDynamic.t.sol", "test": "testPopFromThirdField", "name": "pop from field (cold, 2 slots, 10 uint32 items)", - "gasUsed": 15825 + "gasUsed": 15810 }, { "file": "test/StoreCoreDynamic.t.sol", "test": "testPopFromThirdField", "name": "pop from field (warm, 2 slots, 10 uint32 items)", - "gasUsed": 11833 + "gasUsed": 11818 }, { "file": "test/StoreCoreGas.t.sol", @@ -717,13 +717,13 @@ "file": "test/StoreCoreGas.t.sol", "test": "testDeleteData", "name": "delete record (complex data, 3 slots)", - "gasUsed": 8080 + "gasUsed": 8015 }, { "file": "test/StoreCoreGas.t.sol", "test": "testDeleteDataOffchainTable", "name": "StoreCore: delete record in offchain table", - "gasUsed": 7047 + "gasUsed": 7017 }, { "file": "test/StoreCoreGas.t.sol", @@ -753,67 +753,67 @@ "file": "test/StoreCoreGas.t.sol", "test": "testHooks", "name": "register subscriber", - "gasUsed": 57984 + "gasUsed": 57954 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooks", "name": "set record on table with subscriber", - "gasUsed": 72465 + "gasUsed": 72385 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooks", "name": "set static field on table with subscriber", - "gasUsed": 19967 + "gasUsed": 19837 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooks", "name": "delete record on table with subscriber", - "gasUsed": 18725 + "gasUsed": 18595 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooksDynamicData", "name": "register subscriber", - "gasUsed": 57984 + "gasUsed": 57954 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooksDynamicData", "name": "set (dynamic) record on table with subscriber", - "gasUsed": 165605 + "gasUsed": 165525 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooksDynamicData", "name": "set (dynamic) field on table with subscriber", - "gasUsed": 24476 + "gasUsed": 24446 }, { "file": "test/StoreCoreGas.t.sol", "test": "testHooksDynamicData", "name": "delete (dynamic) record on table with subscriber", - "gasUsed": 20391 + "gasUsed": 20261 }, { "file": "test/StoreCoreGas.t.sol", "test": "testPushToDynamicField", "name": "push to field (1 slot, 1 uint32 item)", - "gasUsed": 9490 + "gasUsed": 9475 }, { "file": "test/StoreCoreGas.t.sol", "test": "testPushToDynamicField", "name": "push to field (2 slots, 10 uint32 items)", - "gasUsed": 32165 + "gasUsed": 32150 }, { "file": "test/StoreCoreGas.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "StoreCore: register table", - "gasUsed": 641064 + "gasUsed": 640944 }, { "file": "test/StoreCoreGas.t.sol", @@ -837,7 +837,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetDynamicData", "name": "set complex record with dynamic data (4 slots)", - "gasUsed": 102553 + "gasUsed": 102513 }, { "file": "test/StoreCoreGas.t.sol", @@ -879,7 +879,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetField", "name": "set static field (1 slot)", - "gasUsed": 31317 + "gasUsed": 31252 }, { "file": "test/StoreCoreGas.t.sol", @@ -891,7 +891,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetField", "name": "set static field (overlap 2 slot)", - "gasUsed": 29973 + "gasUsed": 29908 }, { "file": "test/StoreCoreGas.t.sol", @@ -903,7 +903,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetField", "name": "set dynamic field (1 slot, first dynamic field)", - "gasUsed": 53976 + "gasUsed": 53961 }, { "file": "test/StoreCoreGas.t.sol", @@ -915,7 +915,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetField", "name": "set dynamic field (1 slot, second dynamic field)", - "gasUsed": 32201 + "gasUsed": 32186 }, { "file": "test/StoreCoreGas.t.sol", @@ -927,7 +927,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetStaticData", "name": "set static record (1 slot)", - "gasUsed": 32822 + "gasUsed": 32782 }, { "file": "test/StoreCoreGas.t.sol", @@ -939,7 +939,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetAndGetStaticDataSpanningWords", "name": "set static record (2 slots)", - "gasUsed": 55329 + "gasUsed": 55289 }, { "file": "test/StoreCoreGas.t.sol", @@ -951,19 +951,19 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetDataOffchainTable", "name": "StoreCore: set record in offchain table", - "gasUsed": 12428 + "gasUsed": 12423 }, { "file": "test/StoreCoreGas.t.sol", "test": "testUpdateInDynamicField", "name": "update in field (1 slot, 1 uint32 item)", - "gasUsed": 8850 + "gasUsed": 8835 }, { "file": "test/StoreCoreGas.t.sol", "test": "testUpdateInDynamicField", "name": "push to field (2 slots, 6 uint64 items)", - "gasUsed": 9297 + "gasUsed": 9282 }, { "file": "test/StoreHook.t.sol", @@ -993,13 +993,13 @@ "file": "test/StoreHooks.t.sol", "test": "testOneSlot", "name": "StoreHooks: set field with one elements (cold)", - "gasUsed": 58290 + "gasUsed": 58275 }, { "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: set field (cold)", - "gasUsed": 58290 + "gasUsed": 58275 }, { "file": "test/StoreHooks.t.sol", @@ -1011,55 +1011,55 @@ "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: push 1 element (cold)", - "gasUsed": 12641 + "gasUsed": 12626 }, { "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: pop 1 element (warm)", - "gasUsed": 9973 + "gasUsed": 9958 }, { "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: push 1 element (warm)", - "gasUsed": 10661 + "gasUsed": 10646 }, { "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: update 1 element (warm)", - "gasUsed": 29901 + "gasUsed": 29886 }, { "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: delete record (warm)", - "gasUsed": 10490 + "gasUsed": 10425 }, { "file": "test/StoreHooks.t.sol", "test": "testTable", "name": "StoreHooks: set field (warm)", - "gasUsed": 30442 + "gasUsed": 30427 }, { "file": "test/StoreHooks.t.sol", "test": "testThreeSlots", "name": "StoreHooks: set field with three elements (cold)", - "gasUsed": 80981 + "gasUsed": 80966 }, { "file": "test/StoreHooks.t.sol", "test": "testTwoSlots", "name": "StoreHooks: set field with two elements (cold)", - "gasUsed": 80893 + "gasUsed": 80878 }, { "file": "test/StoreHooksColdLoad.t.sol", "test": "testDelete", "name": "StoreHooks: delete record (cold)", - "gasUsed": 19348 + "gasUsed": 19283 }, { "file": "test/StoreHooksColdLoad.t.sol", @@ -1083,13 +1083,13 @@ "file": "test/StoreHooksColdLoad.t.sol", "test": "testPop", "name": "StoreHooks: pop 1 element (cold)", - "gasUsed": 18405 + "gasUsed": 18390 }, { "file": "test/StoreHooksColdLoad.t.sol", "test": "testUpdate", "name": "StoreHooks: update 1 element (cold)", - "gasUsed": 20348 + "gasUsed": 20333 }, { "file": "test/StoreSwitch.t.sol", @@ -1155,13 +1155,13 @@ "file": "test/Vector2.t.sol", "test": "testRegisterAndGetFieldLayout", "name": "register Vector2 field layout", - "gasUsed": 442567 + "gasUsed": 442447 }, { "file": "test/Vector2.t.sol", "test": "testSetAndGet", "name": "set Vector2 record", - "gasUsed": 33724 + "gasUsed": 33684 }, { "file": "test/Vector2.t.sol", diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index 10be8db3ae..1feaf0d4a3 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -298,23 +298,19 @@ library StoreCore { bytes memory dynamicData, FieldLayout fieldLayout ) internal { - bool isTable = tableId.getType() == RESOURCE_TABLE; - bytes21[] memory hooks = StoreHooks._get(tableId); - if (isTable) { - // Call onBeforeSetRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) - for (uint256 i; i < hooks.length; i++) { - Hook hook = Hook.wrap(hooks[i]); - if (hook.isEnabled(BEFORE_SET_RECORD)) { - IStoreHook(hook.getAddress()).onBeforeSetRecord( - tableId, - keyTuple, - staticData, - encodedLengths, - dynamicData, - fieldLayout - ); - } + // Call onBeforeSetRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) + for (uint256 i; i < hooks.length; i++) { + Hook hook = Hook.wrap(hooks[i]); + if (hook.isEnabled(BEFORE_SET_RECORD)) { + IStoreHook(hook.getAddress()).onBeforeSetRecord( + tableId, + keyTuple, + staticData, + encodedLengths, + dynamicData, + fieldLayout + ); } } @@ -322,7 +318,7 @@ library StoreCore { emit Store_SetRecord(tableId, keyTuple, staticData, encodedLengths, dynamicData); // Early return if the table is an offchain table - if (!isTable) { + if (tableId.getType() != RESOURCE_TABLE) { return; } @@ -391,22 +387,19 @@ library StoreCore { * @param data The data to write to the static data of the record at the start byte. */ function spliceStaticData(ResourceId tableId, bytes32[] memory keyTuple, uint48 start, bytes memory data) internal { - bool isTable = tableId.getType() == RESOURCE_TABLE; uint256 location = StoreCoreInternal._getStaticDataLocation(tableId, keyTuple); bytes21[] memory hooks = StoreHooks._get(tableId); - if (isTable) { - // Call onBeforeSpliceStaticData hooks (before actually modifying the state, so observers have access to the previous state if needed) - for (uint256 i; i < hooks.length; i++) { - Hook hook = Hook.wrap(hooks[i]); - if (hook.isEnabled(BEFORE_SPLICE_STATIC_DATA)) { - IStoreHook(hook.getAddress()).onBeforeSpliceStaticData({ - tableId: tableId, - keyTuple: keyTuple, - start: start, - data: data - }); - } + // Call onBeforeSpliceStaticData hooks (before actually modifying the state, so observers have access to the previous state if needed) + for (uint256 i; i < hooks.length; i++) { + Hook hook = Hook.wrap(hooks[i]); + if (hook.isEnabled(BEFORE_SPLICE_STATIC_DATA)) { + IStoreHook(hook.getAddress()).onBeforeSpliceStaticData({ + tableId: tableId, + keyTuple: keyTuple, + start: start, + data: data + }); } } @@ -414,7 +407,7 @@ library StoreCore { emit StoreCore.Store_SpliceStaticData({ tableId: tableId, keyTuple: keyTuple, start: start, data: data }); // Early return if the table is an offchain table - if (!isTable) { + if (tableId.getType() != RESOURCE_TABLE) { return; } @@ -590,16 +583,12 @@ library StoreCore { * @param fieldLayout The field layout for the record. */ function deleteRecord(ResourceId tableId, bytes32[] memory keyTuple, FieldLayout fieldLayout) internal { - bool isTable = tableId.getType() == RESOURCE_TABLE; - bytes21[] memory hooks = StoreHooks._get(tableId); - if (isTable) { - // Call onBeforeDeleteRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) - for (uint256 i; i < hooks.length; i++) { - Hook hook = Hook.wrap(hooks[i]); - if (hook.isEnabled(BEFORE_DELETE_RECORD)) { - IStoreHook(hook.getAddress()).onBeforeDeleteRecord(tableId, keyTuple, fieldLayout); - } + // Call onBeforeDeleteRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) + for (uint256 i; i < hooks.length; i++) { + Hook hook = Hook.wrap(hooks[i]); + if (hook.isEnabled(BEFORE_DELETE_RECORD)) { + IStoreHook(hook.getAddress()).onBeforeDeleteRecord(tableId, keyTuple, fieldLayout); } } @@ -607,7 +596,7 @@ library StoreCore { emit Store_DeleteRecord(tableId, keyTuple); // Early return if the table is an offchain table - if (!isTable) { + if (tableId.getType() != RESOURCE_TABLE) { return; } From 5535e9fb2c16b89a20f2e0280e567ca31e917379 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 12 Jan 2024 13:47:55 +0000 Subject: [PATCH 17/21] refactor: early return with offchain tables immediately --- packages/store/gas-report.json | 4 ++-- packages/store/src/StoreCore.sol | 36 +++++++++++++++++++------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/packages/store/gas-report.json b/packages/store/gas-report.json index d6c458ad90..1d4043de4c 100644 --- a/packages/store/gas-report.json +++ b/packages/store/gas-report.json @@ -723,7 +723,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testDeleteDataOffchainTable", "name": "StoreCore: delete record in offchain table", - "gasUsed": 7017 + "gasUsed": 4687 }, { "file": "test/StoreCoreGas.t.sol", @@ -951,7 +951,7 @@ "file": "test/StoreCoreGas.t.sol", "test": "testSetDataOffchainTable", "name": "StoreCore: set record in offchain table", - "gasUsed": 12423 + "gasUsed": 8093 }, { "file": "test/StoreCoreGas.t.sol", diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index 1feaf0d4a3..7109b9b4b6 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -298,6 +298,13 @@ library StoreCore { bytes memory dynamicData, FieldLayout fieldLayout ) internal { + // Early return if the table is an offchain table + if (tableId.getType() == RESOURCE_OFFCHAIN_TABLE) { + // Emit event to notify indexers + emit Store_SetRecord(tableId, keyTuple, staticData, encodedLengths, dynamicData); + return; + } + bytes21[] memory hooks = StoreHooks._get(tableId); // Call onBeforeSetRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) for (uint256 i; i < hooks.length; i++) { @@ -317,11 +324,6 @@ library StoreCore { // Emit event to notify indexers emit Store_SetRecord(tableId, keyTuple, staticData, encodedLengths, dynamicData); - // Early return if the table is an offchain table - if (tableId.getType() != RESOURCE_TABLE) { - return; - } - // Store the static data at the static data location uint256 staticDataLocation = StoreCoreInternal._getStaticDataLocation(tableId, keyTuple); uint256 memoryPointer = Memory.dataPointer(staticData); @@ -387,6 +389,13 @@ library StoreCore { * @param data The data to write to the static data of the record at the start byte. */ function spliceStaticData(ResourceId tableId, bytes32[] memory keyTuple, uint48 start, bytes memory data) internal { + // Early return if the table is an offchain table + if (tableId.getType() == RESOURCE_OFFCHAIN_TABLE) { + // Emit event to notify offchain indexers + emit StoreCore.Store_SpliceStaticData({ tableId: tableId, keyTuple: keyTuple, start: start, data: data }); + return; + } + uint256 location = StoreCoreInternal._getStaticDataLocation(tableId, keyTuple); bytes21[] memory hooks = StoreHooks._get(tableId); @@ -406,11 +415,6 @@ library StoreCore { // Emit event to notify offchain indexers emit StoreCore.Store_SpliceStaticData({ tableId: tableId, keyTuple: keyTuple, start: start, data: data }); - // Early return if the table is an offchain table - if (tableId.getType() != RESOURCE_TABLE) { - return; - } - // Store the provided value in storage Storage.store({ storagePointer: location, offset: start, data: data }); @@ -583,6 +587,13 @@ library StoreCore { * @param fieldLayout The field layout for the record. */ function deleteRecord(ResourceId tableId, bytes32[] memory keyTuple, FieldLayout fieldLayout) internal { + // Early return if the table is an offchain table + if (tableId.getType() == RESOURCE_OFFCHAIN_TABLE) { + // Emit event to notify indexers + emit Store_DeleteRecord(tableId, keyTuple); + return; + } + bytes21[] memory hooks = StoreHooks._get(tableId); // Call onBeforeDeleteRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) for (uint256 i; i < hooks.length; i++) { @@ -595,11 +606,6 @@ library StoreCore { // Emit event to notify indexers emit Store_DeleteRecord(tableId, keyTuple); - // Early return if the table is an offchain table - if (tableId.getType() != RESOURCE_TABLE) { - return; - } - // Delete static data uint256 staticDataLocation = StoreCoreInternal._getStaticDataLocation(tableId, keyTuple); Storage.store({ storagePointer: staticDataLocation, offset: 0, data: new bytes(fieldLayout.staticDataLength()) }); From cb82d133aaf60ec525247635804b6e9533c02f80 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 12 Jan 2024 13:50:39 +0000 Subject: [PATCH 18/21] chore: move comments --- packages/store/src/StoreCore.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index 7109b9b4b6..4ab4a702b4 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -305,8 +305,8 @@ library StoreCore { return; } - bytes21[] memory hooks = StoreHooks._get(tableId); // Call onBeforeSetRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) + bytes21[] memory hooks = StoreHooks._get(tableId); for (uint256 i; i < hooks.length; i++) { Hook hook = Hook.wrap(hooks[i]); if (hook.isEnabled(BEFORE_SET_RECORD)) { @@ -396,10 +396,10 @@ library StoreCore { return; } + // Call onBeforeSpliceStaticData hooks (before actually modifying the state, so observers have access to the previous state if needed) uint256 location = StoreCoreInternal._getStaticDataLocation(tableId, keyTuple); bytes21[] memory hooks = StoreHooks._get(tableId); - // Call onBeforeSpliceStaticData hooks (before actually modifying the state, so observers have access to the previous state if needed) for (uint256 i; i < hooks.length; i++) { Hook hook = Hook.wrap(hooks[i]); if (hook.isEnabled(BEFORE_SPLICE_STATIC_DATA)) { @@ -594,8 +594,8 @@ library StoreCore { return; } - bytes21[] memory hooks = StoreHooks._get(tableId); // Call onBeforeDeleteRecord hooks (before actually modifying the state, so observers have access to the previous state if needed) + bytes21[] memory hooks = StoreHooks._get(tableId); for (uint256 i; i < hooks.length; i++) { Hook hook = Hook.wrap(hooks[i]); if (hook.isEnabled(BEFORE_DELETE_RECORD)) { From af2f79d5891496a5a67d0418f1c5f5800f14a4a7 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 12 Jan 2024 13:51:45 +0000 Subject: [PATCH 19/21] chore: comment --- packages/store/src/StoreCore.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/store/src/StoreCore.sol b/packages/store/src/StoreCore.sol index 4ab4a702b4..ff64ea8598 100644 --- a/packages/store/src/StoreCore.sol +++ b/packages/store/src/StoreCore.sol @@ -396,9 +396,9 @@ library StoreCore { return; } - // Call onBeforeSpliceStaticData hooks (before actually modifying the state, so observers have access to the previous state if needed) uint256 location = StoreCoreInternal._getStaticDataLocation(tableId, keyTuple); + // Call onBeforeSpliceStaticData hooks (before actually modifying the state, so observers have access to the previous state if needed) bytes21[] memory hooks = StoreHooks._get(tableId); for (uint256 i; i < hooks.length; i++) { Hook hook = Hook.wrap(hooks[i]); From 03bd4b81ae710b101799858662d8482b06d47d99 Mon Sep 17 00:00:00 2001 From: Fraser Scott Date: Fri, 12 Jan 2024 14:09:41 +0000 Subject: [PATCH 20/21] chore: root gas report --- packages/world-modules/gas-report.json | 82 +++++++++++++------------- packages/world/gas-report.json | 10 ++-- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/packages/world-modules/gas-report.json b/packages/world-modules/gas-report.json index 3b28e69340..885089bac9 100644 --- a/packages/world-modules/gas-report.json +++ b/packages/world-modules/gas-report.json @@ -3,139 +3,139 @@ "file": "test/ERC20.t.sol", "test": "testApprove", "name": "approve", - "gasUsed": 114372 + "gasUsed": 114366 }, { "file": "test/ERC20.t.sol", "test": "testBurn", "name": "burn", - "gasUsed": 75943 + "gasUsed": 75931 }, { "file": "test/ERC20.t.sol", "test": "testMint", "name": "mint", - "gasUsed": 161782 + "gasUsed": 161770 }, { "file": "test/ERC20.t.sol", "test": "testTransfer", "name": "transfer", - "gasUsed": 93028 + "gasUsed": 93016 }, { "file": "test/ERC20.t.sol", "test": "testTransferFrom", "name": "transferFrom", - "gasUsed": 130373 + "gasUsed": 130355 }, { "file": "test/ERC721.t.sol", "test": "testApproveAllGas", "name": "setApprovalForAll", - "gasUsed": 113999 + "gasUsed": 113993 }, { "file": "test/ERC721.t.sol", "test": "testApproveGas", "name": "approve", - "gasUsed": 88005 + "gasUsed": 87999 }, { "file": "test/ERC721.t.sol", "test": "testBurnGas", "name": "burn", - "gasUsed": 101955 + "gasUsed": 101937 }, { "file": "test/ERC721.t.sol", "test": "testMintGas", "name": "mint", - "gasUsed": 169513 + "gasUsed": 169501 }, { "file": "test/ERC721.t.sol", "test": "testSafeMintToEOAGas", "name": "safeMint", - "gasUsed": 169784 + "gasUsed": 169772 }, { "file": "test/ERC721.t.sol", "test": "testSafeTransferFromToEOAGas", "name": "safeTransferFrom", - "gasUsed": 143798 + "gasUsed": 143774 }, { "file": "test/ERC721.t.sol", "test": "testTransferFromGas", "name": "transferFrom", - "gasUsed": 136958 + "gasUsed": 136934 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallComposite", "name": "install keys in table module", - "gasUsed": 1413439 + "gasUsed": 1413433 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallGas", "name": "install keys in table module", - "gasUsed": 1413439 + "gasUsed": 1413433 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallGas", "name": "set a record on a table with keysInTableModule installed", - "gasUsed": 158866 + "gasUsed": 158854 }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallSingleton", "name": "install keys in table module", - "gasUsed": 1413439 + "gasUsed": 1413433 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookCompositeGas", "name": "install keys in table module", - "gasUsed": 1413439 + "gasUsed": 1413433 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookCompositeGas", "name": "change a composite record on a table with keysInTableModule installed", - "gasUsed": 22498 + "gasUsed": 22492 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookCompositeGas", "name": "delete a composite record on a table with keysInTableModule installed", - "gasUsed": 155989 + "gasUsed": 155971 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookGas", "name": "install keys in table module", - "gasUsed": 1413439 + "gasUsed": 1413433 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookGas", "name": "change a record on a table with keysInTableModule installed", - "gasUsed": 21220 + "gasUsed": 21214 }, { "file": "test/KeysInTableModule.t.sol", "test": "testSetAndDeleteRecordHookGas", "name": "delete a record on a table with keysInTableModule installed", - "gasUsed": 85107 + "gasUsed": 85089 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testGetKeysWithValueGas", "name": "install keys with value module", - "gasUsed": 668212 + "gasUsed": 668206 }, { "file": "test/KeysWithValueModule.t.sol", @@ -153,49 +153,49 @@ "file": "test/KeysWithValueModule.t.sol", "test": "testInstall", "name": "install keys with value module", - "gasUsed": 668212 + "gasUsed": 668206 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testInstall", "name": "set a record on a table with KeysWithValueModule installed", - "gasUsed": 135449 + "gasUsed": 135437 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testSetAndDeleteRecordHook", "name": "install keys with value module", - "gasUsed": 668212 + "gasUsed": 668206 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testSetAndDeleteRecordHook", "name": "change a record on a table with KeysWithValueModule installed", - "gasUsed": 103846 + "gasUsed": 103840 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testSetAndDeleteRecordHook", "name": "delete a record on a table with KeysWithValueModule installed", - "gasUsed": 36501 + "gasUsed": 36489 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testSetField", "name": "install keys with value module", - "gasUsed": 668212 + "gasUsed": 668206 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testSetField", "name": "set a field on a table with KeysWithValueModule installed", - "gasUsed": 146684 + "gasUsed": 146672 }, { "file": "test/KeysWithValueModule.t.sol", "test": "testSetField", "name": "change a field on a table with KeysWithValueModule installed", - "gasUsed": 111443 + "gasUsed": 111431 }, { "file": "test/query.t.sol", @@ -267,60 +267,60 @@ "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromCallboundDelegation", "name": "register a callbound delegation", - "gasUsed": 118353 + "gasUsed": 118347 }, { "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromCallboundDelegation", "name": "call a system via a callbound delegation", - "gasUsed": 36703 + "gasUsed": 36697 }, { "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromSystemDelegation", "name": "register a systembound delegation", - "gasUsed": 115906 + "gasUsed": 115900 }, { "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromSystemDelegation", "name": "call a system via a systembound delegation", - "gasUsed": 33875 + "gasUsed": 33869 }, { "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromTimeboundDelegation", "name": "register a timebound delegation", - "gasUsed": 112841 + "gasUsed": 112823 }, { "file": "test/StandardDelegationsModule.t.sol", "test": "testCallFromTimeboundDelegation", "name": "call a system via a timebound delegation", - "gasUsed": 26815 + "gasUsed": 26809 }, { "file": "test/UniqueEntityModule.t.sol", "test": "testInstall", "name": "install unique entity module", - "gasUsed": 699260 + "gasUsed": 694917 }, { "file": "test/UniqueEntityModule.t.sol", "test": "testInstall", "name": "get a unique entity nonce (non-root module)", - "gasUsed": 51063 + "gasUsed": 51045 }, { "file": "test/UniqueEntityModule.t.sol", "test": "testInstallRoot", "name": "installRoot unique entity module", - "gasUsed": 668227 + "gasUsed": 663866 }, { "file": "test/UniqueEntityModule.t.sol", "test": "testInstallRoot", "name": "get a unique entity nonce (root module)", - "gasUsed": 51063 + "gasUsed": 51045 } ] diff --git a/packages/world/gas-report.json b/packages/world/gas-report.json index bdc3d70197..5c87427efd 100644 --- a/packages/world/gas-report.json +++ b/packages/world/gas-report.json @@ -81,7 +81,7 @@ "file": "test/World.t.sol", "test": "testDeleteRecord", "name": "Delete record", - "gasUsed": 9852 + "gasUsed": 9846 }, { "file": "test/World.t.sol", @@ -93,7 +93,7 @@ "file": "test/World.t.sol", "test": "testRegisterFunctionSelector", "name": "Register a function selector", - "gasUsed": 87499 + "gasUsed": 83156 }, { "file": "test/World.t.sol", @@ -105,7 +105,7 @@ "file": "test/World.t.sol", "test": "testRegisterRootFunctionSelector", "name": "Register a root function selector", - "gasUsed": 84806 + "gasUsed": 80462 }, { "file": "test/World.t.sol", @@ -123,13 +123,13 @@ "file": "test/World.t.sol", "test": "testSetField", "name": "Write data to a table field", - "gasUsed": 36918 + "gasUsed": 36912 }, { "file": "test/World.t.sol", "test": "testSetRecord", "name": "Write data to the table", - "gasUsed": 39062 + "gasUsed": 39056 }, { "file": "test/WorldDynamicUpdate.t.sol", From ea87f3443f59afeb0273ad4cec2235b2fa65191e Mon Sep 17 00:00:00 2001 From: Kevin Ingersoll Date: Fri, 12 Jan 2024 07:50:15 -0800 Subject: [PATCH 21/21] Update .changeset/beige-ads-melt.md --- .changeset/beige-ads-melt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/beige-ads-melt.md b/.changeset/beige-ads-melt.md index 4cb3da3d5c..01846b4024 100644 --- a/.changeset/beige-ads-melt.md +++ b/.changeset/beige-ads-melt.md @@ -2,4 +2,4 @@ "@latticexyz/store": patch --- -Fixes the functions in `StoreCore` to emit a storage event after calling the `beforeSetRecord` hook, ensuring that storage events are emitted in the same order that values are set on-chain. +Storage events are now emitted after "before" hooks, so that the resulting logs are now correctly ordered and reflect onchain logic. This resolves issues with store writes and event emissions happening in "before" hooks.