Programs
Anchor → Pinocchio
| Anchor | Pinocchio |
|---|---|
#[program] |
entrypoint!(process_instruction) |
declare_id! |
pub const ID: Address = address!("...") |
| Automatic discriminator dispatch | Manual match on first byte |
Context<T> |
Account slice destructuring |
Basic Structure
#![no_std]
use pinocchio::{AccountView, Address, ProgramResult, entrypoint, error::ProgramError};
pub const ID: Address = pinocchio::address!("MyProgram11111111111111111111111111111111");
entrypoint!(process_instruction);
pub fn process_instruction(
program_id: &Address,
accounts: &[AccountView],
instruction_data: &[u8],
) -> ProgramResult {
if program_id != &ID {
return Err(ProgramError::IncorrectProgramId);
}
match instruction_data.first() {
Some(&0) => initialize(accounts, &instruction_data[1..]),
Some(&1) => update(accounts, &instruction_data[1..]),
_ => Err(ProgramError::InvalidInstructionData),
}
}
fn initialize(accounts: &[AccountView], data: &[u8]) -> ProgramResult { Ok(()) }
fn update(accounts: &[AccountView], data: &[u8]) -> ProgramResult { Ok(()) }
Anchor equivalent:
#[program]
pub mod my_program {
pub fn initialize(ctx: Context<Initialize>) -> Result<()> { Ok(()) }
pub fn update(ctx: Context<Update>) -> Result<()> { Ok(()) }
}
File Layout
src/
├── lib.rs # entrypoint + instruction dispatch
├── state.rs # account state structs
├── error.rs # custom errors
└── processor/
├── mod.rs
├── initialize.rs
└── update.rs
lib.rs with Modules
#![no_std]
mod state;
mod error;
mod processor;
use pinocchio::{AccountView, Address, ProgramResult, entrypoint, error::ProgramError};
pub const ID: Address = pinocchio::address!("...");
#[cfg(feature = "bpf-entrypoint")]
entrypoint!(process_instruction);
pub fn process_instruction(
program_id: &Address,
accounts: &[AccountView],
instruction_data: &[u8],
) -> ProgramResult {
processor::dispatch(program_id, accounts, instruction_data)
}
Entrypoint Options
// Standard - includes allocator + panic handler
entrypoint!(process_instruction);
// Just entrypoint - you provide allocator/panic
program_entrypoint!(process_instruction);
pinocchio::default_allocator!();
pinocchio::default_panic_handler!();
// Lazy - parse accounts on-demand (saves CU for simple programs)
lazy_program_entrypoint!(process_instruction);
Lazy Entrypoint
Parse accounts only when needed (useful for single-instruction programs):
use pinocchio::entrypoint::InstructionContext;
lazy_program_entrypoint!(process_instruction);
default_allocator!();
default_panic_handler!();
fn process_instruction(mut ctx: InstructionContext) -> ProgramResult {
let first = ctx.next_account()?.assume_account(); // Parse first account
let second = ctx.next_account()?.assume_account(); // Parse second account
let data = ctx.instruction_data()?;
let program_id = ctx.program_id()?;
Ok(())
}
No Allocator (Zero Heap)
#![no_std]
pinocchio::no_allocator!();
pinocchio::nostd_panic_handler!();
Building
cargo build-sbf # Standard build
cargo build-sbf --features cpi # With CPI support