feat: new canister settings minimum_msg_cycles_available#10398
feat: new canister settings minimum_msg_cycles_available#10398mraszyk wants to merge 15 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds a new canister setting, minimum_msg_cycles_available, to enforce a minimum attached-cycles threshold on incoming inter-canister requests (ingress unaffected), and wires it through the management canister types, replica execution, and checkpoint persistence.
Changes:
- Extends management canister Candid/Rust types and builders to include
minimum_msg_cycles_available. - Enforces the minimum in replicated execution for incoming inter-canister
Requests, rejecting and refunding when insufficient cycles are attached. - Persists the setting in canister state (checkpoint/protobuf) and adds execution environment tests covering status/defaulting and admission behavior.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| rs/types/management_canister_types/tests/ic.did | Adds the setting to canister_settings / definite_canister_settings DID test definitions. |
| rs/types/management_canister_types/src/lib.rs | Adds field + builder/getter plumbing for minimum_msg_cycles_available in management types. |
| rs/state_manager/src/tip.rs | Serializes minimum_msg_cycles_available into checkpoint canister state bits. |
| rs/state_manager/src/checkpoint.rs | Loads minimum_msg_cycles_available from checkpoint into system state. |
| rs/state_layout/src/state_layout.rs | Adds minimum_msg_cycles_available to CanisterStateBits. |
| rs/state_layout/src/state_layout/proto.rs | Adds protobuf (de)serialization for the new state bit (with backward-compatible default). |
| rs/state_layout/src/state_layout/tests.rs | Updates default CanisterStateBits used in tests to include the new field. |
| rs/replicated_state/src/canister_state/system_state.rs | Adds minimum_msg_cycles_available to SystemState and initializes it to zero. |
| rs/execution_environment/src/canister_settings.rs | Parses/validates the new setting from CanisterSettingsArgs and adds an out-of-range error. |
| rs/execution_environment/src/canister_manager.rs | Applies setting on update; exposes it via canister_status output. |
| rs/execution_environment/src/execution_environment.rs | Enforces minimum cycles for incoming inter-canister requests (reject + refund). |
| rs/execution_environment/tests/canister_settings.rs | Adds range validation and behavioral tests for the setting (status, ingress unaffected, accept/reject, DTS slicing). |
| rs/protobuf/def/state/canister_state_bits/v1/canister_state_bits.proto | Adds protobuf field minimum_msg_cycles_available = 68. |
| rs/protobuf/src/gen/state/state.canister_state_bits.v1.rs | Regenerates protobuf Rust bindings for the new field. |
| rs/replica_tests/tests/canister_lifecycle.rs | Updates canister status expectations to include the new setting value. |
| rs/cycles_account_manager/src/cycles_account_manager.rs | Bumps max payload size constant due to Candid arg size increase. |
| rs/pocket_ic_server/src/pocket_ic.rs | Extends CanisterSettingsArgs literals to include the new field. |
| rs/nervous_system/clients/src/update_settings.rs | Extends CanisterSettingsArgs conversion to include the new field (set to None). |
| packages/ic-management-canister-types/tests/ic.did | Updates public package DID test definitions with the new setting. |
| packages/ic-management-canister-types/src/lib.rs | Documents and adds minimum_msg_cycles_available to the public types crate. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
This pull request changes code owned by the Governance team. Therefore, make sure that
you have considered the following (for Governance-owned code):
-
Update
unreleased_changelog.md(if there are behavior changes, even if they are
non-breaking). -
Are there BREAKING changes?
-
Is a data migration needed?
-
Security review?
How to Satisfy This Automatic Review
-
Go to the bottom of the pull request page.
-
Look for where it says this bot is requesting changes.
-
Click the three dots to the right.
-
Select "Dismiss review".
-
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
No canister behavior changes.
alin-at-dfinity
left a comment
There was a problem hiding this comment.
Dropping this one comment early. In case you agree with it, it will require a lot of renaming and it's probably best to get it out of the way.
| pub environment_variables: Option<Vec<EnvironmentVariable>>, | ||
| /// Indicates the minimum number of cycles required for an incoming message | ||
| /// from another canister. Messages with fewer cycles are rejected with a | ||
| /// `CanisterError`. Ingress messages are not affected. |
There was a problem hiding this comment.
Ingress messages are not affected.
I was thinking this kind of defeats the purpose. Took me a while to realize that there's [whatever the single-replica ingress message filtering mechanism is called]. Maybe mention that, just in case someone is looking at the implementation, trying to figure out how to deal with call spam.
| /// | ||
| /// Default value: `0` (i.e., no minimum enforced). | ||
| pub minimum_msg_cycles_available: Option<Nat>, | ||
| } |
There was a problem hiding this comment.
When I first read the name I thought this was some sort of freezing threshold for cycles reserved for outgoing calls. Maybe we should call it something like "minimum [call] payment"? Or, if you think "pauyment" is only used in the implementation, not the spec, and is thus potentially confusing, then "attached cycles"?
"Available" sounds too much like "balance" or "reservation".
There was a problem hiding this comment.
The motivation for this name was the system API ic0.msg_cycles_available which returns how many cycles have been transferred by the caller (and not yet accepted by the callee) so the new setting is a lower bound for the value of that system API at the very beginning of the call.
But I see your confusion: how does minimum_incoming_call_cycles or minimum_canister_call_cycles sound? (Focus on either incoming/outgoing and ingress/inter-canister, respectively, the combined minimum_incoming_canister_call_cycles is the most precise, but pretty long.)
There was a problem hiding this comment.
minimum_canister_call_cycles sounds more obvious.
I understand now where it comes from, but I suppose msg_cycles_available is both somewhat more specific and somewhat unfortunate too. (o:
alin-at-dfinity
left a comment
There was a problem hiding this comment.
Only one more nitpick, otherwise LGTM.
| wasm_memory_limit: candid::Nat, | ||
| wasm_memory_threshold: candid::Nat, | ||
| environment_variables: Vec<EnvironmentVariable>, | ||
| minimum_msg_cycles_available: candid::Nat, |
There was a problem hiding this comment.
Personal opinion: I would put this somewhere next to the other fields that have to do with cycles, rather than tack it onto the end. Same with SystemState / CanisterStateBits / CanisterStateBits proto.
This PR introduces a new canister setting
minimum_msg_cycles_availablespecifying the minimum amount of cycles that must be available as transferred cycles in an incoming inter-canister call (i.e., ignoring ingress messages).