In this post, we would like to compare PocketIC (update/query) call response types with their counterparts in the Rust IC agent and present an option for making them consistent.
Status Quo
The response type for completed PocketIC (update/query) calls is Result<WasmResult, UserError>
where
pub enum WasmResult {
Reply(Vec<u8>),
Reject(String),
}
pub struct UserError {
pub code: ErrorCode,
pub description: String,
}
or Result<Output, CallError>
where Output
is a successful response type decoded from the raw binary response and
pub enum CallError {
Reject(String),
UserError(UserError),
}
On the other hand, the response type for completed IC agent (update/query) calls is Result<Vec<u8>, AgentError>
where
pub enum AgentError {
CertifiedReject(RejectResponse),
UncertifiedReject(RejectResponse),
...
}
pub struct RejectResponse {
pub reject_code: RejectCode,
pub reject_message: String,
pub error_code: Option<String>,
}
Unexpected variants of AgentError
are omitted because they are less likely to occur in local testing using PocketIC (no remote networking, no certificate/signature validation).
The inconsistency makes it more difficult for developers to comprehend the various call response types and also results in more boilerplate code to extract a successful PocketIC call response (need to unwrap and pattern-match on WasmResult
).
Proposal
We propose the response type for completed PocketIC (update/query) calls to be Result<Vec<u8>, RejectResponse>
or Result<Output, RejectResponse>
where
pub enum RejectCode {
SysFatal = 1,
SysTransient = 2,
DestinationInvalid = 3,
CanisterReject = 4,
CanisterError = 5,
SysUnknown = 6,
}
pub struct RejectResponse {
pub reject_code: RejectCode,
pub reject_message: String,
pub error_code: ErrorCode,
pub certified: bool,
}
Remarks:
- The error-code is non-optional since it is always set.
- It is easy to unwrap successful responses and errors.
- The response types distinguishes between certified and uncertified rejects via a dedicated Boolean field.
Transition
We propose to change the PocketIC call response types in the upcoming PocketIC release. This is going to be a breaking change, but a preliminary research suggests that the transition is feasible:
- pic-js converts the PocketIC server response into a custom response type at a single place;
- OpenChat unwraps the PocketIC library response in a pair of helper functions;
- Internet Identity pattern-matches on
CallError
in a single helper function.
Now we would like to kindly ask PocketIC users if they could please speak up in case the proposed change would result in excessive transition overhead for their canister tests using PocketIC.