Skip to content

Commit

Permalink
replace copy-pasted syscall code with crate import
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinheavey committed Feb 8, 2025
1 parent efb7737 commit 7944520
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 137 deletions.
9 changes: 9 additions & 0 deletions 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 Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ repository = "https://github.com/anza-xyz/pinocchio"
five8_const = "0.1.3"
pinocchio = { path = "sdk/pinocchio", version = ">= 0.6, <= 0.7" }
pinocchio-pubkey = { path = "sdk/pubkey", version = "0.2.1" }
solana-define-syscall = "2.2.0"
16 changes: 3 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,17 @@
<img width="400" alt="Limestone" src="https://github.com/user-attachments/assets/3a1894b4-403f-4c35-90aa-548e7672fe90" />
</p>
<p align="center">
Create Solana programs with no dependencies attached.
Create Solana programs with minimal dependencies attached.
</p>

<p align="center">
<a href="https://github.com/febo/pinocchio/actions/workflows/main.yml"><img src="https://img.shields.io/github/actions/workflow/status/febo/pinocchio/main.yml?logo=GitHub" /></a>
<a href="https://crates.io/crates/pinocchio"><img src="https://img.shields.io/crates/v/pinocchio?logo=rust" /></a>
</p>

<p align="right">
<i>I've got no dependencies</i><br />
<i>To hold me down</i><br />
<i>To make me fret</i><br />
<i>Or make me frown</i><br />
<i>I had dependencies</i><br />
<i>But now I'm free</i><br />
<i>There are no dependencies on me</i>
</p>

## Overview

Pinocchio is a zero-dependency library to create Solana programs in Rust. It takes advantage of the way SBF loaders serialize the program input parameters into a byte array that is then passed to the program's entrypoint to define zero-copy types to read the input. Since the communication between a program and SBF loader &mdash; either at the first time the program is called or when one program invokes the instructions of another program &mdash; is done via a byte array, a program can define its own types. This completely eliminates the dependency on the `solana-program` crate, which in turn mitigates dependency issues by having a crate specifically designed to create on-chain programs.
Pinocchio is a library to create Solana programs in Rust. It takes advantage of the way SBF loaders serialize the program input parameters into a byte array that is then passed to the program's entrypoint to define zero-copy types to read the input. Since the communication between a program and SBF loader &mdash; either at the first time the program is called or when one program invokes the instructions of another program &mdash; is done via a byte array, a program can define its own types. This completely eliminates the dependency on the `solana-program` crate, which in turn mitigates dependency issues by having a crate specifically designed to create on-chain programs.

As a result, Pinocchio can be used as a replacement for [`solana-program`](https://crates.io/crates/solana-program) to write on-chain programs, which are optimized in terms of both compute units consumption and binary size.

Expand All @@ -39,7 +29,7 @@ The library defines:

## Features

* Zero dependencies and `no_std` crate
* Minimal dependencies and `no_std` crate
* Efficient `entrypoint!` macro – no copies or allocations
* Improved CU consumption of cross-program invocations

Expand Down
5 changes: 4 additions & 1 deletion sdk/pinocchio/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pinocchio"
description = "Create Solana programs with no dependencies attached"
description = "Create Solana programs with minimal dependencies attached"
version = "0.7.1"
edition = { workspace = true }
license = { workspace = true }
Expand All @@ -10,6 +10,9 @@ repository = { workspace = true }
[lib]
crate-type = ["rlib"]

[dependencies]
solana-define-syscall = { workspace = true }

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [
'cfg(target_os, values("solana"))',
Expand Down
125 changes: 2 additions & 123 deletions sdk/pinocchio/src/syscalls.rs
Original file line number Diff line number Diff line change
@@ -1,126 +1,5 @@
//! Syscall functions.
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),*) -> ());
}
}

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));
define_syscall!(fn sol_log_compute_units_());
define_syscall!(fn sol_log_pubkey(pubkey_addr: *const u8));
define_syscall!(fn sol_create_program_address(seeds_addr: *const u8, seeds_len: u64, program_id_addr: *const u8, address_bytes_addr: *const u8) -> u64);
define_syscall!(fn sol_try_find_program_address(seeds_addr: *const u8, seeds_len: u64, program_id_addr: *const u8, address_bytes_addr: *const u8, bump_seed_addr: *const u8) -> u64);
define_syscall!(fn sol_sha256(vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64);
define_syscall!(fn sol_keccak256(vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64);
define_syscall!(fn sol_secp256k1_recover(hash: *const u8, recovery_id: u64, signature: *const u8, result: *mut u8) -> u64);
define_syscall!(fn sol_blake3(vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64);
define_syscall!(fn sol_get_clock_sysvar(addr: *mut u8) -> u64);
define_syscall!(fn sol_get_epoch_schedule_sysvar(addr: *mut u8) -> u64);
define_syscall!(fn sol_get_fees_sysvar(addr: *mut u8) -> u64);
define_syscall!(fn sol_get_rent_sysvar(addr: *mut u8) -> u64);
define_syscall!(fn sol_get_last_restart_slot(addr: *mut u8) -> u64);
define_syscall!(fn sol_memcpy_(dst: *mut u8, src: *const u8, n: u64));
define_syscall!(fn sol_memmove_(dst: *mut u8, src: *const u8, n: u64));
define_syscall!(fn sol_memcmp_(s1: *const u8, s2: *const u8, n: u64, result: *mut i32));
define_syscall!(fn sol_memset_(s: *mut u8, c: u8, n: u64));
define_syscall!(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);
define_syscall!(fn sol_invoke_signed_rust(instruction_addr: *const u8, account_infos_addr: *const u8, account_infos_len: u64, signers_seeds_addr: *const u8, signers_seeds_len: u64) -> u64);
define_syscall!(fn sol_set_return_data(data: *const u8, length: u64));
define_syscall!(fn sol_get_return_data(data: *mut u8, length: u64, program_id: *mut Pubkey) -> u64);
define_syscall!(fn sol_log_data(data: *const u8, data_len: u64));
define_syscall!(fn sol_get_processed_sibling_instruction(index: u64, meta: *mut ProcessedSiblingInstruction, program_id: *mut Pubkey, data: *mut u8, accounts: *mut AccountMeta) -> u64);
define_syscall!(fn sol_get_stack_height() -> u64);
define_syscall!(fn sol_curve_validate_point(curve_id: u64, point_addr: *const u8, result: *mut u8) -> u64);
define_syscall!(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);
define_syscall!(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);
define_syscall!(fn sol_curve_pairing_map(curve_id: u64, point: *const u8, result: *mut u8) -> u64);
define_syscall!(fn sol_alt_bn128_group_op(group_op: u64, input: *const u8, input_size: u64, result: *mut u8) -> u64);
define_syscall!(fn sol_big_mod_exp(params: *const u8, result: *mut u8) -> u64);
define_syscall!(fn sol_get_epoch_rewards_sysvar(addr: *mut u8) -> u64);
define_syscall!(fn sol_poseidon(parameters: u64, endianness: u64, vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64);
define_syscall!(fn sol_remaining_compute_units() -> u64);
define_syscall!(fn sol_alt_bn128_compression(op: u64, input: *const u8, input_size: u64, result: *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
}
pub use solana_define_syscall::sys_hash;
pub use solana_define_syscall::{define_syscall, definitions::*};

0 comments on commit 7944520

Please sign in to comment.