Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,12 @@ pub fn process_instruction(
By default, Pinocchio is a `no_std` crate. This means that it does not use any code from the
standard (`std`) library. While this does not affect how Pinocchio is used, there is a one
particular apparent difference. Helpers that need to allocate memory, such as fetching `SlotHashes`
sysvar data, are not available. To enable these helpers, the `std` feature must be enabled when adding
Pinocchio as a dependency:
sysvar data, are not available. To enable these helpers, the `alloc` feature must be enabled when
adding Pinocchio as a dependency:
```
pinocchio = { version = "0.10.0", features = ["std"] }
pinocchio = { version = "0.10.0", features = ["alloc"] }
```
The `alloc` feature uses the `alloc` crate.

## Advance entrypoint configuration

Expand Down
3 changes: 2 additions & 1 deletion sdk/pinocchio/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ unexpected_cfgs = { level = "warn", check-cfg = [
] }

[features]
alloc = []
copy = ["solana-account-view/copy", "solana-address/copy"]
cpi = ["dep:solana-instruction-view"]
std = ["solana-address/std"]
default = ["alloc"]

[dependencies]
solana-account-view = { workspace = true }
Expand Down
76 changes: 36 additions & 40 deletions sdk/pinocchio/src/entrypoint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@ pub mod lazy;

pub use lazy::{InstructionContext, MaybeAccount};

#[cfg(not(feature = "std"))]
#[cfg(not(feature = "alloc"))]
use core::alloc::{GlobalAlloc, Layout};

#[cfg(target_os = "solana")]
pub use alloc::BumpAllocator;
use core::{
cmp::min,
mem::{size_of, MaybeUninit},
Expand All @@ -22,6 +19,9 @@ use crate::{
Address, BPF_ALIGN_OF_U128, MAX_TX_ACCOUNTS,
};

#[cfg(all(target_os = "solana", feature = "alloc"))]
pub use alloc::BumpAllocator;

/// Start address of the memory region used for program heap.
pub const HEAP_START_ADDRESS: u64 = 0x300000000;

Expand Down Expand Up @@ -125,6 +125,7 @@ const STATIC_ACCOUNT_DATA: usize = size_of::<Account>() + MAX_PERMITTED_DATA_INC
/// manually.
///
/// [`crate::nostd_panic_handler`]: https://docs.rs/pinocchio/latest/pinocchio/macro.nostd_panic_handler.html
#[cfg(feature = "alloc")]
#[macro_export]
macro_rules! entrypoint {
( $process_instruction:expr ) => {
Expand Down Expand Up @@ -279,9 +280,9 @@ macro_rules! process_accounts {
//
// Note: The function is marked as `cold` to stop the compiler from optimizing the parsing of
// duplicated accounts, which leads to an overall increase in CU consumption.
#[allow(clippy::clone_on_copy)]
#[cold]
#[inline(always)]
#[allow(clippy::clone_on_copy)]
unsafe fn clone_account_info(
accounts: *mut AccountView,
accounts_slice: *const AccountView,
Expand Down Expand Up @@ -459,14 +460,12 @@ macro_rules! default_panic_handler {
/// This macro sets up a default panic handler that logs the location (file, line and column) where
/// the panic occurred and then calls the syscall `abort()`.
///
/// This macro can only be used when all crates are `no_std` and the `"std"` feature is disabled.
#[cfg(not(feature = "std"))]
/// This macro should be used when all crates are `no_std`.
#[macro_export]
macro_rules! nostd_panic_handler {
() => {
/// A panic handler for `no_std`.
#[cfg(target_os = "solana")]
#[no_mangle]
#[panic_handler]
fn handler(info: &core::panic::PanicInfo<'_>) -> ! {
if let Some(location) = info.location() {
Expand Down Expand Up @@ -502,6 +501,7 @@ macro_rules! nostd_panic_handler {
/// Default global allocator.
///
/// This macro sets up a default global allocator that uses a bump allocator to allocate memory.
#[cfg(feature = "alloc")]
#[macro_export]
macro_rules! default_allocator {
() => {
Expand All @@ -525,12 +525,12 @@ macro_rules! default_allocator {

/// A global allocator that does not allocate memory.
///
/// Using this macro with the `"std"` feature enabled will result in a compile error.
#[cfg(feature = "std")]
/// Using this macro with the `"alloc"` feature enabled will result in a compile error.
#[cfg(feature = "alloc")]
#[macro_export]
macro_rules! no_allocator {
() => {
compile_error!("Feature 'std' cannot be enabled.");
compile_error!("Feature 'alloc' cannot be enabled.");
};
}

Expand All @@ -542,8 +542,8 @@ macro_rules! no_allocator {
///
/// The program will panic if it tries to dynamically allocate memory.
///
/// This is used when the `"std"` feature is disabled.
#[cfg(not(feature = "std"))]
/// This is used when the `"alloc"` feature is disabled.
#[cfg(not(feature = "alloc"))]
#[macro_export]
macro_rules! no_allocator {
() => {
Expand Down Expand Up @@ -602,12 +602,27 @@ macro_rules! no_allocator {
};
}

#[cfg(target_os = "solana")]
mod alloc {
//! The bump allocator used as the default rust heap when running programs.
#[cfg(not(feature = "alloc"))]
/// An allocator that does not allocate memory.
#[cfg_attr(feature = "copy", derive(Copy))]
#[derive(Clone, Debug)]
pub struct NoAllocator;

extern crate alloc;
#[cfg(not(feature = "alloc"))]
unsafe impl GlobalAlloc for NoAllocator {
#[inline]
unsafe fn alloc(&self, _: Layout) -> *mut u8 {
panic!("** NO ALLOCATOR **");
}

#[inline]
unsafe fn dealloc(&self, _: *mut u8, _: Layout) {
// I deny all allocations, so I don't need to free.
}
}

#[cfg(all(target_os = "solana", feature = "alloc"))]
mod alloc {
use core::{
alloc::{GlobalAlloc, Layout},
mem::size_of,
Expand Down Expand Up @@ -653,34 +668,15 @@ mod alloc {
}
}

#[cfg(not(feature = "std"))]
/// An allocator that does not allocate memory.
#[cfg_attr(feature = "copy", derive(Copy))]
#[derive(Clone, Debug)]
pub struct NoAllocator;

#[cfg(not(feature = "std"))]
unsafe impl GlobalAlloc for NoAllocator {
#[inline]
unsafe fn alloc(&self, _: Layout) -> *mut u8 {
panic!("** NO ALLOCATOR **");
}

#[inline]
unsafe fn dealloc(&self, _: *mut u8, _: Layout) {
// I deny all allocations, so I don't need to free.
}
}

#[cfg(all(test, not(target_os = "solana")))]
mod tests {
extern crate std;
extern crate alloc;

use core::{alloc::Layout, ptr::copy_nonoverlapping};
use std::{
use alloc::{
alloc::{alloc, dealloc},
vec,
};
use core::{alloc::Layout, ptr::copy_nonoverlapping};

use super::*;

Expand All @@ -703,7 +699,7 @@ mod tests {
unsafe {
let ptr = alloc(layout);
if ptr.is_null() {
std::alloc::handle_alloc_error(layout);
alloc::alloc::handle_alloc_error(layout);
}
AlignedMemory { ptr, layout }
}
Expand Down
10 changes: 5 additions & 5 deletions sdk/pinocchio/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@
//! code from the standard (`std`) library. While this does not affect how Pinocchio
//! is used, there is a one particular apparent difference. Helpers that need to
//! allocate memory, such as fetching `SlotHashes` sysvar, are not available. To
//! enable these helpers, the `std` feature must be enabled when adding Pinocchio
//! enable these helpers, the `alloc` feature must be enabled when adding Pinocchio
//! as a dependency:
//! ```ignore
//! pinocchio = { version = "0.10.0", features = ["std"] }
//! pinocchio = { version = "0.10.0", features = ["alloc"] }
//! ```
//!
//! ## Advanced entrypoint configuration
Expand Down Expand Up @@ -208,10 +208,10 @@
//! cargo build-sbf --features bpf-entrypoint
//! ```

#![no_std]
#![cfg_attr(not(test), no_std)]

#[cfg(feature = "std")]
extern crate std;
#[cfg(feature = "alloc")]
extern crate alloc;

pub mod entrypoint;
pub mod sysvars;
Expand Down
8 changes: 4 additions & 4 deletions sdk/pinocchio/src/sysvars/slot_hashes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use crate::{
Address,
};

#[cfg(feature = "std")]
use std::boxed::Box;
#[cfg(feature = "alloc")]
use alloc::{boxed::Box, vec::Vec};

/// `SysvarS1otHashes111111111111111111111111111`
pub const SLOTHASHES_ID: Address = Address::new_from_array([
Expand Down Expand Up @@ -299,7 +299,7 @@ impl<'a> SlotHashes<Ref<'a, [u8]>> {
}
}

#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
impl SlotHashes<Box<[u8]>> {
/// Fills the provided buffer with the full `SlotHashes` sysvar data.
///
Expand All @@ -320,7 +320,7 @@ impl SlotHashes<Box<[u8]>> {
/// Allocates an optimal buffer for the sysvar data based on available features.
#[inline(always)]
fn allocate_and_fetch() -> Result<Box<[u8]>, ProgramError> {
let mut buf = std::vec::Vec::with_capacity(MAX_SIZE);
let mut buf = Vec::with_capacity(MAX_SIZE);
unsafe {
// SAFETY: `buf` was allocated with capacity `MAX_SIZE` so its
// pointer is valid for exactly that many bytes. `fill_from_sysvar`
Expand Down
3 changes: 1 addition & 2 deletions sdk/pinocchio/src/sysvars/slot_hashes/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use core::{
ptr,
};

extern crate std;
use std::io::Write;
use std::vec::Vec;

Expand Down Expand Up @@ -460,7 +459,7 @@ fn test_from_account_info_constructor() {
/// `SlotHashes` getters to make sure the view itself works. We do not verify
/// that the syscall populated real on-chain bytes, as doing so requires an
/// environment outside the scope of host `cargo test`.
#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
#[test]
fn test_fetch_allocates_buffer_host() {
const START_SLOT: u64 = 500;
Expand Down
3 changes: 1 addition & 2 deletions sdk/pinocchio/src/sysvars/slot_hashes/test_edge.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::{error::ProgramError, sysvars::slot_hashes::*};
extern crate std;
use super::test_utils::{build_slot_hashes_bytes as raw_slot_hashes, make_account_info};
use crate::{error::ProgramError, sysvars::slot_hashes::*};

#[test]
fn test_wrong_key_from_account_view() {
Expand Down
1 change: 0 additions & 1 deletion sdk/pinocchio/src/sysvars/slot_hashes/test_raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

use super::raw;
use super::*;
extern crate std;

#[test]
fn test_validate_buffer_size() {
Expand Down
1 change: 0 additions & 1 deletion sdk/pinocchio/src/sysvars/slot_hashes/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
//! freely while production code remains `#![no_std]`.

use super::*;
extern crate std;
use crate::account::{Account, AccountView};
use core::ptr;
use std::vec::Vec;
Expand Down