feat: Cap the amount of cycles that move into the per-replica HTTP outcalls allowance - #11012
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates HTTP outcalls pay-as-you-go pricing to (a) support estimating costs for different replication modes via http_request_fee_v2, (b) centralize the pricing formulas in the dedicated pricing crate, and (c) cap per-replica allowances withheld from a caller’s payment to the worst-case spendable amount (while refunding any split remainder instead of silently losing it).
Changes:
- Introduces an explicit replication-kind parameter for
http_request_fee_v2and unifies the implementation underrs/https_outcalls/pricing. - Adds worst-case usage fee computation and uses it to cap withheld per-replica allowances; remainder from allowance splitting stays refundable via the response path.
- Updates system API decoding/encoding + tests/benches to support the extended
cost_http_request_v2payload.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| rs/types/types/src/canister_http.rs | Extends replication representation with ReplicationKind carrying flexible counts; adds defaults and node-count logic. |
| rs/test_utilities/execution_environment/src/lib.rs | Exposes a helper to query max HTTP request usage fee in execution tests. |
| rs/https_outcalls/pricing/src/payg.rs | Refactors tracker charging to use shared fee helpers; adds tests ensuring max-usage bound covers worst-case spend. |
| rs/https_outcalls/pricing/src/fees.rs | Centralizes pricing formulas, adds total_fee and max_usage_fee, and refactors consensus/gossip fee computations. |
| rs/execution_environment/tests/hypervisor.rs | Extends ic0.cost_http_request_v2 tests to cover replication variants and default flexible counts. |
| rs/execution_environment/src/execution_environment/tests.rs | Updates execution-environment tests for new allowance/refund behavior, adds new refund/cap tests. |
| rs/execution_environment/src/execution_environment.rs | Caps withheld allowances by worst-case usage fee and preserves remainder in payment for later refund. |
| rs/execution_environment/benches/system_api/execute_update.rs | Updates benchmark params to include replication mode for cost_http_request_v2. |
| rs/cycles_account_manager/src/cycles_account_manager.rs | Moves fee calculation to pricing crate, adds max-usage-fee API, and extends http_request_fee_v2 signature. |
Suppressed comments (1)
rs/types/types/src/canister_http.rs:257
- Doc comment is grammatically incorrect ("The flexible replication a request...") and is hard to parse. Rewording helps keep the public API docs clear.
/// The flexible replication a request that does not specify its response counts
/// gets on a subnet of `subnet_size` nodes, see [`Self::default_flexible_counts`].
pub fn default_flexible(subnet_size: NumberOfNodes) -> Self {
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
✅ No security or compliance issues detected. Reviewed everything up to d8bb97d. Security Overview
Detected Code Changes
|
pierugo-dfinity
left a comment
There was a problem hiding this comment.
Would be happy if someone else had a second look on the execution layer parts, as I'm less comfortable with that part of the code 🙏 Maybe @mraszyk
Co-authored-by: Pierugo Pace <pierugo.pace@dfinity.org>
Co-authored-by: Pierugo Pace <pierugo.pace@dfinity.org>
mraszyk
left a comment
There was a problem hiding this comment.
LGTM I didn't review all the formulas in the file rs/https_outcalls/pricing/src/fees.rs so I don't approve
... and other smaller fixes.
Background
The new pay-as-you-go pricing for HTTP outcalls consists of three parts:
If the call runs out of cycles at any point in time, it will fail. Therefore, in order to determine the correct amount of cycles to attach to the call, the system API offers a function
http_request_fee_v2which may be used to estimate the expected cost based on some parameters.Proposed Changes
http_request_fee_v2did not have a parameter to choose the "replication" of the outcall (i.e. fully-/non-/flexible-replication), which does have an effect on the cost. We introduce this missing parameter.http_request_fee_v2implementation duplicated the same calculation and constants of the newer pricing crate. We move the implementation ofhttp_request_fee_v2into the pricing crate, to ensure the functions don't diverge.http_request_fee_v2was charging for gossiping the response during fully replicated calls (see the original650consensus cost literal, vs.600now). This is incorrect since responses aren't gossiped in this case, therefore, the unification with the pricing crate removes this extra charge.http_request_fee_v2is of course free to disregard the returned estimate, and attach as many cycles to the outcall as they please (say, their entire life savings). This is dangerous because in the current model, each malicious replica can burn the entirety of their allocated allowance share. To reduce this risk, we use the same functionality called byhttp_request_fee_v2(but with parameters chosen to be as big as possible), to derive a maximum cost. When deriving the per-replica allowance, we now deduct at most the maximum possible cost from the caller's payment. The remaining balance is refunded when a response is delivered, like it is in legacy pricing.(payment - base_cost) / committee_size. Any remainder of this division was silently lost (i.e. charged to the caller but not observed by metrics). With this PR, any remainder is refunded back to the caller instead.Future Work
We can use the function calculating the maximum outcall cost to tighten the bound on cycles that each replica on a free subnet may use to answer a request (currently set to 1T).