Skip to content

fix: detect corrupt block index entries during load#276

Open
MorningLightMountain713 wants to merge 1 commit intomasterfrom
fix/block-index-corruption-check
Open

fix: detect corrupt block index entries during load#276
MorningLightMountain713 wants to merge 1 commit intomasterfrom
fix/block-index-corruption-check

Conversation

@MorningLightMountain713
Copy link
Contributor

@MorningLightMountain713 MorningLightMountain713 commented Mar 20, 2026

Summary

  • A single bit flip in a block index LevelDB value causes GetBlockHash() to compute a wrong hash, inserting the entry under an incorrect key in mapBlockIndex. Child blocks referencing the correct hash via hashPrev create a stub with pprev=NULL. BuildSkip then walks into the stub, hitting assert(pindexWalk->pprev) at chain.cpp:94, which calls abort() and produces a core dump (SIGABRT). Systemd restarts fluxd, which hits the same corruption and crashes again — resulting in an infinite core dump loop (300+ restarts observed on a production node).
  • The existing consistency check (header.GetHash() != GetBlockHash()) misses this because both sides derive from the same corrupt data — it compares the computed hash against itself, not the stored LevelDB key.
  • Add a check comparing the computed hash against key.second (the LevelDB key), which is the authoritative stored hash. Exit cleanly with a descriptive error instead of core dumping.

Test plan

  • Tested on a node with a known single-bit-flip corruption at height 2,225,820
  • Before fix: infinite core dump loop — fluxd: chain.cpp:94: CBlockIndex* CBlockIndex::GetAncestor(int): Assertion 'pindexWalk->pprev' failed. (SIGABRT, exit code 134, 300+ restarts)
  • After fix: single clean exit (code 1) with ERROR: LoadBlockIndex(): corrupt block index entry at height 2225820: computed hash ... != stored key ...
  • Tested on a healthy node: loads normally, no false positives

🤖 Generated with Claude Code

A single bit flip in a block index value causes GetBlockHash() to
compute a wrong hash. The entry gets inserted into mapBlockIndex under
that wrong hash, while child blocks referencing the correct hash via
hashPrev create a stub with NULL pprev. BuildSkip then walks into the
stub and hits assert(pindexWalk->pprev), crashing fluxd in a loop.

The existing consistency check (header.GetHash() != GetBlockHash())
doesn't catch this because both sides derive from the same corrupt
data. Add a check comparing the computed hash against the LevelDB key
(key.second), which is the authoritative stored hash. Use key.second
for insertBlockIndex to ensure the entry goes under the correct hash.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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