canic_core/ops/runtime/
mod.rs1pub mod cycles;
2pub mod log;
3pub mod metrics;
4
5use crate::{
6 VERSION,
7 cdk::{
8 api::{canister_self, trap},
9 println,
10 types::Principal,
11 },
12 ids::{CanisterRole, SubnetRole},
13 log::Topic,
14 ops::{
15 ic::{Network, build_network},
16 service::TimerService,
17 storage::{
18 CanisterInitPayload,
19 directory::{AppDirectoryOps, SubnetDirectoryOps},
20 env::{EnvData, EnvOps},
21 memory::MemoryRegistryOps,
22 topology::{SubnetCanisterRegistryOps, SubnetIdentity},
23 },
24 },
25};
26use canic_memory::runtime::init_eager_tls;
27
28fn init_memory_or_trap(phase: &str) {
29 if let Err(err) = MemoryRegistryOps::init_memory() {
30 println!("[canic] FATAL: memory init failed during {phase}: {err}");
31 let msg = format!("canic init failed during {phase}: memory init failed: {err}");
32 trap(&msg);
33 }
34}
35
36fn ensure_nonroot_env(canister_role: CanisterRole, mut env: EnvData) -> EnvData {
37 let mut missing = Vec::new();
38 if env.prime_root_pid.is_none() {
39 missing.push("prime_root_pid");
40 }
41 if env.subnet_role.is_none() {
42 missing.push("subnet_role");
43 }
44 if env.subnet_pid.is_none() {
45 missing.push("subnet_pid");
46 }
47 if env.root_pid.is_none() {
48 missing.push("root_pid");
49 }
50 if env.canister_role.is_none() {
51 missing.push("canister_role");
52 }
53 if env.parent_pid.is_none() {
54 missing.push("parent_pid");
55 }
56
57 if missing.is_empty() {
58 return env;
59 }
60
61 assert!(
62 build_network() != Some(Network::Ic),
63 "nonroot init missing env fields on ic: {}",
64 missing.join(", ")
65 );
66
67 let root_pid = Principal::from_slice(&[0xBB; 29]);
68 let subnet_pid = Principal::from_slice(&[0xAA; 29]);
69
70 env.prime_root_pid.get_or_insert(root_pid);
71 env.subnet_role.get_or_insert(SubnetRole::PRIME);
72 env.subnet_pid.get_or_insert(subnet_pid);
73 env.root_pid.get_or_insert(root_pid);
74 env.canister_role.get_or_insert(canister_role);
75 env.parent_pid.get_or_insert(root_pid);
76
77 env
78}
79
80pub fn root_init(identity: SubnetIdentity) {
83 println!("");
87 println!("");
88 println!("");
89 crate::log!(
90 Topic::Init,
91 Info,
92 "🔧 --------------------- 'canic v{VERSION} -----------------------",
93 );
94 crate::log!(Topic::Init, Info, "🏁 init: root ({identity:?})");
95
96 init_eager_tls();
98 init_memory_or_trap("root_init");
99
100 let self_pid = canister_self();
102 EnvOps::set_canister_role(CanisterRole::ROOT);
103 EnvOps::set_root_pid(self_pid);
104
105 match identity {
106 SubnetIdentity::Prime => {
107 EnvOps::set_prime_root_pid(self_pid);
108 EnvOps::set_subnet_role(SubnetRole::PRIME);
109 EnvOps::set_subnet_pid(self_pid);
110 }
111 SubnetIdentity::Standard(params) => {
112 EnvOps::set_prime_root_pid(params.prime_root_pid);
113 EnvOps::set_subnet_role(params.subnet_type);
114 EnvOps::set_subnet_pid(self_pid);
115 }
116 SubnetIdentity::Manual(subnet_pid) => {
117 EnvOps::set_prime_root_pid(self_pid);
118 EnvOps::set_subnet_role(SubnetRole::PRIME);
119 EnvOps::set_subnet_pid(subnet_pid);
120 }
121 }
122
123 SubnetCanisterRegistryOps::register_root(self_pid);
124
125 TimerService::start_all_root();
127}
128
129pub fn root_post_upgrade() {
131 crate::log!(Topic::Init, Info, "🏁 post_upgrade: root");
133 init_eager_tls();
134 init_memory_or_trap("root_post_upgrade");
135
136 TimerService::start_all_root();
140}
141
142pub fn nonroot_init(canister_role: CanisterRole, payload: CanisterInitPayload) {
144 crate::log!(Topic::Init, Info, "🏁 init: {}", canister_role);
146 init_eager_tls();
147 init_memory_or_trap("nonroot_init");
148
149 let env = ensure_nonroot_env(canister_role, payload.env);
151 if let Err(err) = EnvOps::import(env) {
152 println!("[canic] FATAL: env import failed during nonroot_init: {err}");
153 let msg = format!("canic init failed during nonroot_init: env import failed: {err}");
154 trap(&msg);
155 }
156 AppDirectoryOps::import(payload.app_directory);
157 SubnetDirectoryOps::import(payload.subnet_directory);
158
159 TimerService::start_all();
161}
162
163pub fn nonroot_post_upgrade(canister_role: CanisterRole) {
165 crate::log!(Topic::Init, Info, "🏁 post_upgrade: {}", canister_role);
167 init_eager_tls();
168 init_memory_or_trap("nonroot_post_upgrade");
169
170 TimerService::start_all();
174}