Skip to content

Commit 53d94aa

Browse files
authored
feat(flexible-outcalls): IC-1952 support flexible responses in CanisterHttpPayload (#9159)
Adds a `flexible_responses: Vec<FlexibleCanisterHttpResponses>` field to the `CanisterHttpPayload` incl. protobuf serialization support. This is a pure type addition with no behavioral changes; construction and validation logic will follow in a subsequent PR.
1 parent 1406b99 commit 53d94aa

File tree

9 files changed

+188
-81
lines changed

9 files changed

+188
-81
lines changed

rs/https_outcalls/consensus/src/payload_builder.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,8 @@ impl CanisterHttpPayloadBuilderImpl {
401401
.collect(),
402402
timeouts,
403403
divergence_responses,
404+
// TODO(flexible-http-outcalls): implement flexible responses
405+
flexible_responses: vec![],
404406
}
405407
}
406408

@@ -416,6 +418,11 @@ impl CanisterHttpPayloadBuilderImpl {
416418
return Ok(());
417419
}
418420

421+
// Flexible responses are not yet supported
422+
if !payload.flexible_responses.is_empty() {
423+
return invalid_artifact(InvalidCanisterHttpPayloadReason::FlexibleResponsesNotEmpty);
424+
}
425+
419426
// Check whether feature is enabled and reject if it isn't.
420427
// NOTE: All payloads that are processed at this point are non-empty
421428
if !self.is_enabled(validation_context).map_err(|err| {

rs/https_outcalls/consensus/src/payload_builder/parse.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use ic_protobuf::{
77
};
88
use ic_types::{
99
NumBytes,
10-
batch::{CanisterHttpPayload, iterator_to_bytes, slice_to_messages},
10+
batch::{
11+
CanisterHttpPayload, FlexibleCanisterHttpResponses, iterator_to_bytes, slice_to_messages,
12+
},
1113
messages::CallbackId,
1214
};
1315
use std::collections::HashSet;
@@ -24,6 +26,9 @@ pub(crate) fn bytes_to_payload(data: &[u8]) -> Result<CanisterHttpPayload, Proxy
2426
Some(MessageType::DivergenceResponse(response)) => {
2527
payload.divergence_responses.push(response.try_into()?)
2628
}
29+
Some(MessageType::FlexibleResponses(flex_responses)) => payload
30+
.flexible_responses
31+
.push(FlexibleCanisterHttpResponses::try_from(flex_responses)?),
2732
None => return Err(ProxyDecodeError::MissingField("message_type")),
2833
}
2934
}
@@ -55,7 +60,14 @@ pub(crate) fn payload_to_bytes(payload: &CanisterHttpPayload, max_size: NumBytes
5560
pb::CanisterHttpResponseWithConsensus::from(response),
5661
)),
5762
}),
58-
);
63+
)
64+
.chain(payload.flexible_responses.iter().map(|flex_responses| {
65+
CanisterHttpResponseMessage {
66+
message_type: Some(MessageType::FlexibleResponses(
67+
pb::FlexibleCanisterHttpResponses::from(flex_responses),
68+
)),
69+
}
70+
}));
5971

6072
iterator_to_bytes(message_iterator, max_size)
6173
}
@@ -94,6 +106,7 @@ fn get_id_from_message(message: CanisterHttpResponseMessage) -> Option<u64> {
94106
.shares
95107
.first()
96108
.and_then(|share| share.metadata.as_ref().map(|md| md.id)),
109+
Some(MessageType::FlexibleResponses(flex_responses)) => Some(flex_responses.callback_id),
97110
Some(MessageType::Timeout(id)) => Some(id),
98111
None => None,
99112
}

rs/https_outcalls/consensus/src/payload_builder/tests.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ fn multiple_payload_test() {
217217
}],
218218
timeouts: vec![],
219219
divergence_responses: vec![],
220+
flexible_responses: vec![],
220221
};
221222
let past_payload = payload_to_bytes(&past_payload, NumBytes::new(4 * 1024 * 1024));
222223

@@ -644,6 +645,7 @@ fn duplicate_validation() {
644645
responses: vec![response_and_metadata_to_proof(&response, &metadata)],
645646
timeouts: vec![],
646647
divergence_responses: vec![],
648+
flexible_responses: vec![],
647649
};
648650
let payload = payload_to_bytes(&payload, NumBytes::new(4 * 1024 * 1024));
649651
let past_payloads = vec![PastPayload {
@@ -697,6 +699,7 @@ fn divergence_response_validation_test() {
697699
}))
698700
.collect(),
699701
}],
702+
flexible_responses: vec![],
700703
};
701704
let payload = payload_to_bytes(&payload, NumBytes::new(4 * 1024 * 1024));
702705

@@ -717,6 +720,7 @@ fn divergence_response_validation_test() {
717720
.map(|node_id| metadata_to_share(node_id.try_into().unwrap(), &metadata))
718721
.collect(),
719722
}],
723+
flexible_responses: vec![],
720724
};
721725
let payload = payload_to_bytes(&payload, NumBytes::new(4 * 1024 * 1024));
722726

@@ -754,6 +758,7 @@ fn divergence_response_validation_test() {
754758
}))
755759
.collect(),
756760
}],
761+
flexible_responses: vec![],
757762
};
758763
let payload = payload_to_bytes(&payload, NumBytes::new(4 * 1024 * 1024));
759764

@@ -1790,6 +1795,7 @@ where
17901795
responses: vec![response_and_metadata_to_proof(&response, &metadata)],
17911796
timeouts: vec![],
17921797
divergence_responses: vec![],
1798+
flexible_responses: vec![],
17931799
};
17941800

17951801
let payload = payload_to_bytes(&payload, NumBytes::new(4 * 1024 * 1024));

rs/https_outcalls/consensus/src/test_utils.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ impl BatchPayloadBuilder for FakeCanisterHttpPayloadBuilder {
3636
responses: self.0.clone(),
3737
timeouts: vec![],
3838
divergence_responses: vec![],
39+
flexible_responses: vec![],
3940
};
4041
payload_to_bytes(&payload, max_size)
4142
}

rs/interfaces/src/canister_http.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ pub enum InvalidCanisterHttpPayloadReason {
7070
DuplicateResponse(CallbackId),
7171
DivergenceProofContainsMultipleCallbackIds,
7272
DivergenceProofDoesNotMeetDivergenceCriteria,
73+
/// The payload contains flexible responses, which are not yet supported
74+
FlexibleResponsesNotEmpty,
7375
/// The payload could not be deserialized
7476
DecodeError(ProxyDecodeError),
7577
}

rs/protobuf/def/types/v1/canister_http.proto

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,22 @@ message CanisterHttpResponseDivergence {
7171
repeated CanisterHttpShare shares = 1;
7272
}
7373

74+
message FlexibleCanisterHttpResponseWithProof {
75+
CanisterHttpResponse response = 1;
76+
CanisterHttpShare proof = 2;
77+
}
78+
79+
message FlexibleCanisterHttpResponses {
80+
uint64 callback_id = 1;
81+
repeated FlexibleCanisterHttpResponseWithProof responses = 2;
82+
}
83+
7484
message CanisterHttpResponseMessage {
7585
oneof message_type {
7686
CanisterHttpResponseWithConsensus response = 1;
7787
uint64 timeout = 2;
7888
CanisterHttpResponseDivergence divergence_response = 3;
89+
FlexibleCanisterHttpResponses flexible_responses = 4;
7990
}
8091
}
8192

rs/protobuf/src/gen/types/types.v1.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,10 +612,24 @@ pub struct CanisterHttpResponseDivergence {
612612
pub shares: ::prost::alloc::vec::Vec<CanisterHttpShare>,
613613
}
614614
#[derive(Clone, PartialEq, ::prost::Message)]
615+
pub struct FlexibleCanisterHttpResponseWithProof {
616+
#[prost(message, optional, tag = "1")]
617+
pub response: ::core::option::Option<CanisterHttpResponse>,
618+
#[prost(message, optional, tag = "2")]
619+
pub proof: ::core::option::Option<CanisterHttpShare>,
620+
}
621+
#[derive(Clone, PartialEq, ::prost::Message)]
622+
pub struct FlexibleCanisterHttpResponses {
623+
#[prost(uint64, tag = "1")]
624+
pub callback_id: u64,
625+
#[prost(message, repeated, tag = "2")]
626+
pub responses: ::prost::alloc::vec::Vec<FlexibleCanisterHttpResponseWithProof>,
627+
}
628+
#[derive(Clone, PartialEq, ::prost::Message)]
615629
pub struct CanisterHttpResponseMessage {
616630
#[prost(
617631
oneof = "canister_http_response_message::MessageType",
618-
tags = "1, 2, 3"
632+
tags = "1, 2, 3, 4"
619633
)]
620634
pub message_type: ::core::option::Option<canister_http_response_message::MessageType>,
621635
}
@@ -629,6 +643,8 @@ pub mod canister_http_response_message {
629643
Timeout(u64),
630644
#[prost(message, tag = "3")]
631645
DivergenceResponse(super::CanisterHttpResponseDivergence),
646+
#[prost(message, tag = "4")]
647+
FlexibleResponses(super::FlexibleCanisterHttpResponses),
632648
}
633649
}
634650
#[derive(Clone, PartialEq, ::prost::Message)]

rs/types/types/src/batch.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ mod vetkd;
99
mod xnet;
1010

1111
pub use self::{
12-
canister_http::{CanisterHttpPayload, MAX_CANISTER_HTTP_PAYLOAD_SIZE},
12+
canister_http::{
13+
CanisterHttpPayload, FlexibleCanisterHttpResponseWithProof, FlexibleCanisterHttpResponses,
14+
MAX_CANISTER_HTTP_PAYLOAD_SIZE,
15+
},
1316
execution_environment::{
1417
CanisterCyclesCostSchedule, CanisterQueryStats, LocalQueryStats, QueryStats,
1518
QueryStatsPayload, RawQueryStats, TotalQueryStats,

0 commit comments

Comments
 (0)