Skip to main content

hopper_runtime/
syscalls.rs

1//! Minimal syscall shims exposed through Hopper Runtime.
2//!
3//! Hopper-owned crates use this module instead of binding directly to backend
4//! SDK syscall paths. That keeps backend differences inside Hopper Runtime.
5
6/// Emit a `sol_log_data` event payload.
7///
8/// # Safety
9///
10/// `segments` must point to a valid array of slice descriptors for the active
11/// backend ABI, and `segments_len` must match the number of entries.
12#[inline(always)]
13pub unsafe fn sol_log_data(segments: *const u8, segments_len: u64) {
14    #[cfg(all(target_os = "solana", feature = "hopper-native-backend"))]
15    // SAFETY: This block is part of Hopper's audited zero-copy/backend boundary; surrounding checks and caller contracts uphold the required raw-pointer, layout, and aliasing invariants.
16    unsafe {
17        hopper_native::syscalls::sol_log_data(segments, segments_len);
18    }
19
20    #[cfg(all(target_os = "solana", feature = "legacy-pinocchio-compat"))]
21    // SAFETY: This block is part of Hopper's audited zero-copy/backend boundary; surrounding checks and caller contracts uphold the required raw-pointer, layout, and aliasing invariants.
22    unsafe {
23        pinocchio::syscalls::sol_log_data(segments, segments_len);
24    }
25
26    #[cfg(all(target_os = "solana", feature = "solana-program-backend"))]
27    {
28        // SAFETY: This block is part of Hopper's audited zero-copy/backend boundary; surrounding checks and caller contracts uphold the required raw-pointer, layout, and aliasing invariants.
29        let slices =
30            unsafe { core::slice::from_raw_parts(segments as *const &[u8], segments_len as usize) };
31        ::solana_program::log::sol_log_data(slices);
32    }
33
34    #[cfg(not(target_os = "solana"))]
35    {
36        let _ = (segments, segments_len);
37    }
38}
39
40/// Compute SHA-256 over a slice-of-slices payload.
41///
42/// # Safety
43///
44/// `vals` must point to a valid array of slice descriptors and `result` must
45/// point to writable storage for 32 output bytes.
46#[inline(always)]
47pub unsafe fn sol_sha256(vals: *const u8, vals_len: u64, result: *mut u8) {
48    #[cfg(all(target_os = "solana", feature = "hopper-native-backend"))]
49    // SAFETY: This block is part of Hopper's audited zero-copy/backend boundary; surrounding checks and caller contracts uphold the required raw-pointer, layout, and aliasing invariants.
50    unsafe {
51        hopper_native::syscalls::sol_sha256(vals, vals_len, result);
52    }
53
54    #[cfg(all(target_os = "solana", feature = "legacy-pinocchio-compat"))]
55    // SAFETY: This block is part of Hopper's audited zero-copy/backend boundary; surrounding checks and caller contracts uphold the required raw-pointer, layout, and aliasing invariants.
56    unsafe {
57        pinocchio::syscalls::sol_sha256(vals, vals_len, result);
58    }
59
60    #[cfg(all(target_os = "solana", feature = "solana-program-backend"))]
61    {
62        // SAFETY: This block is part of Hopper's audited zero-copy/backend boundary; surrounding checks and caller contracts uphold the required raw-pointer, layout, and aliasing invariants.
63        let slices =
64            unsafe { core::slice::from_raw_parts(vals as *const &[u8], vals_len as usize) };
65        let digest = ::solana_program::hash::hashv(slices).to_bytes();
66        // SAFETY: This block is part of Hopper's audited zero-copy/backend boundary; surrounding checks and caller contracts uphold the required raw-pointer, layout, and aliasing invariants.
67        unsafe {
68            core::ptr::copy_nonoverlapping(digest.as_ptr(), result, digest.len());
69        }
70    }
71
72    #[cfg(not(target_os = "solana"))]
73    {
74        let _ = (vals, vals_len, result);
75    }
76}