I have got a manager canister that creates user canisters. These user are actor that takes a principal as argument.
actor class UserBucket(owner: Principal) = this {
...
So far, so good.
Now, through the manager I am trying to implement a function that can update the code of these user canisters.
public func installCode(canisterId: Principal, owner: Principal, wasmModule: Blob): async() {
await IC.install_code({
arg = Blob.toArray(Principal.toBlob(owner));
wasm_module = wasmModule;
mode = #upgrade;
canister_id = canisterId;
});
};
After double checking that all parameters are effectively correctly set I am facing following error when I try to update the code:
Canister a3ukg-3yaaa-aaaai-aa6ta-cai trapped explicitly: IDL error: missing magic bytes
If I get it correctly, it means that my arg
, the owner principal currently converted to [Nat8]
, is not correctly encoded as valid Candid arguments.
Do I get it right?
How do I encode the principal as valid candid arguments?
1 Like
Mmmh not sure to understand how is it related? The actor class works fine, I try to upgrade the WASM code of existing canisters that have been generated on the fly. I try to use the install_code feature (as in the motoko playground).
Ah, so the wasm module is not generated from the actor class? In that case, maybe you can pass arg as an argument as well, and use didc
to encode the principal to a candid blob.
yeah I think it’s what I need but I don’t know how?
how to “encode a principal to a candid blob”?
From CLI, you can run didc encode '(principal "aaaaa-aa")' -f blob
1 Like
I am writing a script in JavaScript (sorry should have had mentioned that earlier) and the backend is in Motoko.
Found something in the playground and candid, so trying the following:
import { IDL } from "@dfinity/candid";
const arg = IDL.encode([IDL.Principal], owner);
but I get an error
Cannot mix BigInt and other types, use explicit conversions
owner
is a principal
console.log(JSON.stringify(owner))
// {"_arr":{"0":154,"1":1 .... "28":2},"_isPrincipal":true}
1 Like
The second argument is an array as well, [owner]
1 Like
Nice
const arg = IDL.encode([IDL.Principal], [owner]);
// -> Uint8Array(38) [68, 73, 68, 76....65, 2]
Now I should check how I can send it to my canister. I used a Blob
but it does not seem happy with it.
Shit, I think it may have worked out!!!
My manager access point
public shared({ caller }) func installCode(canisterId: Principal, owner: Blob, wasmModule: Blob): async() {
await canisterUtils.installCode(canisterId, owner, wasmModule);
};
My utils
public func installCode(canisterId: Principal, owner: Blob, wasmModule: Blob): async() {
await ic.install_code({
arg = owner;
wasm_module = wasmModule;
mode = #upgrade;
canister_id = canisterId;
});
};
The js call
const arg = IDL.encode([IDL.Principal], [owner]);
await actor.installCode(bucketId, [...arg], [...new Uint8Array(buffer)]);
3 Likes
Gosh it indeed works out!
I just added a “hello world” function in the WASM and used above function to update the user canister code ic.rocks now displays the new function
Thanks for the help @chenyan
2 Likes