Skip to content

Commit

Permalink
fix(cli): throw error on schema changes
Browse files Browse the repository at this point in the history
  • Loading branch information
holic committed Oct 26, 2024
1 parent b8afc07 commit f418c89
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 14 deletions.
53 changes: 47 additions & 6 deletions packages/cli/src/deploy/ensureTables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import {
getSchemaTypes,
getValueSchema,
getKeySchema,
KeySchema,
} from "@latticexyz/protocol-parser/internal";
import { debug } from "./debug";
import { getTables } from "./getTables";
import pRetry from "p-retry";
import { Table } from "@latticexyz/config";
import { isDefined } from "@latticexyz/common/utils";

export async function ensureTables({
client,
Expand All @@ -24,15 +24,56 @@ export async function ensureTables({
readonly worldDeploy: WorldDeploy;
readonly tables: readonly Table[];
}): Promise<readonly Hex[]> {
const worldTables = await getTables({ client, worldDeploy });
const worldTableIds = worldTables.map((table) => table.tableId);
const configTables = new Map(
tables.map((table) => {
const keySchema = getSchemaTypes(getKeySchema(table));
const valueSchema = getSchemaTypes(getValueSchema(table));
const keySchemaHex = keySchemaToHex(keySchema);
const valueSchemaHex = valueSchemaToHex(valueSchema);
return [
table.tableId,
{
...table,
keySchema,
keySchemaHex,
valueSchema,
valueSchemaHex,
},
];
}),
);

const existingTables = tables.filter((table) => worldTableIds.includes(table.tableId));
const worldTables = await getTables({ client, worldDeploy });
const existingTables = worldTables.filter(({ tableId }) => configTables.has(tableId));
if (existingTables.length) {
debug("existing tables:", existingTables.map(resourceToLabel).join(", "));

const schemaErrors = existingTables
.map((table) => {
const configTable = configTables.get(table.tableId)!;
if (table.keySchemaHex !== configTable.keySchemaHex || table.valueSchemaHex !== configTable.valueSchemaHex) {
return [
`"${resourceToLabel(table)}" table:`,
` Registered schema: ${JSON.stringify({ schema: getSchemaTypes(table.schema), key: table.key })}`,
` Config schema: ${JSON.stringify({ schema: getSchemaTypes(configTable.schema), key: configTable.key })}`,
].join("\n");
}
})
.filter(isDefined);

if (schemaErrors.length) {
throw new Error(
[
"Table schemas are immutable, but found registered tables with a different schema than what you have configured.",
...schemaErrors,
"You can either update your config with the registered schema or change the table name to register a new table.",
].join("\n\n") + "\n",
);
}
}

const missingTables = tables.filter((table) => !worldTableIds.includes(table.tableId));
const existingTableIds = new Set(existingTables.map(({ tableId }) => tableId));
const missingTables = tables.filter((table) => !existingTableIds.has(table.tableId));
if (missingTables.length) {
debug("registering tables:", missingTables.map(resourceToLabel).join(", "));
return await Promise.all(
Expand All @@ -50,7 +91,7 @@ export async function ensureTables({
args: [
table.tableId,
valueSchemaToFieldLayoutHex(valueSchema),
keySchemaToHex(keySchema as KeySchema),
keySchemaToHex(keySchema),
valueSchemaToHex(valueSchema),
Object.keys(keySchema),
Object.keys(valueSchema),
Expand Down
28 changes: 21 additions & 7 deletions packages/cli/src/deploy/getTables.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Client, decodeAbiParameters, parseAbiParameters } from "viem";
import { Client, Hex, decodeAbiParameters, parseAbiParameters } from "viem";
import { hexToResource } from "@latticexyz/common";
import { WorldDeploy } from "./common";
import { debug } from "./debug";
Expand All @@ -16,7 +16,12 @@ import { fetchBlockLogs } from "@latticexyz/block-logs-stream";
import { flattenStoreLogs, getStoreLogs } from "@latticexyz/store/internal";

// TODO: add label and namespaceLabel once we register it onchain
type DeployedTable = Omit<Table, "label" | "namespaceLabel">;
type DeployedTable = Omit<Table, "label" | "namespaceLabel"> & {
readonly keySchema: Schema;
readonly keySchemaHex: Hex;
readonly valueSchema: Schema;
readonly valueSchemaHex: Hex;
};

export async function getTables({
client,
Expand Down Expand Up @@ -49,12 +54,17 @@ export async function getTables({
log.args.keyTuple,
);
const { type, namespace, name } = hexToResource(tableId);
const value = decodeValueArgs(getSchemaTypes(getValueSchema(storeConfig.namespaces.store.tables.Tables)), log.args);
const recordValue = decodeValueArgs(
getSchemaTypes(getValueSchema(storeConfig.namespaces.store.tables.Tables)),
log.args,
);

const solidityKeySchema = hexToSchema(value.keySchema);
const solidityValueSchema = hexToSchema(value.valueSchema);
const keyNames = decodeAbiParameters(parseAbiParameters("string[]"), value.abiEncodedKeyNames)[0];
const fieldNames = decodeAbiParameters(parseAbiParameters("string[]"), value.abiEncodedFieldNames)[0];
const keySchemaHex = recordValue.keySchema;
const valueSchemaHex = recordValue.valueSchema;
const solidityKeySchema = hexToSchema(keySchemaHex);
const solidityValueSchema = hexToSchema(valueSchemaHex);
const keyNames = decodeAbiParameters(parseAbiParameters("string[]"), recordValue.abiEncodedKeyNames)[0];
const fieldNames = decodeAbiParameters(parseAbiParameters("string[]"), recordValue.abiEncodedFieldNames)[0];

const valueAbiTypes = [...solidityValueSchema.staticFields, ...solidityValueSchema.dynamicFields];

Expand All @@ -73,6 +83,10 @@ export async function getTables({
tableId,
schema: { ...keySchema, ...valueSchema },
key: Object.keys(keySchema),
keySchema,
keySchemaHex,
valueSchema,
valueSchemaHex,
};
});

Expand Down
2 changes: 1 addition & 1 deletion packages/protocol-parser/src/getKeySchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export type getKeySchema<table extends PartialTable> = PartialTable extends tabl
? ResolvedKeySchema
: {
readonly [fieldName in Extract<keyof table["schema"], table["key"][number]>]: table["schema"][fieldName] & {
type: StaticAbiType;
readonly type: StaticAbiType;
};
};

Expand Down

0 comments on commit f418c89

Please sign in to comment.