Skip to content

feat(compression/cnft-burn): add pinocchio example - #719

Open
MarkFeder wants to merge 3 commits into
solana-foundation:mainfrom
MarkFeder:compression-cnft-burn-pinocchio
Open

feat(compression/cnft-burn): add pinocchio example#719
MarkFeder wants to merge 3 commits into
solana-foundation:mainfrom
MarkFeder:compression-cnft-burn-pinocchio

Conversation

@MarkFeder

Copy link
Copy Markdown
Contributor

Ports compression/cnft-burn to Pinocchio — the first Pinocchio example in compression/.

Program

A single instruction that CPIs into mpl-bubblegum's Burn, replacing a compressed NFT's leaf with an empty node. The burn arguments (root, data_hash, creator_hash, nonce, index) are already in bubblegum's wire order, so the CPI data is the discriminator followed by the instruction data verbatim — no borsh round-trip.

Two things differ from the Anchor variant:

  • Variable-length account list. The merkle proof arrives as an account tail, so the CPI accounts are built into a fixed-size stack array and passed with invoke_with_bounds instead of the const-generic invoke. MAX_PROOF_ACCOUNTS is capped at 24, which keeps the list off the heap and covers any proof that fits in a transaction.
  • CPI target is a constant. The bubblegum program is still taken as an account (it has to be in the transaction), but the CPI always targets the hardcoded program id. The tree authority is rederived on-chain and checked before the CPI.

Tests

The Anchor variant is in .ghaignore because its tests need devnet and a DAS indexer. This one runs entirely under LiteSVM against the mainnet-dumped bubblegum, account-compression and noop programs (prepare.mjs dumps them on postinstall, same pattern as nft-operations):

  1. allocates a depth-3 tree and initializes it via create_tree
  2. mints a cNFT with mint_v1
  3. burns it through the Pinocchio program

Steps 1 and 2 recompute the expected root off-chain and assert it against the tree's own change log, so the leaf, data and creator hashes the burn depends on are verified independently rather than just "the transaction succeeded". Step 3 asserts the tree is empty again afterwards.

Verification

cargo build-sbf, isolated and workspace clippy -D warnings, cargo fmt --check --all, tsc --noEmit, prettier --check, and the 3-test LiteSVM suite all pass locally.

Ports the Anchor cnft-burn example to Pinocchio: a single instruction that
CPIs into mpl-bubblegum's `Burn` to remove a compressed NFT's leaf from its
concurrent merkle tree.

The merkle proof arrives as a variable-length account tail, so the CPI account
list is built into a fixed-size stack array and passed with
`invoke_with_bounds` rather than the const-generic `invoke`.

Unlike the Anchor variant, whose tests need devnet and a DAS indexer, the
LiteSVM suite runs entirely locally: it creates a tree, mints a cNFT and burns
it against the mainnet-dumped bubblegum, account-compression and noop
programs, recomputing the leaf and root off-chain to check them against the
tree's own state.
@MarkFeder
MarkFeder requested a review from dev-jodee as a code owner September 1, 2026 09:42
@greptile-apps

greptile-apps Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds a Pinocchio compressed-NFT burn example that forwards Bubblegum burn arguments through CPI and verifies the flow with LiteSVM.

  • Adds the on-chain burn handler, Bubblegum PDA validation, and bounded variable-length proof forwarding.
  • Adds fixture preparation and end-to-end tests covering tree creation, minting, and burning.
  • Registers the program in the Rust workspace and adds its JavaScript and Rust dependencies.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the previously reported persistent Solana CLI endpoint mutation is removed by applying the mainnet override only to each program-dump command.

Important Files Changed

Filename Overview
compression/cnft-burn/pinocchio/prepare.mjs Dumps each required mainnet program with a command-scoped cluster override, resolving the prior persistent CLI configuration mutation.
compression/cnft-burn/pinocchio/program/src/instructions/burn_cnft.rs Implements the bounded Bubblegum burn CPI, validates instruction length and tree authority, and forwards proof accounts.
compression/cnft-burn/pinocchio/tests/test.ts Exercises tree creation, compressed-NFT minting, root verification, and burning under LiteSVM.
compression/cnft-burn/pinocchio/package.json Defines fixture preparation, build, deployment, and test scripts with dependencies resolved by the committed lockfile.
Cargo.toml Adds the Pinocchio cNFT burn program to the Rust workspace.

Reviews (3): Last reviewed commit: "cnft-burn: raise the proof cap to the pr..." | Re-trigger Greptile

Comment thread compression/cnft-burn/pinocchio/prepare.mjs Outdated
`solana config set -um` persisted mainnet into the developer's CLI config, so a
plain `pnpm install` could silently redirect their later deploys. Passing `-um`
to `solana program dump` targets mainnet for that command alone.
A 24-node cap could reject a valid proof: proofs are `max_depth - canopy_depth`
nodes and SPL Account Compression allows a max_depth of 30, so a canopy-less
deep tree needs all 30 — and address lookup tables make that transaction fit.
At 30 the bound can no longer reject anything valid; it only keeps the CPI
account list on the stack.
@MarkFeder

Copy link
Copy Markdown
Contributor Author

@amilz could you take a look at this one when you get a chance?

No open review threads left on it, so it is ready for maintainer review. It is one of 23 open Pinocchio ports I have up — they are independent and self-contained, so they can be reviewed and merged in any order: https://github.com/solana-developers/program-examples/pulls/MarkFeder

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant