I need to update the code in one of the canisters controlled by my SNS backend.
I have the management library setup, i just need to know how i include the wasm_module, arg and sender canister version…
public func updateManagerCanisterWasm() : async () {
let IC : Management.Management = actor (Environment.Default);
let updateResult = await (
IC.install_code(
{
mode = #upgrade(null);
canister_id = Principal.fromText("ljxqq-4iaaa-aaaal-qjd4a-cai");
wasm_module = wasm_module;
arg = Blob;
sender_canister_version = ?Nat64;
}),
);
};
The canister file is defined as an actor class and I’m not sure how I get it to be a wasm module for upgrade since I’ve only ever just created a new actor class as a canister and not upgraded one.
So the wasm isn’t created since the canister isn’t defined in dfx.json, it’s created dynamically by the backend.
I did have a look through the solution in that thread a few times, I’m surprise this would be the way, obviously it’s a fudge, surely there is a proper way to handle this core part of the workflow, updating dynamically created canisters?
I’m currently thinking the way to go is to create a new project for building dynamic canisters, add the actor class I want, build it using dfx.json then use David’s solution mentioned here.
I can see that it’s controlled by bboqb-jiaaa-aaaal-qb6ea-cai (OpenFPL Dapp Canister) that in turn is controlled by the SNS (which can be seen from the fact that its controller is the OpenFPL SNS Root canister).
To upgrade ljxqq-4iaaa-aaaal-qjd4a-cai, you should do the following:
Obtain a new WASM that you would like to upgrade your target canister to. This can be done by compiling the Motoko source code into a WASM module. To that end, either use dfx build (which requires a project file defined under dfx.json) or run moc directly, e.g.: $(dfx cache show)/moc main.mo
Since your target canister isn’t directly controlled by the DAO, you would need to take one of the following approaches:
A. Make the DAO directly control the target canister by adding SNS Root (gyito-zyaaa-aaaaq-aacpq-cai) as its controller. This most likely requires implementing some new (but rather simple) functionality for the current controller of your target, namely bboqb-jiaaa-aaaal-qb6ea-cai, making it call the API for changing canister’s settings (just once would be enough). This can be done by dispatching a timer via IC-CDK.
B. Extend the functionality of the current controller (bboqb-jiaaa-aaaal-qb6ea-cai) to enable it to upgrade your target canister. This seems like much more involved depending on design details.
Thanks for getting back to me, I’m fine with approach A, however building the canister with dfx cache show results in an error when referencing the mo:base libraries
Now if you have an SNS canister itself that is upgrading you have a couple different paths. If it it is an actor class you can use the system upgrade stuff in motoko:
Not obviously this only works if you have the actor referenced in your “parent” canister and you have upgraded that canister with the new code using the quill stuff above. And also you need to know the list of canisters…but if you have all of that you can set up a timer to loop through your list and upgrade one a round until they are all upgraded.
Ok so I am able to get a list of canisters from my main backend and my manager canister I would like to upgrade does have a reference to the backend canister.
Is is an actor class:
If you see from the project solution the actor class is referenced by the parent class as it uses it to create the canister. You can see the manager canister being created on line 1413 here:
If ManagerComposite is your parent and MangementCanister is your child then it should be as easy as looping through your
for(thisItem in uniqueManagerCanisterIds.vals()){
let oldManagement = actor(Principal.toText())
let newManagement = await (system ManagerCanister._ManagerCanister)(#upgrade oldManagement)();
}
That should upgrade all of them provided the list is complete.
Note: You MAY want to stop them all first and then start them after the upgrade depending on what kind of processes you have running on those canisters and if they make untrusted calls to other canisters or not. I think the general best practice is to stop them.