ic_cdk/api/mod.rs
1//! System API and low level functions for it.
2use candid::Principal;
3use std::convert::TryFrom;
4
5pub mod call;
6pub mod management_canister;
7pub mod stable;
8
9/// Prints the given message.
10pub fn print<S: std::convert::AsRef<str>>(s: S) {
11 let s = s.as_ref();
12 // SAFETY: `s`, being &str, is a readable sequence of bytes and therefore can be passed to ic0.debug_print.
13 unsafe {
14 ic0::debug_print(s.as_ptr() as i32, s.len() as i32);
15 }
16}
17
18/// Traps with the given message.
19pub fn trap(message: &str) -> ! {
20 // SAFETY: `message`, being &str, is a readable sequence of bytes and therefore can be passed to ic0.trap.
21 unsafe {
22 ic0::trap(message.as_ptr() as i32, message.len() as i32);
23 }
24 unreachable!()
25}
26
27/// Get current timestamp, in nanoseconds since the epoch (1970-01-01)
28pub fn time() -> u64 {
29 // SAFETY: ic0.time is always safe to call.
30 unsafe { ic0::time() as u64 }
31}
32
33/// Returns the caller of the current call.
34pub fn caller() -> Principal {
35 // SAFETY: ic0.msg_caller_size is always safe to call.
36 let len: u32 = unsafe { ic0::msg_caller_size() as u32 };
37 let mut bytes = vec![0u8; len as usize];
38 // SAFETY: Because `bytes` is mutable, and allocated to `len` bytes, it is safe to be passed to `ic0.msg_caller_copy` with a 0-offset.
39 unsafe {
40 ic0::msg_caller_copy(bytes.as_mut_ptr() as i32, 0, len as i32);
41 }
42 Principal::try_from(&bytes).unwrap()
43}
44
45/// Returns the canister id as a blob.
46pub fn id() -> Principal {
47 // SAFETY: ic0.canister_self_size is always safe to call.
48 let len: u32 = unsafe { ic0::canister_self_size() as u32 };
49 let mut bytes = vec![0u8; len as usize];
50 // SAFETY: Because `bytes` is mutable, and allocated to `len` bytes, it is safe to be passed to `ic0.canister_self_copy` with a 0-offset.
51 unsafe {
52 ic0::canister_self_copy(bytes.as_mut_ptr() as i32, 0, len as i32);
53 }
54 Principal::try_from(&bytes).unwrap()
55}
56
57/// Get the amount of funds available in the canister.
58pub fn canister_balance() -> u64 {
59 // SAFETY: ic0.canister_cycle_balance is always safe to call.
60 unsafe { ic0::canister_cycle_balance() as u64 }
61}
62
63/// Get the amount of funds available in the canister.
64pub fn canister_balance128() -> u128 {
65 let mut recv = 0u128;
66 // SAFETY: recv is writable and the size expected by ic0.canister_cycle_balance128.
67 unsafe { ic0::canister_cycle_balance128(&mut recv as *mut u128 as i32) }
68 recv
69}
70
71/// Sets the certified data of this canister.
72///
73/// Canisters can store up to 32 bytes of data that is certified by
74/// the system on a regular basis. One can call [data_certificate]
75/// function from a query call to get a certificate authenticating the
76/// value set by calling this function.
77///
78/// This function can only be called from the following contexts:
79/// * "canister_init", "canister_pre_upgrade" and "canister_post_upgrade"
80/// hooks.
81/// * "canister_update" calls.
82/// * reply or reject callbacks.
83///
84/// # Panics
85///
86/// * This function traps if data.len() > 32.
87/// * This function traps if it's called from an illegal context
88/// (e.g., from a query call).
89pub fn set_certified_data(data: &[u8]) {
90 // SAFETY: because data is a slice ref, its pointer and length are valid to pass to ic0.certified_data_set.
91 unsafe { ic0::certified_data_set(data.as_ptr() as i32, data.len() as i32) }
92}
93
94/// When called from a query call, returns the data certificate authenticating
95/// certified_data set by this canister.
96///
97/// Returns None if called not from a query call.
98pub fn data_certificate() -> Option<Vec<u8>> {
99 // SAFETY: ic0.data_certificate_present is always safe to call.
100 if unsafe { ic0::data_certificate_present() } == 0 {
101 return None;
102 }
103
104 // SAFETY: ic0.data_certificate_size is always safe to call.
105 let n = unsafe { ic0::data_certificate_size() };
106 let mut buf = vec![0u8; n as usize];
107 // SAFETY: Because `buf` is mutable and allocated to `n` bytes, it is valid to receive from ic0.data_certificate_bytes with no offset
108 unsafe {
109 ic0::data_certificate_copy(buf.as_mut_ptr() as i32, 0i32, n);
110 }
111 Some(buf)
112}
113
114/// Returns the number of instructions that the canister executed since the last [entry
115/// point](https://internetcomputer.org/docs/current/references/ic-interface-spec/#entry-points).
116#[inline]
117pub fn instruction_counter() -> u64 {
118 performance_counter(0)
119}
120
121/// Get the value of specified performance counter.
122///
123/// Supported counter type:
124/// 0 : instruction counter. The number of WebAssembly instructions the system has determined that the canister has executed.
125#[inline]
126pub fn performance_counter(counter_type: u32) -> u64 {
127 // SAFETY: ic0.performance_counter is always safe to call.
128 unsafe { ic0::performance_counter(counter_type as i32) as u64 }
129}
130
131/// Get the value of canister version.
132pub fn canister_version() -> u64 {
133 // SAFETY: ic0.canister_version is always safe to call.
134 unsafe { ic0::canister_version() as u64 }
135}
136
137/// Determine if a Principal is a controller of the canister.
138pub fn is_controller(principal: &Principal) -> bool {
139 let slice = principal.as_slice();
140 // SAFETY: `principal.as_bytes()`, being `&[u8]`, is a readable sequence of bytes and therefore safe to pass to `ic0.is_controller`.
141 unsafe { ic0::is_controller(slice.as_ptr() as i32, slice.len() as i32) != 0 }
142}