Skip to content

Commit

Permalink
Extract define-syscall crate (anza-xyz#1827)
Browse files Browse the repository at this point in the history
* move define_syscall macro to its own crate

* use solana-define-syscall in solana-poseidon

* add missing dep to solana-program

* update crate version to match workspace

* macro hygiene fix

* fix define_syscall call

* re-export sys_hash in solana-program for backwards compatibility

* convert tabs to spaces

* put re-export behind #[cfg(target_feature = "static-syscalls")]
  • Loading branch information
kevinheavey authored and samkim-crypto committed Jul 31, 2024
1 parent 21d397d commit e88d1b5
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 96 deletions.
8 changes: 7 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ members = [
"core",
"cost-model",
"curves/*",
"define-syscall",
"dos",
"download-utils",
"entry",
Expand Down Expand Up @@ -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" }
Expand Down
13 changes: 13 additions & 0 deletions define-syscall/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"]
84 changes: 84 additions & 0 deletions define-syscall/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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
}
3 changes: 3 additions & 0 deletions poseidon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
10 changes: 1 addition & 9 deletions poseidon/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 6 additions & 0 deletions programs/sbf/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions sdk/program/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
94 changes: 8 additions & 86 deletions sdk/program/src/syscalls/definitions.rs
Original file line number Diff line number Diff line change
@@ -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));
Expand Down Expand Up @@ -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
}

0 comments on commit e88d1b5

Please sign in to comment.