Skip to content

Commit

Permalink
feat(store,world): polish store methods (#1581)
Browse files Browse the repository at this point in the history
  • Loading branch information
alvrs authored Sep 23, 2023
1 parent af639a2 commit cea754d
Show file tree
Hide file tree
Showing 87 changed files with 2,965 additions and 2,704 deletions.
128 changes: 128 additions & 0 deletions .changeset/wicked-squids-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
---
"@latticexyz/block-logs-stream": patch
"@latticexyz/cli": patch
"@latticexyz/common": minor
"@latticexyz/dev-tools": patch
"@latticexyz/store-sync": patch
"@latticexyz/store": major
"@latticexyz/world": major
"create-mud": patch
---

- The external `setRecord` and `deleteRecord` methods of `IStore` no longer accept a `FieldLayout` as input, but load it from storage instead.
This is to prevent invalid `FieldLayout` values being passed, which could cause the onchain state to diverge from the indexer state.
However, the internal `StoreCore` library still exposes a `setRecord` and `deleteRecord` method that allows a `FieldLayout` to be passed.
This is because `StoreCore` can only be used internally, so the `FieldLayout` value can be trusted and we can save the gas for accessing storage.

```diff
interface IStore {
function setRecord(
ResourceId tableId,
bytes32[] calldata keyTuple,
bytes calldata staticData,
PackedCounter encodedLengths,
bytes calldata dynamicData,
- FieldLayout fieldLayout
) external;

function deleteRecord(
ResourceId tableId,
bytes32[] memory keyTuple,
- FieldLayout fieldLayout
) external;
}
```

- The `spliceStaticData` method and `Store_SpliceStaticData` event of `IStore` and `StoreCore` no longer include `deleteCount` in their signature.
This is because when splicing static data, the data after `start` is always overwritten with `data` instead of being shifted, so `deleteCount` is always the length of the data to be written.

```diff

event Store_SpliceStaticData(
ResourceId indexed tableId,
bytes32[] keyTuple,
uint48 start,
- uint40 deleteCount,
bytes data
);

interface IStore {
function spliceStaticData(
ResourceId tableId,
bytes32[] calldata keyTuple,
uint48 start,
- uint40 deleteCount,
bytes calldata data
) external;
}
```

- The `updateInField` method has been removed from `IStore`, as it's almost identical to the more general `spliceDynamicData`.
If you're manually calling `updateInField`, here is how to upgrade to `spliceDynamicData`:

```diff
- store.updateInField(tableId, keyTuple, fieldIndex, startByteIndex, dataToSet, fieldLayout);
+ uint8 dynamicFieldIndex = fieldIndex - fieldLayout.numStaticFields();
+ store.spliceDynamicData(tableId, keyTuple, dynamicFieldIndex, uint40(startByteIndex), uint40(dataToSet.length), dataToSet);
```

- All other methods that are only valid for dynamic fields (`pushToField`, `popFromField`, `getFieldSlice`)
have been renamed to make this more explicit (`pushToDynamicField`, `popFromDynamicField`, `getDynamicFieldSlice`).

Their `fieldIndex` parameter has been replaced by a `dynamicFieldIndex` parameter, which is the index relative to the first dynamic field (i.e. `dynamicFieldIndex` = `fieldIndex` - `numStaticFields`).
The `FieldLayout` parameter has been removed, as it was only used to calculate the `dynamicFieldIndex` in the method.

```diff
interface IStore {
- function pushToField(
+ function pushToDynamicField(
ResourceId tableId,
bytes32[] calldata keyTuple,
- uint8 fieldIndex,
+ uint8 dynamicFieldIndex,
bytes calldata dataToPush,
- FieldLayout fieldLayout
) external;

- function popFromField(
+ function popFromDynamicField(
ResourceId tableId,
bytes32[] calldata keyTuple,
- uint8 fieldIndex,
+ uint8 dynamicFieldIndex,
uint256 byteLengthToPop,
- FieldLayout fieldLayout
) external;

- function getFieldSlice(
+ function getDynamicFieldSlice(
ResourceId tableId,
bytes32[] memory keyTuple,
- uint8 fieldIndex,
+ uint8 dynamicFieldIndex,
- FieldLayout fieldLayout,
uint256 start,
uint256 end
) external view returns (bytes memory data);
}
```

- `IStore` has a new `getDynamicFieldLength` length method, which returns the byte length of the given dynamic field and doesn't require the `FieldLayout`.

```diff
IStore {
+ function getDynamicFieldLength(
+ ResourceId tableId,
+ bytes32[] memory keyTuple,
+ uint8 dynamicFieldIndex
+ ) external view returns (uint256);
}

```

- `IStore` now has additional overloads for `getRecord`, `getField`, `getFieldLength` and `setField` that don't require a `FieldLength` to be passed, but instead load it from storage.

- `IStore` now exposes `setStaticField` and `setDynamicField` to save gas by avoiding the dynamic inference of whether the field is static or dynamic.

- The `getDynamicFieldSlice` method no longer accepts reading outside the bounds of the dynamic field.
This is to avoid returning invalid data, as the data of a dynamic field is not deleted when the record is deleted, but only its length is set to zero.
2 changes: 1 addition & 1 deletion docs/pages/store/spec.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ When a record or a single field is edited, or when a record is deleted, Store em

```solidity
event Store_SetRecord(bytes32 indexed tableId, bytes32[] keyTuple, bytes staticData, bytes32 encodedLengths, bytes dynamicData),
event Store_SpliceStaticData(bytes32 indexed tableId, bytes32[] keyTuple, uint48 start, uint40 deleteCount, bytes data),
event Store_SpliceStaticData(bytes32 indexed tableId, bytes32[] keyTuple, uint48 start, bytes data),
event Store_SpliceDynamicData(bytes32 indexed tableId, bytes32[] keyTuple, uint48 start, uint40 deleteCount, bytes data, bytes32 encodedLengths),
event Store_DeleteRecord(bytes32 indexed tableId, bytes32[] keyTuple),
```
Expand Down
24 changes: 12 additions & 12 deletions e2e/packages/contracts/src/codegen/tables/Multi.sol

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 8 additions & 8 deletions e2e/packages/contracts/src/codegen/tables/Number.sol

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit cea754d

Please sign in to comment.