Skip to content

feat(root): New method: create_canister_and_install_code#9610

Open
daniel-wong-dfinity-org wants to merge 1 commit intomasterfrom
create_canister_and_install_code-root-daniel-wong
Open

feat(root): New method: create_canister_and_install_code#9610
daniel-wong-dfinity-org wants to merge 1 commit intomasterfrom
create_canister_and_install_code-root-daniel-wong

Conversation

@daniel-wong-dfinity-org
Copy link
Copy Markdown
Contributor

@daniel-wong-dfinity-org daniel-wong-dfinity-org commented Mar 26, 2026

Only callable by governance.

As usual, this does the "real work" of a new upcoming proposal type that creates a new canister in a non-NNS subnet (and install code into the new canister).

Prior Work

This new proposal type overlaps a bit with the existing NnsCanisterInstall proposal type. This differs in a couple of key ways:

  1. The created canister can live in other subnets.
  2. The created canister is NOT designated as an NNS canister (in Registry).

Behavior Details

This uses bounded wait so that NNS (Root and Governance canisters) does not get stuck as a result of an unresponsive subnet (either because it is malicious, or otherwise messed up).

The canister is created using cycles from the Root canister's balance. This is like how when SNS-WASM creates canisters, cycles are taken from its own balance. Keeping Root topped up is beyond the scope of this feature.

Testing

No tests yet. Those will be in a future PR. This is ok, because only Governance is allowed to call this new method, and no code path in Governance calls it yet.

References

Next PR 👉

@github-actions github-actions bot added the feat label Mar 26, 2026
@daniel-wong-dfinity-org daniel-wong-dfinity-org changed the title feat(root): Added create_canister_and_install_code method to NNS Root. feat(root): New method: create_canister_and_install_code Mar 26, 2026
// proposal gets executed. This is probably not ideal, but it is the
// same pattern that SNS-WASM uses when creating a Service Nervous Systems
// (see `this_canister_has_enough_cycles` in rs/nns/sns-wasm/src/sns_wasm.rs).
.with_cycles(STANDARD_CREATE_CANISTER_CYCLES)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the use case to create canisters in application subnets? If not, then this is not necessary? I don't think it would hurt, since I don't expect anyone to try having root subsidize the creation fee by risking 25 ICP.

Copy link
Copy Markdown
Contributor Author

@daniel-wong-dfinity-org daniel-wong-dfinity-org Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH, I'm not really sure which subnets people are hoping to target. Let me ask Björn about this...

In any case, AFAICT, it isn't "actually harmful" to give the canister some initial cycles when it doesn't need them. The only "harm" is that we have to keep Root topped up, but that can be automated very easily (with Cycle Ops), and the cost of the cycles themselves is negligible.

But if canister creation REQUIRES cycles, then, deleting this is harmful, because then, there is NO way to formulate a proposal (that does what the proposer wants). What's nice about this is that it maximizes the possibilities at a "small" cost.

Soap Box/Tangent

In general, I think when we add a feature, we should not limit it to only KNOWN use cases. So many times, people spec-ing out a new feature here have said,

Why would a user ever want to do THAT? Since we cannot imagine it, we conclude that there is no legitimate use for that, so let's explicitly block it.

but then a couple of months or so later, a user asks,

Hey, why are you blocking me from doing this?? WTF??

If a feature can easily be generalized, we should make it as capable as possible. It's not our job to prematurely limit what users do. We should only block an action when it is actually harmful (e.g. due to being very subtle).

And ofc, we shouldn't spend extra time (scope creep) on extending capabilities if there is no good reason to believe that they'll actually be used.

Back to Planet Earth: Add initial_cycles Field

I think what we can maybe do here is make cycles a parameter of the proposal. WDYT?

I would kind of like to make cycles field required, but ofc, UIs can always fill in that field without the user EXPLICITLY telling the UI what value to use. E.g.

type CreateCansterAndInstallCodeRequest = record {
  ...

  initial_cycles: opt nat64;
};

With this, we could reject initial_cycles: null. But then, UIs (like ic-admin) can always just do

let initial_cycles = flags
    .initial_cycles
    .unwrap_or_default(); // NOOOOO!!!
create_canister_and_install_code.initial_cycles = Some(initial_cycles);

to make things more convenient for the user. If a UI does something like that ☝️, my hope that the actual human operator explicitly indicated their desired value (for initial_cycles) is defeated.

Comment on lines +197 to +199
canister_settings : opt CanisterSettings;
wasm_module : blob;
install_arg : blob;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NCR. I would go for just "create_canister" and let other proposals take care of installing code and updating settings.

My reasoning:
(1) no partial failure - if the execution fails, we need to determine whether the canister was created in order to decide what to do.
(2) for the last 2 canisters in the NNS subnet, we went for "dummy wasm" initially: (canister skeleton for 135859, and empty wasm for 138487

Neither is a strong reason, so NCR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I like the simplicity of this idea. It definitely crossed my mind as I was working on this.

TBH, I can't think of a reason that install_canister MUST be included. It just seems like it would be pretty convenient.

Thanks for pointing out those two proposals. They definitely give some indication as to how often install_code would be desired IN ACTUAL PRACTICE.

Personally, it has always boggled my mind that create_canister and install_code are separate. (Meanwhile, upgrade and re-install are just "modes" of install_code, even though upgrade and re-install differ WILDLY in terms of their inherent destructiveness 🤷) I guess what I don't really understand is, "Why would anyone ever want a canister with no code? Isn't the whole point of a canister to DO shit?? With no code, a canister is not doing any actual work. All it is doing is existing...".

@daniel-wong-dfinity-org daniel-wong-dfinity-org marked this pull request as ready for review March 27, 2026 10:08
@daniel-wong-dfinity-org daniel-wong-dfinity-org requested a review from a team as a code owner March 27, 2026 10:08
Copy link
Copy Markdown
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pull request changes code owned by the Governance team. Therefore, make sure that
you have considered the following (for Governance-owned code):

  1. Update unreleased_changelog.md (if there are behavior changes, even if they are
    non-breaking).

  2. Are there BREAKING changes?

  3. Is a data migration needed?

  4. Security review?

How to Satisfy This Automatic Review

  1. Go to the bottom of the pull request page.

  2. Look for where it says this bot is requesting changes.

  3. Click the three dots to the right.

  4. Select "Dismiss review".

  5. In the text entry box, respond to each of the numbered items in the previous
    section, declare one of the following:

  • Done.

  • $REASON_WHY_NO_NEED. E.g. for unreleased_changelog.md, "No
    canister behavior changes.", or for item 2, "Existing APIs
    behave as before.".

Brief Guide to "Externally Visible" Changes

"Externally visible behavior change" is very often due to some NEW canister API.

Changes to EXISTING APIs are more likely to be "breaking".

If these changes are breaking, make sure that clients know how to migrate, how to
maintain their continuity of operations.

If your changes are behind a feature flag, then, do NOT add entrie(s) to
unreleased_changelog.md in this PR! But rather, add entrie(s) later, in the PR
that enables these changes in production.

Reference(s)

For a more comprehensive checklist, see here.

GOVERNANCE_CHECKLIST_REMINDER_DEDUP

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants