fix: Insert HTTP outcalls pay-as-you-go refunds into the refund pool - #11045
Open
eichhorl wants to merge 3 commits into
Open
fix: Insert HTTP outcalls pay-as-you-go refunds into the refund pool#11045eichhorl wants to merge 3 commits into
eichhorl wants to merge 3 commits into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR changes how pay-as-you-go HTTP outcall refunds are handled so they can be delivered even if the calling canister migrates to a different subnet during a subnet split. Instead of directly crediting canister balances when spend reports (or delivered-context timeouts) are processed, refunds are inserted into the subnet-wide refund pool for Message Routing to deliver to the correct host subnet.
Changes:
- Update HTTP outcall spend-report accounting to pool refunds via
ReplicatedState::add_refund()instead of directly crediting canister balances. - Promote refund-pooling to a public
ReplicatedStatemethod (and remove the test-only trait hook). - Update tests and documentation/comments to reflect pooled refund semantics.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| rs/types/types/src/messages/inter_canister.rs | Clarifies Refund message documentation to cover refunds that occur outside of responses (including HTTP outcalls). |
| rs/state_manager/src/split/tests.rs | Cleans up imports after add_refund becomes an inherent ReplicatedState method. |
| rs/replicated_state/src/replicated_state.rs | Adds public ReplicatedState::add_refund() and removes the test-trait variant. |
| rs/messaging/src/canister_http_spent.rs | Pools HTTP outcall refunds into the refund pool and updates unit tests to validate pooling behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
✅ No security or compliance issues detected. Reviewed everything up to c046b86. Security Overview
Detected Code Changes
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Background
Under the new HTTP outcalls pay-as-you-go pricing, the caller's payment is split into a per-replica allowance which is stored in the context. Each replica consumes part of this allowance to produce their share of the response. Any unspent cycles out of this allowance are transferred back to the caller (initial refund). A late replica which didn't participate in the response, may still issue its refund later, after the call already received a response. Both the initial and late refunds are credited to the canister directly.
For this purpose, there are two collections holding HTTP outcalls in the call context manager: one holding in progress requests (waiting for the response and initial refund), and one holding delivered requests (waiting for late asynchronous refunds).
Problem
During a subnet split, some canisters may move to a different subnet. Currently, all HTTP contexts stay on the original subnet (A'). Most (if not all) of the in-progress contexts will likely time out because:
For legacy pricing, this is generally fine, since any refund is part of the timeout response, which can still be routed to the calling canister, even if it moved to a different subnet.
However, under pay-as-you-go pricing, any refunds can no longer be credited if the canister moved to a different subnet.
Proposed Changes
Instead of crediting refunds to canisters directly, insert them into the "refund pool" such that they may be routed to the target canister, even if that canister moved to a different subnet.