Skip to content

Header tree DoS hardening. #1112

Description

@evoskuil

Status

Landed in chaser_organize: checkpoint gate (forks below the top reached checkpoint rejected before chain state construction), checkpoint purge (tree swept at/below each checkpoint as crossed), currency shrink (one-shot bucket reclamation, rebuild not rehash(0)).

Open: tree growth above the top reached checkpoint is unbounded. Bounded only by (attacker work) / (era difficulty above the reached checkpoint), a divisor arbitrarily small during IBD and decaying forever. Width is the problem, not length: unlimited siblings may attach at any height, each a valid header.

The structural result

Evaluation state for an in-progress branch lives in exactly one of three places:

  1. We hold it — unbounded. Bounding requires refusing valid headers (a consensus rule) or discarding retained ones (an attacker trigger). Both closed.
  2. The peer holds it under commitment, re-presenting on demand — bounded by construction, costs double download and per-peer positional state.
  3. Nobody holds it — cannot evaluate extensions, cannot reorg.

The remaining question is narrow: can any form of (2) be afforded at 100+ peers? Its costs all scale with the peer count we run high deliberately, so that finding the strong chain does not depend on any one peer.

Closed avenues

  • Selective eviction — holes mid-branch; get_branch_work and get_chain_state assume retention.
  • Purge on capacity — attacker triggers it at will; the trigger is the attack.
  • Behavioral classification, per-peer tracking — tracks compliant behavior, classifier input is attacker-chosen, and multiplies the honest case to bound the abnormal one.
  • Work-threshold admission — cannot evaluate without downloading, and no finite prefix proves a branch cannot later win; any threshold on an extensible branch is pseudo-finality.
  • Per-height hash lists — closes width, but a large per-chain artifact, and leaves the above-checkpoint region open and cheapening.
  • Entry slimming — worthwhile separately, but moves a constant.

bitcoind reference (headerssync.h/.cpp)

Two-phase. Presync accumulates work storing one salted bit per 641 headers at a randomized offset; on reaching the threshold, redownload re-requests the chain, checks commitments, and buffers 15218 compressed headers (48B, prevhash dropped) before permanent storage. Threshold is max(tip_work - 144*proof(tip), MinimumChainWork) — the reorganization criterion with slack, not a novel quantity; applies in steady state, not only IBD.

Per peer: ~183B commitments for an honest chain, ~650KB worst case, ~713KiB redownload buffer. Cheap at 8 peers, ~71MiB at 100. Explicitly incomplete: ~23.7 bits of commitment security, and attackers are permitted to inflate permanent index growth by 20% while sustaining the attack.

Per-peer binding is intrinsic: a positional commitment array is only meaningful against the chain that produced it. Our tree is shareable precisely because it is keyed by hash, i.e. because it retains the headers. The only real contribution is do not retain while evaluating.

Entry slimming (independent)

Entries retain a full chain_state (~1.2KB) against a 112B payload. Retain header plus context (~24B, needed to avoid a second roll at organization); sparse full-state anchors every K entries, attach rolling forward from the nearest anchor below (arithmetic over in-tree headers, no I/O); a moving cursor alongside state_ for O(1) honest tip extension. Tips-only retention is wrong twice: below-anchor attach forces a store query per junk header, and under width attack every sibling is a tip. Companion, cross-repo: cumulative work per header record, retiring the populate_work walk. Net ~180B per entry.

Notes

  • rehash(0) may release nothing and MSVC releases nothing (measured, empty or not). Reclamation must rebuild the container. Cross-platform, not an MSVC quirk.
  • The currency event must not clear entries — currency is a fact about our branch only, and proves nothing about other retained branches.
  • Checkpoint recency governs the floor difficulty of the exposed region; a stale set widens the region and lowers its price at once.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions