feat(dash-spv): block locator + staged fork detection#803
Conversation
Replace the single-hash `GetHeaders` locator with a dashd-style exponential-backoff locator so peers on a fork can find a recent common ancestor. Route header batches whose `prev_blockhash` resolves to a non-tip stored header into a per-peer `ForkBuffer`, validating each header against PoW, BIP113 MTP, and a port of dashd's DGW v3 retarget anchored at the fork ancestor. Branches age out after a 60s TTL and on peer disconnect. A `ForkCandidate` is exposed via `take_pending_fork_candidate` for the sync coordinator to promote once a fork's extension work beats the active chain.
📝 WalkthroughWalkthroughThis PR implements a staged fork candidate buffering system integrated with Dark Gravity Wave v3 difficulty retargeting. It replaces the legacy ChangesFork candidate staging and DGW v3 retargeting
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@CodeRabbit review |
✅ Action performedReview finished.
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## dev #803 +/- ##
==========================================
+ Coverage 72.67% 72.89% +0.21%
==========================================
Files 322 323 +1
Lines 71363 72034 +671
==========================================
+ Hits 51866 52507 +641
- Misses 19497 19527 +30
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
dash-spv/src/sync/block_headers/fork_buffer.rs (1)
142-150: 💤 Low valueClarify
total_worksemantics inBufferedBranchvsForkCandidate.The
total_workstored inBufferedBranch(line 150) is the fork extension's work only (accumulated fromChainWork::zero()), not the cumulative work including the ancestor chain. This is compared againstactive_extension_workintake_winning_candidate, which is correct for determining the winner.However, the returned
ForkCandidate.total_work(line 194) inherits this same "extension-only" value. If downstream code expects cumulative chain work, this could cause issues. Consider either:
- Renaming to
extension_workfor clarity, or- Adding a doc comment to
ForkCandidate::total_workclarifying it represents extension work only.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@dash-spv/src/sync/block_headers/fork_buffer.rs` around lines 142 - 150, The BufferedBranch.total_work currently holds only the fork-extension work (computed via ChainWork::accumulate(ChainWork::zero(), ...)), but ForkCandidate::total_work is populated with that same extension-only value and may be misleading; update the code to make the semantics explicit: either rename BufferedBranch.total_work to extension_work and propagate that rename everywhere (including where branches are inserted and read in take_winning_candidate) or add a clear doc comment on ForkCandidate::total_work stating it represents extension-only work; if you choose to expose cumulative work instead, compute cumulative_work by adding the ancestor chain work to the extension (use the ancestor chain's ChainWork when constructing ForkCandidate in take_winning_candidate) and return that value. Ensure all references to BufferedBranch.total_work, ForkCandidate::total_work, and the comparison in take_winning_candidate remain consistent after the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@dash-spv/src/sync/block_headers/fork_buffer.rs`:
- Around line 142-150: The BufferedBranch.total_work currently holds only the
fork-extension work (computed via ChainWork::accumulate(ChainWork::zero(),
...)), but ForkCandidate::total_work is populated with that same extension-only
value and may be misleading; update the code to make the semantics explicit:
either rename BufferedBranch.total_work to extension_work and propagate that
rename everywhere (including where branches are inserted and read in
take_winning_candidate) or add a clear doc comment on ForkCandidate::total_work
stating it represents extension-only work; if you choose to expose cumulative
work instead, compute cumulative_work by adding the ancestor chain work to the
extension (use the ancestor chain's ChainWork when constructing ForkCandidate in
take_winning_candidate) and return that value. Ensure all references to
BufferedBranch.total_work, ForkCandidate::total_work, and the comparison in
take_winning_candidate remain consistent after the change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 6f571b9f-9afd-443b-9c85-4d3c1d6dfccd
📒 Files selected for processing (16)
dash-spv/src/chain/chain_tip.rsdash-spv/src/chain/chain_work.rsdash-spv/src/chain/difficulty.rsdash-spv/src/chain/mod.rsdash-spv/src/client/lifecycle.rsdash-spv/src/error.rsdash-spv/src/network/mod.rsdash-spv/src/sync/block_headers/fork_buffer.rsdash-spv/src/sync/block_headers/manager.rsdash-spv/src/sync/block_headers/mod.rsdash-spv/src/sync/block_headers/pipeline.rsdash-spv/src/sync/block_headers/segment_state.rsdash-spv/src/sync/block_headers/sync_manager.rsdash-spv/src/test_utils/chain_tip.rsdash-spv/src/test_utils/mod.rsdash/src/pow.rs
💤 Files with no reviewable changes (2)
- dash-spv/src/test_utils/mod.rs
- dash-spv/src/test_utils/chain_tip.rs
Replace the single-hash
GetHeaderslocator with a dashd-style exponential-backoff locator so peers on a fork can find a recent common ancestor.Route header batches whose
prev_blockhashresolves to a non-tip stored header into a per-peerForkBuffer, validating each header against PoW, BIP113 MTP, and a port of dashd's DGW v3 retarget anchored at the fork ancestor. Branches age out after a 60s TTL and on peer disconnect. AForkCandidateis exposed viatake_pending_fork_candidatefor the sync coordinator to promote once a fork's extension work beats the active chain.Summary by CodeRabbit
Release Notes
New Features
Bug Fixes