Skip to content

Commit

Permalink
fix(cli): function selector lookup during deploy (#2800)
Browse files Browse the repository at this point in the history
  • Loading branch information
alvrs committed May 8, 2024
1 parent 0d4e302 commit 0ae9189
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 31 deletions.
8 changes: 8 additions & 0 deletions .changeset/blue-countries-drive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@latticexyz/cli": patch
---

The deploy CLI now uses logs to find registered function selectors and their corresponding function signatures.
Previously only function signatures were fetched via logs and then mapped to function selectors via `getRecord` calls,
but this approach failed for namespaced function selectors of non-root system,
because the function signature table includes both the namespaced and non-namespaced signature but the function selector table only includes the namespaced selector that is registered on the world.
68 changes: 37 additions & 31 deletions packages/cli/src/deploy/getFunctions.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { Client, toFunctionSelector, parseAbiItem } from "viem";
import { Client, parseAbiItem } from "viem";
import { WorldDeploy, WorldFunction, worldTables } from "./common";
import { debug } from "./debug";
import { storeSetRecordEvent } from "@latticexyz/store";
import { getLogs } from "viem/actions";
import { decodeValueArgs } from "@latticexyz/protocol-parser/internal";
import { getTableValue } from "./getTableValue";
import { hexToResource } from "@latticexyz/common";
import { decodeKey, decodeValueArgs } from "@latticexyz/protocol-parser/internal";

export async function getFunctions({
client,
Expand All @@ -15,44 +13,52 @@ export async function getFunctions({
readonly worldDeploy: WorldDeploy;
}): Promise<readonly WorldFunction[]> {
// This assumes we only use `FunctionSelectors._set(...)`, which is true as of this writing.
debug("looking up function signatures for", worldDeploy.address);
const logs = await getLogs(client, {
debug("looking up function selectors for", worldDeploy.address);
const selectorLogs = await getLogs(client, {
strict: true,
fromBlock: worldDeploy.deployBlock,
toBlock: worldDeploy.stateBlock,
address: worldDeploy.address,
event: parseAbiItem(storeSetRecordEvent),
args: { tableId: worldTables.world_FunctionSignatures.tableId },
args: { tableId: worldTables.world_FunctionSelectors.tableId },
});

const selectors = selectorLogs.map((log) => {
return {
...decodeValueArgs(worldTables.world_FunctionSelectors.valueSchema, log.args),
...decodeKey(worldTables.world_FunctionSelectors.keySchema, log.args.keyTuple),
};
});
debug("found", selectors.length, "function selectors for", worldDeploy.address);

const signatures = logs.map((log) => {
const value = decodeValueArgs(worldTables.world_FunctionSignatures.valueSchema, log.args);
return value.functionSignature;
// This assumes we only use `FunctionSignatures._set(...)`, which is true as of this writing.
debug("looking up function signatures for", worldDeploy.address);
const signatureLogs = await getLogs(client, {
strict: true,
fromBlock: worldDeploy.deployBlock,
toBlock: worldDeploy.stateBlock,
address: worldDeploy.address,
event: parseAbiItem(storeSetRecordEvent),
args: { tableId: worldTables.world_FunctionSignatures.tableId },
});
debug("found", signatures.length, "function signatures for", worldDeploy.address);

// TODO: parallelize with a bulk getRecords
const functions = await Promise.all(
signatures.map(async (signature) => {
const selector = toFunctionSelector(signature);
const { systemId, systemFunctionSelector } = await getTableValue({
client,
worldDeploy,
table: worldTables.world_FunctionSelectors,
key: { worldFunctionSelector: selector },
});
const { namespace, name } = hexToResource(systemId);
// TODO: find away around undoing contract logic (https://github.com/latticexyz/mud/issues/1708)
const systemFunctionSignature = namespace === "" ? signature : signature.replace(`${namespace}_${name}_`, "");
return {
signature,
selector,
systemId,
systemFunctionSignature,
systemFunctionSelector,
};
const selectorToSignature = Object.fromEntries(
signatureLogs.map((log) => {
return [
decodeKey(worldTables.world_FunctionSignatures.keySchema, log.args.keyTuple).functionSelector,
decodeValueArgs(worldTables.world_FunctionSignatures.valueSchema, log.args).functionSignature,
];
}),
);
debug("found", signatureLogs.length, "function signatures for", worldDeploy.address);

const functions = selectors.map(({ worldFunctionSelector, systemFunctionSelector, systemId }) => ({
selector: worldFunctionSelector,
signature: selectorToSignature[worldFunctionSelector],
systemFunctionSelector,
systemFunctionSignature: selectorToSignature[systemFunctionSelector],
systemId,
}));

return functions;
}

0 comments on commit 0ae9189

Please sign in to comment.