Skip to content

Commit b40ad06

Browse files
committed
First draft of flexible http outcalls
1 parent f18a0f6 commit b40ad06

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

docs/references/_attachments/ic.did

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,21 @@ type http_request_args = record {
317317
};
318318
};
319319

320+
type flexible_http_request_args = record {
321+
url : text;
322+
method : variant { get; head; post };
323+
headers : vec http_header;
324+
body : opt blob;
325+
transform : opt record {
326+
function : func(record { response : http_request_result; context : blob }) -> (http_request_result) query;
327+
context : blob;
328+
};
329+
responses_from : variant {
330+
all_replicas;
331+
replica_count: nat32;
332+
};
333+
}
334+
320335
type ecdsa_public_key_args = record {
321336
canister_id : opt canister_id;
322337
derivation_path : vec blob;
@@ -489,6 +504,7 @@ service ic : {
489504
deposit_cycles : (deposit_cycles_args) -> ();
490505
raw_rand : () -> (raw_rand_result);
491506
http_request : (http_request_args) -> (http_request_result);
507+
flexible_http_request : (flexible_http_request_args) -> (vec http_request_result);
492508

493509
// Threshold ECDSA signature
494510
ecdsa_public_key : (ecdsa_public_key_args) -> (ecdsa_public_key_result);

docs/references/ic-interface-spec.md

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,6 +1527,7 @@ defaulting to `I = i32` if the canister declares no memory.
15271527
15281528
ic0.subnet_self_size : () -> I; // *
15291529
ic0.subnet_self_copy : (dst : I, offset : I, size : I) -> (); // *
1530+
ic0.subnet_self_replica_count : () -> i32; // *
15301531
15311532
ic0.msg_method_name_size : () -> I; // F
15321533
ic0.msg_method_name_copy : (dst : I, offset : I, size : I) -> (); // F
@@ -1569,6 +1570,8 @@ defaulting to `I = i32` if the canister declares no memory.
15691570
ic0.cost_call : (method_name_size: i64, payload_size : i64, dst : I) -> (); // * s
15701571
ic0.cost_create_canister : (dst : I) -> (); // * s
15711572
ic0.cost_http_request : (request_size : i64, max_res_bytes : i64, dst : I) -> (); // * s
1573+
ic0.cost_flexible_http_request :
1574+
(request_size : i64, replica_count: i32, dst : I) -> (); // * s
15721575
ic0.cost_sign_with_ecdsa : (src : I, size : I, ecdsa_curve: i32, dst : I) -> i32; // * s
15731576
ic0.cost_sign_with_schnorr : (src : I, size : I, algorithm: i32, dst : I) -> i32; // * s
15741577
ic0.cost_vetkd_derive_key : (src : I, size : I, vetkd_curve: i32, dst : I) -> i32; // * s
@@ -1749,9 +1752,10 @@ A canister can learn about its own identity:
17491752

17501753
A canister can learn about the subnet it is running on:
17511754

1752-
- `ic0.subnet_self_size : () → I` and `ic0.subnet_self_copy: (dst : I, offset : I, size : I) → ()`; `I ∈ {i32, i64}`
1755+
- `ic0.subnet_self_size : () → I`, `ic0.subnet_self_copy: (dst : I, offset : I, size : I) → ()`; `I ∈ {i32, i64}`, and `ic0.subnet_self_replica_count : () -> i32`
1756+
1757+
These functions allow the canister to query the subnet id (as a blob) of the subnet on which the canister is running, and to retrieve the number of replicas that are currently on the subnet.
17531758

1754-
These functions allow the canister to query the subnet id (as a blob) of the subnet on which the canister is running.
17551759

17561760
### Canister status {#system-api-canister-status}
17571761

@@ -2164,6 +2168,10 @@ These system calls return costs in Cycles, represented by 128 bits, which will b
21642168

21652169
`max_res_bytes` is the maximum response length the caller wishes to accept (the caller should provide the default value of `2,000,000` if no maximum response length is provided in the actual request to the management canister).
21662170

2171+
- `ic0.cost_flexible_http_request(request_size : i64, replica_count: i32, dst : I) -> ()`; `I ∈ {i32, i64}`
2172+
2173+
The cost of a canister http outcall via [`flexible_http_request`](#ic-flexible_http_request). The `request_size` is same as for `cost_http_request` and covers the url, headers, body and transform. The `replica_count` is the number to be used in the call to `flexible_http_request`.
2174+
21672175
- `ic0.cost_sign_with_ecdsa(src : I, size : I, ecdsa_curve: i32, dst : I) -> i32`; `I ∈ {i32, i64}`
21682176

21692177
- `ic0.cost_sign_with_schnorr(src : I, size : I, algorithm: i32, dst : I) -> i32`; `I ∈ {i32, i64}`
@@ -2820,6 +2828,34 @@ If you do not specify the `max_response_bytes` parameter, the maximum of a `2MB`
28202828

28212829
:::
28222830

2831+
### IC method `flexible_http_request` {#ic-flexible_http_request}
2832+
2833+
This is a variant of the [`http_request`](#ic-http_request) method that allows the caller to select how many IC replicas issue the request, and returns potentially multiple responses instead of a single one, one from each replica issuing the request. Use cases include calling HTTP endpoints that provide rapidly changing information, calling non-idempotent endpoints (by issuing the request from a single replica only), calling endpoints that provide signed data whose authenticity can be checked without trusting the endpoint, and letting the user pick a trade-off between cheaper calls (fewer replicas responding) and stronger integrity guarantees (more replicas responding).
2834+
2835+
The arguments of the call are as for `http_request`, except that:
2836+
2837+
- there is an additional argument `responses_from`, which can be set to either `all_replicas` or to a particular `replica_count` with a given (positive) number of replicas. The number of replicas must not exceed the subnet size.
2838+
2839+
- `max_response_bytes` argument is not needed.
2840+
2841+
The other arguments, `url`, `method`, `headers`, `body`, and `transform` are the same as for `http_request`. The result is a vector of responses, with each individual response having the same structure as a `http_request` response, providing `status`, `headers`, and `body` fields.
2842+
2843+
As for `http_request`, the endpoint specified by the provided `url` should be idempotent. The one exception is when a `replica_count` of 1 is used in `responses_from`. The request restrictions are also the same as for the `http_request` method:
2844+
2845+
- The total number of bytes in the request must not exceed `2MB` (`2,000,000`) bytes.
2846+
2847+
- Only the `GET`, `HEAD`, and `POST` methods are supported.
2848+
2849+
- The number of headers must not exceed `64`.
2850+
2851+
- The number of bytes representing a header name or value must not exceed `8KiB`.
2852+
2853+
- The total number of bytes representing the header names and values must not exceed `48KiB`.
2854+
2855+
The response from the remote server must not exceed `2MB`. Moreover, the total size of the result, that is, the sum of the responses returned by the different replicas (possibly after the transform function), must also not exceed 2MB.
2856+
2857+
Cycles to pay for the call must be explicitly transferred with the call, i.e., they are not automatically deducted from the caller's balance implicitly (e.g., as for inter-canister calls). The upfront cycles cost covers a call that maxes out the resource usage during processing, for example, hitting the `2MB` limit on the size of the response. The unused cycles are then refunded to the caller.
2858+
28232859
### IC method `node_metrics_history` {#ic-node_metrics_history}
28242860

28252861
This method can only be called by canisters, i.e., it cannot be called by external users via ingress messages.

0 commit comments

Comments
 (0)