Skip to content

fix: Insert HTTP outcalls pay-as-you-go refunds into the refund pool - #11045

Open
eichhorl wants to merge 3 commits into
masterfrom
eichhorl/pool-payg-refunds
Open

fix: Insert HTTP outcalls pay-as-you-go refunds into the refund pool#11045
eichhorl wants to merge 3 commits into
masterfrom
eichhorl/pool-payg-refunds

Conversation

@eichhorl

@eichhorl eichhorl commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

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:

  1. The committee of a fully-replicated request changed completely, and can no longer collect the required shares.
  2. The dedicated node of a non-replicated request may now be on a different subnet.
  3. The chosen (min, max, total_requests) of a flexible outcall no longer make sense on a subnet half the size.
  4. The selected committee of a flexible outcall was split into two subnets.
  5. The transform function belongs to a canister that no longer exists on the subnet.

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.

@github-actions github-actions Bot added the fix label Aug 6, 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

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 ReplicatedState method (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.

@eichhorl
eichhorl marked this pull request as ready for review August 6, 2026 09:53
@eichhorl
eichhorl requested a review from a team as a code owner August 6, 2026 09:53
@zeropath-ai

zeropath-ai Bot commented Aug 6, 2026

Copy link
Copy Markdown

No security or compliance issues detected. Reviewed everything up to c046b86.

Security Overview
Detected Code Changes
Change Type Relevant files
Refactor ► rs/messaging/src/canister_http_spent.rs
    Adjust HTTP outcall refund accounting; remove direct balance crediting in favor of pooled refunds
► rs/replicated_state/src/replicated_state.rs
    Add add_refund method to pool refunds for recipients; adjust imports and testing exposure accordingly
► rs/types/types/src/messages/inter_canister.rs
    Update XNet refund description to reflect refunds outside of a response and anonymous refunds

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.

2 participants