Skip to content

Commit

Permalink
feat(store): rename events for readability and consistency with errors (
Browse files Browse the repository at this point in the history
  • Loading branch information
alvrs committed Sep 22, 2023
1 parent e5d208e commit af639a2
Show file tree
Hide file tree
Showing 22 changed files with 476 additions and 408 deletions.
43 changes: 43 additions & 0 deletions .changeset/stale-schools-wait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
"@latticexyz/block-logs-stream": patch
"@latticexyz/dev-tools": patch
"@latticexyz/store-sync": patch
"@latticexyz/store": major
---

`Store` events have been renamed for consistency and readability.
If you're parsing `Store` events manually, you need to update your ABI.
If you're using the MUD sync stack, the new events are already integrated and no further changes are necessary.

```diff
- event StoreSetRecord(
+ event Store_SetRecord(
ResourceId indexed tableId,
bytes32[] keyTuple,
bytes staticData,
bytes32 encodedLengths,
bytes dynamicData
);
- event StoreSpliceStaticData(
+ event Store_SpliceStaticData(
ResourceId indexed tableId,
bytes32[] keyTuple,
uint48 start,
uint40 deleteCount,
bytes data
);
- event StoreSpliceDynamicData(
+ event Store_SpliceDynamicData(
ResourceId indexed tableId,
bytes32[] keyTuple,
uint48 start,
uint40 deleteCount,
bytes data,
bytes32 encodedLengths
);
- event StoreDeleteRecord(
+ event Store_DeleteRecord(
ResourceId indexed tableId,
bytes32[] keyTuple
);
```
9 changes: 5 additions & 4 deletions docs/pages/store/spec.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import { Aside } from "../../components/Aside";
When a record or a single field is edited, or when a record is deleted, Store emits a standard event with enough information for off-chain actors to reconstruct the new version of the Store with event-sourcing.

```solidity
event StoreSetRecord(uint256 tableId, bytes32[] keyTuple, bytes data);
event StoreSetField(uint256 tableId, bytes32[] keyTuple, uint8 schemaIndex, bytes data);
event StoreDeleteRecord(uint256 tableId, bytes32[] keyTuple);
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_SpliceDynamicData(bytes32 indexed tableId, bytes32[] keyTuple, uint48 start, uint40 deleteCount, bytes data, bytes32 encodedLengths),
event Store_DeleteRecord(bytes32 indexed tableId, bytes32[] keyTuple),
```

Each event includes the table ID and each key encoded as `bytes32`.
Expand All @@ -22,7 +23,7 @@ MUD comes with many libraries and services in order to reconstruct the state of
### Data encoding

`bytes data` uses custom encoding, which MUD networking stack decodes.
Each event carries only data. To get a table's schema (information on how to decode it), use `IStore.getSchema(tableId)` or listen to `StoreSetRecord` updates of the schema table.
Each event carries only data. To get a table's schema (information on how to decode it), use `IStore.getSchema(tableId)` or listen to `Store_SetRecord` updates of the schema table.

Schema is a way to dynamically store solidity types.
Use the [schema-type package](https://github.com/latticexyz/mud/tree/main/packages/schema-type) to work with it directly.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ contract ChatNamespacedTest is MudTest {
bytes32[] memory keyTuple;
string memory value = "test";
vm.expectEmit(true, true, true, true);
emit StoreCore.StoreSetRecord(
emit StoreCore.Store_SetRecord(
MessageTableTableId,
keyTuple,
new bytes(0),
Expand Down
7 changes: 4 additions & 3 deletions packages/block-logs-stream/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ latestBlockNumber$
publicClient,
address,
events: parseAbi([
"event StoreDeleteRecord(bytes32 tableId, bytes32[] keyTuple)",
"event StoreSetField(bytes32 tableId, bytes32[] keyTuple, uint8 schemaIndex, bytes data)",
"event StoreSetRecord(bytes32 tableId, bytes32[] keyTuple, bytes data)",
"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_SpliceDynamicData(bytes32 indexed tableId, bytes32[] keyTuple, uint48 start, uint40 deleteCount, bytes data, bytes32 encodedLengths)",
"event Store_DeleteRecord(bytes32 indexed tableId, bytes32[] keyTuple)",
]),
}),
mergeMap(({ logs }) => from(groupLogsByBlockNumber(logs)))
Expand Down
8 changes: 5 additions & 3 deletions packages/dev-tools/src/actions/WriteSummary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,11 @@ export function WriteSummary({ write }: Props) {
{table.namespace}:{table.name}
</td>
<td className="whitespace-nowrap">
{eventName === "StoreSetRecord" ? <span className="text-green-500 font-bold">=</span> : null}
{eventName === "StoreSetField" ? <span className="text-green-500 font-bold">+</span> : null}
{eventName === "StoreDeleteRecord" ? <span className="text-red-500 font-bold">-</span> : null}
{eventName === "Store_SetRecord" ? <span className="text-green-500 font-bold">=</span> : null}
{eventName === "Store_SpliceStaticData" || eventName === "Store_SpliceDynamicData" ? (
<span className="text-green-500 font-bold">+</span>
) : null}
{eventName === "Store_DeleteRecord" ? <span className="text-red-500 font-bold">-</span> : null}
</td>
<td className="whitespace-nowrap overflow-hidden text-ellipsis">
{hexKeyTupleToEntity((args as any).keyTuple)}
Expand Down
8 changes: 4 additions & 4 deletions packages/dev-tools/src/events/EventIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ type Props = {

export function EventIcon({ type }: Props) {
switch (type) {
case "StoreSetRecord":
case "Store_SetRecord":
return <span className="text-green-500 font-bold">=</span>;
case "StoreSpliceStaticData":
case "StoreSpliceDynamicData":
case "Store_SpliceStaticData":
case "Store_SpliceDynamicData":
return <span className="text-cyan-500 font-bold">+</span>;
case "StoreDeleteRecord":
case "Store_DeleteRecord":
return <span className="text-red-500 font-bold">-</span>;
default:
return assertExhaustive(type, `Unexpected event type: ${type}`);
Expand Down
6 changes: 3 additions & 3 deletions packages/dev-tools/src/events/LogsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,17 @@ export function LogsTable({ logs }: Props) {
</td>
<td className="px-1 whitespace-nowrap overflow-hidden text-ellipsis">
{/* TODO: decode these values if we can */}
{log.eventName === "StoreSetRecord"
{log.eventName === "Store_SetRecord"
? JSON.stringify({
staticData: log.args.staticData,
encodedLengths: log.args.encodedLengths,
dynamicData: log.args.dynamicData,
})
: null}
{log.eventName === "StoreSpliceStaticData"
{log.eventName === "Store_SpliceStaticData"
? JSON.stringify({ start: log.args.start, deleteCount: log.args.deleteCount, data: log.args.data })
: null}
{log.eventName === "StoreSpliceDynamicData"
{log.eventName === "Store_SpliceDynamicData"
? JSON.stringify({
start: log.args.start,
deleteCount: log.args.deleteCount,
Expand Down
2 changes: 1 addition & 1 deletion packages/store-sync/src/createStoreSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export async function createStoreSync<TConfig extends StoreConfig = StoreConfig>
const logs: StorageAdapterLog[] = tables.flatMap((table) =>
table.records.map(
(record): StorageAdapterLog => ({
eventName: "StoreSetRecord",
eventName: "Store_SetRecord",
address: table.address,
args: {
tableId: table.tableId,
Expand Down
4 changes: 2 additions & 2 deletions packages/store-sync/src/isTableRegistrationLog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import { StorageAdapterLog, schemasTableId } from "./common";

export function isTableRegistrationLog(
log: StorageAdapterLog
): log is StorageAdapterLog & { eventName: "StoreSetRecord" } {
return log.eventName === "StoreSetRecord" && log.args.tableId === schemasTableId;
): log is StorageAdapterLog & { eventName: "Store_SetRecord" } {
return log.eventName === "Store_SetRecord" && log.args.tableId === schemasTableId;
}
2 changes: 1 addition & 1 deletion packages/store-sync/src/logToTable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe("logToTable", () => {
expect(
logToTable({
address: "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c",
eventName: "StoreSetRecord",
eventName: "Store_SetRecord",
args: {
tableId: "0x74626d756473746f72650000000000005461626c657300000000000000000000",
keyTuple: ["0x74626d756473746f72650000000000005461626c657300000000000000000000"],
Expand Down
2 changes: 1 addition & 1 deletion packages/store-sync/src/logToTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { hexToResourceId } from "@latticexyz/common";

// TODO: add tableToLog

export function logToTable(log: StorageAdapterLog & { eventName: "StoreSetRecord" }): Table {
export function logToTable(log: StorageAdapterLog & { eventName: "Store_SetRecord" }): Table {
const [tableId, ...otherKeys] = log.args.keyTuple;
if (otherKeys.length) {
console.warn("registerSchema event is expected to have only one key in key tuple, but got multiple", log);
Expand Down
8 changes: 4 additions & 4 deletions packages/store-sync/src/postgres/postgresStorage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe("postgresStorage", async () => {
{
"chainId": 31337,
"lastError": null,
"lastUpdatedBlockNumber": 5n,
"lastUpdatedBlockNumber": 6n,
"schemaVersion": 1,
},
]
Expand All @@ -74,7 +74,7 @@ describe("postgresStorage", async () => {
"key": "0x5FbDB2315678afecb367f032d93F642f64180aa3::NumberList",
"keySchema": {},
"lastError": null,
"lastUpdatedBlockNumber": 5n,
"lastUpdatedBlockNumber": 6n,
"name": "NumberList",
"namespace": "",
"schemaVersion": 1,
Expand All @@ -94,7 +94,7 @@ describe("postgresStorage", async () => {
"key": "0x5FbDB2315678afecb367f032d93F642f64180aa3::NumberList",
"keySchema": {},
"lastError": null,
"lastUpdatedBlockNumber": 5n,
"lastUpdatedBlockNumber": 6n,
"name": "NumberList",
"namespace": "",
"schemaVersion": 1,
Expand All @@ -114,7 +114,7 @@ describe("postgresStorage", async () => {
"__encodedLengths": "0x0000000000000000000000000000000000000000000000000800000000000008",
"__isDeleted": false,
"__key": "0x",
"__lastUpdatedBlockNumber": 5n,
"__lastUpdatedBlockNumber": 6n,
"__staticData": null,
"value": [
420,
Expand Down
8 changes: 4 additions & 4 deletions packages/store-sync/src/postgres/postgresStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export async function postgresStorage<TConfig extends StoreConfig = StoreConfig>

debug(log.eventName, log);

if (log.eventName === "StoreSetRecord") {
if (log.eventName === "Store_SetRecord") {
const value = decodeValueArgs(table.valueSchema, log.args);
debug("upserting record", {
namespace: table.namespace,
Expand Down Expand Up @@ -128,7 +128,7 @@ export async function postgresStorage<TConfig extends StoreConfig = StoreConfig>
},
})
.execute();
} else if (log.eventName === "StoreSpliceStaticData") {
} else if (log.eventName === "Store_SpliceStaticData") {
// TODO: verify that this returns what we expect (doesn't error/undefined on no record)
const previousValue = (await tx.select().from(sqlTable).where(eq(sqlTable.__key, uniqueKey)).execute())[0];
const previousStaticData = (previousValue?.__staticData as Hex) ?? "0x";
Expand Down Expand Up @@ -167,7 +167,7 @@ export async function postgresStorage<TConfig extends StoreConfig = StoreConfig>
},
})
.execute();
} else if (log.eventName === "StoreSpliceDynamicData") {
} else if (log.eventName === "Store_SpliceDynamicData") {
// TODO: verify that this returns what we expect (doesn't error/undefined on no record)
const previousValue = (await tx.select().from(sqlTable).where(eq(sqlTable.__key, uniqueKey)).execute())[0];
const previousDynamicData = (previousValue?.__dynamicData as Hex) ?? "0x";
Expand Down Expand Up @@ -211,7 +211,7 @@ export async function postgresStorage<TConfig extends StoreConfig = StoreConfig>
},
})
.execute();
} else if (log.eventName === "StoreDeleteRecord") {
} else if (log.eventName === "Store_DeleteRecord") {
// TODO: should we upsert so we at least have a DB record of when a thing was created/deleted within the same block?
debug("deleting record", {
namespace: table.namespace,
Expand Down
8 changes: 4 additions & 4 deletions packages/store-sync/src/recs/recsStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export function recsStorage<TConfig extends StoreConfig = StoreConfig>({

const entity = hexKeyTupleToEntity(log.args.keyTuple);

if (log.eventName === "StoreSetRecord") {
if (log.eventName === "Store_SetRecord") {
const value = decodeValueArgs(table.valueSchema, log.args);
debug("setting component", {
namespace: table.namespace,
Expand All @@ -94,7 +94,7 @@ export function recsStorage<TConfig extends StoreConfig = StoreConfig>({
__encodedLengths: log.args.encodedLengths,
__dynamicData: log.args.dynamicData,
});
} else if (log.eventName === "StoreSpliceStaticData") {
} else if (log.eventName === "Store_SpliceStaticData") {
// TODO: add tests that this works when no record had been set before
const previousValue = getComponentValue(component, entity);
const previousStaticData = (previousValue?.__staticData as Hex) ?? "0x";
Expand All @@ -117,7 +117,7 @@ export function recsStorage<TConfig extends StoreConfig = StoreConfig>({
...newValue,
__staticData: newStaticData,
});
} else if (log.eventName === "StoreSpliceDynamicData") {
} else if (log.eventName === "Store_SpliceDynamicData") {
// TODO: add tests that this works when no record had been set before
const previousValue = getComponentValue(component, entity);
const previousDynamicData = (previousValue?.__dynamicData as Hex) ?? "0x";
Expand All @@ -142,7 +142,7 @@ export function recsStorage<TConfig extends StoreConfig = StoreConfig>({
__encodedLengths: log.args.encodedLengths,
__dynamicData: newDynamicData,
});
} else if (log.eventName === "StoreDeleteRecord") {
} else if (log.eventName === "Store_DeleteRecord") {
debug("deleting component", {
namespace: table.namespace,
name: table.name,
Expand Down
8 changes: 4 additions & 4 deletions packages/store-sync/src/sqlite/sqliteStorage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ describe("sqliteStorage", async () => {
{
"chainId": 31337,
"lastError": null,
"lastUpdatedBlockNumber": 5n,
"lastUpdatedBlockNumber": 6n,
"schemaVersion": 1,
},
]
Expand All @@ -77,7 +77,7 @@ describe("sqliteStorage", async () => {
"id": "0x5FbDB2315678afecb367f032d93F642f64180aa3____NumberList",
"keySchema": {},
"lastError": null,
"lastUpdatedBlockNumber": 5n,
"lastUpdatedBlockNumber": 6n,
"name": "NumberList",
"namespace": "",
"schemaVersion": 1,
Expand All @@ -97,7 +97,7 @@ describe("sqliteStorage", async () => {
"id": "0x5FbDB2315678afecb367f032d93F642f64180aa3____NumberList",
"keySchema": {},
"lastError": null,
"lastUpdatedBlockNumber": 5n,
"lastUpdatedBlockNumber": 6n,
"name": "NumberList",
"namespace": "",
"schemaVersion": 1,
Expand All @@ -117,7 +117,7 @@ describe("sqliteStorage", async () => {
"__encodedLengths": "0x0000000000000000000000000000000000000000000000000800000000000008",
"__isDeleted": false,
"__key": "0x",
"__lastUpdatedBlockNumber": 5n,
"__lastUpdatedBlockNumber": 6n,
"__staticData": null,
"value": [
420,
Expand Down
8 changes: 4 additions & 4 deletions packages/store-sync/src/sqlite/sqliteStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export async function sqliteStorage<TConfig extends StoreConfig = StoreConfig>({
const uniqueKey = concatHex(log.args.keyTuple as Hex[]);
const key = decodeKey(table.keySchema, log.args.keyTuple);

if (log.eventName === "StoreSetRecord") {
if (log.eventName === "Store_SetRecord") {
const value = decodeValueArgs(table.valueSchema, log.args);
debug("upserting record", {
namespace: table.namespace,
Expand Down Expand Up @@ -127,7 +127,7 @@ export async function sqliteStorage<TConfig extends StoreConfig = StoreConfig>({
},
})
.run();
} else if (log.eventName === "StoreSpliceStaticData") {
} else if (log.eventName === "Store_SpliceStaticData") {
// TODO: verify that this returns what we expect (doesn't error/undefined on no record)
const previousValue = (await tx.select().from(sqlTable).where(eq(sqlTable.__key, uniqueKey)).execute())[0];
const previousStaticData = (previousValue?.__staticData as Hex) ?? "0x";
Expand Down Expand Up @@ -165,7 +165,7 @@ export async function sqliteStorage<TConfig extends StoreConfig = StoreConfig>({
},
})
.run();
} else if (log.eventName === "StoreSpliceDynamicData") {
} else if (log.eventName === "Store_SpliceDynamicData") {
const previousValue = (await tx.select().from(sqlTable).where(eq(sqlTable.__key, uniqueKey)).execute())[0];
const previousDynamicData = (previousValue?.__dynamicData as Hex) ?? "0x";
const newDynamicData = spliceHex(previousDynamicData, log.args.start, log.args.deleteCount, log.args.data);
Expand Down Expand Up @@ -207,7 +207,7 @@ export async function sqliteStorage<TConfig extends StoreConfig = StoreConfig>({
},
})
.run();
} else if (log.eventName === "StoreDeleteRecord") {
} else if (log.eventName === "Store_DeleteRecord") {
// TODO: should we upsert so we at least have a DB record of when a thing was created/deleted within the same block?
debug("deleting record", {
namespace: table.namespace,
Expand Down
8 changes: 4 additions & 4 deletions packages/store/src/IStore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -85,29 +85,29 @@ interface IStoreRead {
}

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

// Set full record (including full dynamic data)
function setRecord(
Expand Down
Loading

0 comments on commit af639a2

Please sign in to comment.