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