canic_core/ops/request/
response.rs1use crate::{
9 Error,
10 interface::ic::{canister::upgrade_canister, deposit_cycles},
11 ops::{
12 canister::create_and_install_canister,
13 model::memory::topology::subnet::SubnetCanisterRegistryOps,
14 prelude::*,
15 request::{
16 CreateCanisterParent, CreateCanisterRequest, CyclesRequest, Request, RequestOpsError,
17 UpgradeCanisterRequest,
18 },
19 wasm::WasmOps,
20 },
21};
22
23#[derive(CandidType, Clone, Debug, Deserialize)]
29pub enum Response {
30 CreateCanister(CreateCanisterResponse),
31 UpgradeCanister(UpgradeCanisterResponse),
32 Cycles(CyclesResponse),
33}
34
35#[derive(CandidType, Clone, Debug, Deserialize)]
41pub struct CreateCanisterResponse {
42 pub new_canister_pid: Principal,
43}
44
45#[derive(CandidType, Clone, Debug, Deserialize)]
51pub struct UpgradeCanisterResponse {}
52
53#[derive(CandidType, Clone, Debug, Deserialize)]
59pub struct CyclesResponse {
60 pub cycles_transferred: u128,
61}
62
63pub async fn response(req: Request) -> Result<Response, Error> {
65 OpsError::require_root()?;
66
67 match req {
68 Request::CreateCanister(req) => create_canister_response(&req).await,
69 Request::UpgradeCanister(req) => upgrade_canister_response(&req).await,
70 Request::Cycles(req) => cycles_response(&req).await,
71 }
72}
73
74async fn create_canister_response(req: &CreateCanisterRequest) -> Result<Response, Error> {
76 let caller = msg_caller();
77
78 let parent_pid = match &req.parent {
80 CreateCanisterParent::Canister(pid) => *pid,
81 CreateCanisterParent::Root => canister_self(),
82 CreateCanisterParent::ThisCanister => caller,
83
84 CreateCanisterParent::Parent => SubnetCanisterRegistryOps::try_get_parent(caller)
85 .map_err(|_| RequestOpsError::ParentNotFound(caller))?,
86
87 CreateCanisterParent::Directory(ty) => {
88 SubnetCanisterRegistryOps::try_get_type(ty)
89 .map_err(|_| RequestOpsError::CanisterRoleNotFound(ty.clone()))?
90 .pid
91 }
92 };
93
94 let new_canister_pid =
95 create_and_install_canister(&req.canister_role, parent_pid, req.extra_arg.clone()).await?;
96
97 Ok(Response::CreateCanister(CreateCanisterResponse {
98 new_canister_pid,
99 }))
100}
101
102async fn upgrade_canister_response(req: &UpgradeCanisterRequest) -> Result<Response, Error> {
104 let caller = msg_caller();
105 let registry_entry = SubnetCanisterRegistryOps::try_get(req.canister_pid)
106 .map_err(|_| RequestOpsError::ChildNotFound(req.canister_pid))?;
107
108 if registry_entry.parent_pid != Some(caller) {
109 return Err(RequestOpsError::NotChildOfCaller(req.canister_pid, caller).into());
110 }
111
112 let wasm = WasmOps::try_get(®istry_entry.ty)?;
114 upgrade_canister(registry_entry.pid, wasm.bytes()).await?;
115 SubnetCanisterRegistryOps::update_module_hash(registry_entry.pid, wasm.module_hash())?;
116
117 Ok(Response::UpgradeCanister(UpgradeCanisterResponse {}))
118}
119
120async fn cycles_response(req: &CyclesRequest) -> Result<Response, Error> {
122 deposit_cycles(msg_caller(), req.cycles).await?;
123
124 let cycles_transferred = req.cycles;
125
126 Ok(Response::Cycles(CyclesResponse { cycles_transferred }))
127}