Solana/More Developer Tools/Rewriting the Simple Data Storage Program with Pinocchio
This section builds on pxsol-ss to demonstrate how to rewrite it with Pinocchio. The final course code lives in the pxsol-ss-pinocchio repository.
Migration Work
The first changes we need are how we query rent_exemption and bump_seed. Here's the before/after:
Old
let rent_exemption = solana_program::rent::Rent::get()?.minimum_balance(data.len());
let bump_seed = solana_program::pubkey::Pubkey::find_program_address(&[&account_user.key.to_bytes()], program_id).1;
New
let rent_exemption = pinocchio::sysvars::rent::Rent::get()?.minimum_balance(data.len());
let bump_seed = &[pinocchio::pubkey::find_program_address(&[&account_user.key()[..]], program_id).1];
To check if the PDA is already initialized:
Old
if **account_data.try_borrow_lamports().unwrap() == 0 { ...
New
if account_data.lamports() == 0 { ...
To call the system program and create the PDA: in Pinocchio, system calls are wrapped in the pinocchio_system crate with a cleaner API. Before/after:
Old
solana_program::program::invoke_signed(
&solana_program::system_instruction::create_account(
account_user.key,
account_data.key,
rent_exemption,
data.len() as u64,
program_id,
),
accounts,
&[&[&account_user.key.to_bytes(), &[bump_seed]]],
)?;
New
pinocchio_system::instructions::CreateAccount {
from: &account_user,
to: &account_data,
lamports: rent_exemption,
space: data.len() as u64,
owner: program_id,
}
.invoke_signed(&[signer])?;
To write data into the PDA:
Old
account_data.data.borrow_mut().copy_from_slice(data);
New
account_data.try_borrow_mut_data().unwrap().copy_from_slice(data);
To adjust balances:
Old
**account_user.lamports.borrow_mut() = account_user.lamports() + account_data.lamports() - rent_exemption;
**account_data.lamports.borrow_mut() = rent_exemption;
New
*account_user.try_borrow_mut_lamports().unwrap() += account_data.lamports() - rent_exemption;
*account_data.try_borrow_mut_lamports().unwrap() = rent_exemption;
Migration done—here's the full code:
use pinocchio::sysvars::Sysvar;
pinocchio::entrypoint!(process_instruction);
pub fn process_instruction(
program_id: &pinocchio::pubkey::Pubkey,
accounts: &[pinocchio::account_info::AccountInfo],
data: &[u8],
) -> pinocchio::ProgramResult {
let account_user = accounts[0];
let account_data = accounts[1];
let rent_exemption = pinocchio::sysvars::rent::Rent::get()?.minimum_balance(data.len());
let bump_seed = &[pinocchio::pubkey::find_program_address(&[&account_user.key()[..]], program_id).1];
let signer_seed = pinocchio::seeds!(account_user.key(), bump_seed);
let signer = pinocchio::instruction::Signer::from(&signer_seed);
// Data account is not initialized. Create an account and write data into it.
if account_data.lamports() == 0 {
pinocchio_system::instructions::CreateAccount {
from: &account_user,
to: &account_data,
lamports: rent_exemption,
space: data.len() as u64,
owner: program_id,
}
.invoke_signed(&[signer])?;
account_data.try_borrow_mut_data().unwrap().copy_from_slice(data);
return Ok(());
}
// Fund the data account to let it rent exemption.
if rent_exemption > account_data.lamports() {
pinocchio_system::instructions::Transfer {
from: &account_user,
to: &account_data,
lamports: rent_exemption - account_data.lamports(),
}
.invoke()?;
}
// Withdraw excess funds and return them to users. Since the funds in the pda account belong to the program, we do
// not need to use instructions to transfer them here.
if rent_exemption < account_data.lamports() {
*account_user.try_borrow_mut_lamports().unwrap() += account_data.lamports() - rent_exemption;
*account_data.try_borrow_mut_lamports().unwrap() = rent_exemption;
}
// Realloc space.
account_data.resize(data.len())?;
// Overwrite old data with new data.
account_data.try_borrow_mut_data().unwrap().copy_from_slice(data);
Ok(())
}
Finally, let's test that the program works. Run these to build, deploy, and test:
$ python make.py deploy
# 2025/05/20 16:06:38 main: deploy program pubkey="T6vZUAQyiFfX6968XoJVmXxpbZwtnKfQbNNBYrcxkcp"
# Save some data.
$ python make.py save "The quick brown fox jumps over the lazy dog"
# Load data.
$ python make.py load
# The quick brown fox jumps over the lazy dog.
# Save some data and overwrite the old data.
$ python make.py save "片云天共远, 永夜月同孤."
# Load data.
$ python make.py load
# 片云天共远, 永夜月同孤.
Key Metrics Comparison
| pxsol-ss | pxsol-ss-pinocchio | |
|---|---|---|
| Build time | 1m10.242s | 0m1.930s |
| Artifact size | 75K | 29K |
| Dependencies | 189 | 7 |
From these metrics you can see clear improvements in build time, artifact size, and dependency count after rewriting with Pinocchio. This shows Pinocchio is a compelling alternative to solana-program for simplifying development and boosting efficiency. We strongly recommend using Pinocchio for new Solana program development.