From 11f57882a228a1c0f98bf5ccdef216d2bbcb04aa Mon Sep 17 00:00:00 2001 From: David Dal Busco Date: Fri, 22 Nov 2024 08:50:43 +0100 Subject: [PATCH] feat: install code arguments inherited from Candid (#768) # Motivation The `install_code` arguments for the `mode` have grown in complexity as `Upgrade` now accepts parameters. Therefore, mapping the arguments those not makes that much sense anymore as we would have to declare variant within the types of the library as well. Therefore, this PR replaces the custom params types with the inherited Candid types. # Changes - Replace `InstallMode` with Candid `canister_install_mode` - Expose candid type - Remove mapper - Adapt code --------- Signed-off-by: David Dal Busco Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> --- CHANGELOG.md | 6 ++ packages/ic-management/README.md | 52 +++++++------- .../src/ic-management.canister.spec.ts | 69 +++++++++++++++---- .../src/ic-management.canister.ts | 17 ++--- packages/ic-management/src/index.ts | 1 + .../src/types/ic-management.params.ts | 24 +------ 6 files changed, 97 insertions(+), 72 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27bdf75d..6baa748c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 2024.xx.yy-hhmmZ + +# Breaking changes + +- Inherits canister installation code arguments from Candid. + # 2024.11.21-1600Z ## Overview diff --git a/packages/ic-management/README.md b/packages/ic-management/README.md index 6670b214..92fa8e07 100644 --- a/packages/ic-management/README.md +++ b/packages/ic-management/README.md @@ -54,7 +54,7 @@ const { status, memory_size, ...rest } = await canisterStatus(YOUR_CANISTER_ID); ### :factory: ICManagementCanister -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L39) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L38) #### Methods @@ -84,7 +84,7 @@ const { status, memory_size, ...rest } = await canisterStatus(YOUR_CANISTER_ID); | -------- | ---------------------------------------------------------------- | | `create` | `(options: ICManagementCanisterOptions) => ICManagementCanister` | -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L44) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L43) ##### :gear: createCanister @@ -94,7 +94,7 @@ Create a new canister | ---------------- | ------------------------------------------------------------------------------------- | | `createCanister` | `({ settings, senderCanisterVersion, }?: CreateCanisterParams) => Promise` | -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L84) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L83) ##### :gear: updateSettings @@ -104,17 +104,17 @@ Update canister settings | ---------------- | ------------------------------------------------------------------------------------------- | | `updateSettings` | `({ canisterId, senderCanisterVersion, settings, }: UpdateSettingsParams) => Promise` | -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L107) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L106) ##### :gear: installCode Install code to a canister -| Method | Type | -| ------------- | ----------------------------------------------------------------------------------------------------- | -| `installCode` | `({ mode, canisterId, wasmModule, arg, senderCanisterVersion, }: InstallCodeParams) => Promise` | +| Method | Type | +| ------------- | -------------------------------------------------------------------------------------------------- | +| `installCode` | `({ canisterId, wasmModule, senderCanisterVersion, ...rest }: InstallCodeParams) => Promise` | -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L132) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L131) ##### :gear: uploadChunk @@ -129,7 +129,7 @@ Parameters: - `params.canisterId`: The canister in which the chunks will be stored. - `params.chunk`: A chunk of Wasm module. -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L160) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L157) ##### :gear: clearChunkStore @@ -143,7 +143,7 @@ Parameters: - `params.canisterId`: The canister in which the chunks are stored. -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L180) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L177) ##### :gear: storedChunks @@ -157,15 +157,15 @@ Parameters: - `params.canisterId`: The canister in which the chunks are stored. -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L199) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L196) ##### :gear: installChunkedCode Installs code that had previously been uploaded in chunks. -| Method | Type | -| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `installChunkedCode` | `({ mode, arg, senderCanisterVersion, chunkHashesList, targetCanisterId, storeCanisterId, wasmModuleHash, }: InstallChunkedCodeParams) => Promise` | +| Method | Type | +| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | +| `installChunkedCode` | `({ senderCanisterVersion, chunkHashesList, targetCanisterId, storeCanisterId, wasmModuleHash, ...rest }: InstallChunkedCodeParams) => Promise` | Parameters: @@ -177,7 +177,7 @@ Parameters: - `params.storeCanisterId`: Specifies the canister in whose chunk storage the chunks are stored (this parameter defaults to target_canister if not specified). - `params.wasmModuleHash`: The Wasm module hash as hex string. Used to check that the SHA-256 hash of wasm_module is equal to the wasm_module_hash parameter and can calls install_code with parameters. -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L224) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L221) ##### :gear: uninstallCode @@ -187,7 +187,7 @@ Uninstall code from a canister | --------------- | -------------------------------------------------------------------------------- | | `uninstallCode` | `({ canisterId, senderCanisterVersion, }: UninstallCodeParams) => Promise` | -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L257) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L252) ##### :gear: startCanister @@ -197,7 +197,7 @@ Start a canister | --------------- | ------------------------------------------ | | `startCanister` | `(canisterId: Principal) => Promise` | -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L275) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L270) ##### :gear: stopCanister @@ -207,7 +207,7 @@ Stop a canister | -------------- | ------------------------------------------ | | `stopCanister` | `(canisterId: Principal) => Promise` | -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L287) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L282) ##### :gear: canisterStatus @@ -217,7 +217,7 @@ Get canister details (memory size, status, etc.) | ---------------- | ------------------------------------------------------------ | | `canisterStatus` | `(canisterId: Principal) => Promise` | -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L298) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L293) ##### :gear: deleteCanister @@ -227,7 +227,7 @@ Deletes a canister | ---------------- | ------------------------------------------ | | `deleteCanister` | `(canisterId: Principal) => Promise` | -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L312) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L307) ##### :gear: provisionalCreateCanisterWithCycles @@ -237,7 +237,7 @@ Creates a canister. Only available on development instances. | ------------------------------------- | ------------------------------------------------------------------------------------------------------- | | `provisionalCreateCanisterWithCycles` | `({ settings, amount, canisterId, }?: ProvisionalCreateCanisterWithCyclesParams) => Promise` | -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L327) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L322) ##### :gear: fetchCanisterLogs @@ -247,7 +247,7 @@ Given a canister ID as input, this method returns a vector of logs of that canis | ------------------- | ---------------------------------------------------------------- | | `fetchCanisterLogs` | `(canisterId: Principal) => Promise` | -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L350) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L345) ##### :gear: takeCanisterSnapshot @@ -265,7 +265,7 @@ Parameters: Can be provided as a `string` or a `Uint8Array`. If not provided, a new snapshot will be created. -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L376) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L371) ##### :gear: listCanisterSnapshots @@ -280,7 +280,7 @@ Parameters: - `params`: - Parameters for the listing operation. - `params.canisterId`: - The ID of the canister for which snapshots will be listed. -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L405) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L400) ##### :gear: loadCanisterSnapshot @@ -297,7 +297,7 @@ Parameters: - `params.snapshotId`: - The ID of the snapshot to load. - `params.senderCanisterVersion`: - The optional sender canister version. If provided, its value must be equal to ic0.canister_version. -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L431) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L426) ##### :gear: deleteCanisterSnapshot @@ -313,7 +313,7 @@ Parameters: - `params.canisterId`: - The ID of the canister for which the snapshot will be deleted. - `params.snapshotId`: - The ID of the snapshot to delete. -[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L462) +[:link: Source](https://github.com/dfinity/ic-js/tree/main/packages/ic-management/src/ic-management.canister.ts#L457) diff --git a/packages/ic-management/src/ic-management.canister.spec.ts b/packages/ic-management/src/ic-management.canister.spec.ts index c2995d57..9e7507bc 100644 --- a/packages/ic-management/src/ic-management.canister.spec.ts +++ b/packages/ic-management/src/ic-management.canister.spec.ts @@ -4,6 +4,7 @@ import { toNullable } from "@dfinity/utils"; import { mock } from "jest-mock-extended"; import type { _SERVICE as IcManagementService, + canister_install_mode, chunk_hash, list_canister_snapshots_result, take_canister_snapshot_result, @@ -21,10 +22,8 @@ import type { InstallCodeParams, } from "./types/ic-management.params"; import { - InstallMode, LogVisibility, UnsupportedLogVisibility, - toInstallMode, type ClearChunkStoreParams, type InstallChunkedCodeParams, type StoredChunksParams, @@ -37,6 +36,52 @@ import { decodeSnapshotId } from "./utils/ic-management.utils"; describe("ICManagementCanister", () => { const mockAgent: HttpAgent = mock(); + const mockInstallCodeModes: canister_install_mode[] = [ + { install: null }, + { reinstall: null }, + { upgrade: [] }, + { + upgrade: [ + { + wasm_memory_persistence: [], + skip_pre_upgrade: [], + }, + ], + }, + { + upgrade: [ + { + wasm_memory_persistence: [{ keep: null }], + skip_pre_upgrade: [], + }, + ], + }, + { + upgrade: [ + { + wasm_memory_persistence: [{ replace: null }], + skip_pre_upgrade: [], + }, + ], + }, + { + upgrade: [ + { + wasm_memory_persistence: [], + skip_pre_upgrade: [true], + }, + ], + }, + { + upgrade: [ + { + wasm_memory_persistence: [{ replace: null }], + skip_pre_upgrade: [false], + }, + ], + }, + ]; + const createICManagement = async (service: IcManagementService) => { return ICManagementCanister.create({ agent: mockAgent, @@ -210,7 +255,7 @@ describe("ICManagementCanister", () => { }); describe("installCode", () => { - it.each([InstallMode.Install, InstallMode.Reinstall, InstallMode.Upgrade])( + it.each(mockInstallCodeModes)( "calls install_code with mode %s", async (mode) => { const params: InstallCodeParams = { @@ -228,7 +273,7 @@ describe("ICManagementCanister", () => { expect(service.install_code).toHaveBeenCalledWith({ wasm_module: params.wasmModule, - mode: toInstallMode(params.mode), + mode: params.mode, canister_id: params.canisterId, arg: params.arg, sender_canister_version: [], @@ -239,7 +284,7 @@ describe("ICManagementCanister", () => { it("throws Error", async () => { const params: InstallCodeParams = { wasmModule: new Uint8Array([1, 2, 3]), - mode: InstallMode.Install, + mode: { install: null }, arg: new Uint8Array(), canisterId: mockCanisterId, }; @@ -581,7 +626,7 @@ describe("ICManagementCanister", () => { chunkHashesList: [{ hash: [1, 2, 3] }, { hash: [4, 5, 6] }], }; - it.each([InstallMode.Install, InstallMode.Reinstall, InstallMode.Upgrade])( + it.each(mockInstallCodeModes)( "calls install_chunked_code with mode %s", async (mode) => { const params: InstallChunkedCodeParams = { @@ -598,7 +643,7 @@ describe("ICManagementCanister", () => { expect(service.install_chunked_code).toHaveBeenCalledWith({ wasm_module_hash: params.wasmModuleHash, - mode: toInstallMode(params.mode), + mode: params.mode, target_canister: params.targetCanisterId, store_canister: toNullable(), arg: params.arg, @@ -611,7 +656,7 @@ describe("ICManagementCanister", () => { it("should accept sha256 as hex string parameter", async () => { const params: InstallChunkedCodeParams = { ...installParams, - mode: InstallMode.Upgrade, + mode: { upgrade: [] }, wasmModuleHash: sha256HashHex, }; const service = mock(); @@ -623,7 +668,7 @@ describe("ICManagementCanister", () => { expect(service.install_chunked_code).toHaveBeenCalledWith({ wasm_module_hash: sha256HashUint8Array, - mode: toInstallMode(params.mode), + mode: params.mode, target_canister: params.targetCanisterId, store_canister: toNullable(), arg: params.arg, @@ -635,7 +680,7 @@ describe("ICManagementCanister", () => { it("should optionally target a particular store canister", async () => { const params: InstallChunkedCodeParams = { ...installParams, - mode: InstallMode.Upgrade, + mode: { upgrade: [] }, wasmModuleHash: sha256HashHex, storeCanisterId: mockCanisterId, }; @@ -648,7 +693,7 @@ describe("ICManagementCanister", () => { expect(service.install_chunked_code).toHaveBeenCalledWith({ wasm_module_hash: sha256HashUint8Array, - mode: toInstallMode(params.mode), + mode: { upgrade: [] }, target_canister: params.targetCanisterId, store_canister: toNullable(mockCanisterId), arg: params.arg, @@ -660,7 +705,7 @@ describe("ICManagementCanister", () => { it("throws Error", async () => { const params: InstallChunkedCodeParams = { ...installParams, - mode: InstallMode.Install, + mode: { install: null }, wasmModuleHash: sha256HashUint8Array, }; const error = new Error("Test"); diff --git a/packages/ic-management/src/ic-management.canister.ts b/packages/ic-management/src/ic-management.canister.ts index aa974752..5dfc3cdd 100644 --- a/packages/ic-management/src/ic-management.canister.ts +++ b/packages/ic-management/src/ic-management.canister.ts @@ -18,7 +18,6 @@ import { idlFactory } from "../candid/ic-management.idl"; import type { ICManagementCanisterOptions } from "./types/canister.options"; import { toCanisterSettings, - toInstallMode, type ClearChunkStoreParams, type CreateCanisterParams, type InstallChunkedCodeParams, @@ -122,7 +121,7 @@ export class ICManagementCanister { * Install code to a canister * * @param {Object} params - * @param {InstallMode} params.mode + * @param {canister_install_mode} params.mode * @param {Principal} params.canisterId * @param {Uint8Array} params.wasmModule * @param {Uint8Array} params.arg @@ -130,19 +129,17 @@ export class ICManagementCanister { * @returns {Promise} */ installCode = ({ - mode, canisterId, wasmModule, - arg, senderCanisterVersion, + ...rest }: InstallCodeParams): Promise => { const { install_code } = this.service; return install_code({ - mode: toInstallMode(mode), + ...rest, canister_id: canisterId, wasm_module: wasmModule, - arg, sender_canister_version: toNullable(senderCanisterVersion), }); }; @@ -212,7 +209,7 @@ export class ICManagementCanister { * @link https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-install_chunked_code * * @param {InstallChunkedCodeParams} params - * @param {InstallMode} params.mode Installation, re-installation or upgrade. + * @param {canister_install_mode} params.mode Installation, re-installation or upgrade. * @param {Uint8Array} params.arg The arguments of the canister. * @param {Uint8Array | undefined} params.senderCanisterVersion The optional sender_canister_version parameter can contain the caller's canister version. * @param {Array} params.chunkHashesList The list of chunks of the Wasm module to install. @@ -222,21 +219,19 @@ export class ICManagementCanister { * @returns {Promise} */ installChunkedCode = async ({ - mode, - arg, senderCanisterVersion, chunkHashesList, targetCanisterId, storeCanisterId, wasmModuleHash, + ...rest }: InstallChunkedCodeParams): Promise => { const { install_chunked_code } = this.service; await install_chunked_code({ - mode: toInstallMode(mode), + ...rest, target_canister: targetCanisterId, store_canister: toNullable(storeCanisterId), - arg, sender_canister_version: toNullable(senderCanisterVersion), chunk_hashes_list: chunkHashesList, wasm_module_hash: diff --git a/packages/ic-management/src/index.ts b/packages/ic-management/src/index.ts index 8980d299..4a6b5dec 100644 --- a/packages/ic-management/src/index.ts +++ b/packages/ic-management/src/index.ts @@ -1,4 +1,5 @@ export type { + canister_install_mode, canister_log_record, canister_status_result, chunk_hash, diff --git a/packages/ic-management/src/types/ic-management.params.ts b/packages/ic-management/src/types/ic-management.params.ts index cf5726f3..20b61688 100644 --- a/packages/ic-management/src/types/ic-management.params.ts +++ b/packages/ic-management/src/types/ic-management.params.ts @@ -67,30 +67,8 @@ export interface UpdateSettingsParams { settings: CanisterSettings; } -export enum InstallMode { - Install, - Reinstall, - Upgrade, -} - -export const toInstallMode = ( - installMode: InstallMode, -): canister_install_mode => { - switch (installMode) { - case InstallMode.Install: - return { install: null }; - case InstallMode.Reinstall: - return { reinstall: null }; - case InstallMode.Upgrade: - // TODO: Support Upgrade mode skipping pre-upgrade and wasm_memory_persistence - // `upgrade` can also have `[{ skip_pre_upgrade: [] | [boolean] }]` - // or wasm_memory_persistence : opt variant { keep; replace; }; - return { upgrade: [] }; - } -}; - export interface InstallCodeParams { - mode: InstallMode; + mode: canister_install_mode; canisterId: Principal; wasmModule: Uint8Array; arg: Uint8Array;