diff --git a/Cargo.lock b/Cargo.lock index c71bd32fbab642..8e13c3ccd8a785 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6188,6 +6188,10 @@ dependencies = [ "thiserror", ] +[[package]] +name = "solana-define-syscall" +version = "2.1.0" + [[package]] name = "solana-dos" version = "2.1.0" @@ -6788,6 +6792,7 @@ version = "2.1.0" dependencies = [ "ark-bn254", "light-poseidon", + "solana-define-syscall", "thiserror", ] @@ -6836,6 +6841,7 @@ dependencies = [ "serial_test", "sha2 0.10.8", "sha3 0.10.8", + "solana-define-syscall", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-logger", diff --git a/Cargo.toml b/Cargo.toml index 195ea0c3680fa4..02ab28a0acea10 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ members = [ "core", "cost-model", "curves/*", + "define-syscall", "dos", "download-utils", "entry", @@ -346,6 +347,7 @@ solana-connection-cache = { path = "connection-cache", version = "=2.1.0", defau solana-core = { path = "core", version = "=2.1.0" } solana-cost-model = { path = "cost-model", version = "=2.1.0" } solana-curve25519 = { path = "curves/curve25519", version = "=2.1.0" } +solana-define-syscall = { path = "define-syscall", version = "=2.1.0" } solana-download-utils = { path = "download-utils", version = "=2.1.0" } solana-entry = { path = "entry", version = "=2.1.0" } solana-faucet = { path = "faucet", version = "=2.1.0" } diff --git a/define-syscall/Cargo.toml b/define-syscall/Cargo.toml new file mode 100644 index 00000000000000..af8ef66d74450e --- /dev/null +++ b/define-syscall/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "solana-define-syscall" +description = "Solana define_syscall macro. For internal use only." +documentation = "https://docs.rs/solana-define-syscall" +version = { workspace = true } +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +edition = { workspace = true } + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] diff --git a/define-syscall/src/lib.rs b/define-syscall/src/lib.rs new file mode 100644 index 00000000000000..7e94b953bfef4d --- /dev/null +++ b/define-syscall/src/lib.rs @@ -0,0 +1,84 @@ +#[cfg(target_feature = "static-syscalls")] +#[macro_export] +macro_rules! define_syscall { + (fn $name:ident($($arg:ident: $typ:ty),*) -> $ret:ty) => { + #[inline] + pub unsafe fn $name($($arg: $typ),*) -> $ret { + // this enum is used to force the hash to be computed in a const context + #[repr(usize)] + enum Syscall { + Code = $crate::sys_hash(stringify!($name)), + } + + let syscall: extern "C" fn($($arg: $typ),*) -> $ret = core::mem::transmute(Syscall::Code); + syscall($($arg),*) + } + + }; + (fn $name:ident($($arg:ident: $typ:ty),*)) => { + define_syscall!(fn $name($($arg: $typ),*) -> ()); + } +} + +#[cfg(not(target_feature = "static-syscalls"))] +#[macro_export] +macro_rules! define_syscall { + (fn $name:ident($($arg:ident: $typ:ty),*) -> $ret:ty) => { + extern "C" { + pub fn $name($($arg: $typ),*) -> $ret; + } + }; + (fn $name:ident($($arg:ident: $typ:ty),*)) => { + define_syscall!(fn $name($($arg: $typ),*) -> ()); + } +} + +#[cfg(target_feature = "static-syscalls")] +pub const fn sys_hash(name: &str) -> usize { + murmur3_32(name.as_bytes(), 0) as usize +} + +#[cfg(target_feature = "static-syscalls")] +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 = hash ^ pre_mix([buf[i * 4], 0, 0, 0]); + } + 2 => { + hash = hash ^ pre_mix([buf[i * 4], buf[i * 4 + 1], 0, 0]); + } + 3 => { + hash = hash ^ pre_mix([buf[i * 4], buf[i * 4 + 1], buf[i * 4 + 2], 0]); + } + _ => { /* unreachable!() */ } + } + + hash = hash ^ buf.len() as u32; + hash = hash ^ (hash.wrapping_shr(16)); + hash = hash.wrapping_mul(0x85ebca6b); + hash = hash ^ (hash.wrapping_shr(13)); + hash = hash.wrapping_mul(0xc2b2ae35); + hash = hash ^ (hash.wrapping_shr(16)); + + hash +} diff --git a/poseidon/Cargo.toml b/poseidon/Cargo.toml index 2787f501e57ff8..09f40b2ac65ecb 100644 --- a/poseidon/Cargo.toml +++ b/poseidon/Cargo.toml @@ -12,6 +12,9 @@ edition = { workspace = true } [dependencies] thiserror = { workspace = true } +[target.'cfg(target_os = "solana")'.dependencies] +solana-define-syscall = { workspace = true } + [target.'cfg(not(target_os = "solana"))'.dependencies] ark-bn254 = { workspace = true } light-poseidon = { workspace = true } diff --git a/poseidon/src/lib.rs b/poseidon/src/lib.rs index f4b6530a1d5aa4..81bd84f80d2a04 100644 --- a/poseidon/src/lib.rs +++ b/poseidon/src/lib.rs @@ -170,15 +170,7 @@ impl PoseidonHash { } #[cfg(target_os = "solana")] -extern "C" { - pub fn sol_poseidon( - parameters: u64, - endianness: u64, - vals: *const u8, - val_len: u64, - hash_result: *mut u8, - ) -> u64; -} +solana_define_syscall::define_syscall!(fn sol_poseidon(parameters: u64, endianness: u64, vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64); /// Return a Poseidon hash for the given data with the given elliptic curve and /// endianness. diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index 8a192d1b538512..2851a373c75521 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -4937,6 +4937,10 @@ dependencies = [ "thiserror", ] +[[package]] +name = "solana-define-syscall" +version = "2.1.0" + [[package]] name = "solana-download-utils" version = "2.1.0" @@ -5273,6 +5277,7 @@ version = "2.1.0" dependencies = [ "ark-bn254", "light-poseidon", + "solana-define-syscall", "thiserror", ] @@ -5314,6 +5319,7 @@ dependencies = [ "serde_derive", "sha2 0.10.8", "sha3 0.10.8", + "solana-define-syscall", "solana-sanitize", "solana-sdk-macro", "thiserror", diff --git a/sdk/program/Cargo.toml b/sdk/program/Cargo.toml index 45a6927d8cc447..a798bcada04608 100644 --- a/sdk/program/Cargo.toml +++ b/sdk/program/Cargo.toml @@ -44,6 +44,7 @@ thiserror = { workspace = true } # hashbrown dependency as optional. [target.'cfg(target_os = "solana")'.dependencies] getrandom = { workspace = true, features = ["custom"] } +solana-define-syscall = { workspace = true } [target.'cfg(not(target_os = "solana"))'.dependencies] ark-bn254 = { workspace = true } diff --git a/sdk/program/src/syscalls/definitions.rs b/sdk/program/src/syscalls/definitions.rs index bdae7960b33da3..5988cbb76d4073 100644 --- a/sdk/program/src/syscalls/definitions.rs +++ b/sdk/program/src/syscalls/definitions.rs @@ -1,40 +1,12 @@ -use crate::{ - instruction::{AccountMeta, ProcessedSiblingInstruction}, - pubkey::Pubkey, -}; - #[cfg(target_feature = "static-syscalls")] -macro_rules! define_syscall { - (fn $name:ident($($arg:ident: $typ:ty),*) -> $ret:ty) => { - #[inline] - pub unsafe fn $name($($arg: $typ),*) -> $ret { - // this enum is used to force the hash to be computed in a const context - #[repr(usize)] - enum Syscall { - Code = sys_hash(stringify!($name)), - } - - let syscall: extern "C" fn($($arg: $typ),*) -> $ret = core::mem::transmute(Syscall::Code); - syscall($($arg),*) - } - - }; - (fn $name:ident($($arg:ident: $typ:ty),*)) => { - define_syscall!(fn $name($($arg: $typ),*) -> ()); - } -} - -#[cfg(not(target_feature = "static-syscalls"))] -macro_rules! define_syscall { - (fn $name:ident($($arg:ident: $typ:ty),*) -> $ret:ty) => { - extern "C" { - pub fn $name($($arg: $typ),*) -> $ret; - } - }; - (fn $name:ident($($arg:ident: $typ:ty),*)) => { - define_syscall!(fn $name($($arg: $typ),*) -> ()); - } -} +pub use solana_define_syscall::sys_hash; +use { + crate::{ + instruction::{AccountMeta, ProcessedSiblingInstruction}, + pubkey::Pubkey, + }, + solana_define_syscall::define_syscall, +}; define_syscall!(fn sol_log_(message: *const u8, len: u64)); define_syscall!(fn sol_log_64_(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64)); @@ -77,53 +49,3 @@ define_syscall!(fn sol_get_epoch_rewards_sysvar(addr: *mut u8) -> u64); // this cannot go through sol_get_sysvar but can be removed once no longer in use define_syscall!(fn sol_get_fees_sysvar(addr: *mut u8) -> u64); - -#[cfg(target_feature = "static-syscalls")] -pub const fn sys_hash(name: &str) -> usize { - murmur3_32(name.as_bytes(), 0) as usize -} - -#[cfg(target_feature = "static-syscalls")] -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 = hash ^ pre_mix([buf[i * 4], 0, 0, 0]); - } - 2 => { - hash = hash ^ pre_mix([buf[i * 4], buf[i * 4 + 1], 0, 0]); - } - 3 => { - hash = hash ^ pre_mix([buf[i * 4], buf[i * 4 + 1], buf[i * 4 + 2], 0]); - } - _ => { /* unreachable!() */ } - } - - hash = hash ^ buf.len() as u32; - hash = hash ^ (hash.wrapping_shr(16)); - hash = hash.wrapping_mul(0x85ebca6b); - hash = hash ^ (hash.wrapping_shr(13)); - hash = hash.wrapping_mul(0xc2b2ae35); - hash = hash ^ (hash.wrapping_shr(16)); - - hash -}