Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(store,world): move around interfaces and base contracts #1602

Merged
merged 8 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/quick-years-juggle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@latticexyz/store": major
"@latticexyz/world": minor
---

- Moves Store events into its own `IStoreEvents` interface
- Moves Store interfaces to their own files
- Adds a `StoreData` abstract contract to initialize a Store and expose the Store version

If you're using MUD out of the box, you won't have to make any changes. You will only need to update if you're using any of the base Store interfaces.
241 changes: 2 additions & 239 deletions packages/store/src/IStore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,244 +2,7 @@
pragma solidity >=0.8.21;

import { IStoreErrors } from "./IStoreErrors.sol";
import { PackedCounter } from "./PackedCounter.sol";
import { FieldLayout } from "./FieldLayout.sol";
import { Schema } from "./Schema.sol";
import { IStoreHook } from "./IStoreHook.sol";
import { ResourceId } from "./ResourceId.sol";

interface IStoreRead {
event HelloStore(bytes32 indexed storeVersion);

function storeVersion() external view returns (bytes32);

function getFieldLayout(ResourceId tableId) external view returns (FieldLayout fieldLayout);

function getValueSchema(ResourceId tableId) external view returns (Schema valueSchema);

function getKeySchema(ResourceId tableId) external view returns (Schema keySchema);

/**
* Get full record (all fields, static and dynamic data) for the given tableId and key tuple, loading the field layout from storage
*/
function getRecord(
ResourceId tableId,
bytes32[] calldata keyTuple
) external view returns (bytes memory staticData, PackedCounter encodedLengths, bytes memory dynamicData);

/**
* Get full record (all fields, static and dynamic data) for the given tableId and key tuple, with the given field layout
*/
function getRecord(
ResourceId tableId,
bytes32[] calldata keyTuple,
FieldLayout fieldLayout
) external view returns (bytes memory staticData, PackedCounter encodedLengths, bytes memory dynamicData);

/**
* Get a single field from the given tableId and key tuple, loading the field layout from storage
*/
function getField(
ResourceId tableId,
bytes32[] calldata keyTuple,
uint8 fieldIndex
) external view returns (bytes memory data);

/**
* Get a single field from the given tableId and key tuple, with the given field layout
*/
function getField(
ResourceId tableId,
bytes32[] calldata keyTuple,
uint8 fieldIndex,
FieldLayout fieldLayout
) external view returns (bytes memory data);

/**
* Get a single static field from the given tableId and key tuple, with the given value field layout.
* Note: the field value is left-aligned in the returned bytes32, the rest of the word is not zeroed out.
* Consumers are expected to truncate the returned value as needed.
*/
function getStaticField(
ResourceId tableId,
bytes32[] calldata keyTuple,
uint8 fieldIndex,
FieldLayout fieldLayout
) external view returns (bytes32);

/**
* Get a single dynamic field from the given tableId and key tuple at the given dynamic field index.
* (Dynamic field index = field index - number of static fields)
*/
function getDynamicField(
ResourceId tableId,
bytes32[] memory keyTuple,
uint8 dynamicFieldIndex
) external view returns (bytes memory);

/**
* Get the byte length of a single field from the given tableId and key tuple, loading the field layout from storage
*/
function getFieldLength(
ResourceId tableId,
bytes32[] memory keyTuple,
uint8 fieldIndex
) external view returns (uint256);

/**
* Get the byte length of a single field from the given tableId and key tuple, with the given value field layout
*/
function getFieldLength(
ResourceId tableId,
bytes32[] memory keyTuple,
uint8 fieldIndex,
FieldLayout fieldLayout
) external view returns (uint256);

/**
* Get the byte length of a single dynamic field from the given tableId and key tuple
*/
function getDynamicFieldLength(
ResourceId tableId,
bytes32[] memory keyTuple,
uint8 dynamicFieldIndex
) external view returns (uint256);

/**
* Get a byte slice (including start, excluding end) of a single dynamic field from the given tableId and key tuple, with the given value field layout.
* The slice is unchecked and will return invalid data if `start`:`end` overflow.
*/
function getDynamicFieldSlice(
ResourceId tableId,
bytes32[] memory keyTuple,
uint8 dynamicFieldIndex,
uint256 start,
uint256 end
) external view returns (bytes memory data);
}

interface IStoreWrite {
event Store_SetRecord(
ResourceId indexed tableId,
bytes32[] keyTuple,
bytes staticData,
PackedCounter encodedLengths,
bytes dynamicData
);
event Store_SpliceStaticData(ResourceId indexed tableId, bytes32[] keyTuple, uint48 start, bytes data);
event Store_SpliceDynamicData(
ResourceId indexed tableId,
bytes32[] keyTuple,
uint48 start,
uint40 deleteCount,
PackedCounter encodedLengths,
bytes data
);
event Store_DeleteRecord(ResourceId indexed tableId, bytes32[] keyTuple);

// Set full record (including full dynamic data)
function setRecord(
ResourceId tableId,
bytes32[] calldata keyTuple,
bytes calldata staticData,
PackedCounter encodedLengths,
bytes calldata dynamicData
) external;

// Splice data in the static part of the record
function spliceStaticData(
ResourceId tableId,
bytes32[] calldata keyTuple,
uint48 start,
bytes calldata data
) external;

// Splice data in the dynamic part of the record
function spliceDynamicData(
ResourceId tableId,
bytes32[] calldata keyTuple,
uint8 dynamicFieldIndex,
uint40 startWithinField,
uint40 deleteCount,
bytes calldata data
) external;

// Set partial data at field index
function setField(ResourceId tableId, bytes32[] calldata keyTuple, uint8 fieldIndex, bytes calldata data) external;

// Set partial data at field index
function setField(
ResourceId tableId,
bytes32[] calldata keyTuple,
uint8 fieldIndex,
bytes calldata data,
FieldLayout fieldLayout
) external;

function setStaticField(
ResourceId tableId,
bytes32[] calldata keyTuple,
uint8 fieldIndex,
bytes calldata data,
FieldLayout fieldLayout
) external;

function setDynamicField(
ResourceId tableId,
bytes32[] calldata keyTuple,
uint8 dynamicFieldIndex,
bytes calldata data
) external;

// Push encoded items to the dynamic field at field index
function pushToDynamicField(
ResourceId tableId,
bytes32[] calldata keyTuple,
uint8 dynamicFieldIndex,
bytes calldata dataToPush
) external;

// Pop byte length from the dynamic field at field index
function popFromDynamicField(
ResourceId tableId,
bytes32[] calldata keyTuple,
uint8 dynamicFieldIndex,
uint256 byteLengthToPop
) external;

// Set full record (including full dynamic data)
function deleteRecord(ResourceId tableId, bytes32[] memory keyTuple) external;
}

/**
* The IStoreData interface includes methods for reading and writing table values.
* These methods are frequently invoked during runtime, so it is essential to prioritize
* optimizing their gas cost
*/
interface IStoreData is IStoreRead, IStoreWrite {

}

/**
* The IStoreRegistration interface includes methods for managing table field layouts,
* metadata, and hooks, which are usually called once in the setup phase of an application,
* making them less performance critical than the IStoreData methods.
*/
interface IStoreRegistration {
function registerTable(
ResourceId tableId,
FieldLayout fieldLayout,
Schema keySchema,
Schema valueSchema,
string[] calldata keyNames,
string[] calldata fieldNames
) external;

// Register hook to be called when a record or field is set or deleted
function registerStoreHook(ResourceId tableId, IStoreHook hookAddress, uint8 enabledHooksBitmap) external;

// Unregister a hook for the given tableId
function unregisterStoreHook(ResourceId tableId, IStoreHook hookAddress) external;
}
import { IStoreData } from "./IStoreData.sol";
import { IStoreRegistration } from "./IStoreRegistration.sol";

interface IStore is IStoreData, IStoreRegistration, IStoreErrors {}
16 changes: 16 additions & 0 deletions packages/store/src/IStoreData.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.21;

import { IStoreRead } from "./IStoreRead.sol";
import { IStoreWrite } from "./IStoreWrite.sol";

/**
* The IStoreData interface includes methods for reading and writing table values.
* These methods are frequently invoked during runtime, so it is essential to prioritize
* optimizing their gas cost
*/
interface IStoreData is IStoreRead, IStoreWrite {
event HelloStore(bytes32 indexed storeVersion);

function storeVersion() external view returns (bytes32);
}
25 changes: 25 additions & 0 deletions packages/store/src/IStoreEvents.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.21;

import { ResourceId } from "./ResourceId.sol";
import { PackedCounter } from "./PackedCounter.sol";

interface IStoreEvents {
event Store_SetRecord(
ResourceId indexed tableId,
bytes32[] keyTuple,
bytes staticData,
PackedCounter encodedLengths,
bytes dynamicData
);
event Store_SpliceStaticData(ResourceId indexed tableId, bytes32[] keyTuple, uint48 start, bytes data);
event Store_SpliceDynamicData(
ResourceId indexed tableId,
bytes32[] keyTuple,
uint48 start,
uint40 deleteCount,
PackedCounter encodedLengths,
bytes data
);
event Store_DeleteRecord(ResourceId indexed tableId, bytes32[] keyTuple);
}
Loading