ex3_ic_agent/agent/
replica_api.rs

1use crate::{export::Principal, AgentError};
2use ic_certification::Label;
3use serde::{Deserialize, Serialize};
4use serde_repr::{Deserialize_repr, Serialize_repr};
5
6#[derive(Debug, Clone, Deserialize, Serialize)]
7#[serde(rename_all = "snake_case")]
8pub struct Envelope<T: Serialize> {
9    pub content: T,
10    #[serde(default)]
11    #[serde(skip_serializing_if = "Option::is_none")]
12    #[serde(with = "serde_bytes")]
13    pub sender_pubkey: Option<Vec<u8>>,
14    #[serde(default)]
15    #[serde(skip_serializing_if = "Option::is_none")]
16    #[serde(with = "serde_bytes")]
17    pub sender_sig: Option<Vec<u8>>,
18}
19
20#[derive(Debug, Clone, Deserialize, Serialize)]
21#[serde(tag = "request_type")]
22pub enum AsyncContent {
23    #[serde(rename = "call")]
24    CallRequest {
25        #[serde(default)]
26        #[serde(skip_serializing_if = "Option::is_none")]
27        #[serde(with = "serde_bytes")]
28        nonce: Option<Vec<u8>>,
29        ingress_expiry: u64,
30        sender: Principal,
31        canister_id: Principal,
32        method_name: String,
33        #[serde(with = "serde_bytes")]
34        arg: Vec<u8>,
35    },
36}
37
38// A request as submitted to /api/v2/.../call
39#[derive(Debug, Clone, Deserialize, Serialize)]
40#[serde(tag = "request_type")]
41pub enum CallRequestContent {
42    #[serde(rename = "call")]
43    CallRequest {
44        #[serde(default)]
45        #[serde(skip_serializing_if = "Option::is_none")]
46        #[serde(with = "serde_bytes")]
47        nonce: Option<Vec<u8>>,
48        ingress_expiry: u64,
49        sender: Principal,
50        canister_id: Principal,
51        method_name: String,
52        #[serde(with = "serde_bytes")]
53        arg: Vec<u8>,
54    },
55}
56
57// A request as submitted to /api/v2/.../read_state
58#[derive(Debug, Clone, Deserialize, Serialize)]
59#[serde(tag = "request_type")]
60pub enum ReadStateContent {
61    #[serde(rename = "read_state")]
62    ReadStateRequest {
63        ingress_expiry: u64,
64        sender: Principal,
65        paths: Vec<Vec<Label>>,
66    },
67}
68
69// A request as submitted to /api/v2/.../query
70#[derive(Debug, Clone, Deserialize, Serialize)]
71#[serde(tag = "request_type")]
72pub enum QueryContent {
73    #[serde(rename = "query")]
74    QueryRequest {
75        ingress_expiry: u64,
76        sender: Principal,
77        canister_id: Principal,
78        method_name: String,
79        #[serde(with = "serde_bytes")]
80        arg: Vec<u8>,
81    },
82}
83
84#[derive(Debug, Clone, Deserialize, Serialize)]
85#[serde(tag = "request_type")]
86pub enum SyncContent {
87    #[serde(rename = "read_state")]
88    ReadStateRequest {
89        ingress_expiry: u64,
90        sender: Principal,
91        paths: Vec<Vec<Label>>,
92    },
93    #[serde(rename = "query")]
94    QueryRequest {
95        ingress_expiry: u64,
96        sender: Principal,
97        canister_id: Principal,
98        method_name: String,
99        #[serde(with = "serde_bytes")]
100        arg: Vec<u8>,
101    },
102}
103
104#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
105pub struct ReadStateResponse {
106    #[serde(with = "serde_bytes")]
107    pub certificate: Vec<u8>,
108}
109
110#[derive(Debug, Clone, Deserialize, Serialize)]
111#[serde(tag = "status")]
112pub enum Status {
113    #[serde(rename = "unknown")]
114    Unknown {},
115    #[serde(rename = "received")]
116    Received {},
117    #[serde(rename = "processing")]
118    Processing {},
119    #[serde(rename = "replied")]
120    Replied { reply: RequestStatusResponseReplied },
121    #[serde(rename = "rejected")]
122    Rejected {
123        reject_code: u64,
124        reject_message: String,
125    },
126    #[serde(rename = "done")]
127    Done {},
128}
129
130#[derive(Debug, Clone, Deserialize, Serialize)]
131#[serde(untagged)]
132pub enum RequestStatusResponseReplied {
133    CallReply(CallReply),
134}
135
136#[derive(Debug, Clone, Deserialize, Serialize)]
137pub struct CallReply {
138    #[serde(with = "serde_bytes")]
139    pub arg: Vec<u8>,
140}
141
142#[derive(Debug, Clone, Deserialize, Serialize)]
143#[serde(tag = "status")]
144pub enum QueryResponse {
145    #[serde(rename = "replied")]
146    Replied { reply: CallReply },
147    #[serde(rename = "rejected")]
148    Rejected(RejectResponse),
149}
150
151/// An IC execution error received from the replica.
152#[derive(Debug, Clone, Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq)]
153pub struct RejectResponse {
154    /// The [reject code](https://smartcontracts.org/docs/interface-spec/index.html#reject-codes) returned by the replica.
155    pub reject_code: RejectCode,
156    /// The rejection message.
157    pub reject_message: String,
158    /// The optional [error code](https://smartcontracts.org/docs/interface-spec/index.html#error-codes) returned by the replica.
159    #[serde(default)]
160    pub error_code: Option<String>,
161}
162
163/// See the [interface spec](https://smartcontracts.org/docs/interface-spec/index.html#reject-codes).
164#[derive(
165    Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize_repr, Deserialize_repr, Ord, PartialOrd,
166)]
167#[repr(u8)]
168pub enum RejectCode {
169    /// Fatal system error, retry unlikely to be useful
170    SysFatal = 1,
171    /// Transient system error, retry might be possible.
172    SysTransient = 2,
173    /// Invalid destination (e.g. canister/account does not exist)
174    DestinationInvalid = 3,
175    /// Explicit reject by the canister.
176    CanisterReject = 4,
177    /// Canister error (e.g., trap, no response)
178    CanisterError = 5,
179}
180
181impl TryFrom<u64> for RejectCode {
182    type Error = AgentError;
183
184    fn try_from(value: u64) -> Result<Self, AgentError> {
185        match value {
186            1 => Ok(RejectCode::SysFatal),
187            2 => Ok(RejectCode::SysTransient),
188            3 => Ok(RejectCode::DestinationInvalid),
189            4 => Ok(RejectCode::CanisterReject),
190            5 => Ok(RejectCode::CanisterError),
191            _ => Err(AgentError::MessageError(format!(
192                "Received an invalid reject code {}",
193                value
194            ))),
195        }
196    }
197}