Skip to content

Add a KeyManager canister macro (Rust) and mixin (Motoko) #422

Open

Description

@marc0olo

Motivation

EncryptedMaps has a canister macro (export_encrypted_maps_canister!, Rust) and mixin (EncryptedMapsCanister, Motoko) that generate a complete, correct canister interface from a few lines. The KeyManager has no equivalent — adopters (and our own reference canisters) hand-write the actor/module wiring, which is error-prone.

That risk is not hypothetical. #421 fixed two upgrade-safety bugs that existed purely because the KeyManager reference canisters were hand-written:

  • Rust (ic_vetkeys_manager_canister): no #[post_upgrade] → after an upgrade the state wrapper stayed None and every endpoint trapped.
  • Motoko (ic_vetkeys_manager_canister): the state field was transient → enhanced orthogonal persistence wiped it on upgrade.

A macro/mixin makes this class of mistake impossible for adopters, the same way it already does for EncryptedMaps.

Scope

  • Rust: an export_key_manager_canister! macro that generates #[init] + #[post_upgrade] and every #[query]/#[update] endpoint, taking the Memory instances from the caller (mirroring export_encrypted_maps_canister!).
  • Motoko: a KeyManagerCanister mixin (mo:ic-vetkeys/key_manager/Canister) with the persisted let state + transient wrapper, include-able into a persistent actor.
  • Dogfood both in the reference canisters (backend/{rs,mo}/canisters/ic_vetkeys_manager_canister), replacing the hand-written wiring.
  • Prove the generated Candid is byte-identical to today's. Not via the
    interface-sync guard, which cannot do this — see the correction below.

Order: Motoko first, Rust follows #447

The two halves are gated on different things, and only the Rust one is blocked.

Notes

  • No frontend release required: the generated Candid must match the current ic_vetkeys_manager_canister.did exactly, so @icp-sdk/vetkeys and its committed declarations are unaffected.
  • Correction — the interface-sync guard cannot enforce that for the Motoko half. frontend/ic_vetkeys/make_did_bindings.sh regenerates the TS declarations from .did files under backend/rs/canisters/ only, and no Motoko canister commits a .did at all. The guard therefore proves frontend ↔ Rust; nothing compares the Motoko canister's interface to anything. Motoko/Rust agreement is enforced behaviourally, by the shared integration suite running against the compiled Motoko wasm (backend/mo/canisters/*/Makefile:13, via CUSTOM_WASM_PATH). So the Motoko half of this issue needs those behavioural tests, not the interface guard.
  • That gap is filed as CI: the committed .did files are never checked against the canisters they describe #445, and is an argument for Motoko: define EncryptedMapsCanister in terms of includable parts, so an adopter can own one endpoint #443's ask 4 (ship the canonical Candid as a package artifact): one committed artifact would let the Rust canister, the Motoko canister and adopters all diff against the same thing.
  • Backend releases would carry it: a new ic-vetkeys Rust crate + Motoko mops version (as 0.8.0 / 0.6.0 did for EncryptedMaps).

Follow-up to #421. Companion to the original EncryptedMaps macro/mixin work in #402.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions