Public beta · By Asymmetric Research
Invariant fuzzing framework for Solana.
Crucible is a coverage-guided fuzzing framework for Solana programs, built by Asymmetric Research.
Sample run · Solana Stake program
> crucible run stake invariant_test [FUZZ_PULSE] [00:22] iter: 1240713, iter/sec: 57830, pool: 31619/250k (12.4%), crashes: 1, edges: 1176/4290 (27.4%), branches: 917/2145, workers: 12 [FUZZ_FINDING] summary:stake > lamports for activated stake account (0): 63997717120 > 59705032705 === FUZZ SEQUENCE (5 executed, 0 skipped) === 1. delegate_stake(authority=null, stake_account=0, vote_account=null) -> OK 2. advance_slots(slots=43330) -> OK 3. deactivate(authority=null, stake_account=0) -> OK 4. withdraw(authority=null, custodian_signature=true, lamports=4294967295, leave_reserve=true, stake_account=0) -> OK 5. delegate_stake(authority=null, stake_account=0, vote_account=null) -> OK [VIOLATION] =========================================
What it does
Coverage-guided fuzzing at the sBPF level.
Crucible is an invariant fuzzing framework that uses type-aware mutators over transaction sequences. Edge coverage from the real sBPF runtime and unique state coverage guide the exploration. You write a one-line safety invariant; Crucible finds the composition that breaks it.
TestContext API
A LiteSVM wrapper with account builders, cheat codes, time and epoch warps, and typed transaction results. Cuts harness boilerplate 50-70%.
sBPF edge coverage
Register-level tracing turns every branch in the real compiled program into a feedback signal. Source-level LCOV reports included, viewable with genhtml.
Stateless & stateful modes
Two modes: stateless (~10k exec/s, cold restart per iteration) and stateful (up to ~100k exec/s, snapshot-based state pool with state coverage feedback). Both scale near-linearly across cores.
Mainnet forking
Clone live accounts from any RPC endpoint into the harness. Fuzz against realistic state without writing account generators.
How it works
Write the property. Run the fuzzer.
Crucible tests are written as three pieces. Setup runs once and is snapshotted. Actions mutate state. Invariants are checked after every action, and the first violation stops the run.
Setup
fn setup() -> Self
- Initialize accounts, deploy programs, create initial state
- Runs once, then snapshotted, cloned per iteration
Actions
action_* methods
- Macro auto-discovers them
- Typically one transaction, but can wrap multi-transaction flows (e.g. flashloans)
#[range(..)]for constrained params- Adding an action = one new method
Invariants
#[invariant_test]
- Checked after every action
fuzz_assert!(...)for assertions- First violation stops the run and captures the reproducing sequence
Five minutes in
Get started with Crucible.
For hands-on support and custom harnesses, get in touch with the AR team:
[email protected]