You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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 — either at the first time the program is called or when one program invokes the instructions of another program — 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
+
<pstyle="font-size: 12px; color: #999999">
28
+
<strong><sup>*</sup></strong> It includes only dependencies to Solana SDK types — i.e., no <i>external</i> dependencies.
29
+
</p>
29
30
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
31
32
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.
39
34
40
35
## Features
41
36
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
45
41
46
42
## Getting started
47
43
@@ -57,21 +53,21 @@ This will add `pinocchio` as a dependency to your project.
57
53
58
54
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.
59
55
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:
61
57
62
58
*[`program_entrypoint!`](https://docs.rs/pinocchio/latest/pinocchio/macro.program_entrypoint.html): declares the program entrypoint
63
59
*[`default_allocator!`](https://docs.rs/pinocchio/latest/pinocchio/macro.default_allocator.html): declares the default (bump) global allocator
64
60
*[`default_panic_handler!`](https://docs.rs/pinocchio/latest/pinocchio/macro.default_panic_handler.html): declares the default panic handler
65
61
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.
67
63
68
64
To use the `entrypoint!` macro, use the following in your entrypoint definition:
69
65
```rust
70
66
usepinocchio::{
71
67
account::AccountView,
68
+
Address,
72
69
entrypoint,
73
-
ProgramResult,
74
-
Address
70
+
ProgramResult
75
71
};
76
72
77
73
entrypoint!(process_instruction);
@@ -91,17 +87,17 @@ The information from the input is parsed into their own entities:
91
87
*`accounts`: the accounts received
92
88
*`instruction_data`: data for the instruction
93
89
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:
95
91
```rust
96
92
program_entrypoint!(process_instruction);
97
93
default_allocator!();
98
94
default_panic_handler!();
99
95
```
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.
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 — 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 — 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.
105
101
106
102
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.
107
103
@@ -166,21 +162,41 @@ pub fn process_instruction(
166
162
> ⚠️ **Note:**
167
163
> The `no_allocator!` macro can also be used in combination with the `lazy_program_entrypoint!`.
168
164
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
+
letlamports=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 — 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.
170
192
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:
176
193
```
177
-
pinocchio = { version = "0.10.0", features = ["alloc"] }
194
+
pinocchio = { version = "0.10.0", features = ["cpi"] }
178
195
```
179
-
The `alloc` feature uses the `alloc` crate.
180
196
181
197
## Advance entrypoint configuration
182
198
183
-
The symbols emitted by the entrypoint macros — program entrypoint, global allocator and default panic handler — 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 — program entrypoint, global allocator and default panic handler — 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`.
//! 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.
16
8
//!
17
9
//! ## Defining the program entrypoint
18
10
//!
@@ -23,17 +15,23 @@
23
15
//! and [panic handler](https://doc.rust-lang.org/nomicon/panic-handler.html) using
24
16
//! the [`default_allocator!`] and [`default_panic_handler!`] macros.
25
17
//!
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:
28
21
//!
29
22
//! * [`program_entrypoint!`]: declares the program entrypoint
30
23
//! * [`default_allocator!`]: declares the default (bump) global allocator
31
24
//! * [`default_panic_handler!`]: declares the default panic handler
32
25
//!
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
+
//!
33
31
//! To use the `entrypoint!` macro, use the following in your entrypoint definition:
34
32
//! ```ignore
35
33
//! use pinocchio::{
36
-
//! AccountView,
34
+
//! account::AccountView,
37
35
//! Address,
38
36
//! entrypoint,
39
37
//! ProgramResult
@@ -56,18 +54,16 @@
56
54
//! * `accounts`: the accounts received
57
55
//! * `instruction_data`: data for the instruction
58
56
//!
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:
64
61
//! ```ignore
65
62
//! program_entrypoint!(process_instruction);
66
63
//! default_allocator!();
67
64
//! default_panic_handler!();
68
65
//! ```
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.
71
67
//!
72
68
//! ### [`lazy_program_entrypoint!`]
73
69
//!
@@ -160,16 +156,44 @@
160
156
//! 💡 The [`no_allocator!`] macro can also be used in combination with the
161
157
//! [`lazy_program_entrypoint!`].
162
158
//!
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:
0 commit comments