Skip to content

fix(dash-spv): extend the CFHeaders queue from the tick, not only on a header event - #964

Draft
romchornyi wants to merge 1 commit into
devfrom
fix/filter-headers-resume-from-tick
Draft

fix(dash-spv): extend the CFHeaders queue from the tick, not only on a header event#964
romchornyi wants to merge 1 commit into
devfrom
fix/filter-headers-resume-from-tick

Conversation

@romchornyi

Copy link
Copy Markdown
Contributor

Issue being fixed or feature implemented

Filter-header sync can stop permanently mid-scan and never resume, while the client keeps looking healthy.

handle_new_headers is the only thing that ever extends the CFHeaders queue, and it runs solely off BlockHeaderSyncComplete and BlockHeadersStored. Block-header storage can advance without either reaching this manager — a segment completing out of order promotes a run of buffered headers, and on a long scan that is how the last stretch of the chain lands. When that happens the manager keeps the target it was last told about, its queue drains, and nothing re-arms it.

Block headers, ChainLocks and inv announcements carry on normally, so from the outside the client looks alive while sync is frozen.

Observed on a mainnet restore:

time event
19:12:58 CFHeaders queue last extended, to height 2 398 000
19:36:48 block headers reach 2 523 515 (Segment 38: complete)
filter headers never move again

Filters and blocks sat at 95% with last_activity climbing past twenty minutes. The wallet's transactions stop arriving at that point, because the persisted watermark cannot advance past the filter frontier.

Same shape as #960 (promote finished header segments from the tick, not only on a message), in the neighbouring pipeline.

What was done?

tick() re-reads the block-header tip from storage and calls handle_new_headers when it has moved past what this manager was last told. Added stored_block_header_tip() on the manager for that read — the storage handle is private to the sibling module, and this keeps it that way rather than widening the field.

No change to the event paths; this is purely an additional way in.

How Has This Been Tested?

test_tick_extends_when_storage_tip_advanced_without_an_event drives exactly the failing sequence: a manager mid-sync that was last told the tip was 1000, storage advanced past that with no event delivered, then one tick.

The test is falsifiable and was checked both ways:

  • with this change — passes
  • with only sync_manager.rs stashed — fails with tick must pick up a tip that advanced without an event

Full dash-spv lib suite: 556 passed, 0 failed, 2 ignored.

Not yet verified end-to-end on mainnet. The mechanism is covered by the unit test, and an app-level run over a patched local checkout completed normally, but that run was on testnet — the network where the stall was originally observed has not been re-run against this build. Keeping this as a draft for that reason.

Breaking Changes

None. Additive: one new private-to-module accessor and an extra branch in tick.

Checklist

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

…a header event

`handle_new_headers` is the only thing that ever extends the filter-header
queue, and it runs solely off `BlockHeaderSyncComplete` and
`BlockHeadersStored`. Block-header storage can advance without either
reaching this manager: a segment completing out of order promotes a run
of buffered headers, and on a long scan that is how the last stretch of
the chain lands.

When that happens the manager keeps the target it was last told about,
its queue drains, and nothing re-arms it. Filter headers then stop for
good while block headers, ChainLocks and inv announcements carry on — so
the client looks alive while sync is frozen, which is what makes this
hard to spot from the outside.

Observed on a mainnet restore: the queue was last extended to height
2_398_000 at 19:12:58, block headers reached 2_523_515 at 19:36:48, and
filter headers never moved again — filters and blocks stuck at 95% with
`last_activity` climbing past twenty minutes.

The tick now re-reads the tip from storage and calls `handle_new_headers`
when it has moved past what this manager knows. Same shape as promoting
finished header segments from the tick (#960): trust the tick, not the
message.

The regression test drives exactly that sequence — storage advances with
no event delivered — and fails without this change.
@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8a796eaa-1063-47b3-862c-e0357c8f2c76

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Aug 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.90%. Comparing base (f4b907c) to head (d9a653c).

Additional details and impacted files
@@           Coverage Diff           @@
##              dev     #964   +/-   ##
=======================================
  Coverage   76.89%   76.90%           
=======================================
  Files         329      329           
  Lines       82332    82372   +40     
=======================================
+ Hits        63312    63347   +35     
- Misses      19020    19025    +5     
Flag Coverage Δ
core 78.25% <ø> (ø)
ffi 52.08% <ø> (ø)
rpc 20.00% <ø> (ø)
spv 91.94% <100.00%> (-0.01%) ⬇️
wallet 78.87% <ø> (ø)
Files with missing lines Coverage Δ
dash-spv/src/sync/filter_headers/manager.rs 92.39% <100.00%> (+1.36%) ⬆️
dash-spv/src/sync/filter_headers/sync_manager.rs 100.00% <ø> (ø)

... and 3 files with indirect coverage changes

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.

2 participants