Skip to content

bch(M5): re-download a merkle-rejected block body (no height blackhole) - #206

Merged
frstrtr merged 2 commits into
masterfrom
bch/m5-blockdl-reject-redownload
Jun 19, 2026
Merged

bch(M5): re-download a merkle-rejected block body (no height blackhole)#206
frstrtr merged 2 commits into
masterfrom
bch/m5-blockdl-reject-redownload

Conversation

@frstrtr

@frstrtr frstrtr commented Jun 19, 2026

Copy link
Copy Markdown
Owner

What

A full block whose body fails the merkle-root check in emit_full_block is dropped, but the block handler still called on_block_received — which keeps the hash in m_known permanently. Since enqueue() dedupes on m_known, the height could never be re-requested: one corrupt/malicious body silently and permanently blackholed that height, starving the ABLA size feed and block-connector there.

Fix

BlockDownloadWindow::on_block_rejected: free the window slot and re-queue the hash to the front for another download attempt, bounded by DEFAULT_MAX_BLOCK_REJECTS so a peer that persistently serves a bad body cannot drive an unbounded getdata loop (after the cap, the hash is abandoned, still deduped). The merkle-drop path is routed through it; compact-block reconstruction paths are unaffected (data is local, nothing to re-request).

Scope / compat

  • Pure SPV/IBD plumbing — no PoW, share format, coinbase commitment, AuxPoW, or PPLNS surface. p2pool-merged-v36 surface: NONE.
  • Per-coin isolation: src/impl/bch/ only; header-only, build-inert (bch stays skip-green).
  • Companion to bch(M5): drop evicted-then-arrived block from the download queue #204 (false-evict re-download); inverse case — a rejected body must be re-requestable, not permanently received.

Test

block_download_test.cpp: re-download after reject (slot freed, requeued front, NOT blackholed), no double-queue when expire() already requeued, and the bounded-reject abandonment cap. Builds + runs ALL PASS locally.

frstrtr added 2 commits June 19, 2026 12:06
expire() requeues a timed-out in-flight block to the FRONT of the pending
queue and records it in m_evicted. If the (merely slow) peer then delivers
that block, on_block_received bumped false_evict_count but left the hash in
the queue -- so the next next_requests() drain re-getdata'd a block already
in hand. Remove the hash from the queue on the false-evict path (linear scan;
eviction is rare, healthy sync keeps false_evict at 0). A hash already
re-issued sits in m_in_flight, not the queue, so the scan is a no-op there.

Adds an evicted-then-arrived test pinning both legs: false_evict_count flags
the premature eviction (distinct from a clean arrival) AND queued()==0 / a
following drain is empty -- no re-download. Refreshes the stale header note
that still claimed eviction was deferred (it is implemented and NodeP2P-driven).

PURE block-download window plumbing; p2pool-merged-v36 surface NONE; per-coin
isolation src/impl/bch/ only; header + test build-inert (bch skip-green).
A full block whose body failed the merkle-root check in emit_full_block
was dropped, yet the block handler still called on_block_received -- which
keeps the hash in m_known permanently. enqueue() dedupes on m_known, so the
height could never be re-requested: a single corrupt or malicious body
silently and permanently blackholed that height, starving the ABLA size
feed and the block-connector there forever.

Add BlockDownloadWindow::on_block_rejected: free the window slot and
re-queue the hash to the front for another download attempt, bounded by
DEFAULT_MAX_BLOCK_REJECTS so a peer that persistently serves a bad body
cannot drive an unbounded getdata loop (after the cap the hash is
abandoned, still deduped). Route the merkle-drop path through it; the
compact-block reconstruction paths are unaffected (data is local).

Pure SPV/IBD plumbing -- no PoW, share format, coinbase commitment, or
PPLNS surface. Per-coin isolation: src/impl/bch/ only.
@frstrtr
frstrtr merged commit 2a54ce9 into master Jun 19, 2026
18 checks passed
@frstrtr
frstrtr deleted the bch/m5-blockdl-reject-redownload branch June 19, 2026 13:15
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