Is there a way to programmatically retrieve the wasm module of a canister?

I’d like to program a canister (let’s call it canister A) to be able to retrieve the wasm module of another canister (canister B) so that canister A can use the wasm module from canister B to upgrade a third canister (canister C). Is this possible to do?

For context, I’m building a dapp that is designed to be such that ownership of the dapp is easily transferable without the need for technical expertise. To achieve this, i coded the dapp so that it’s backend canister is the controller of: 1.) itself, 2.) the front end canister and 3.) a third “manager” canister that exists only to deliver upgrades to the backend canister since a canister cannot upgrade itself (the manager canister is the only other controller of the backend canister and the manager canister is only controlled by the backend canister and itself).

for each instance of the dapp, a utility NFT is minted. The dapp is programmed to be able to execute updates to its canister settings upon itself but only when called by the principal that is the owner of the corresponding NFT- thus granting the NFT owner sole influence over the dapp’s canister settings.

Eventually, i want to create a DAO that will, among other things, serve as a master copy that the many instances of the dapp will reference when they upgrade themselves. Because the dapps will need to upgrade themselves using the wasm module of the master copy, i need a way for the separate instances of the dapp to be able to retrieve that wasm module programmatically.

Currently, the only method I’ve come up with for programmatically installing a wasm file to a canister is to store the wasm module as a blob in the stable memory of a canister somewhere and call the canister to retrieve the wasm blob that’s stored. This method is not ideal since it requires a trusted party to upload the wasm to the canister where it’s stored and there’s no way for others to verify that the wasm module uploaded to the stable memory is the proper module that corresponds to the code that’s promised.

2 Likes

There’s currently no official way to retrieve a canister’s wasm. A few weeks ago there was some discussion about adding a setting to canisters to have their wasm downloaded, but I can’t find it anymore.

I see two main workarounds:

  1. what you already described, manually uploading the wasm to stable memory. Has all the drawbacks you described, but it is possible to verify that the wasm matches by installing the wasm and comparing module hashes. If you expose the wasm publicly, anyone can do that.
  2. probably not suited for your use case: Use canister metadata to point to how the wasm can be obtained, again verified by comparing module hashes. See this thread for more info on that approach: [RFC] Canister Metadata Standard

Is there any security reasons why this feature can’t be added to the canisters’ functionality? Or is it just a matter of building it out?

Building a way for canisters to retrieve the wasm code of other canisters would make it easy for devs to deliver code changes to canisters that they don’t control (with permission of the canister controller, of course). That’s a feature that’s necessary in order for non-technical canister owners to be able to own dapps where they decide what code they choose to install to their dapps and it’s very much worth pursuing.

IIRC under the assumption of allowing this on an opt-in basis, nobody had any real security concerns. I think it’s just a matter of prioritisation. @dsarlis is most likely to be in the know.

1 Like

@dsarlis, are there current plans to have this feature implemented anytime soon? And if so, how soon?

It’s a crucial feature for my dapp which could be ready to release as soon as April. If this feature is not high priority, how can i get this feature moved up on the priority list?

1 Like

I don’t have anything against this feature, but I still don’t really see why you are dependent on this. For example, you can have a blackholed canister where you can upload wasm modules, but only the holder of the utility NFT can trigger the installation/upgrade.

1 Like

@Jesse @Severin I think there might be a misunderstanding here. What we’ve talked about is a way to retrieve the hash of the wasm of a canister even when you’re not the controller (essentially making the result of a canister_status call public). This is not the same as retrieving the actual wasm module which I understand Jesse wants. I am not aware of anyone working on exposing this or remember any discussion around it (if you find a relevant link, please share it).

Fwiw, I’m also not opposed to having this ability, especially if it’s opt in, but I also wouldn’t say it would be a big priority given other high priority projects we’re working on and what we have lined up for the next few months. There are ways you can get the wasm module if you want, both Severin and Dominic I think gave you some ideas and you could achieve verification of the wasm module even by third parties with the suggested approaches.

Are you sure? The module hash has always been public. dfx canister info has shown that since forever

dfx canister info works by retrieving this information through the state tree, see relevant section in the interface spec. This is fine as long as you’re ok retrieving this information “off-chain” but people have been asking for a way to retrieve this “on-chain”, i.e. from canisters through the management call canister_status. This is currently private in the sense that only controllers of the canister can access it, not anyone. Here’s a relevant discussion about this.

@domwoe @dsarlis @Severin

When i made the original post, i didn’t realize that you could verify the module hash as y’all have described. But even with that possibility, now the issue with the approach of storing the wasm in stable memory, is that:

1.) it requires a whole other canister to be built and

2.) in order to verify the wasm hash, it requires me to install the code first, then verify the hash. If any bad actor plants malware in the wasm module, that won’t be caught until after the wasm module as been installed to a canister. I guess the solution to that problem would be a dummy canister that’s used to install the wasm and retrieve the hash, but at that point, it’s getting more convoluted than it needs to be.

It’d be a lot cleaner if it were possible to retrieve the wasm module from a canister directly. That way, I’d be able to just have other instances of the dapp retrieve the code from the master copy which has already undergone a round of consensus.

And I’d hate to do all the work to implement the approach you all suggested, only to have to undo it once the ability to directly retrieve a canister’s wasm module becomes available.

Is there anyway i could petition to have this feature moved up in priority on the DFINITY foundations rode map?

To support my case for this being worthy of prioritizing, I want to mention that this feature would be a clean solution to the last engineering challenge that i have with respect to creating a dapp that is replicable, transferable & mutable while simultaneously requiring zero technical skills for a user to be able to own the dapp, transfer ownership of the dapp or upgrade the code. @dominicwilliams recently mentioned the concept of such a dapp in his recent Tweet . I don’t know if he realized how close this sort of dapp is to being implemented on the IC.

I also want to mention that i intend to adopt CigDao (@cryptoisgood) as the DAO infrastructure that hosts the Master copy. Having the feature I’m requesting would not only contribute directly to the success of my project, but also to the success of CigDao as well since it’d enable me to adopte/utilize their technology.

If it’s not feasible to have this feature moved up in priority by the DFINITY team, I’m willing to write the code myself and submit a proposal, but I’d need lots of correspondence as I don’t even know where to start and it’d be my very first proposal so I’m sure I’d have a bunch of rookie questions for you all. Again, I’m willing to do this if the DFINITY foundation is unable to prioritize & implement this feature anytime soon. Soon being some time within the next 3-5 months.

1 Like

Hey @Jesse,

feel free to start a discussion about your proposal in a dedicated thread to make sure that there’s enough deliberation and community traction.

Said that I still think this feature (as far as I understand it) is neither necessary nor sufficient for your use case. I’d be happy to jump on a call next week to talk about it.

2 Likes

I’ll take some time to write up a post on it. And I’d love to hop on a call next week. How do you prefer we set that up?

You can compute the hash of the wasm blob in canister code before you deploy it.

Regarding your general application, it sounds like you want a way to ship wasm modules on chain. So why not make a canister whose purpose it to store wasm modules and deliver them to anyone who wants them? You can upload a wasm module, the canister computes its hash and stores it under the hash as a key. Now anyone can call and request the module for a given module hash. This is independent from what is installed on chain, so the store can even hold modules that aren’t installed anywhere. And if you want to clone a canister that is installed already then you get the canister’s module hash through the system and then ask this canister for the module blob. So the “opt-in” step for a canister controller to activate sharing of his wasm module would be to upload it to this store.

This works for modules that are <2 MB. For larger ones, it would require pagination.

The feature you describe would become more interesting if you turn it into cloning of canisters without even sharing the wasm module with anyone. That means, say a canister controller has opted-in to cloning. Then anyone could call the system and ask to deploy a clone of that canister and would get the same wasm module installed without actually getting to see the wasm module. That adds something new that isn’t possible by other means today. But IMO when it gets really exciting is when you can clone a canister with state.

4 Likes

GitHub - aviate-labs/crypto.mo: Crypto Package for Motoko will do this for you in motoko…you will just need to read in the bytes for your chunks.

1 Like

There’s a discussion happening about this here:

1 Like