Skip to content

feat(registry): ensure no version deployment is in progress when splitting a cloud engine + that the record was not changed - #11242

Open
pierugo-dfinity wants to merge 3 commits into
masterfrom
pierugo/subnet-splitting/engine-version-cannot-change
Open

feat(registry): ensure no version deployment is in progress when splitting a cloud engine + that the record was not changed#11242
pierugo-dfinity wants to merge 3 commits into
masterfrom
pierugo/subnet-splitting/engine-version-cannot-change

Conversation

@pierugo-dfinity

@pierugo-dfinity pierugo-dfinity commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Even though splitting cloud engines are not supported for now, this PR makes the registry additionally check that the StandardEngineReplicaVersionRecord hasn't changed during the time taken to generate fresh key material for the two new subnets during a split.
This is to avoid weird interactions where an upgrade would trigger at the same time as a subnet split.

It also adds unit tests for the other records that were previously checked.

Also, ensure that no version is in deployment when splitting a cloud engine, as the newly created engine could otherwise end up in a different replica version as the original engine.

@github-actions github-actions Bot added the feat label Aug 20, 2026
@pierugo-dfinity
pierugo-dfinity marked this pull request as ready for review August 21, 2026 06:56
@pierugo-dfinity
pierugo-dfinity requested a review from a team as a code owner August 21, 2026 06:56

@github-actions github-actions Bot left a comment

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.

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

@zeropath-ai

zeropath-ai Bot commented Aug 21, 2026

Copy link
Copy Markdown

No security or compliance issues detected. Reviewed everything up to 531cc43.

Security Overview
Detected Code Changes
Change Type Relevant files
Enhancement ► rs/registry/canister/src/mutations/do_split_subnet.rs
      Implement Cloud Engine split restriction logic and related error handling
► rs/registry/canister/src/mutations/do_update_standard_engine_replica_version.rs
      Expose get_standard_engine_replica_version_record as pub
Bug Fix ► rs/registry/canister/src/mutations/do_split_subnet.rs
      Add CloudEngineDeploymentInProgress error and guard conditions to prevent splits during deployment
Documentation ► rs/registry/canister/unreleased_changelog.md
      Describe new behavior for subnet splits during standard engine replica version deployment

@pierugo-dfinity
pierugo-dfinity dismissed github-actions[bot]’s stale review August 21, 2026 07:23
  1. Done.
  2. Nothing breaks.
  3. No migration needed.
  4. No security review needed.
@pierugo-dfinity
pierugo-dfinity requested a balanced review from Copilot August 21, 2026 07:23

Copilot AI left a comment

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.

Pull request overview

Adds concurrency checks around subnet splitting and expands guard tests.

Changes:

  • Guards the standard engine replica-version record during DKG generation.
  • Adds parameterized tests for all guarded records.
  • Documents the behavior change.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
rs/registry/canister/unreleased_changelog.md Records the new split failure condition.
rs/registry/canister/src/mutations/do_split_subnet.rs Adds the guard and related tests.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +388 to +390
// The replica version that the newly created subnet is going to run may be derived from
// this record, so it must not change under our feet either.
if record_changed_across_versions(make_standard_engine_replica_version_record_key()) {

@pierugo-dfinity pierugo-dfinity Aug 21, 2026

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.

Cloud engines are indeed not supported for the moment, but they could be in the future. This PR preemptively adds this check in case we forget to do so when enabling the feature for cloud engines.

It is true that it could abort a subnet split that was intended for regular subnets even though this record only affects cloud engines, but I would keep it as is for simplicity since this has quite a low probability of happening anyways (the async call should take about 10 seconds).

Something else came to mind though: 531cc43. Cloud engines shouldn't be split if the deployment of a new replica version is in progress as the new subnet could end up in a new version.

@pierugo-dfinity
pierugo-dfinity requested a balanced review from Copilot August 21, 2026 07:57
@pierugo-dfinity pierugo-dfinity changed the title feat(registry): ensure standard engine replica version is not changed during a subnet split feat(registry): ensure no version deployment is in progress when splitting a cloud engine + that the record was not changed Aug 21, 2026

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment on lines +294 to +296
if 0.0 < standard_engine_replica_version_record.deployment_progress
&& standard_engine_replica_version_record.deployment_progress < 1.0
{

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.

The probability of hitting a priority precisely equal to 0.0 is negligible (1/2^64), and I could imagine that a priority 0.0 could genuinely happen in practice to tell all cloud engines to stay on old_replica_version_id. So I think this is fine, but I leave the final decision to the code owners.

Comment on lines +294 to +295
if 0.0 < standard_engine_replica_version_record.deployment_progress
&& standard_engine_replica_version_record.deployment_progress < 1.0

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.

I would say that 0.0 indicates that a deployment is in progress. Only when it reaches 1.0 would I say it's complete. But even then, changing from 1.0 to < 1.0 is (currently) allowed... But maybe, we can disallow roll back once it reaches 1.0? That would be fine, because you can still roll back by doing

{
  new: previous
  old: current
  progress: ...
}

if current is already at 100%.

Anyway, this is moot if we go with my other suggestion.

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.

Changing from 1.0 to < 1.0 is not a problem because these would end up in different registry versions. We ensure in Consensus that while the subnet is getting split, it only reads at the registry version at which the registry is applying those mutations, not before, not later.

The problem is that even for a fixed registry version, two engines reading the same record can derive a different replica version. Only 0.0 or 1.0 ensure that both engines will derive the same version, though I have to say that since this is a continuous spectrum, only 1.0 is strictly valid since one of the engines could have a priority of exactly 0.0. I just wanted to relax the check 0.0 is expected to be used somewhat frequently, but I'm happy to change it to 1.0 only.

Comment on lines +287 to +293
// We want to reject a split if the source subnet is a cloud engine and a deployment of
// a new replica version is in progress. This is because the new destination subnet will
// have a new subnet ID which we do not know yet and could end up upgrading to a
// different version. We would like to avoid weird situations where both a split and an
// upgrade are scheduled at the same time, so we enforce that the cloud engine
// deployment is complete before allowing a split. In that case, it is guaranteed that
// both subnets will be on the same replica version after the split.

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.

This seems verbose.

Basically, we want upgrading a subnet and splitting it to be mutually exclusive, right?

In that case, what I'd suggest is that we just disallow splitting engines that have blank replica_version_id. Seems simpler, right?

What I like about my suggestion is that splitting one engine does NOT block upgrading all the others. That seems like a feature we really want to preserve.

Furthermore, what we can do here (to more conveniently fulfill "engines with blank replica_version_id cannot be split") is fill in the replica_version_id field, fix the field to whatever StandardEngineReplicaVersion is currently assigning the engine to. But this is just a convenience; you could instead force people to do a deploy_guestos to fix the replica_version_id manually.

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.

Seems simpler, right?

Simpler in code but definitely not simpler operationally, since you'd first need to set replica_version_id to the engine, then unset the field on both created engines -> 3 additional proposals + potential human error in the loop.

What I like about my suggestion is that splitting one engine does NOT block upgrading all the others.

The current implementation satisfies that too. It's the other way around: upgrading the others will block splitting an engine (which is acceptable).

fix the field to whatever StandardEngineReplicaVersion is currently assigning the engine to

Hmm, yes that could work, but you'd still need 2 proposals to unset them. That would make it asymmetric + it isn't natural to make an operation responsible for splitting a subnet also mutate that subnet's replica version.

}

#[cfg(test)]
mod tests {

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.

I have not reviewed changes past this line. Let me resolve this once I've done that.

Comment on lines +15 to +16
* A subnet-split request will now fail if a concurrent call modified the `StandardEngineReplicaVersionRecord`
while the fresh key material was being generated for the splitting subnet.

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.

Does this only apply to engines that have blank replica_version_id?

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.

No this applies to all subnets including engines setting their replica_version_id and regular subnets. This is suboptimal, but I kept it as is for simplicity.
See discussion here and feel free to suggest relaxing that check if you think it is worth the added complexity.

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.

3 participants