Skip to content
This repository has been archived by the owner on Aug 16, 2024. It is now read-only.

Commit

Permalink
useContractSchemaRpc: Parse schema based on module version (#45)
Browse files Browse the repository at this point in the history
## Purpose

Make fetching/parsing of contract schema more precise based on the
module version information that is now exposed by the gRPC client.

This in turn also documents the relationship between module and schema
versions.

## Changes

Use module version to determine what custom sections to look for and add
comments explaining the expected results.
  • Loading branch information
bisgardo authored Aug 7, 2023
1 parent 9a13ae0 commit 5f0da43
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 14 deletions.
3 changes: 2 additions & 1 deletion packages/wallet-connectors/src/WalletConnect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ function serializeUpdateContractMessage(
}

/**
* Convert schema into the object format expected by the Mobile crypto library.
* Convert schema into the object format expected by the Mobile crypto library (function 'parameter_to_json')
* which decodes the parameter before presenting it to the user for approval.
* @param schema The schema object.
*/
function convertSchemaFormat(schema: Schema | undefined) {
Expand Down
48 changes: 35 additions & 13 deletions samples/contractupdate/src/useContractSchemaRpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,31 @@ export interface SchemaRpcResult {
schema: Schema;
}

function findCustomSections(m: WebAssembly.Module) {
function findCustomSections(m: WebAssembly.Module, moduleVersion: number) {
function getCustomSections(sectionName: string, schemaVersion: SchemaVersion | undefined) {
const s = WebAssembly.Module.customSections(m, sectionName);
return s.length === 0 ? undefined : { sectionName, schemaVersion, contents: s };
}
// First look for embedded version, then v1, then v0. The "v"s being off by 1 is not an error.
return (
getCustomSections('concordium-schema', undefined) ||
getCustomSections('concordium-schema-v2', SchemaVersion.V1) ||
getCustomSections('concordium-schema-v1', SchemaVersion.V0)
);

// First look for section containing schema with embedded version, then "-v1" or "-v2" depending on the module version.
// See also comment in 'useContractSchemaRpc'.
switch (moduleVersion) {
case 0:
return (
getCustomSections('concordium-schema', undefined) || // always v0
getCustomSections('concordium-schema-v1', SchemaVersion.V0) // v0 (not a typo)
);
case 1:
return (
getCustomSections('concordium-schema', undefined) || // v1, v2, or v3
getCustomSections('concordium-schema-v2', SchemaVersion.V1) // v1 (not a typo)
);
}
return getCustomSections('concordium-schema', undefined); // expecting to find this section in future module versions
}

function findSchema(m: WebAssembly.Module): Result<SchemaRpcResult | undefined, string> {
const sections = findCustomSections(m);
function findSchema(m: WebAssembly.Module, moduleVersion: 0 | 1): Result<SchemaRpcResult | undefined, string> {
const sections = findCustomSections(m, moduleVersion);
if (!sections) {
return ok(undefined);
}
Expand All @@ -39,13 +49,25 @@ export function useContractSchemaRpc(rpc: ConcordiumGRPCClient, contract: Info)
const [result, setResult] = useState<Result<SchemaRpcResult | undefined, string>>();
useEffect(() => {
ResultAsync.fromPromise(rpc.getModuleSource(new ModuleReference(contract.moduleRef)), errorString)
.andThen((r) => {
if (!r) {
.andThen(({ version, source }) => {
if (source.length === 0) {
return err('module source is empty');
}
return ResultAsync.fromPromise(WebAssembly.compile(r.source), errorString);
// The module can contain a schema in one of two different custom sections.
// The supported sections depend on the module version.
// The schema version can be either defined by the section name or embedded into the actual schema:
// - Both v0 and v1 modules support the section 'concordium-schema' where the schema includes the version.
// - For v0 modules this is always a v0 schema.
// - For v1 modules this can be a v1, v2, or v3 schema.
// - V0 modules additionally support section 'concordium-schema-v1' which always contain a v0 schema (not a typo).
// - V1 modules additionally support section 'concordium-schema-v2' which always contain a v1 schema (not a typo).
// The section 'concordium-schema' is the most common and is what the current tooling produces.
return ResultAsync.fromPromise(
WebAssembly.compile(source).then((module) => ({ module, version })),
errorString
);
})
.andThen(findSchema)
.andThen(({ module, version }) => findSchema(module, version))
.then(setResult);
}, [contract, rpc]);
return result;
Expand Down

0 comments on commit 5f0da43

Please sign in to comment.