1#![warn(missing_docs, missing_debug_implementations)]
5#![deny(elided_lifetimes_in_paths)]
6
7use std::borrow::Cow;
8
9use candid::Principal;
10use ic_certification::Label;
11pub use request_id::{to_request_id, RequestId, RequestIdError};
12use serde::{Deserialize, Serialize};
13use serde_repr::{Deserialize_repr, Serialize_repr};
14use thiserror::Error;
15
16mod request_id;
17pub mod signed;
18
19#[derive(Debug, Clone, Deserialize, Serialize)]
22#[serde(rename_all = "snake_case")]
23pub struct Envelope<'a> {
24 pub content: Cow<'a, EnvelopeContent>,
26 #[serde(default, skip_serializing_if = "Option::is_none", with = "serde_bytes")]
28 pub sender_pubkey: Option<Vec<u8>>,
29 #[serde(default, skip_serializing_if = "Option::is_none", with = "serde_bytes")]
32 pub sender_sig: Option<Vec<u8>>,
33 #[serde(default, skip_serializing_if = "Option::is_none")]
35 pub sender_delegation: Option<Vec<SignedDelegation>>,
36}
37
38impl Envelope<'_> {
39 pub fn encode_bytes(&self) -> Vec<u8> {
41 let mut serializer = serde_cbor::Serializer::new(Vec::new());
42 serializer.self_describe().unwrap();
43 self.serialize(&mut serializer)
44 .expect("infallible Envelope::serialize");
45 serializer.into_inner()
46 }
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
51#[serde(tag = "request_type", rename_all = "snake_case")]
52pub enum EnvelopeContent {
53 Call {
55 #[serde(default, skip_serializing_if = "Option::is_none", with = "serde_bytes")]
57 nonce: Option<Vec<u8>>,
58 ingress_expiry: u64,
60 sender: Principal,
62 canister_id: Principal,
64 method_name: String,
66 #[serde(with = "serde_bytes")]
68 arg: Vec<u8>,
69 },
70 ReadState {
72 ingress_expiry: u64,
74 sender: Principal,
76 paths: Vec<Vec<Label>>,
78 },
79 Query {
81 ingress_expiry: u64,
83 sender: Principal,
85 canister_id: Principal,
87 method_name: String,
89 #[serde(with = "serde_bytes")]
91 arg: Vec<u8>,
92 #[serde(default, skip_serializing_if = "Option::is_none", with = "serde_bytes")]
94 nonce: Option<Vec<u8>>,
95 },
96}
97
98impl EnvelopeContent {
99 pub fn ingress_expiry(&self) -> u64 {
101 let (Self::Call { ingress_expiry, .. }
102 | Self::Query { ingress_expiry, .. }
103 | Self::ReadState { ingress_expiry, .. }) = self;
104 *ingress_expiry
105 }
106 pub fn sender(&self) -> &Principal {
108 let (Self::Call { sender, .. }
109 | Self::Query { sender, .. }
110 | Self::ReadState { sender, .. }) = self;
111 sender
112 }
113 pub fn to_request_id(&self) -> RequestId {
117 to_request_id(self)
118 .expect("to_request_id::<EnvelopeContent> should always succeed but did not")
119 }
120}
121
122#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
124pub struct ReadStateResponse {
125 #[serde(with = "serde_bytes")]
129 pub certificate: Vec<u8>,
130}
131
132#[derive(Debug, Serialize, Deserialize)]
134#[serde(tag = "status", rename_all = "snake_case")]
135pub enum TransportCallResponse {
136 Replied {
138 #[serde(with = "serde_bytes")]
140 certificate: Vec<u8>,
141 },
142
143 NonReplicatedRejection(RejectResponse),
145
146 Accepted,
150}
151
152#[derive(Debug, PartialEq, Eq, Clone, Hash)]
154pub enum CallResponse<Out> {
155 Response(Out),
157 Poll(RequestId),
160}
161
162impl<Out> CallResponse<Out> {
163 #[inline]
165 pub fn map<Out2>(self, f: impl FnOnce(Out) -> Out2) -> CallResponse<Out2> {
166 match self {
167 Self::Poll(p) => CallResponse::Poll(p),
168 Self::Response(r) => CallResponse::Response(f(r)),
169 }
170 }
171}
172
173impl<T, E> CallResponse<Result<T, E>> {
174 #[inline]
176 pub fn transpose(self) -> Result<CallResponse<T>, E> {
177 match self {
178 Self::Poll(p) => Ok(CallResponse::Poll(p)),
179 Self::Response(r) => r.map(CallResponse::Response),
180 }
181 }
182}
183
184impl<T> CallResponse<Option<T>> {
185 #[inline]
187 pub fn transpose(self) -> Option<CallResponse<T>> {
188 match self {
189 Self::Poll(p) => Some(CallResponse::Poll(p)),
190 Self::Response(r) => r.map(CallResponse::Response),
191 }
192 }
193}
194
195impl<T> CallResponse<(T,)> {
196 #[inline]
198 pub fn detuple(self) -> CallResponse<T> {
199 match self {
200 Self::Poll(p) => CallResponse::Poll(p),
201 Self::Response(r) => CallResponse::Response(r.0),
202 }
203 }
204}
205
206#[derive(Debug, Clone, Deserialize, Serialize)]
208#[serde(tag = "status", rename_all = "snake_case")]
209pub enum QueryResponse {
210 Replied {
212 reply: ReplyResponse,
214
215 #[serde(default, skip_serializing_if = "Vec::is_empty")]
217 signatures: Vec<NodeSignature>,
218 },
219 Rejected {
221 #[serde(flatten)]
223 reject: RejectResponse,
224
225 #[serde(default, skip_serializing_if = "Vec::is_empty")]
227 signatures: Vec<NodeSignature>,
228 },
229}
230
231impl QueryResponse {
232 pub fn signable(&self, request_id: RequestId, timestamp: u64) -> Vec<u8> {
236 #[derive(Serialize)]
237 #[serde(tag = "status", rename_all = "snake_case")]
238 enum QueryResponseSignable<'a> {
239 Replied {
240 reply: &'a ReplyResponse, request_id: RequestId,
242 timestamp: u64,
243 },
244 Rejected {
245 reject_code: RejectCode,
246 reject_message: &'a String,
247 #[serde(default)]
248 error_code: Option<&'a String>,
249 request_id: RequestId,
250 timestamp: u64,
251 },
252 }
253 let response = match self {
254 Self::Replied { reply, .. } => QueryResponseSignable::Replied {
255 reply,
256 request_id,
257 timestamp,
258 },
259 Self::Rejected { reject, .. } => QueryResponseSignable::Rejected {
260 error_code: reject.error_code.as_ref(),
261 reject_code: reject.reject_code,
262 reject_message: &reject.reject_message,
263 request_id,
264 timestamp,
265 },
266 };
267 let mut signable = Vec::with_capacity(44);
268 signable.extend_from_slice(b"\x0Bic-response");
269 signable.extend_from_slice(to_request_id(&response).unwrap().as_slice());
270 signable
271 }
272
273 pub fn signatures(&self) -> &[NodeSignature] {
275 let (Self::Rejected { signatures, .. } | Self::Replied { signatures, .. }) = self;
276 signatures
277 }
278}
279
280#[derive(Debug, Clone, Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq)]
282pub struct RejectResponse {
283 pub reject_code: RejectCode,
285 pub reject_message: String,
287 #[serde(default)]
289 pub error_code: Option<String>,
290}
291
292#[derive(
294 Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize_repr, Deserialize_repr, Ord, PartialOrd,
295)]
296#[repr(u8)]
297pub enum RejectCode {
298 SysFatal = 1,
300 SysTransient = 2,
302 DestinationInvalid = 3,
304 CanisterReject = 4,
306 CanisterError = 5,
308}
309
310impl TryFrom<u64> for RejectCode {
311 type Error = InvalidRejectCodeError;
312
313 fn try_from(value: u64) -> Result<Self, InvalidRejectCodeError> {
314 match value {
315 1 => Ok(RejectCode::SysFatal),
316 2 => Ok(RejectCode::SysTransient),
317 3 => Ok(RejectCode::DestinationInvalid),
318 4 => Ok(RejectCode::CanisterReject),
319 5 => Ok(RejectCode::CanisterError),
320 _ => Err(InvalidRejectCodeError(value)),
321 }
322 }
323}
324
325#[derive(Debug, Error)]
327#[error("Invalid reject code {0}")]
328pub struct InvalidRejectCodeError(pub u64);
329
330#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone)]
334pub enum RequestStatusResponse {
335 Unknown,
337 Received,
339 Processing,
341 Replied(ReplyResponse),
343 Rejected(RejectResponse),
345 Done,
347}
348
349#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Serialize, Deserialize)]
351pub struct ReplyResponse {
352 #[serde(with = "serde_bytes")]
354 pub arg: Vec<u8>,
355}
356
357#[derive(Debug, Clone, Serialize, Deserialize)]
362pub struct Delegation {
363 #[serde(with = "serde_bytes")]
365 pub pubkey: Vec<u8>,
366 pub expiration: u64,
368 #[serde(default, skip_serializing_if = "Option::is_none")]
370 pub targets: Option<Vec<Principal>>,
371}
372
373const IC_REQUEST_DELEGATION_DOMAIN_SEPARATOR: &[u8] = b"\x1Aic-request-auth-delegation";
374
375impl Delegation {
376 pub fn signable(&self) -> Vec<u8> {
379 let hash = to_request_id(self).unwrap();
380 let mut bytes = Vec::with_capacity(59);
381 bytes.extend_from_slice(IC_REQUEST_DELEGATION_DOMAIN_SEPARATOR);
382 bytes.extend_from_slice(hash.as_slice());
383 bytes
384 }
385}
386
387#[derive(Debug, Clone, Serialize, Deserialize)]
389pub struct SignedDelegation {
390 pub delegation: Delegation,
392 #[serde(with = "serde_bytes")]
394 pub signature: Vec<u8>,
395}
396
397#[derive(Debug, Clone, Serialize, Deserialize, Eq, Ord, PartialEq, PartialOrd)]
399pub struct NodeSignature {
400 pub timestamp: u64,
402 #[serde(with = "serde_bytes")]
404 pub signature: Vec<u8>,
405 pub identity: Principal,
407}
408
409#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
411pub struct SubnetMetrics {
412 pub num_canisters: u64,
414 pub canister_state_bytes: u64,
416 #[serde(with = "map_u128")]
418 pub consumed_cycles_total: u128,
419 pub update_transactions_total: u64,
421}
422
423mod map_u128 {
424 use serde::{
425 de::{Error, IgnoredAny, MapAccess, Visitor},
426 ser::SerializeMap,
427 Deserializer, Serializer,
428 };
429 use std::fmt;
430
431 pub fn serialize<S: Serializer>(val: &u128, s: S) -> Result<S::Ok, S::Error> {
432 let low = *val & u64::MAX as u128;
433 let high = *val >> 64;
434 let mut map = s.serialize_map(Some(2))?;
435 map.serialize_entry(&0, &low)?;
436 map.serialize_entry(&1, &(high != 0).then_some(high))?;
437 map.end()
438 }
439
440 pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<u128, D::Error> {
441 d.deserialize_map(MapU128Visitor)
442 }
443
444 struct MapU128Visitor;
445
446 impl<'de> Visitor<'de> for MapU128Visitor {
447 type Value = u128;
448
449 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
450 formatter.write_str("a map of low and high")
451 }
452
453 fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
454 let (_, low): (IgnoredAny, u64) = map
455 .next_entry()?
456 .ok_or_else(|| A::Error::missing_field("0"))?;
457 let opt: Option<(IgnoredAny, Option<u64>)> = map.next_entry()?;
458 let high = opt.and_then(|x| x.1).unwrap_or(0);
459 Ok(((high as u128) << 64) | low as u128)
460 }
461 }
462}