ic0/lib.rs
1//! Bindings to the [Internet Computer system API](https://internetcomputer.org/docs/current/references/ic-interface-spec#system-api-imports).
2//!
3//! The raw bindings can be found in the [`sys`] module. The functions in the crate root provide slightly higher-level
4//! bindings in terms of slices instead of pointers/lengths, accurately typed pointers, etc., but otherwise does not adapt
5//! the API. Where this is all that is needed for the functions to be safe, they are marked as safe, but function pointers
6//! cannot be made safe and as such `call_new` is still unsafe.
7//!
8//! Any function `ic0.foo` that would write to a user buffer has two versions, `foo` which takes `&mut [u8]` and
9//! `foo_uninit` which takes `&mut [MaybeUninit<u8>]`.
10
11#![warn(
12 elided_lifetimes_in_paths,
13 missing_debug_implementations,
14 unsafe_op_in_unsafe_fn,
15 clippy::undocumented_unsafe_blocks,
16 clippy::missing_safety_doc
17)]
18
19use std::mem::MaybeUninit;
20
21pub mod sys;
22
23#[inline]
24pub fn msg_arg_data_size() -> usize {
25 // SAFETY: ic0.msg_arg_data_size is always safe to call
26 unsafe { sys::msg_arg_data_size() }
27}
28
29#[inline]
30pub fn msg_arg_data_copy(dst: &mut [u8], offset: usize) {
31 // SAFETY: dst is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.msg_arg_data_copy
32 // The offset parameter does not affect safety
33 unsafe { sys::msg_arg_data_copy(dst.as_mut_ptr() as usize, offset, dst.len()) }
34}
35
36/// # Safety
37///
38/// This function will fully initialize `dst` (or trap if it cannot).
39#[inline]
40pub fn msg_arg_data_copy_uninit(dst: &mut [MaybeUninit<u8>], offset: usize) {
41 // SAFETY: dst is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.msg_arg_data_copy
42 // The offset parameter does not affect safety
43 unsafe { sys::msg_arg_data_copy(dst.as_mut_ptr() as usize, offset, dst.len()) }
44}
45
46#[inline]
47pub fn msg_caller_size() -> usize {
48 // SAFETY: ic0.msg_caller_size is always safe to call
49 unsafe { sys::msg_caller_size() }
50}
51
52#[inline]
53pub fn msg_caller_copy(dst: &mut [u8], offset: usize) {
54 // SAFETY: dst is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.msg_caller_copy
55 // The offset parameter does not affect safety
56 unsafe { sys::msg_caller_copy(dst.as_mut_ptr() as usize, offset, dst.len()) }
57}
58
59/// # Safety
60///
61/// This function will fully initialize `dst` (or trap if it cannot).
62#[inline]
63pub fn msg_caller_copy_uninit(dst: &mut [MaybeUninit<u8>], offset: usize) {
64 // SAFETY: dst is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.msg_caller_copy
65 // The offset parameter does not affect safety
66 unsafe { sys::msg_caller_copy(dst.as_mut_ptr() as usize, offset, dst.len()) }
67}
68
69#[inline]
70pub fn msg_reject_code() -> u32 {
71 // SAFETY: ic0.msg_reject_code is always safe to call
72 unsafe { sys::msg_reject_code() }
73}
74
75#[inline]
76pub fn msg_reject_msg_size() -> usize {
77 // SAFETY: ic0.msg_reject_msg_size is always safe to call
78 unsafe { sys::msg_reject_msg_size() }
79}
80
81#[inline]
82pub fn msg_reject_msg_copy(dst: &mut [u8], offset: usize) {
83 // SAFETY: dst is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.msg_reject_msg_copy
84 // The offset parameter does not affect safety
85 unsafe { sys::msg_reject_msg_copy(dst.as_mut_ptr() as usize, offset, dst.len()) }
86}
87
88/// # Safety
89///
90/// This function will fully initialize `dst` (or trap if it cannot).
91#[inline]
92pub fn msg_reject_msg_copy_uninit(dst: &mut [MaybeUninit<u8>], offset: usize) {
93 // SAFETY: dst is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.msg_reject_msg_copy
94 // The offset parameter does not affect safety
95 unsafe { sys::msg_reject_msg_copy(dst.as_mut_ptr() as usize, offset, dst.len()) }
96}
97
98#[inline]
99pub fn msg_deadline() -> u64 {
100 // SAFETY: ic0.msg_deadline is always safe to call
101 unsafe { sys::msg_deadline() }
102}
103
104#[inline]
105pub fn msg_reply_data_append(data: &[u8]) {
106 // SAFETY: data is a readable sequence of bytes and therefore safe to pass as ptr and len to ic0.msg_reply_data_append
107 unsafe { sys::msg_reply_data_append(data.as_ptr() as usize, data.len()) }
108}
109
110#[inline]
111pub fn msg_reply() {
112 // SAFETY: ic0.msg_reply is always safe to call
113 unsafe { sys::msg_reply() }
114}
115
116#[inline]
117pub fn msg_reject(message: &[u8]) {
118 // SAFETY: message is a readable sequence of bytes and therefore safe to pass as ptr and len to ic0.msg_reject
119 unsafe { sys::msg_reject(message.as_ptr() as usize, message.len()) }
120}
121
122#[inline]
123pub fn msg_cycles_available128() -> u128 {
124 let mut dst_bytes = [0_u8; 16];
125 // SAFETY: dst_bytes is a writable sequence of 16 bytes and therefore safe to pass as ptr to ic0.msg_cycles_available128
126 unsafe {
127 sys::msg_cycles_available128(dst_bytes.as_mut_ptr() as usize);
128 }
129 u128::from_le_bytes(dst_bytes)
130}
131
132#[inline]
133pub fn msg_cycles_refunded128() -> u128 {
134 let mut dst_bytes = [0_u8; 16];
135 // SAFETY: dst_bytes is a writable sequence of 16 bytes and therefore safe to pass as ptr to ic0.msg_cycles_refunded128
136 unsafe {
137 sys::msg_cycles_refunded128(dst_bytes.as_mut_ptr() as usize);
138 }
139 u128::from_le_bytes(dst_bytes)
140}
141
142#[inline]
143pub fn msg_cycles_accept128(max: u128) -> u128 {
144 let (high, low) = to_high_low(max);
145 let mut dst_bytes = [0_u8; 16];
146 // SAFETY: dst_bytes is a writable sequence of 16 bytes and therefore safe to pass as ptr to ic0.msg_cycles_accept128
147 // The max_amount_high and max_amount_low parameters do not affect safety
148 unsafe {
149 sys::msg_cycles_accept128(high, low, dst_bytes.as_mut_ptr() as usize);
150 }
151 u128::from_le_bytes(dst_bytes)
152}
153
154#[inline]
155pub fn cycles_burn128(amount: u128) -> u128 {
156 let (high, low) = to_high_low(amount);
157 let mut dst_bytes = [0_u8; 16];
158 // SAFETY: dst_bytes is a writable sequence of 16 bytes and therefore safe to pass to ic0.cycles_burn128
159 // The amount_high and amount_low parameters do not affect safety
160 unsafe {
161 sys::cycles_burn128(high, low, dst_bytes.as_mut_ptr() as usize);
162 }
163 u128::from_le_bytes(dst_bytes)
164}
165
166#[inline]
167pub fn canister_self_size() -> usize {
168 // SAFETY: ic0.canister_self_size is always safe to call
169 unsafe { sys::canister_self_size() }
170}
171
172#[inline]
173pub fn canister_self_copy(dst: &mut [u8], offset: usize) {
174 // SAFETY: dst is a writable sequence of bytes and therefore safe to pass to ic0.canister_self_copy
175 // The offset parameter does not affect safety
176 unsafe { sys::canister_self_copy(dst.as_mut_ptr() as usize, offset, dst.len()) }
177}
178
179#[inline]
180pub fn canister_cycle_balance128() -> u128 {
181 let mut dst_bytes = [0_u8; 16];
182 // SAFETY: dst_bytes is a writable sequence of 16 bytes and therefore safe to pass to ic0.canister_cycle_balance128
183 unsafe {
184 sys::canister_cycle_balance128(dst_bytes.as_mut_ptr() as usize);
185 }
186 u128::from_le_bytes(dst_bytes)
187}
188
189#[inline]
190pub fn canister_liquid_cycle_balance128() -> u128 {
191 let mut dst_bytes = [0_u8; 16];
192 // SAFETY: dst_bytes is a writable sequence of 16 bytes and therefore safe to pass to ic0.canister_liquid_cycle_balance128
193 unsafe {
194 sys::canister_liquid_cycle_balance128(dst_bytes.as_mut_ptr() as usize);
195 }
196 u128::from_le_bytes(dst_bytes)
197}
198
199#[inline]
200pub fn canister_status() -> u32 {
201 // SAFETY: ic0.canister_status is always safe to call.
202 unsafe { sys::canister_status() }
203}
204
205#[inline]
206pub fn canister_version() -> u64 {
207 // SAFETY: ic0.canister_version is always safe to call.
208 unsafe { sys::canister_version() }
209}
210
211#[inline]
212pub fn subnet_self_size() -> usize {
213 // SAFETY: ic0.subnet_self_size is always safe to call.
214 unsafe { sys::subnet_self_size() }
215}
216
217#[inline]
218pub fn subnet_self_copy(dst: &mut [u8], offset: usize) {
219 // SAFETY: dst is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.subnet_self_copy
220 // The offset parameter does not affect safety
221 unsafe { sys::subnet_self_copy(dst.as_mut_ptr() as usize, offset, dst.len()) }
222}
223
224/// # Safety
225///
226/// This function will fully initialize `dst` (or trap if it cannot).
227#[inline]
228pub fn subnet_self_copy_uninit(dst: &mut [MaybeUninit<u8>], offset: usize) {
229 // SAFETY: dst is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.subnet_self_copy
230 // The offset parameter does not affect safety
231 unsafe { sys::subnet_self_copy(dst.as_mut_ptr() as usize, offset, dst.len()) }
232}
233
234#[inline]
235pub fn msg_method_name_size() -> usize {
236 // SAFETY: ic0.msg_method_name_size is always safe to call
237 unsafe { sys::msg_method_name_size() }
238}
239
240#[inline]
241pub fn msg_method_name_copy(dst: &mut [u8], offset: usize) {
242 // SAFETY: dst is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.msg_method_name_copy
243 // The offset parameter does not affect safety
244 unsafe { sys::msg_method_name_copy(dst.as_mut_ptr() as usize, offset, dst.len()) }
245}
246
247/// # Safety
248///
249/// This function will fully initialize `dst` (or trap if it cannot).
250#[inline]
251pub fn msg_method_name_copy_uninit(dst: &mut [MaybeUninit<u8>], offset: usize) {
252 // SAFETY: dst is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.msg_method_name_copy
253 // The offset parameter does not affect safety
254 unsafe { sys::msg_method_name_copy(dst.as_mut_ptr() as usize, offset, dst.len()) }
255}
256
257#[inline]
258pub fn accept_message() {
259 // SAFETY: ic0.accept_message is always safe to call
260 unsafe { sys::accept_message() }
261}
262
263/// # Safety
264///
265/// - `reply_fn` is required to be safely callable as a canister entrypoint with `reply_env`.
266/// - `reject_fn` is required to be safely callable as a canister entrypoint with `reject_env`.
267/// - Ownership of `reply_env` and `reject_env` is acquired by this function.
268/// - `reply_fn`, if called, will receive ownership of `reply_env`, `reject_env`, and [`cleanup_env`](call_on_cleanup).
269/// - `reject_fn`, if called, will receive ownership of `reply_env`, `reject_env`, and [`cleanup_env`](call_on_cleanup).
270#[inline]
271pub unsafe fn call_new(
272 callee: &[u8],
273 name: &str,
274 reply_fn: unsafe extern "C" fn(env: usize),
275 reply_env: usize,
276 reject_fn: unsafe extern "C" fn(env: usize),
277 reject_env: usize,
278) {
279 // SAFETY:
280 // - callee, being &[u8], is a readable sequence of bytes and therefore safe to pass as ptr and len
281 // as the callee in ic0.call_new
282 // - name is a readable string and therefore safe to pass as ptr and len as the name in ic0.call_new
283 // - reply_fn is a function with signature (env : usize) -> () and required to be a safe entrypoint if reply_env is used
284 // as the env, and is therefore safe to pass as the reply fn for ic0.call_new if reply_env is passed as the reply env
285 // - reply_env is the correct env parameter for reply_fn
286 // - reject_fn is a function with signature (env : usize) -> () and required to be a safe entrypoint if reject_env is used
287 // as the env, and is therefore safe to pass as the reject fn for ic0.call_new if reject_env is passed as the reject env
288 // - reject_env is the correct env parameter for reject_fn
289 unsafe {
290 sys::call_new(
291 callee.as_ptr() as usize,
292 callee.len(),
293 name.as_ptr() as usize,
294 name.len(),
295 reply_fn as usize,
296 reply_env,
297 reject_fn as usize,
298 reject_env,
299 );
300 }
301}
302
303#[inline]
304pub fn call_new_oneway(callee: &[u8], name: &str) {
305 // SAFETY:
306 // - callee, being &[u8], is a readable sequence of bytes and therefore safe to pass as ptr and len
307 // as the callee in ic0.call_new
308 // - name is a readable string and therefore safe to pass as ptr and len as the name in ic0.call_new
309 // - `usize::MAX` is a function pointer the wasm module cannot possibly contain and is therefore safe to pass as
310 // `reply_fun` and `reject_fun` to ic0.call_new
311 // - When the `reply_fun` and `reject_fun` functions do not exist and therefore will never be called, any value
312 // is safe to pass as `reply_env` and `reject_env` to `ic0.call_new`
313 //
314 // See https://www.joachim-breitner.de/blog/789-Zero-downtime_upgrades_of_Internet_Computer_canisters#one-way-calls for more context.
315 unsafe {
316 sys::call_new(
317 callee.as_ptr() as usize,
318 callee.len(),
319 name.as_ptr() as usize,
320 name.len(),
321 usize::MAX,
322 usize::MAX,
323 usize::MAX,
324 usize::MAX,
325 );
326 }
327}
328
329/// # Safety
330///
331/// - `cleanup_fn` is required to be safely callable as a canister entrypoint with `cleanup_env`.
332/// - Ownership of `cleanup_env` is acquired by this function.
333/// - `cleanup_fn`, if called, will receive ownership of `cleanup_env`, [`reply_env`](call_new), and [`reject_env`](call_new)
334#[inline]
335pub unsafe fn call_on_cleanup(cleanup_fn: unsafe extern "C" fn(env: usize), cleanup_env: usize) {
336 // SAFETY:
337 // - cleanup_fn is a function with signature (env : usize) -> () and required to be a safe entrypoint if cleanup_env is used
338 // as the env, and is therefore safe to pass as the fn for ic0.call_on_cleanup if cleanup_env is passed as the env
339 // - cleanup_env is the correct env parameter for cleanup_fn
340 unsafe {
341 sys::call_on_cleanup(cleanup_fn as usize, cleanup_env);
342 }
343}
344
345#[inline]
346pub fn call_data_append(data: &[u8]) {
347 // SAFETY: data is a readable sequence of bytes and therefore safe to pass as ptr and len to ic0.call_data_append
348 unsafe { sys::call_data_append(data.as_ptr() as usize, data.len()) }
349}
350
351#[inline]
352pub fn call_with_best_effort_response(timeout_seconds: u32) {
353 // SAFETY: ic0.call_with_best_effort_response is always safe to call
354 unsafe { sys::call_with_best_effort_response(timeout_seconds) }
355}
356
357#[inline]
358pub fn call_cycles_add128(amount: u128) {
359 let (high, low) = to_high_low(amount);
360 // SAFETY: ic0.call_cycles_add128 is always safe to call
361 unsafe { sys::call_cycles_add128(high, low) }
362}
363
364/// # Safety
365///
366/// If `call_perform` returns a nonzero value, the ownership of [`reply_env`](call_new), [`reject_env`](call_new), and
367/// [`cleanup_env`](call_on_cleanup) is released to the caller.
368///
369/// If `call_perform` returns 0, then (from the perspective of safety, *not* semantics) exactly one of
370/// [`reply_fn`](call_new), [`reject_fn`](call_new), or [`cleanup_fn`](call_on_cleanup) will be called, exactly once.
371#[inline]
372pub fn call_perform() -> u32 {
373 // SAFETY: ic0.call_perform is always safe to call
374 unsafe { sys::call_perform() }
375}
376
377#[inline]
378pub fn stable64_size() -> u64 {
379 // SAFETY: ic0.stable64_size is always safe to call
380 unsafe { sys::stable64_size() }
381}
382
383#[inline]
384pub fn stable64_grow(new_pages: u64) -> u64 {
385 // SAFETY: ic0.stable64_grow is always safe to call
386 unsafe { sys::stable64_grow(new_pages) }
387}
388
389#[inline]
390pub fn stable64_write(data: &[u8], offset: u64) {
391 // SAFETY: data is a readable sequence of bytes and therefore is safe to pass as ptr and len to ic0.stable64_write
392 // The offset parameter does not affect safety
393 unsafe { sys::stable64_write(offset, data.as_ptr() as usize as u64, data.len() as u64) }
394}
395
396#[inline]
397pub fn stable64_read(dst: &mut [u8], offset: u64) {
398 // SAFETY: dst is a writable sequence of bytes and therefore is safe to pass as ptr and len to ic0.stable64_read
399 // The offset parameter does not affect safety
400 unsafe { sys::stable64_read(dst.as_mut_ptr() as usize as u64, offset, dst.len() as u64) }
401}
402
403/// # Safety
404///
405/// This function will fully initialize `dst` (or trap if it cannot).
406#[inline]
407pub fn stable64_read_uninit(dst: &mut [MaybeUninit<u8>], offset: u64) {
408 // SAFETY: dst is a writable sequence of bytes and therefore is safe to pass as ptr and len to ic0.stable64_read
409 // The offset parameter does not affect safety
410 unsafe { sys::stable64_read(dst.as_mut_ptr() as usize as u64, offset, dst.len() as u64) }
411}
412
413#[inline]
414pub fn root_key_size() -> usize {
415 // SAFETY: ic0.root_key_size is always safe to call
416 unsafe { sys::root_key_size() }
417}
418
419#[inline]
420pub fn root_key_copy(dst: &mut [u8], offset: usize) {
421 // SAFETY: dst is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.root_key_copy
422 // The offset parameter does not affect safety
423 unsafe { sys::root_key_copy(dst.as_mut_ptr() as usize, offset, dst.len()) }
424}
425
426/// # Safety
427///
428/// This function will fully initialize `dst` (or trap if it cannot).
429#[inline]
430pub fn root_key_copy_uninit(dst: &mut [MaybeUninit<u8>], offset: usize) {
431 // SAFETY: dst is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.root_key_copy
432 // The offset parameter does not affect safety
433 unsafe { sys::root_key_copy(dst.as_mut_ptr() as usize, offset, dst.len()) }
434}
435
436#[inline]
437pub fn certified_data_set(data: &[u8]) {
438 // SAFETY: data is a readable sequence of bytes and therefore safe to pass as ptr and len to ic0.certified_data_set
439 unsafe { sys::certified_data_set(data.as_ptr() as usize, data.len()) }
440}
441
442#[inline]
443pub fn data_certificate_present() -> u32 {
444 // SAFETY: ic0.data_certificate_present is always safe to call
445 unsafe { sys::data_certificate_present() }
446}
447
448#[inline]
449pub fn data_certificate_size() -> usize {
450 // SAFETY: ic0.data_certificate_size is always safe to call
451 unsafe { sys::data_certificate_size() }
452}
453
454#[inline]
455pub fn data_certificate_copy(dst: &mut [u8], offset: usize) {
456 // SAFETY: dst, being &mut [u8], is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.data_certificate_copy
457 // The offset parameter does not affect safety
458 unsafe { sys::data_certificate_copy(dst.as_mut_ptr() as usize, offset, dst.len()) }
459}
460
461/// # Safety
462///
463/// This function will fully initialize `dst` (or trap if it cannot).
464#[inline]
465pub fn data_certificate_copy_uninit(dst: &mut [MaybeUninit<u8>], offset: usize) {
466 // SAFETY: dst, being &mut [u8], is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.data_certificate_copy
467 // The offset parameter does not affect safety
468 unsafe { sys::data_certificate_copy(dst.as_mut_ptr() as usize, offset, dst.len()) }
469}
470
471#[inline]
472pub fn time() -> u64 {
473 // SAFETY: ic0.time is always safe to call
474 unsafe { sys::time() }
475}
476
477#[inline]
478pub fn global_timer_set(timestamp: u64) -> u64 {
479 // SAFETY: ic0.global_timer_set is always safe to call
480 unsafe { sys::global_timer_set(timestamp) }
481}
482
483#[inline]
484pub fn performance_counter(counter_type: u32) -> u64 {
485 // SAFETY: ic0.performance_counter is always safe to call
486 unsafe { sys::performance_counter(counter_type) }
487}
488
489#[inline]
490pub fn is_controller(principal: &[u8]) -> u32 {
491 // SAFETY: principal is a readable sequence of bytes and therefore safe to pass as ptr and len to ic0.is_controller
492 unsafe { sys::is_controller(principal.as_ptr() as usize, principal.len()) }
493}
494
495#[inline]
496pub fn in_replicated_execution() -> u32 {
497 // SAFETY: ic0.in_replicated_execution is always safe to call
498 unsafe { sys::in_replicated_execution() }
499}
500
501#[inline]
502pub fn cost_call(method_name_size: u64, payload_size: u64) -> u128 {
503 let mut dst_bytes = [0_u8; 16];
504 // SAFETY: dst_bytes is a writable sequence of 16 bytes and therefore safe to pass as ptr to ic0.cost_call
505 // The method_name_size and payload_size parameters do not affect safety
506 unsafe {
507 sys::cost_call(
508 method_name_size,
509 payload_size,
510 dst_bytes.as_mut_ptr() as usize,
511 );
512 }
513 u128::from_le_bytes(dst_bytes)
514}
515
516#[inline]
517pub fn cost_create_canister() -> u128 {
518 let mut dst_bytes = [0_u8; 16];
519 // SAFETY: dst_bytes is a writable sequence of 16 bytes and therefore safe to pass as ptr to ic0.cost_create_canister
520 unsafe {
521 sys::cost_create_canister(dst_bytes.as_mut_ptr() as usize);
522 }
523 u128::from_le_bytes(dst_bytes)
524}
525
526#[inline]
527pub fn cost_http_request(request_size: u64, max_res_bytes: u64) -> u128 {
528 let mut dst_bytes = [0_u8; 16];
529 // SAFETY: dst_bytes is a writable sequence of 16 bytes and therefore safe to pass as ptr to ic0.cost_http_request
530 // The request_size and max_res_bytes parameters do not affect safety
531 unsafe {
532 sys::cost_http_request(request_size, max_res_bytes, dst_bytes.as_mut_ptr() as usize);
533 }
534 u128::from_le_bytes(dst_bytes)
535}
536
537#[inline]
538pub fn cost_sign_with_ecdsa(key_name: &str, ecdsa_curve: u32) -> (u128, u32) {
539 let mut dst_bytes = [0_u8; 16];
540 // SAFETY:
541 // - key_name is a readable string and therefore safe to pass as ptr and len src to ic0.cost_sign_with_ecdsa
542 // - dst_bytes is a writable sequence of 16 bytes and therefore safe to pass as ptr dst to ic0.cost_sign_with_ecdsa
543 // The ecdsa_curve parameter does not affect safety
544 let code = unsafe {
545 sys::cost_sign_with_ecdsa(
546 key_name.as_ptr() as usize,
547 key_name.len(),
548 ecdsa_curve,
549 dst_bytes.as_mut_ptr() as usize,
550 )
551 };
552 (u128::from_le_bytes(dst_bytes), code)
553}
554
555#[inline]
556pub fn cost_sign_with_schnorr(key_name: &str, algorithm: u32) -> (u128, u32) {
557 let mut dst_bytes = [0_u8; 16];
558 // SAFETY:
559 // - key_name is a readable string and therefore safe to pass as ptr and len src to ic0.cost_sign_with_schnorr
560 // - dst_bytes is a writable sequence of 16 bytes and therefore safe to pass as ptr dst to ic0.cost_sign_with_schnorr
561 // The algorithm parameter does not affect safety
562 let code = unsafe {
563 sys::cost_sign_with_schnorr(
564 key_name.as_ptr() as usize,
565 key_name.len(),
566 algorithm,
567 dst_bytes.as_mut_ptr() as usize,
568 )
569 };
570 (u128::from_le_bytes(dst_bytes), code)
571}
572
573#[inline]
574pub fn cost_vetkd_derive_key(key_name: &str, vetkd_curve: u32) -> (u128, u32) {
575 let mut dst_bytes = [0_u8; 16];
576 // SAFETY:
577 // - key_name is a readable string and therefore safe to pass as ptr and len path to ic0.cost_vetkd_derive_key
578 // - dst_bytes is a writable sequence of 16 bytes and therefore safe to pass as ptr dst to ic0.cost_vetkd_derive_key
579 // The vetkd_curve parameter does not affect safety
580 let code = unsafe {
581 sys::cost_vetkd_derive_key(
582 key_name.as_ptr() as usize,
583 key_name.len(),
584 vetkd_curve,
585 dst_bytes.as_mut_ptr() as usize,
586 )
587 };
588 (u128::from_le_bytes(dst_bytes), code)
589}
590
591#[inline]
592pub fn env_var_count() -> usize {
593 // SAFETY: ic0.env_var_count is always safe to call
594 unsafe { sys::env_var_count() }
595}
596
597#[inline]
598pub fn env_var_name_size(index: usize) -> usize {
599 // SAFETY: ic0.env_var_name_size is always safe to call
600 unsafe { sys::env_var_name_size(index) }
601}
602
603#[inline]
604pub fn env_var_name_copy(index: usize, dst: &mut [u8], offset: usize) {
605 // SAFETY: dst is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.env_var_name_copy
606 unsafe { sys::env_var_name_copy(index, dst.as_mut_ptr() as usize, offset, dst.len()) }
607}
608
609/// # Safety
610///
611/// This function will fully initialize `dst` (or trap if it cannot).
612#[inline]
613pub fn env_var_name_copy_uninit(index: usize, dst: &mut [MaybeUninit<u8>], offset: usize) {
614 // SAFETY: dst is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.env_var_name_copy
615 unsafe { sys::env_var_name_copy(index, dst.as_mut_ptr() as usize, offset, dst.len()) }
616}
617
618#[inline]
619pub fn env_var_name_exists(name: &str) -> u32 {
620 // SAFETY: name is a readable string and therefore safe to pass as ptr and len to ic0.env_var_name_exists
621 unsafe { sys::env_var_name_exists(name.as_ptr() as usize, name.len()) }
622}
623
624#[inline]
625pub fn env_var_value_size(name: &str) -> usize {
626 // SAFETY: name is a readable string and therefore safe to pass as ptr and len to ic0.env_var_value_size
627 unsafe { sys::env_var_value_size(name.as_ptr() as usize, name.len()) }
628}
629
630#[inline]
631pub fn env_var_value_copy(name: &str, dst: &mut [u8], offset: usize) {
632 // SAFETY:
633 // - name is a readable string and therefore safe to pass as ptr and len to ic0.env_var_value_copy
634 // - dst is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.env_var_value_copy
635 unsafe {
636 sys::env_var_value_copy(
637 name.as_ptr() as usize,
638 name.len(),
639 dst.as_mut_ptr() as usize,
640 offset,
641 dst.len(),
642 )
643 }
644}
645
646/// # Safety
647///
648/// This function will fully initialize `dst` (or trap if it cannot).
649#[inline]
650pub fn env_var_value_copy_uninit(name: &str, dst: &mut [MaybeUninit<u8>], offset: usize) {
651 // SAFETY:
652 // - name is a readable string and therefore safe to pass as ptr and len to ic0.env_var_value_copy
653 // - dst is a writable sequence of bytes and therefore safe to pass as ptr and len to ic0.env_var_value_copy
654 unsafe {
655 sys::env_var_value_copy(
656 name.as_ptr() as usize,
657 name.len(),
658 dst.as_mut_ptr() as usize,
659 offset,
660 dst.len(),
661 )
662 }
663}
664
665#[inline]
666pub fn debug_print(message: &[u8]) {
667 // SAFETY: message is a readable sequence of bytes and therefore safe to pass as ptr and len to ic0.debug_print
668 unsafe { sys::debug_print(message.as_ptr() as usize, message.len()) }
669}
670
671#[inline]
672pub fn trap(message: &[u8]) -> ! {
673 // SAFETY: message is a readable sequence of bytes and therefore safe to pass as ptr and len to ic0.trap
674 unsafe { sys::trap(message.as_ptr() as usize, message.len()) }
675 unreachable!("trap should halt execution immediately")
676}
677
678#[inline]
679fn to_high_low(x: u128) -> (u64, u64) {
680 let high = (x >> 64) as u64;
681 let low = (x & u128::from(u64::MAX)) as u64;
682 (high, low)
683}