Repository navigation
ibd: fetch archived bodies above the tip after a crash - #1068
Conversation
There was a problem hiding this comment.
Summary
A crash after the Class A append and before confirmed[] advances leaves header_txs bodies above the connected tip. Restart seeds those hashes as archived, densify's need_hash_at skips them, and the tip-hole race only runs once the body queue is quarter full. This PR asks one peer for each archived hash in the contiguous tip hole (at most 32) when that race is off. That getdata is the right unlock for a thin queue. On this base the bodies then confirm as plan=None with an IBD skeleton, and a same-batch spend still dies in load. The new journey never builds that spend, so it stays green while an ordinary block halts.
Issue counts by severity
- bugs: 1
- suggestions: 2
- nits: 0
6e3d736 to
e54f288
Compare
A batch with an invalid block is retried from its archived bodies. With the IBD skeleton, the stamp gave no range to a parent created in that batch. Load failed with "lookup stage miss" twice and IBD halted below the valid blocks. Fill ranges for the batch's own creates on that retry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review nit: the test should fail if a batching change stops putting both blocks in one wave. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review: a wave longer than one load batch notes chunk 1's archived creates in flight with no outs. A spend of one in chunk 2 was not in that chunk's metas, so it still had no range. Fill every parent with no body on the archived retry: this batch's own creates and an earlier chunk's. Skeleton parents keep their body and in-flight pins are still skipped. Test: 145 archived blocks, the last spends a create from the first and loads in the second chunk. The stamp.rs module note and the invariants row name the exception. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A crash between the Class A write and the tip advance leaves bodies above the tip. On restart the resume seed marks them archived, densify skips archived hashes, and the tip-hole cover only ran once the queue was a quarter full. With a short chain left, IBD sat at the old tip. Cover archived tip holes with one peer when there is no race. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review: crash-recovery.md said Class A never leads tip. A crash between the Class A write and the tip advance leaves bodies above it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The end-of-IBD journey now plants two Class A blocks above a catch-up-only tip. The second spends a create of the first and one of its own. The restart must fetch both and connect them. Docs: Class A never leads tip on a clean run; point the crash exception at crash-recovery.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
e54f288 to
2bc94cf
Compare
There was a problem hiding this comment.
Summary
When the body queue is not in the tip-hole race, densify still skips a Class A seed (need_hash_at returns on is_known_archived, and claim_ready does not treat Class A alone as in hand). The new arm sends those archived tip holes through cover_tip_holes, one peer each, which is the re-get the resume seed already expected: known Class A is not a download skip, because the RAM body queue is empty after a restart and confirm needs peer wire. A best-chain hole that is not archived still waits for densify. Out-of-order connect is still the confirm path's problem, and the same-batch spend above the tip is locked by crash_with_class_a_above_tip together with #1067.
Prior notes are addressed: the branch carries the #1067 fill, the journey spends the archived parent rather than a confirmed coinbase, and architecture, concurrency, and crash-recovery say Class A leads the tip only inside that crash window.
The assign comment is the counterintuitive why (densify will not fetch the seed, and only this cover runs when the race is off).
Issue counts by severity
- bugs: 0
- suggestions: 0
- nits: 0
Rebase is done. This head is ahead of master, mergeable, and its first three commits are #1067's tip. Merge #1067 first.
Stacked on #1067. The first three commits are #1067. Please merge #1067 first.
Summary
A crash between the Class A write and the tip advance leaves bodies above the tip. I hit this with
kill -9during a regtest IBD.On restart:
need_hash_at: "tip-hole cover re-gets tip batch"),race_tip).So when the queue stays thin, nobody asks for tip+1 and IBD sits at the old tip.
assign_work_ordered tip_holes = contiguous_tip_holes(...) if race_tip cover_tip_batch_holes(...) + else + cover_tip_holes(archived tip holes, one peer)Evidence
kill -9three times during a 1,500-block regtest IBD whose blocks spend same-block outputs, then restart:hole=,0.0/s)lookup stage miss)lookup stage miss)hole=,0.0/s)hole=,0.0/s)"stuck" is this PR. "halted" is #1067.
New beat in
end_of_ibd_follow. A fresh store runs catch-up IBD only. Then two new blocks are written as Class A above its tip. The second block spends a create of the first and one of its own. Then it restarts against the miner.tip=104 hole=2 (0.0/s)until the test gives up.engine fault halt @106(lookup stage miss).On mainnet the race starts once 1,000 bodies or 256 MiB are queued, so a deep IBD recovers late. A crash near the end of IBD can stay stuck.
The cover asks one peer per hole. If that peer stalls, the quiet-peer disconnect or the normal race takes over.
Merge Danger
Door: two-way
Blast Radius: small. Only archived tip holes when there is no race. One peer, at most 32 hashes.
🤖 Generated with Claude Code