Skip to content

test: exercise the cycles changes of a DTS execution on resume - #11197

Draft
mraszyk wants to merge 1 commit into
masterfrom
mraszyk/dts-resume-cycles-test-coverage
Draft

test: exercise the cycles changes of a DTS execution on resume#11197
mraszyk wants to merge 1 commit into
masterfrom
mraszyk/dts-resume-cycles-test-coverage

Conversation

@mraszyk

@mraszyk mraszyk commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

dts_resume_succeeds_after_cycles_increase and
dts_install_code_resume_succeeds_after_cycles_increase assert that the cycles added to a canister while its execution is paused are preserved. That property holds because all cycles changes of a DTS execution are applied relative to the balance of the clean canister state: the Wasm execution reports a CyclesBalanceChange delta and the prepaid execution cycles are refunded relative as well. The long-running executions of the tests, however, did not change their own cycles balance at all, so only the refund half of that reasoning was covered.

Every long-running execution now performs a CyclesWorkout after it has been paused, i.e. while it is being resumed, so that the balance it reports is not merely the balance of the clean canister state minus the refunded prepaid execution cycles. Each context enables the operations it supports:

  • ic0.cycles_burn128 is available everywhere.
  • ic0.msg_cycles_accept128 only moves cycles if the call context has a non-zero balance, hence the new LongRunningCall::InterCanisterUpdate scenario, whose long-running update call is driven by an inter-canister call carrying cycles.
  • ic0.call_new, ic0.call_cycles_add128, and ic0.call_perform are unavailable in replicated queries, cleanup callbacks, and canister_init.
  • Growing the memory reserves cycles for the extra storage. A replicated query does not persist its execution state changes and hence does not reserve; canister_init does not reserve while it runs, so install_code reserves for the memory its module grew at the end.
  • ic0.mint_cycles128 is left out: it is only available to the cycles minting canister, and being that canister would make validate_cycle_change skip the validation of all the other operations.

The tests assert that each operation took effect with exactly the same amounts in both runs, which is what makes the final balances differ by exactly the added cycles. Their counterparts
dts_resume_fails_due_to_cycles_decrease and
dts_install_code_resume_fails_due_to_cycles_decrease assert that none of the operations took effect, since the cycles changes of a failed execution are dropped along with the rest of its state changes.

`dts_resume_succeeds_after_cycles_increase` and
`dts_install_code_resume_succeeds_after_cycles_increase` assert that the
cycles added to a canister while its execution is paused are preserved.
That property holds because all cycles changes of a DTS execution are
applied relative to the balance of the clean canister state: the Wasm
execution reports a `CyclesBalanceChange` delta and the prepaid execution
cycles are refunded relative as well. The long-running executions of the
tests, however, did not change their own cycles balance at all, so only
the refund half of that reasoning was covered.

Every long-running execution now performs a `CyclesWorkout` after it has
been paused, i.e. while it is being resumed, so that the balance it
reports is not merely the balance of the clean canister state minus the
refunded prepaid execution cycles. Each context enables the operations it
supports:

 * `ic0.cycles_burn128` is available everywhere.
 * `ic0.msg_cycles_accept128` only moves cycles if the call context has a
   non-zero balance, hence the new `LongRunningCall::InterCanisterUpdate`
   scenario, whose long-running update call is driven by an
   inter-canister call carrying cycles.
 * `ic0.call_new`, `ic0.call_cycles_add128`, and `ic0.call_perform` are
   unavailable in replicated queries, cleanup callbacks, and
   `canister_init`.
 * Growing the memory reserves cycles for the extra storage. A replicated
   query does not persist its execution state changes and hence does not
   reserve; `canister_init` does not reserve while it runs, so
   `install_code` reserves for the memory its module grew at the end.
 * `ic0.mint_cycles128` is left out: it is only available to the cycles
   minting canister, and being that canister would make
   `validate_cycle_change` skip the validation of all the other
   operations.

The tests assert that each operation took effect with exactly the same
amounts in both runs, which is what makes the final balances differ by
exactly the added cycles. Their counterparts
`dts_resume_fails_due_to_cycles_decrease` and
`dts_install_code_resume_fails_due_to_cycles_decrease` assert that none
of the operations took effect, since the cycles changes of a failed
execution are dropped along with the rest of its state changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the test label Aug 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant