Skip to content

test: Core v31.1 verdict-only height-1 block differential fuzz (Q-30) - #323

Merged
reardencode merged 9 commits into
masterfrom
test/core-diff-fuzz
Sep 4, 2026
Merged

test: Core v31.1 verdict-only height-1 block differential fuzz (Q-30)#323
reardencode merged 9 commits into
masterfrom
test/core-diff-fuzz

Conversation

@rearden-grok

@rearden-grok rearden-grok Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Summary

First meaningful in-tree differential fuzz (Q-30): libFuzzer mutates a height-1 regtest block, runs in-process ChainHub::accept_received_block, and submitblocks the same bytes to official Bitcoin Core v31.1 bitcoind (downloaded tarball, SHA256 pinned in inventory.toml [release]). Compare accept vs reject only.

Default cargo test --workspace does not download Core, bind RPC, or compile fuzz/. Fuzz is not a required PR check.

Why download, not build

third_party/bitcoin is a sparse clone (src/test/data + test). It cannot produce bitcoind. Official tarball hashes:

  • x86_64 b80d9c3e04da78fb6f0569685673418cf686fadba9042d926d13fb87ff503f9e
  • aarch64 dcf1873f2208ba4f962f3398d47e154c39c0084be8f4553e05c940d0ace3d004

Harness vs finding

  • Consensus split → panic! (libFuzzer crash-*) → docs/external_findings/ + named regression. Do not churn production in this PR to silence it.
  • Dead oracle / hash mismatch / env / comparisons==0 → exit 2, no crash artifact.
  • Height-1 only: rewind_to_height(0) on us; Core invalidateblock until getblockcount==0. Diff hub overlays bip34@1 only (global ChainParams::regtest() unchanged).

Operator: workflow commit

The GitHub App cannot push .github/workflows/*. Local tip on test/core-diff-fuzz has one extra commit after this PR head:

ci: nightly block_differential job

Please push it from a machine with workflows permission:

git -C /tmp/rbtc-core-diff-fuzz log -1 --oneline
git push origin test/core-diff-fuzz

That commit adds the nightly block_differential job (timeout-minutes: 50, tarball cache, rust-cache fuzz -> fuzz/target, no job-level CARGO_TARGET_DIR) and required-CI hooks for pin/fetch tests + fuzz workspace fmt. Prefer workflow_dispatch on fuzz once after that push.

Pin/fetch tests are already hooked from scripts/fuzz-run.test.sh (required test job) so they run before the workflow commit.

Nightly command (after workflow lands)

./scripts/fuzz-run.sh block_differential

Q-30 stays Open (spend-pad / script-wire / BIP324 later).

rbitcoin-grok added 9 commits September 4, 2026 10:16
Differential fuzz needs the same Core release as the sparse submodule
without building bitcoind from it. Record official linux tarball SHA256s
in inventory.toml [release] and print them via release_pin.py (no network).
Required CI already runs fuzz-run.test.sh; hook the new pin test there so
it is gated before the operator workflow commit.
Download the inventory-pinned Core v31.1 tarball, verify SHA256, and
extract only bin/bitcoind into ~/.cache/rbitcoin/core-bitcoind. Tests use
a file:// stub tarball so default CI never hits the network.
Extract nonce-only regtest PoW grind from mine_regtest_paying so the
differential harness can fix prev/bits/time/merkle/nonce without rewriting
fuzzer-owned version or txdata. Commit a height-1 seed for the fuzz corpus.
Add block_diff: Core submitblock JSON/skip map, accept_received_block
verdict mapping, compare_one with rewind_to_height(0), BIP34 overlay on
the diff hub only, env/cookie/HTTP helpers. Pins use a mock oracle so
default cargo test never fetches Core or binds RPC.
Isolated cargo-fuzz bin calls compare_one against a spawned official
bitcoind. Env gates HEAD_SCALE/IO/CORE_BITCOIND before opening the store.
Not a workspace member; default cargo test does not compile it.
Add block_differential: fetch bitcoind, --sanitizer none, -jobs=1, tee a
log and fail if comparisons=0. Unset CARGO_TARGET_DIR around cargo-fuzz
so worktree target/dev does not steal fuzz/target. block_wire path unchanged.
TESTING.md owns how to run height-1 verdict-only fuzz vs official Core
v31.1 bitcoind. Q-30 stays Open. Default cargo test does not fetch Core.
Hash/OutPoint/ScriptBuf are test-only; clippy -D warnings failed on the
lib graph. Keep Hash in the test module for from_byte_array.
Second fuzz.yml job: no CARGO_TARGET_DIR, rust-cache fuzz/target, cache
the v31.1 tarball, --sanitizer none via fuzz-run.sh. Required test job
runs pin/fetch script tests; fmt also checks the fuzz workspace. Not a
required check. Operator may need to push this workflow commit.
@reardencode
reardencode merged commit f7c520f into master Sep 4, 2026
13 checks passed
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