#![cfg_attr(target_os = "solana", allow(unused_doc_comments))]
#[doc(hidden)]
pub const fn sys_hash(name: &str) -> usize {
murmur3_32(name.as_bytes(), 0) as usize
}
const fn murmur3_32(buf: &[u8], seed: u32) -> u32 {
const fn pre_mix(buf: [u8; 4]) -> u32 {
u32::from_le_bytes(buf)
.wrapping_mul(0xcc9e2d51)
.rotate_left(15)
.wrapping_mul(0x1b873593)
}
let mut hash = seed;
let mut i = 0;
while i < buf.len() / 4 {
let buf = [buf[i * 4], buf[i * 4 + 1], buf[i * 4 + 2], buf[i * 4 + 3]];
hash ^= pre_mix(buf);
hash = hash.rotate_left(13);
hash = hash.wrapping_mul(5).wrapping_add(0xe6546b64);
i += 1;
}
match buf.len() % 4 {
0 => {}
1 => {
hash ^= pre_mix([buf[i * 4], 0, 0, 0]);
}
2 => {
hash ^= pre_mix([buf[i * 4], buf[i * 4 + 1], 0, 0]);
}
3 => {
hash ^= pre_mix([buf[i * 4], buf[i * 4 + 1], buf[i * 4 + 2], 0]);
}
_ => { }
}
hash ^= buf.len() as u32;
hash ^= hash.wrapping_shr(16);
hash = hash.wrapping_mul(0x85ebca6b);
hash ^= hash.wrapping_shr(13);
hash = hash.wrapping_mul(0xc2b2ae35);
hash ^= hash.wrapping_shr(16);
hash
}
#[macro_export]
macro_rules! define_syscall {
(@reloc $(#[$attr:meta])* $vis:vis fn $name:ident($($arg:ident: $typ:ty),* $(,)?) -> $ret:ty) => {
extern "C" {
$(#[$attr])*
$vis fn $name($($arg: $typ),*) -> $ret;
}
};
(@reloc $(#[$attr:meta])* $vis:vis fn $name:ident($($arg:ident: $typ:ty),* $(,)?) -> $ret:ty; link_name = $sym:literal) => {
extern "C" {
#[link_name = $sym]
$(#[$attr])*
$vis fn $name($($arg: $typ),*) -> $ret;
}
};
(@static $(#[$attr:meta])* $vis:vis fn $name:ident($($arg:ident: $typ:ty),* $(,)?) -> $ret:ty; hash = $sym:expr) => {
$(#[$attr])*
#[inline]
$vis unsafe fn $name($($arg: $typ),*) -> $ret {
#[repr(usize)]
enum Syscall {
Code = $crate::syscalls::sys_hash($sym),
}
let syscall: extern "C" fn($($arg: $typ),*) -> $ret =
unsafe { core::mem::transmute(Syscall::Code) };
syscall($($arg),*)
}
};
(#[link_name = $sym:literal] $(#[$attr:meta])* $vis:vis fn $name:ident($($arg:ident: $typ:ty),* $(,)?) -> $ret:ty) => {
#[cfg(not(any(feature = "static-syscalls", target_feature = "static-syscalls")))]
$crate::define_syscall!(@reloc $(#[$attr])* $vis fn $name($($arg: $typ),*) -> $ret; link_name = $sym);
#[cfg(any(feature = "static-syscalls", target_feature = "static-syscalls"))]
$crate::define_syscall!(@static $(#[$attr])* $vis fn $name($($arg: $typ),*) -> $ret; hash = $sym);
};
(#[link_name = $sym:literal] $(#[$attr:meta])* $vis:vis fn $name:ident($($arg:ident: $typ:ty),* $(,)?)) => {
$crate::define_syscall!(#[link_name = $sym] $(#[$attr])* $vis fn $name($($arg: $typ),*) -> ());
};
($(#[$attr:meta])* $vis:vis fn $name:ident($($arg:ident: $typ:ty),* $(,)?) -> $ret:ty) => {
#[cfg(not(any(feature = "static-syscalls", target_feature = "static-syscalls")))]
$crate::define_syscall!(@reloc $(#[$attr])* $vis fn $name($($arg: $typ),*) -> $ret);
#[cfg(any(feature = "static-syscalls", target_feature = "static-syscalls"))]
$crate::define_syscall!(@static $(#[$attr])* $vis fn $name($($arg: $typ),*) -> $ret; hash = stringify!($name));
};
($(#[$attr:meta])* $vis:vis fn $name:ident($($arg:ident: $typ:ty),* $(,)?)) => {
$crate::define_syscall!($(#[$attr])* $vis fn $name($($arg: $typ),*) -> ());
};
}
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_log_(message: *const u8, len: u64));
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_log_64_(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64));
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_log_compute_units_());
#[cfg(all(target_os = "solana", feature = "remaining-compute-units-syscall"))]
define_syscall!(pub fn sol_remaining_compute_units() -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_log_data(data: *const u8, data_len: u64));
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_invoke_signed_c(
instruction_addr: *const u8,
account_infos_addr: *const u8,
account_infos_len: u64,
signers_seeds_addr: *const u8,
signers_seeds_len: u64
) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_create_program_address(
seeds_addr: *const u8,
seeds_len: u64,
program_id_addr: *const u8,
address_addr: *mut u8
) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_try_find_program_address(
seeds_addr: *const u8,
seeds_len: u64,
program_id_addr: *const u8,
address_addr: *mut u8,
bump_seed_addr: *mut u8
) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_sha256(vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_curve_validate_point(
curve_id: u64,
point_addr: *const u8,
result_point_addr: *mut u8
) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_curve_group_op(
curve_id: u64,
group_op: u64,
left_input_addr: *const u8,
right_input_addr: *const u8,
result_point_addr: *mut u8
) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_curve_multiscalar_mul(
curve_id: u64,
scalars_addr: *const u8,
points_addr: *const u8,
points_len: u64,
result_point_addr: *mut u8
) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_keccak256(vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_blake3(vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_secp256k1_recover(
hash: *const u8,
recovery_id: u64,
signature: *const u8,
result: *mut u8
) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_poseidon(
parameters: u64,
endianness: u64,
vals: *const u8,
val_len: u64,
hash_result: *mut u8
) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_alt_bn128_group_op(
group_op: u64,
input: *const u8,
input_size: u64,
result: *mut u8
) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_alt_bn128_compression(
op: u64,
input: *const u8,
input_size: u64,
result: *mut u8
) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_big_mod_exp(params: *const u8, result: *mut u8) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_set_return_data(data: *const u8, length: u64));
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_get_return_data(data: *mut u8, length: u64, program_id: *mut u8) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_get_clock_sysvar(addr: *mut u8) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_get_rent_sysvar(addr: *mut u8) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_get_epoch_schedule_sysvar(addr: *mut u8) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_panic_(file: *const u8, len: u64, line: u64, column: u64) -> !);
#[cfg(target_os = "solana")]
define_syscall!(pub fn abort() -> !);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_memcpy_(dst: *mut u8, src: *const u8, n: u64));
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_memmove_(dst: *mut u8, src: *const u8, n: u64));
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_memcmp_(s1: *const u8, s2: *const u8, n: u64, result: *mut i32));
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_memset_(s: *mut u8, c: u8, n: u64));
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_get_stack_height() -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_get_processed_sibling_instruction(
index: u64,
meta: *mut u8,
program_id: *mut u8,
data: *mut u8,
accounts: *mut u8
) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_get_last_restart_slot(addr: *mut u8) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_get_sysvar(
sysvar_id_addr: *const u8,
result: *mut u8,
offset: u64,
length: u64
) -> u64);
#[cfg(target_os = "solana")]
define_syscall!(pub fn sol_get_epoch_stake(vote_address: *const u8) -> u64);
#[cfg(test)]
mod tests {
#[allow(dead_code)]
mod generated {
crate::define_syscall!(
pub fn __hopper_probe_syscall(a: *const u8, n: u64) -> u64
);
crate::define_syscall!(
#[link_name = "sol_memset_"]
pub fn __hopper_probe_alias(a: *mut u8, c: u8, n: u64)
);
}
#[test]
fn sys_hash_matches_known_agave_constants() {
assert_eq!(super::sys_hash("sol_memcmp_"), 0x5FDC_DE31);
assert_eq!(super::sys_hash("abort"), 0xB6FC_1A11);
assert_eq!(super::sys_hash("sol_memcpy_"), 0x717C_C4A3);
assert_eq!(super::sys_hash("sol_memset_"), 0x3770_FB22);
assert_eq!(super::sys_hash("sol_memmove_"), 0x4343_71F8);
assert_eq!(super::sys_hash("sol_invoke_signed_c"), 0xA22B_9C85);
}
#[cfg(any(feature = "static-syscalls", target_feature = "static-syscalls"))]
#[test]
fn static_arm_expands_to_callable_fn() {
let f: unsafe fn(*const u8, u64) -> u64 = generated::__hopper_probe_syscall;
assert!(f as usize != 0);
}
}