Skip to content

Commit 830639f

Browse files
committed
Update crate details
1 parent 76f57e7 commit 830639f

File tree

3 files changed

+109
-65
lines changed

3 files changed

+109
-65
lines changed

README.md

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
<img width="400" alt="Limestone" src="https://github.com/user-attachments/assets/3a1894b4-403f-4c35-90aa-548e7672fe90" />
66
</p>
77
<p align="center">
8-
Create Solana programs with no dependencies attached.
8+
Create Solana programs with no dependencies<sup>*</sup> attached.
99
</p>
1010

1111
<p align="center">
1212
<a href="https://github.com/anza-xyz/pinocchio/actions/workflows/main.yml"><img src="https://img.shields.io/github/actions/workflow/status/anza-xyz/pinocchio/main.yml?logo=GitHub" /></a>
1313
<a href="https://crates.io/crates/pinocchio"><img src="https://img.shields.io/crates/v/pinocchio?logo=rust" /></a>
14+
<a href="https://docs.rs/pinocchio"><img src="https://img.shields.io/docsrs/pinocchio?logo=docsdotrs" /></a>
1415
</p>
1516

1617
<p align="right">
@@ -23,25 +24,20 @@
2324
<i>There are no dependencies on me</i>
2425
</p>
2526

26-
## Overview
27-
28-
Pinocchio is a zero-dependency library to create Solana programs in Rust. It takes advantage of the way SVM 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 SVM 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.
27+
<p style="font-size: 12px; color: #999999">
28+
<strong><sup>*</sup></strong> It includes only dependencies to Solana SDK types &mdash; i.e., no <i>external</i> dependencies.
29+
</p>
2930

30-
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.
31+
## Overview
3132

32-
The library defines:
33-
* program entrypoint
34-
* core data types
35-
* logging macros
36-
* `syscall` functions
37-
* access to system accounts (`sysvars`)
38-
* cross-program invocation
33+
Pinocchio is a *no-external* dependencies library to create Solana programs in Rust. The only dependencies are types from the Solana SDK specifically designed for on-chain programs. This mitigates dependency issues and offers an efficient zero-copy library to write programs, optimized in terms of both compute units consumption and binary size.
3934

4035
## Features
4136

42-
* Zero dependencies and `no_std` crate
43-
* Efficient `entrypoint!` macro – no copies or allocations
44-
* Improved CU consumption of cross-program invocations
37+
* `no_std` crate
38+
* no-external dependencies
39+
* efficient `program_entrypoint!` macro – no copies or allocations
40+
* lightweight `lazy_program_entrypoint` providing more control over how the input is parsed
4541

4642
## Getting started
4743

@@ -57,21 +53,21 @@ This will add `pinocchio` as a dependency to your project.
5753

5854
A Solana program needs to define an entrypoint, which will be called by the runtime to begin the program execution. The `entrypoint!` macro emits the common boilerplate to set up the program entrypoint. The macro will also set up [global allocator](https://doc.rust-lang.org/stable/core/alloc/trait.GlobalAlloc.html) and [custom panic hook](https://github.com/anza-xyz/rust/blob/2830febbc59d44bdd7ad2c3b81731f1d08b96eba/library/std/src/sys/pal/sbf/mod.rs#L49) using the [default_allocator!](https://docs.rs/pinocchio/latest/pinocchio/macro.default_allocator.html) and [default_panic_handler!](https://docs.rs/pinocchio/latest/pinocchio/macro.default_panic_handler.html) macros.
5955

60-
The [`entrypoint!`](https://docs.rs/pinocchio/latest/pinocchio/macro.entrypoint.html) is a convenience macro that invokes three other macros to set all symbols required for a program execution:
56+
The [`entrypoint!`](https://docs.rs/pinocchio/latest/pinocchio/macro.entrypoint.html) is a convenience macro that invokes three other macros to set all components required for a program execution:
6157

6258
* [`program_entrypoint!`](https://docs.rs/pinocchio/latest/pinocchio/macro.program_entrypoint.html): declares the program entrypoint
6359
* [`default_allocator!`](https://docs.rs/pinocchio/latest/pinocchio/macro.default_allocator.html): declares the default (bump) global allocator
6460
* [`default_panic_handler!`](https://docs.rs/pinocchio/latest/pinocchio/macro.default_panic_handler.html): declares the default panic handler
6561

66-
If all dependencies are `no_std`, you should append [`nostd_panic_handler!`](https://docs.rs/pinocchio/latest/pinocchio/macro.nostd_panic_handler.html) to declare a rust runtime panic handler. There's no need to do this if any dependency is `std` since rust compiler will emit std panic handler.
62+
When all dependencies are `no_std`, you should use [`nostd_panic_handler!`](https://docs.rs/pinocchio/latest/pinocchio/macro.nostd_panic_handler.html) instead of `default_panic_handler!` to declare a rust runtime panic handler. There's no need to do this when any dependency is `std` since rust compiler will emit a panic handler.
6763

6864
To use the `entrypoint!` macro, use the following in your entrypoint definition:
6965
```rust
7066
use pinocchio::{
7167
account::AccountView,
68+
Address,
7269
entrypoint,
73-
ProgramResult,
74-
Address
70+
ProgramResult
7571
};
7672

7773
entrypoint!(process_instruction);
@@ -91,17 +87,17 @@ The information from the input is parsed into their own entities:
9187
* `accounts`: the accounts received
9288
* `instruction_data`: data for the instruction
9389

94-
`pinocchio` also offers variations of the program entrypoint (`lazy_program_allocator`) and global allocator (`no_allocator`). In order to use these, the program needs to specify the program entrypoint, global allocator and panic handler individually. The `entrypoint!` macro is equivalent to writing:
90+
`pinocchio` also offers variations of the program entrypoint (`lazy_program_entrypoint`) and global allocator (`no_allocator`). In order to use these, the program needs to specify the program entrypoint, global allocator and panic handler individually. The `entrypoint!` macro is equivalent to writing:
9591
```rust
9692
program_entrypoint!(process_instruction);
9793
default_allocator!();
9894
default_panic_handler!();
9995
```
100-
Any of these macros can be replaced by other implementations and `pinocchio` offers a couple of variants for this.
96+
Any of these macros can be replaced by alternative implementations.
10197

10298
📌 [`lazy_program_entrypoint!`](https://docs.rs/pinocchio/latest/pinocchio/macro.lazy_program_entrypoint.html)
10399

104-
The `entrypoint!` macro looks similar to the "standard" one found in `solana-program`. It parses the whole input and provides the `program_id`, `accounts` and `instruction_data` separately. This consumes compute units before the program begins its execution. In some cases, it is beneficial for a program to have more control when the input parsing is happening, even whether the parsing is needed or not &mdash; this is the purpose of the [`lazy_program_entrypoint!`](https://docs.rs/pinocchio/latest/pinocchio/macro.lazy_program_entrypoint.html) macro. This macro only wraps the program input and provides methods to parse the input on demand.
100+
The `entrypoint!` macro looks similar to the "standard" one found in [`solana-program-entrypoint`](https://docs.rs/solana-program-entrypoint/latest/solana_program_entrypoint/macro.entrypoint.html). It parses the whole input and provides the `program_id`, `accounts` and `instruction_data` separately. This consumes compute units before the program begins its execution. In some cases, it is beneficial for a program to have more control when the input parsing is happening, even whether the parsing is needed or not &mdash; this is the purpose of the [`lazy_program_entrypoint!`](https://docs.rs/pinocchio/latest/pinocchio/macro.lazy_program_entrypoint.html) macro. This macro only wraps the program input and provides methods to parse the input on demand.
105101

106102
The `lazy_entrypoint` is suitable for programs that have a single or very few instructions, since it requires the program to handle the parsing, which can become complex as the number of instructions increases. For *larger* programs, the [`program_entrypoint!`](https://docs.rs/pinocchio/latest/pinocchio/macro.program_entrypoint.html) will likely be easier and more efficient to use.
107103

@@ -166,21 +162,41 @@ pub fn process_instruction(
166162
> ⚠️ **Note:**
167163
> The `no_allocator!` macro can also be used in combination with the `lazy_program_entrypoint!`.
168164
169-
## Crate feature: `std`
165+
Since the `no_allocator!` macro does not allocate memory, the `32kb` memory region reserved for the heap remains unused. To take advantage of this, the `no_allocator!` macro emits an `allocate_unchecked` helper function that allows you to manually reserve memory for a type at compile time.
166+
167+
```rust
168+
/// static allocation:
169+
/// - 0 is the offset when the type will be allocated
170+
/// - `allocate_unchecked` returns a mutable reference to the allocated type
171+
let lamports = allocate_unchecked::<u64>(0);
172+
*lamports = 1_000_000_000;
173+
```
174+
175+
Note that it is the developer's responsibility to ensure that types do not overlap in memory &mdash; the `offset + <size of type>` of different types must not overlap.
176+
177+
## Crate features
178+
179+
### `alloc`
180+
181+
The `alloc` feature is enabled by default and it uses the [`alloc`](https://doc.rust-lang.org/alloc/) crate. This provides access to dynamic memory allocation in combination with the `default_allocator`, e.g., required to use `String` and `Vec` in a program. Helpers that need to allocate memory, such as fetching `SlotHashes` sysvar data, are also available.
182+
183+
When no allocation is needed or desired, the feature can be disabled:
184+
185+
```
186+
pinocchio = { version = "0.10.0", default-features = false }
187+
```
188+
189+
### `cpi`
190+
191+
The `cpi` feature enables the cross-program invocation helpers, as well as types to define instructions and signer information.
170192

171-
By default, Pinocchio is a `no_std` crate. This means that it does not use any code from the
172-
standard (`std`) library. While this does not affect how Pinocchio is used, there is a one
173-
particular apparent difference. Helpers that need to allocate memory, such as fetching `SlotHashes`
174-
sysvar data, are not available. To enable these helpers, the `alloc` feature must be enabled when
175-
adding Pinocchio as a dependency:
176193
```
177-
pinocchio = { version = "0.10.0", features = ["alloc"] }
194+
pinocchio = { version = "0.10.0", features = ["cpi"] }
178195
```
179-
The `alloc` feature uses the `alloc` crate.
180196

181197
## Advance entrypoint configuration
182198

183-
The symbols emitted by the entrypoint macros &mdash; program entrypoint, global allocator and default panic handler &mdash; can only be defined once globally. If the program crate is also intended to be used as a library, it is common practice to define a Cargo [feature](https://doc.rust-lang.org/cargo/reference/features.html) in your program crate to conditionally enable the module that includes the `entrypoint!` macro invocation. The convention is to name the feature `bpf-entrypoint`.
199+
The components emitted by the entrypoint macros &mdash; program entrypoint, global allocator and default panic handler &mdash; can only be defined once globally. If the program crate is also intended to be used as a library, it is common practice to define a Cargo [feature](https://doc.rust-lang.org/cargo/reference/features.html) in your program crate to conditionally enable the module that includes the `entrypoint!` macro invocation. The convention is to name the feature `bpf-entrypoint`.
184200

185201
```rust
186202
#[cfg(feature = "bpf-entrypoint")]

sdk/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@ readme = "./README.md"
88
repository = { workspace = true }
99
rust-version = { workspace = true }
1010

11+
[package.metadata.docs.rs]
12+
targets = ["x86_64-unknown-linux-gnu"]
13+
all-features = true
14+
rustdoc-args = ["--cfg=docsrs"]
15+
1116
[lib]
1217
crate-type = ["rlib"]
1318

1419
[lints.rust]
1520
unexpected_cfgs = { level = "warn", check-cfg = [
1621
'cfg(target_os, values("solana"))',
17-
'cfg(target_feature, values("static-syscalls"))',
1822
] }
1923

2024
[features]

sdk/src/lib.rs

Lines changed: 57 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
1-
//! # Pinocchio
1+
//! # A library to create Solana programs in Rust
22
//!
3-
//! Pinocchio is a "no-external" dependencies library to create Solana programs
4-
//! in Rust, which means that the only dependencies are from the Solana SDK. This
5-
//! reduces the chance of dependency conflicts when compiling the program.
6-
//!
7-
//! It takes advantage of the way SVM loaders serialize the program input
8-
//! parameters into a byte array that is then passed to the program's entrypoint
9-
//! to use zero-copy types to read the input - these types are defined in an efficient
10-
//! way taking into consideration that they will be used in on-chain programs.
11-
//!
12-
//! It is intended to be used by on-chain programs only; for off-chain programs,
13-
//! use instead [`solana-sdk`] crates.
14-
//!
15-
//! [`solana-sdk`]: https://docs.rs/solana-sdk/latest/solana_sdk/
3+
//! Pinocchio is a *no-external* dependencies library to create Solana programs
4+
//! in Rust. The only dependencies are types from the Solana SDK specifically
5+
//! designed for on-chain programs. This mitigates dependency issues and offers
6+
//! an efficient zero-copy library to write programs, optimized in terms of both
7+
//! compute units consumption and binary size.
168
//!
179
//! ## Defining the program entrypoint
1810
//!
@@ -23,17 +15,23 @@
2315
//! and [panic handler](https://doc.rust-lang.org/nomicon/panic-handler.html) using
2416
//! the [`default_allocator!`] and [`default_panic_handler!`] macros.
2517
//!
26-
//! The [`entrypoint!`] is a convenience macro that invokes three other macros to set
27-
//! all symbols required for a program execution:
18+
//! The [`entrypoint!`](https://docs.rs/pinocchio/latest/pinocchio/macro.entrypoint.html)
19+
//! is a convenience macro that invokes three other macros to set all components
20+
//! required for a program execution:
2821
//!
2922
//! * [`program_entrypoint!`]: declares the program entrypoint
3023
//! * [`default_allocator!`]: declares the default (bump) global allocator
3124
//! * [`default_panic_handler!`]: declares the default panic handler
3225
//!
26+
//! When all dependencies are `no_std`, you should use [`nostd_panic_handler!`](https://docs.rs/pinocchio/latest/pinocchio/macro.nostd_panic_handler.html)
27+
//! instead of `default_panic_handler!` to declare a rust runtime panic handler.
28+
//! There's no need to do this when any dependency is `std` since rust compiler will
29+
//! emit a panic handler.
30+
//!
3331
//! To use the `entrypoint!` macro, use the following in your entrypoint definition:
3432
//! ```ignore
3533
//! use pinocchio::{
36-
//! AccountView,
34+
//! account::AccountView,
3735
//! Address,
3836
//! entrypoint,
3937
//! ProgramResult
@@ -56,18 +54,16 @@
5654
//! * `accounts`: the accounts received
5755
//! * `instruction_data`: data for the instruction
5856
//!
59-
//! Pinocchio also offers variations of the program entrypoint
60-
//! ([`lazy_program_entrypoint`]) and global allocator ([`no_allocator`]). In
61-
//! order to use these, the program needs to specify the program entrypoint,
62-
//! global allocator and panic handler individually. The [`entrypoint!`] macro
63-
//! is equivalent to writing:
57+
//! `pinocchio` also offers variations of the program entrypoint (`lazy_program_entrypoint`)
58+
//! and global allocator (`no_allocator`). In order to use these, the program needs to
59+
//! specify the program entrypoint, global allocator and panic handler individually. The
60+
//! `entrypoint!` macro is equivalent to writing:
6461
//! ```ignore
6562
//! program_entrypoint!(process_instruction);
6663
//! default_allocator!();
6764
//! default_panic_handler!();
6865
//! ```
69-
//! Any of these macros can be replaced by other implementations and Pinocchio
70-
//! offers a couple of variants for this.
66+
//! Any of these macros can be replaced by alternative implementations.
7167
//!
7268
//! ### [`lazy_program_entrypoint!`]
7369
//!
@@ -160,16 +156,44 @@
160156
//! 💡 The [`no_allocator!`] macro can also be used in combination with the
161157
//! [`lazy_program_entrypoint!`].
162158
//!
163-
//! ## `std` crate feature
159+
//! Since the `no_allocator!` macro does not allocate memory, the `32kb` memory region
160+
//! reserved for the heap remains unused. To take advantage of this, the `no_allocator!`
161+
//! macro emits an `allocate_unchecked` helper function that allows you to manually
162+
//! reserve memory for a type at compile time.
163+
//! ```ignore
164+
//! /// static allocation:
165+
//! /// - 0 is the offset when the type will be allocated
166+
//! /// - `allocate_unchecked` returns a mutable reference to the allocated type
167+
//! let lamports = allocate_unchecked::<u64>(0);
168+
//! *lamports = 1_000_000_000;
169+
//! ```
170+
//!
171+
//! Note that it is the developer's responsibility to ensure that types do not overlap
172+
//! in memory - the `offset + <size of type>` of different types must not overlap.
173+
//!
174+
//! ## Crate features
175+
//!
176+
//! ### `alloc`
177+
//!
178+
//! The `alloc` feature is enabled by default and it uses the [`alloc`](https://doc.rust-lang.org/alloc/)
179+
//! crate. This provides access to dynamic memory allocation in combination with the
180+
//! [`default_allocator!`], e.g., required to use `String` and `Vec` in a program.
181+
//! Helpers that need to allocate memory, such as fetching [`crate::sysvars::slot_hashes::SlotHashes::fetch`]
182+
//! sysvar data, are also available.
183+
//!
184+
//! When no allocation is needed or desired, the feature can be disabled:
185+
//!
186+
//! ```ignore
187+
//! pinocchio = { version = "0.10.0", default-features = false }
188+
//! ```
189+
//!
190+
//! ### `cpi`
191+
//!
192+
//! The `cpi` feature enables the cross-program invocation helpers, as well as types
193+
//! to define instructions and signer information.
164194
//!
165-
//! By default, Pinocchio is a `no_std` crate. This means that it does not use any
166-
//! code from the standard (`std`) library. While this does not affect how Pinocchio
167-
//! is used, there is a one particular apparent difference. Helpers that need to
168-
//! allocate memory, such as fetching `SlotHashes` sysvar, are not available. To
169-
//! enable these helpers, the `alloc` feature must be enabled when adding Pinocchio
170-
//! as a dependency:
171195
//! ```ignore
172-
//! pinocchio = { version = "0.10.0", features = ["alloc"] }
196+
//! pinocchio = { version = "0.10.0", features = ["cpi"] }
173197
//! ```
174198
//!
175199
//! ## Advanced entrypoint configuration
@@ -185,7 +209,7 @@
185209
//! #[cfg(feature = "bpf-entrypoint")]
186210
//! mod entrypoint {
187211
//! use pinocchio::{
188-
//! AccountView,
212+
//! account::AccountView,
189213
//! Address,
190214
//! entrypoint,
191215
//! ProgramResult

0 commit comments

Comments
 (0)