canic_core/ops/rpc/
response.rs1use crate::{
9 Error,
10 log::Topic,
11 ops::{
12 ic::deposit_cycles,
13 orchestration::orchestrator::{CanisterLifecycleOrchestrator, LifecycleEvent},
14 prelude::*,
15 rpc::{
16 CreateCanisterParent, CreateCanisterRequest, CyclesRequest, Request, RequestOpsError,
17 UpgradeCanisterRequest,
18 },
19 storage::topology::subnet::SubnetCanisterRegistryOps,
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 let role = req.canister_role.clone();
78 let parent_desc = format!("{:?}", &req.parent);
79
80 let result: Result<Response, Error> = async {
81 let parent_pid = match &req.parent {
83 CreateCanisterParent::Canister(pid) => *pid,
84 CreateCanisterParent::Root => canister_self(),
85 CreateCanisterParent::ThisCanister => caller,
86
87 CreateCanisterParent::Parent => SubnetCanisterRegistryOps::try_get_parent(caller)
88 .map_err(|_| RequestOpsError::ParentNotFound(caller))?,
89
90 CreateCanisterParent::Directory(role) => {
91 SubnetCanisterRegistryOps::try_get_type(role)
92 .map_err(|_| RequestOpsError::CanisterRoleNotFound(role.clone()))?
93 .pid
94 }
95 };
96
97 let event = LifecycleEvent::Create {
98 role: req.canister_role.clone(),
99 parent: parent_pid,
100 extra_arg: req.extra_arg.clone(),
101 };
102
103 let result = CanisterLifecycleOrchestrator::apply(event).await?;
104 let new_canister_pid = result
105 .new_canister_pid
106 .ok_or(RequestOpsError::MissingNewCanisterPid)?;
107
108 Ok(Response::CreateCanister(CreateCanisterResponse {
109 new_canister_pid,
110 }))
111 }
112 .await;
113
114 if let Err(err) = &result {
115 log!(
116 Topic::CanisterLifecycle,
117 Warn,
118 "create_canister_response failed (caller={caller}, role={role}, parent={parent_desc}): {err}"
119 );
120 }
121
122 result
123}
124
125async fn upgrade_canister_response(req: &UpgradeCanisterRequest) -> Result<Response, Error> {
127 let caller = msg_caller();
128
129 let registry_entry = SubnetCanisterRegistryOps::try_get(req.canister_pid)
130 .map_err(|_| RequestOpsError::ChildNotFound(req.canister_pid))?;
131
132 if registry_entry.parent_pid != Some(caller) {
133 return Err(RequestOpsError::NotChildOfCaller(req.canister_pid, caller).into());
134 }
135
136 let event = LifecycleEvent::Upgrade {
137 pid: registry_entry.pid,
138 };
139
140 CanisterLifecycleOrchestrator::apply(event).await?;
141
142 Ok(Response::UpgradeCanister(UpgradeCanisterResponse {}))
143}
144
145async fn cycles_response(req: &CyclesRequest) -> Result<Response, Error> {
147 deposit_cycles(msg_caller(), req.cycles).await?;
148
149 let cycles_transferred = req.cycles;
150
151 Ok(Response::Cycles(CyclesResponse { cycles_transferred }))
152}