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/// Gets 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/// Gets 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/// Gets 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/// Returns the number of WebAssembly instructions the canister has executed
122/// within the call context of the current Message execution since
123/// Call context creation.
124///
125/// The counter monotonically increases across all message executions
126/// in the call context until the corresponding call context is removed.
127#[inline]
128pub fn call_context_instruction_counter() -> u64 {
129    performance_counter(1)
130}
131
132/// Gets the value of specified performance counter.
133///
134/// Supported counter types:
135/// * `0` : current execution instruction counter. The number of WebAssembly
136///         instructions the canister has executed since the beginning of the
137///         current Message execution.
138/// * `1` : call context instruction counter. The number of WebAssembly
139///         instructions the canister has executed within the call context
140///         of the current Message execution since Call context creation.
141///         The counter monotonically increases across all message executions
142///         in the call context until the corresponding call context is removed.
143#[inline]
144pub fn performance_counter(counter_type: u32) -> u64 {
145    // SAFETY: ic0.performance_counter is always safe to call.
146    unsafe { ic0::performance_counter(counter_type as i32) as u64 }
147}
148
149/// Gets the value of canister version.
150pub fn canister_version() -> u64 {
151    // SAFETY: ic0.canister_version is always safe to call.
152    unsafe { ic0::canister_version() as u64 }
153}
154
155/// Determines if a Principal is a controller of the canister.
156pub fn is_controller(principal: &Principal) -> bool {
157    let slice = principal.as_slice();
158    // SAFETY: `principal.as_bytes()`, being `&[u8]`, is a readable sequence of bytes and therefore safe to pass to `ic0.is_controller`.
159    unsafe { ic0::is_controller(slice.as_ptr() as i32, slice.len() as i32) != 0 }
160}
161
162/// Burns cycles from the canister.
163///
164/// Returns the amount of cycles that were actually burned.
165pub fn cycles_burn(amount: u128) -> u128 {
166    let amount_high = (amount >> 64) as u64;
167    let amount_low = (amount & u64::MAX as u128) as u64;
168    let mut dst = 0u128;
169    // SAFETY: `dst` is writable and sixteen bytes wide, and therefore safe to pass to ic0.cycles_burn128
170    unsafe {
171        ic0::cycles_burn128(
172            amount_high as i64,
173            amount_low as i64,
174            &mut dst as *mut u128 as i32,
175        )
176    }
177    dst
178}