Skip to content

Conversation

@pauldelucia
Copy link
Member

@pauldelucia pauldelucia commented Nov 27, 2025

If you sync from checkpoint, disconnect, and reconnect, filter headers were being loaded from storage at 0 instead of checkpoint.

Summary by CodeRabbit

  • Bug Fixes
    • Fixed blockchain sync height calculation during checkpoint-based synchronization so the next sync height never regresses when the node's tip is behind the configured sync base, improving synchronization correctness and stability.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 27, 2025

Walkthrough

The store_filter_headers function's next-blockchain-height calculation was adjusted: when a checkpoint sync base exists and the current tip is below that checkpoint, the next height is set to the checkpoint; otherwise the prior tip+1 behavior remains. The None-tip path is unchanged.

Changes

Cohort / File(s) Change Summary
Height calculation refinement
dash-spv/src/storage/disk/filters.rs
Modified next_blockchain_height calculation in store_filter_headers: for Some(tip) if sync_base_height > 0 and tip < sync_base_height then set next_blockchain_height = sync_base_height, otherwise set next_blockchain_height = tip + 1. The None case is unchanged.

Sequence Diagram(s)

sequenceDiagram
  participant Caller as store_filter_headers
  participant Storage as FiltersStorage

  Caller->>Storage: request store headers (has sync_base_height)
  alt tip is Some
    Storage->>Storage: if sync_base_height > 0 and tip < sync_base_height
    alt tip < sync_base_height
      Storage-->>Caller: next_blockchain_height = sync_base_height
    else tip >= sync_base_height
      Storage-->>Caller: next_blockchain_height = tip + 1
    end
  else tip is None
    Storage-->>Caller: next_blockchain_height = (unchanged) sync_base_height/path
  end
  Note right of Storage `#D3E4CD`: Decision focused on tip vs checkpoint\n(unchanged None-case)
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Verify the conditional correctly handles tip < sync_base_height.
  • Confirm the None-case remains correct in surrounding logic.
  • Check for off-by-one or integer underflow/overflow edge cases.

Poem

🐰 I nibble code where checkpoints lay,
If tips fall short, I hop and stay—
Keep heights firm until the climb,
No eager leap ahead of time.
A tiny tweak, a steadier pace, hooray!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main fix: filter headers not resuming from checkpoint on reconnect, which matches the primary change in the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/filters-resync

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.

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
dash-spv/src/storage/disk/filters.rs (1)

22-30: Checkpoint-aware next_blockchain_height logic correctly fixes the reconnect behavior

Anchoring next_blockchain_height to sync_base_height when sync_base_height > 0 and cached_filter_tip_height is still below the checkpoint ensures that new filter headers are written starting at the checkpoint, not into pre-checkpoint indices. That keeps the checkpoint-relative storage mapping consistent on reconnect and avoids mixing “genesis-style” indices with checkpoint-based ones, which aligns with the PR objective.

Given this guard, the next_blockchain_height < sync_base_height branch in the storage index computation (Lines 48–56) should now be unreachable in normal operation. You might consider tightening that path to make the invariant explicit, e.g. via a debug_assert!(next_blockchain_height >= sync_base_height) and keeping the tracing::warn! as a defensive fallback, so any future regressions are easier to spot during development.

Also applies to: 44-56

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4e9ef04 and 0b163c5.

📒 Files selected for processing (1)
  • dash-spv/src/storage/disk/filters.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: DCG-Claude
Repo: dashpay/rust-dashcore PR: 0
File: :0-0
Timestamp: 2025-06-26T16:01:37.609Z
Learning: The mempool tracking infrastructure (UnconfirmedTransaction, MempoolState, configuration, and mempool_filter.rs) is fully implemented and integrated in the Dash SPV client as of this PR, including client logic, FFI APIs, and tests.
📚 Learning: 2025-06-26T16:01:37.609Z
Learnt from: DCG-Claude
Repo: dashpay/rust-dashcore PR: 0
File: :0-0
Timestamp: 2025-06-26T16:01:37.609Z
Learning: The mempool tracking infrastructure (UnconfirmedTransaction, MempoolState, configuration, and mempool_filter.rs) is fully implemented and integrated in the Dash SPV client as of this PR, including client logic, FFI APIs, and tests.

Applied to files:

  • dash-spv/src/storage/disk/filters.rs

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
dash-spv/src/storage/disk/filters.rs (1)

22-28: Checkpoint resume behavior looks correct; consider logging the unexpected tip < sync_base_height case.

The new conditional cleanly fixes the reconnect-from-checkpoint issue: when a cached tip is behind the checkpoint, you now restart from sync_base_height instead of tip + 1, while leaving genesis-sync and normal continuation (tip ≥ checkpoint) semantics unchanged. That’s consistent with how storage indices are derived later in the loop and avoids writing headers at pre‑checkpoint indices.

Since tip < sync_base_height should generally not happen in a healthy checkpointed flow (other than the specific reconnect scenario you’re targeting), you might optionally emit a tracing::warn! in that branch to surface any future unexpected state transitions:

Some(tip) => {
    if sync_base_height > 0 && tip < sync_base_height {
        tracing::warn!(
            "cached_filter_tip_height ({}) is below sync_base_height ({}); \
             resetting next_blockchain_height to checkpoint",
            tip,
            sync_base_height
        );
        sync_base_height
    } else {
        tip + 1
    }
}

This keeps the fix while making it easier to spot misconfigurations or future regressions around checkpoint handling.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0b163c5 and 050a5cd.

📒 Files selected for processing (1)
  • dash-spv/src/storage/disk/filters.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: DCG-Claude
Repo: dashpay/rust-dashcore PR: 0
File: :0-0
Timestamp: 2025-06-26T16:01:37.609Z
Learning: The mempool tracking infrastructure (UnconfirmedTransaction, MempoolState, configuration, and mempool_filter.rs) is fully implemented and integrated in the Dash SPV client as of this PR, including client logic, FFI APIs, and tests.

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