bch(M5): re-download a merkle-rejected block body (no height blackhole) - #206
Merged
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A full block whose body fails the merkle-root check in
emit_full_blockis dropped, but theblockhandler still calledon_block_received— which keeps the hash inm_knownpermanently. Sinceenqueue()dedupes onm_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 byDEFAULT_MAX_BLOCK_REJECTSso 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
src/impl/bch/only; header-only, build-inert (bch stays skip-green).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.