Skip to content

fix(control-panel): consume deploy quota before spending cycles - #652

Draft
MRmarioruci wants to merge 1 commit into
mainfrom
fix/consume-deploy-quota-before-spend
Draft

fix(control-panel): consume deploy quota before spending cycles#652
MRmarioruci wants to merge 1 commit into
mainfrom
fix/consume-deploy-quota-before-spend

Conversation

@MRmarioruci

@MRmarioruci MRmarioruci commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Change

deploy_station checks the per-user quota (user.can_deploy_station()) and the controller checks the global quota before any work happens, but both counters are advanced only inside add_deployed_station, which runs on the fully successful path.

Creating and funding the station happens in between and is irreversible. A deployment that fails after those calls has spent cycles while leaving both counters untouched, so the check that gates the next attempt sees no change.

The quota is now charged immediately before the first irreversible spend. Recording the station id and registering it with the fund manager stay on the success path, where the canister id exists. Failures before the charge point — unknown user, uninitialised config, quota exceeded — still consume nothing.

admins is also validated up front. Station init requires at least one user, so an empty list cannot succeed, and checking it before any spend costs nothing.

Tests

  • consume_deploy_quota_charges_the_user_without_recording_a_station — exhausting the per-user quota yields QuotaExceeded and no station is recorded, confirming the charge is independent of success.
  • consume_deploy_quota_advances_the_global_limiter.

cargo test -p control-panel --lib passes (209). Clippy and cargo fmt clean.

Note

This changes observable behaviour: a deployment that fails after canister creation now consumes a day's quota. That is deliberate, since the cycles were spent regardless, but it means a user hitting a genuine infrastructure error loses quota. Releasing the charge on failure cannot distinguish a no-spend failure from a post-spend one once the creation call has returned.

deploy_station checked the per-user and global rate limiters before doing
any work, but only advanced them inside add_deployed_station, which runs
on the fully successful path. Creating and funding the station happens
well before that and is irreversible, so a deployment that failed after
those steps had already spent real cycles while leaving both counters
untouched. The pre-flight check therefore always passed and the spend was
unbounded.

The failure was also trivially forced rather than incidental: station init
rejects an empty user list, so passing no admins fails deterministically
after the station has been created and funded.

Charge the quota immediately before the first irreversible spend, and
reject an empty admin list up front so that path costs nothing at all.
Recording the station and registering it for monitoring stay on the
success path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant