Skip to content

Commit

Permalink
feat(store,world): set protocol version, add tests (#2412)
Browse files Browse the repository at this point in the history
  • Loading branch information
holic committed Mar 12, 2024
1 parent 711f6e2 commit 9aa5e78
Show file tree
Hide file tree
Showing 21 changed files with 192 additions and 43 deletions.
6 changes: 6 additions & 0 deletions .changeset/green-eggs-end.md
@@ -0,0 +1,6 @@
---
"@latticexyz/store": major
"@latticexyz/world": major
---

Set the protocol version to `2.0.0` for each Store and World.
6 changes: 3 additions & 3 deletions docs/pages/store/reference/misc.mdx
Expand Up @@ -2683,10 +2683,10 @@ bytes2 constant RESOURCE_OFFCHAIN_TABLE = "ot";

#### STORE_VERSION

Contains a constant representing the version of the Store.
Contains a constant representing the version of the Store protocol.

_Identifier for the current Store version._
_Identifier for the current Store protocol version._

```solidity
bytes32 constant STORE_VERSION = "1.0.0-unaudited";
bytes32 constant STORE_VERSION = "2.0.0";
```
8 changes: 4 additions & 4 deletions docs/pages/store/reference/store-core.mdx
Expand Up @@ -1041,17 +1041,17 @@ constructor();

#### storeVersion

Retrieves the version of the store.
Retrieves the protocol version of the Store.

```solidity
function storeVersion() public pure returns (bytes32);
```

**Returns**

| Name | Type | Description |
| -------- | --------- | ---------------------------------------------- |
| `<none>` | `bytes32` | The current version of the store as a bytes32. |
| Name | Type | Description |
| -------- | --------- | ---------------------------------- |
| `<none>` | `bytes32` | The protocol version of the Store. |

## StoreRead

Expand Down
4 changes: 2 additions & 2 deletions docs/pages/store/reference/store.mdx
Expand Up @@ -17,7 +17,7 @@ IStore implements the error interfaces for each library that it uses.

#### HelloStore

Emitted when the store is initialized.
Emitted when the Store is created.

```solidity
event HelloStore(bytes32 indexed storeVersion);
Expand All @@ -27,7 +27,7 @@ event HelloStore(bytes32 indexed storeVersion);

| Name | Type | Description |
| -------------- | --------- | ---------------------------------- |
| `storeVersion` | `bytes32` | The version of the Store contract. |
| `storeVersion` | `bytes32` | The protocol version of the Store. |

#### Store_SetRecord

Expand Down
6 changes: 3 additions & 3 deletions docs/pages/world/reference/misc.mdx
Expand Up @@ -99,10 +99,10 @@ function revertWithBytes(bytes memory reason) pure;

#### WORLD_VERSION

Contains a constant representing the version of the World.
Contains a constant representing the version of the World protocol.

_Identifier for the current World version._
_Identifier for the current World protocol version._

```solidity
bytes32 constant WORLD_VERSION = "1.0.0-unaudited";
bytes32 constant WORLD_VERSION = "2.0.0";
```
16 changes: 8 additions & 8 deletions docs/pages/world/reference/world-external.mdx
Expand Up @@ -16,17 +16,17 @@ _._

#### storeVersion

Retrieves the version of the store.
Retrieves the protocol version of the Store.

```solidity
function storeVersion() public pure returns (bytes32);
```

**Returns**

| Name | Type | Description |
| -------- | --------- | ---------------------------------------------- |
| `<none>` | `bytes32` | The current version of the store as a bytes32. |
| Name | Type | Description |
| -------- | --------- | ---------------------------------- |
| `<none>` | `bytes32` | The protocol version of the Store. |

#### registerTable

Expand Down Expand Up @@ -718,17 +718,17 @@ so it's ABI should include these errors._

#### worldVersion

Retrieve the version of the World.
Retrieve the protocol version of the World.

```solidity
function worldVersion() external view returns (bytes32);
```

**Returns**

| Name | Type | Description |
| -------- | --------- | ------------------------------------ |
| `<none>` | `bytes32` | The version identifier of the World. |
| Name | Type | Description |
| -------- | --------- | ---------------------------------- |
| `<none>` | `bytes32` | The protocol version of the World. |

#### creator

Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/deploy/common.ts
Expand Up @@ -21,8 +21,8 @@ export const worldDeployEvents = [helloStoreEvent, helloWorldEvent] as const;
export const worldAbi = [...IBaseWorldAbi, ...IModuleAbi] as const;

// Ideally, this should be an append-only list. Before adding more versions here, be sure to add backwards-compatible support for old Store/World versions.
export const supportedStoreVersions = ["1.0.0-unaudited"];
export const supportedWorldVersions = ["1.0.0-unaudited"];
export const supportedStoreVersions = ["2.0.0"];
export const supportedWorldVersions = ["2.0.0"];

// TODO: extend this to include factory+deployer address? so we can reuse the deployer for a world?
export type WorldDeploy = {
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/src/deploy/logsToWorldDeploy.ts
@@ -1,4 +1,4 @@
import { AbiEventSignatureNotFoundError, Log, decodeEventLog, hexToString, parseAbi, trim } from "viem";
import { AbiEventSignatureNotFoundError, Log, decodeEventLog, hexToString, parseAbi } from "viem";
import { WorldDeploy, worldDeployEvents } from "./common";
import { isDefined } from "@latticexyz/common/utils";

Expand Down Expand Up @@ -31,10 +31,10 @@ export function logsToWorldDeploy(logs: readonly Log<bigint, number, false>[]):
address: log.address,
deployBlock: log.blockNumber,
...(log.eventName === "HelloWorld"
? { worldVersion: hexToString(trim(log.args.worldVersion, { dir: "right" })) }
? { worldVersion: hexToString(log.args.worldVersion).replace(/\0+$/, "") }
: null),
...(log.eventName === "HelloStore"
? { storeVersion: hexToString(trim(log.args.storeVersion, { dir: "right" })) }
? { storeVersion: hexToString(log.args.storeVersion).replace(/\0+$/, "") }
: null),
}),
{},
Expand Down
4 changes: 2 additions & 2 deletions packages/store/src/IStoreEvents.sol
Expand Up @@ -10,8 +10,8 @@ import { PackedCounter } from "./PackedCounter.sol";
*/
interface IStoreEvents {
/**
* @notice Emitted when the store is initialized.
* @param storeVersion The version of the Store contract.
* @notice Emitted when the Store is created.
* @param storeVersion The protocol version of the Store.
*/
event HelloStore(bytes32 indexed storeVersion);

Expand Down
4 changes: 2 additions & 2 deletions packages/store/src/StoreData.sol
Expand Up @@ -25,8 +25,8 @@ abstract contract StoreData is IStoreData, StoreRead {
}

/**
* @notice Retrieves the version of the store.
* @return The current version of the store as a bytes32.
* @notice Retrieves the protocol version of the Store.
* @return The protocol version of the Store.
*/
function storeVersion() public pure returns (bytes32) {
return STORE_VERSION;
Expand Down
8 changes: 4 additions & 4 deletions packages/store/src/version.sol
Expand Up @@ -2,10 +2,10 @@
pragma solidity >=0.8.24;

/**
* @title Store version
* @title Store protocol version
* @author MUD (https://mud.dev) by Lattice (https://lattice.xyz)
* @notice Contains a constant representing the version of the Store.
* @notice Contains a constant representing the version of the Store protocol.
*/

/// @dev Identifier for the current Store version.
bytes32 constant STORE_VERSION = "1.0.0-unaudited";
/// @dev Identifier for the current Store protocol version.
bytes32 constant STORE_VERSION = "2.0.0";
34 changes: 34 additions & 0 deletions packages/store/ts/protocol-snapshots/2.0.0.snap
@@ -0,0 +1,34 @@
[
"error Store_IndexOutOfBounds(uint256 length, uint256 accessedIndex)",
"error Store_InvalidBounds(uint256 start, uint256 end)",
"error Store_TableNotFound(bytes32 tableId, string tableIdString)",
"event HelloStore(bytes32 indexed storeVersion)",
"event Store_DeleteRecord(bytes32 indexed tableId, bytes32[] keyTuple)",
"event Store_SetRecord(bytes32 indexed tableId, bytes32[] keyTuple, bytes staticData, bytes32 encodedLengths, bytes dynamicData)",
"event Store_SpliceDynamicData(bytes32 indexed tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, uint48 start, uint40 deleteCount, bytes32 encodedLengths, bytes data)",
"event Store_SpliceStaticData(bytes32 indexed tableId, bytes32[] keyTuple, uint48 start, bytes data)",
"function deleteRecord(bytes32 tableId, bytes32[] keyTuple)",
"function getDynamicField(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex) view returns (bytes data)",
"function getDynamicFieldLength(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex) view returns (uint256)",
"function getDynamicFieldSlice(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, uint256 start, uint256 end) view returns (bytes)",
"function getField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes32 fieldLayout) view returns (bytes data)",
"function getField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex) view returns (bytes data)",
"function getFieldLayout(bytes32 tableId) view returns (bytes32 fieldLayout)",
"function getFieldLength(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes32 fieldLayout) view returns (uint256)",
"function getFieldLength(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex) view returns (uint256)",
"function getKeySchema(bytes32 tableId) view returns (bytes32 keySchema)",
"function getRecord(bytes32 tableId, bytes32[] keyTuple, bytes32 fieldLayout) view returns (bytes staticData, bytes32 encodedLengths, bytes dynamicData)",
"function getRecord(bytes32 tableId, bytes32[] keyTuple) view returns (bytes staticData, bytes32 encodedLengths, bytes dynamicData)",
"function getStaticField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes32 fieldLayout) view returns (bytes32 data)",
"function getValueSchema(bytes32 tableId) view returns (bytes32 valueSchema)",
"function popFromDynamicField(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, uint256 byteLengthToPop)",
"function pushToDynamicField(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, bytes dataToPush)",
"function setDynamicField(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, bytes data)",
"function setField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes data, bytes32 fieldLayout)",
"function setField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes data)",
"function setRecord(bytes32 tableId, bytes32[] keyTuple, bytes staticData, bytes32 encodedLengths, bytes dynamicData)",
"function setStaticField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes data, bytes32 fieldLayout)",
"function spliceDynamicData(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, uint40 startWithinField, uint40 deleteCount, bytes data)",
"function spliceStaticData(bytes32 tableId, bytes32[] keyTuple, uint48 start, bytes data)",
"function storeVersion() pure returns (bytes32)",
]
17 changes: 17 additions & 0 deletions packages/store/ts/protocolVersions.test.ts
@@ -0,0 +1,17 @@
import { describe, expect, it } from "vitest";
import fs from "node:fs";
import StoreAbi from "../out/StoreData.sol/StoreData.abi.json";
import { formatAbi } from "abitype";
import { protocolVersions } from "./protocolVersions";

const [, currentVersion] = fs.readFileSync(`${__dirname}/../src/version.sol`, "utf8").match(/VERSION = "(.*?)"/) ?? [];

const currentAbi = formatAbi(StoreAbi).sort((a, b) => a.localeCompare(b));

describe("Store protocol version", () => {
it("is up to date", async () => {
expect(currentVersion).toMatch(/^\d+\.\d+\.\d+$/);
expect(protocolVersions).toHaveProperty(currentVersion);
await expect(currentAbi).toMatchFileSnapshot(`${__dirname}/protocol-snapshots/${currentVersion}.snap`);
});
});
4 changes: 4 additions & 0 deletions packages/store/ts/protocolVersions.ts
@@ -0,0 +1,4 @@
// History of protocol versions and a short description of what changed in each.
export const protocolVersions = {
"2.0.0": "Initial v2 release. See mud.dev/changelog for the full list of changes from v1.",
};
4 changes: 2 additions & 2 deletions packages/world/gas-report.json
Expand Up @@ -57,13 +57,13 @@
"file": "test/Factories.t.sol",
"test": "testCreate2Factory",
"name": "deploy contract via Create2",
"gasUsed": 4965450
"gasUsed": 4960875
},
{
"file": "test/Factories.t.sol",
"test": "testWorldFactoryGas",
"name": "deploy world via WorldFactory",
"gasUsed": 12796228
"gasUsed": 12796213
},
{
"file": "test/World.t.sol",
Expand Down
4 changes: 2 additions & 2 deletions packages/world/src/IWorldEvents.sol
Expand Up @@ -13,8 +13,8 @@ import { ResourceId } from "./WorldResourceId.sol";
*/
interface IWorldEvents {
/**
* @dev Emitted upon successful World initialization.
* @param worldVersion The version of the World being initialized.
* @notice Emitted when the World is created.
* @param worldVersion The protocol version of the World.
*/
event HelloWorld(bytes32 indexed worldVersion);
}
4 changes: 2 additions & 2 deletions packages/world/src/IWorldKernel.sol
Expand Up @@ -65,8 +65,8 @@ interface IWorldCall {
*/
interface IWorldKernel is IWorldModuleInstallation, IWorldCall, IWorldErrors, IWorldEvents, IModuleErrors {
/**
* @notice Retrieve the version of the World.
* @return The version identifier of the World.
* @notice Retrieve the protocol version of the World.
* @return The protocol version of the World.
*/
function worldVersion() external view returns (bytes32);

Expand Down
8 changes: 4 additions & 4 deletions packages/world/src/version.sol
Expand Up @@ -2,10 +2,10 @@
pragma solidity >=0.8.24;

/**
* @title World version
* @title World protocol version
* @author MUD (https://mud.dev) by Lattice (https://lattice.xyz)
* @notice Contains a constant representing the version of the World.
* @notice Contains a constant representing the version of the World protocol.
*/

/// @dev Identifier for the current World version.
bytes32 constant WORLD_VERSION = "1.0.0-unaudited";
/// @dev Identifier for the current World protocol version.
bytes32 constant WORLD_VERSION = "2.0.0";
67 changes: 67 additions & 0 deletions packages/world/ts/protocol-snapshots/2.0.0.snap
@@ -0,0 +1,67 @@
[
"constructor()",
"error Module_AlreadyInstalled()",
"error Module_MissingDependency(address dependency)",
"error Module_NonRootInstallNotSupported()",
"error Module_RootInstallNotSupported()",
"error PackedCounter_InvalidLength(uint256 length)",
"error Slice_OutOfBounds(bytes data, uint256 start, uint256 end)",
"error Store_IndexOutOfBounds(uint256 length, uint256 accessedIndex)",
"error Store_InvalidBounds(uint256 start, uint256 end)",
"error Store_InvalidResourceType(bytes2 expected, bytes32 resourceId, string resourceIdString)",
"error Store_InvalidSplice(uint40 startWithinField, uint40 deleteCount, uint40 fieldLength)",
"error Store_TableNotFound(bytes32 tableId, string tableIdString)",
"error World_AccessDenied(string resource, address caller)",
"error World_AlreadyInitialized()",
"error World_CallbackNotAllowed(bytes4 functionSelector)",
"error World_DelegationNotFound(address delegator, address delegatee)",
"error World_FunctionSelectorAlreadyExists(bytes4 functionSelector)",
"error World_FunctionSelectorNotFound(bytes4 functionSelector)",
"error World_InsufficientBalance(uint256 balance, uint256 amount)",
"error World_InterfaceNotSupported(address contractAddress, bytes4 interfaceId)",
"error World_InvalidNamespace(bytes14 namespace)",
"error World_InvalidResourceId(bytes32 resourceId, string resourceIdString)",
"error World_InvalidResourceType(bytes2 expected, bytes32 resourceId, string resourceIdString)",
"error World_ResourceAlreadyExists(bytes32 resourceId, string resourceIdString)",
"error World_ResourceNotFound(bytes32 resourceId, string resourceIdString)",
"error World_SystemAlreadyExists(address system)",
"error World_UnlimitedDelegationNotAllowed()",
"event HelloStore(bytes32 indexed storeVersion)",
"event HelloWorld(bytes32 indexed worldVersion)",
"event Store_DeleteRecord(bytes32 indexed tableId, bytes32[] keyTuple)",
"event Store_SetRecord(bytes32 indexed tableId, bytes32[] keyTuple, bytes staticData, bytes32 encodedLengths, bytes dynamicData)",
"event Store_SpliceDynamicData(bytes32 indexed tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, uint48 start, uint40 deleteCount, bytes32 encodedLengths, bytes data)",
"event Store_SpliceStaticData(bytes32 indexed tableId, bytes32[] keyTuple, uint48 start, bytes data)",
"fallback()",
"function call(bytes32 systemId, bytes callData) payable returns (bytes)",
"function callFrom(address delegator, bytes32 systemId, bytes callData) payable returns (bytes)",
"function creator() view returns (address)",
"function deleteRecord(bytes32 tableId, bytes32[] keyTuple)",
"function getDynamicField(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex) view returns (bytes data)",
"function getDynamicFieldLength(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex) view returns (uint256)",
"function getDynamicFieldSlice(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, uint256 start, uint256 end) view returns (bytes)",
"function getField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes32 fieldLayout) view returns (bytes data)",
"function getField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex) view returns (bytes data)",
"function getFieldLayout(bytes32 tableId) view returns (bytes32 fieldLayout)",
"function getFieldLength(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes32 fieldLayout) view returns (uint256)",
"function getFieldLength(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex) view returns (uint256)",
"function getKeySchema(bytes32 tableId) view returns (bytes32 keySchema)",
"function getRecord(bytes32 tableId, bytes32[] keyTuple, bytes32 fieldLayout) view returns (bytes staticData, bytes32 encodedLengths, bytes dynamicData)",
"function getRecord(bytes32 tableId, bytes32[] keyTuple) view returns (bytes staticData, bytes32 encodedLengths, bytes dynamicData)",
"function getStaticField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes32 fieldLayout) view returns (bytes32 data)",
"function getValueSchema(bytes32 tableId) view returns (bytes32 valueSchema)",
"function initialize(address initModule)",
"function installRootModule(address module, bytes encodedArgs)",
"function popFromDynamicField(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, uint256 byteLengthToPop)",
"function pushToDynamicField(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, bytes dataToPush)",
"function setDynamicField(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, bytes data)",
"function setField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes data, bytes32 fieldLayout)",
"function setField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes data)",
"function setRecord(bytes32 tableId, bytes32[] keyTuple, bytes staticData, bytes32 encodedLengths, bytes dynamicData)",
"function setStaticField(bytes32 tableId, bytes32[] keyTuple, uint8 fieldIndex, bytes data, bytes32 fieldLayout)",
"function spliceDynamicData(bytes32 tableId, bytes32[] keyTuple, uint8 dynamicFieldIndex, uint40 startWithinField, uint40 deleteCount, bytes data)",
"function spliceStaticData(bytes32 tableId, bytes32[] keyTuple, uint48 start, bytes data)",
"function storeVersion() pure returns (bytes32)",
"function worldVersion() pure returns (bytes32)",
"receive() external payable",
]
17 changes: 17 additions & 0 deletions packages/world/ts/protocolVersions.test.ts
@@ -0,0 +1,17 @@
import { describe, expect, it } from "vitest";
import fs from "node:fs";
import WorldAbi from "../out/World.sol/World.abi.json";
import { formatAbi } from "abitype";
import { protocolVersions } from "./protocolVersions";

const [, currentVersion] = fs.readFileSync(`${__dirname}/../src/version.sol`, "utf8").match(/VERSION = "(.*?)"/) ?? [];

const currentAbi = formatAbi(WorldAbi).sort((a, b) => a.localeCompare(b));

describe("World protocol version", () => {
it("is up to date", async () => {
expect(currentVersion).toMatch(/^\d+\.\d+\.\d+$/);
expect(protocolVersions).toHaveProperty(currentVersion);
await expect(currentAbi).toMatchFileSnapshot(`${__dirname}/protocol-snapshots/${currentVersion}.snap`);
});
});
4 changes: 4 additions & 0 deletions packages/world/ts/protocolVersions.ts
@@ -0,0 +1,4 @@
// History of protocol versions and a short description of what changed in each.
export const protocolVersions = {
"2.0.0": "Initial v2 release. See mud.dev/changelog for the full list of changes from v1.",
};

0 comments on commit 9aa5e78

Please sign in to comment.