Skip to content

fuzz: Marinade crucible harness + FuzzCorp CI - #93

Closed
talllo wants to merge 4 commits into
marinade-finance:mainfrom
talllo:fuzz/marinade-crucible-harness
Closed

fuzz: Marinade crucible harness + FuzzCorp CI#93
talllo wants to merge 4 commits into
marinade-finance:mainfrom
talllo:fuzz/marinade-crucible-harness

Conversation

@talllo

@talllo talllo commented Aug 20, 2026

Copy link
Copy Markdown

What

Adds a coverage-guided fuzz harness for marinade_finance under fuzz/marinade, plus a GitHub Actions workflow that builds and submits a bundle to FuzzCorp — building everything fresh on every PR, nothing static.

The harness runs against a fork of real mainnet Marinade state and asserts runtime invariants after every action:

  • P-0001…P-0014 — conservation, solvency, mSOL/LP supply integrity, no-free-value on the value paths, crank neutrality, and per-world consistency.
  • P-0007 — a target-panic detector: SBF panics (unchecked-arith overflow with overflow-checks = true, unwrap/expect, index OOB, assert!) are swallowed by the VM as failed txs, so this scans tx logs and turns any target panic into a reported crash.

CI — everything built from source, on every PR

.github/workflows/fuzzcorp.yml runs on every PR and push to main (ubuntu-latest, amd64 — matches the FuzzCorp fleet):

  1. Builds the program from this ref's sourceanchor build with the repo's pinned anchor 0.27 / solana 1.14.29 toolchain (via the verifiable-build image). So each change is fuzzed against its own program, not a committed .so snapshot.
  2. Tracks crucible maincargo update -p crucible-* pulls the latest fuzzer before building the harness.
  3. Assembles the bundle and uploads it via asymmetric-research/fuzz-upload-action@v2.

Required repo configuration (Settings → Secrets and variables → Actions):

  • secret FUZZ_API_KEY — a FuzzCorp service-account key
  • var FUZZ_ORGANIZATION = marinade
  • var FUZZ_PROJECT = liquid-staking-program

Notes

  • Nothing bulky/generated is committed: the program .so and IDL are built in CI; the 97 mainnet fixture .bin files are shipped as one 160K fixtures-mainnet.tar.gz (embedded at compile time; build-bundle.sh unpacks it).
  • Fuzzing concentrates on a 5-validator/stake subset of the fork (SCOUT_FORK_FUZZ_N) so it drives a few targets into deep states rather than spreading across ~692 validators.
  • This is a campaign build: three already-documented findings are deliberately suppressed so P-0007 surfaces only new panics. (A repro_findings feature re-enables all three for one-time verification.)

@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 299c190d-d7b8-4294-841c-98894d57d548

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@talllo
talllo marked this pull request as draft August 20, 2026 18:17
talllo and others added 3 commits August 20, 2026 20:12
Adds a coverage-guided fuzz harness for `marinade_finance` under fuzz/marinade,
driven against a fork of real mainnet Marinade state, plus a GitHub Actions
workflow that builds it and submits a bundle to FuzzCorp on every push to main.

- fuzz/marinade/src/main.rs — the harness. Runtime invariants P-0001..P-0014
  (conservation, solvency, supply integrity, no-free-value, and P-0007, a
  target-panic detector) are asserted after every action.
- fuzz/marinade/fixtures/mainnet/** — real mainnet account snapshots, embedded
  at compile time (include_bytes!).
- fuzz/marinade/programs/marinade_program.so — the target program, loaded at
  runtime.
- fuzz/marinade/idls/marinade.json — program IDL, read at compile time by
  declare_fuzz_program!.
- fuzz/marinade/build-bundle.sh — builds the harness and assembles a FuzzCorp
  bundle (amd64, crucible driver) under build/.
- .github/workflows/fuzzcorp.yml — ubuntu-latest (amd64, native — matches the
  worker fleet) build + upload via asymmetric-research/fuzz-upload-action@v2.

crucible deps are pinned to rev 432481a (immune to branch rebases). Three
documented findings are suppressed in this campaign build so the P-0007 panic
detector surfaces only NEW panics rather than re-reporting known ones.

CI needs three repo settings: secret FUZZ_API_KEY, vars FUZZ_ORGANIZATION=marinade
and FUZZ_PROJECT=liquid-staking-program.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Remove non-build fixture metadata (per-account *.json, *.txt address lists,
  extra *.md) — only the *.bin snapshots are embedded, so these just bloated the
  PR. 102 files removed.
- Consolidate the README into one short file.
- Cap fuzz target selection to a 5-validator/stake subset (SCOUT_FORK_FUZZ_N):
  the real fork loads ~692 validators / ~46 stakes, which spread the fuzzer thin;
  it now concentrates on 5 targets and drives them into deeper states. Only the
  target-selection picks are capped — validator lookups and merge-append keep the
  real counts, so the fork stays consistent (no invariant-consistency change).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Stop committing generated/bulky artifacts and fuzz each PR against its own program:

- Remove the committed program .so (1.2M) and IDL (96K). CI now builds them from
  this repo's program source with the pinned anchor 0.27 / solana 1.14.29 toolchain
  (via the verifiable-build image), so every PR is fuzzed against its own program
  build rather than a stale snapshot.
- Compress the 97 mainnet fixture .bin files into one 160K archive
  (fixtures-mainnet.tar.gz); build-bundle.sh unpacks it before the include_bytes!
  build.
- Workflow now runs on every pull_request and on push to main (was push-only), and
  uploads only when secrets are available (fork PRs still build as a check).

fuzz/marinade now tracks just the harness source, Cargo files, README, build script,
and the fixtures archive.
@talllo

talllo commented Aug 21, 2026

Copy link
Copy Markdown
Author

Superseded by #96 — recreated with clean commit history (no AI attribution) and the program/IDL built in CI instead of committed.

@talllo talllo closed this Aug 21, 2026
Track crucible `main` (branch, not a pinned rev) so the harness is built and fuzzed
against the latest fuzzer. CI adds a `cargo update -p crucible-*` step before the
build to pull the newest main on every run.

Combined with building the program from source per-PR, nothing is a static snapshot:
each change is compiled against the latest fuzzer and the freshly-built program, then
fuzzed. Verified locally: harness builds + fuzzes clean against crucible main.
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