fix(dash-spv): collect the scripts derived by every application of a block, not only the tracked one - #1007
Closed
llbartekll wants to merge 1 commit into
Closed
Conversation
…block, not only the tracked one A block is applied more than once during a scan: re-applied by a batch rescan for scripts derived after its first application, or delivered again for an in-flight re-request. Each application can recognise outputs the previous one could not, and derive further scripts through gap widening. The BlockProcessed handler collected new scripts only when the tracker still held the block's in-flight entry — which the first delivery consumes — so the scripts derived by every later application were dropped: neither noted in the durable pending-sweep set nor collected for the batch rescan and the committed-range sweep. On a CoinJoin-heavy mainnet wallet (fresh import, release build) 297 of the 3 645 gap-widened scripts were derived by re-applied blocks and lost. The blocks that spend the coins paid to those addresses match only on the coins' prevout scripts, so they were never found; the wallet ended the scan with 11 spent coins credited (#1006). Settle the in-flight entry and the pending count from the tracked delivery only, but collect new scripts from every delivery: into the tracked batch while it is active, else the batch covering the block, else the lowest active batch — whose commit rescans it, every later batch and the committed prefix. With no active batch the scripts stay in the durable pending-sweep set and are replayed by the next scan, as before. The rescan and sweep log lines now carry the script count. Regression test: a second BlockProcessed for an already-settled block must leave its scripts both in the pending-sweep set and in the batch's collected scripts. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Contributor
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueThanks 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 |
This was referenced Sep 9, 2026
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## fix/key-wallet-rescan-changeset #1007 +/- ##
================================================================
Coverage 77.70% 77.71%
================================================================
Files 329 329
Lines 84256 84271 +15
================================================================
+ Hits 65475 65494 +19
+ Misses 18781 18777 -4
|
Contributor
Author
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.
Follow-up to #979, fixes #1006. Stacked on
fix/key-wallet-rescan-changeset(#979) because it lands on top of the durable pending-sweep set that branch introduces; it can be re-targeted todevonce #979 merges.Issue being fixed
A block is applied to the wallet more than once during a scan: re-applied by a batch rescan for scripts derived after its first application, or delivered again for an in-flight re-request. Each application can recognise outputs the previous one could not (the pools grew in between) and derive further scripts through gap widening. The
BlockProcessedhandler collected those scripts only when the tracker still held the block's in-flight entry — which the first delivery consumes — so the scripts derived by every later application were dropped on the floor: neither recorded in the durable pending-sweep set nor collected for the batch rescan and the committed-range sweep.Measured on a CoinJoin-heavy mainnet wallet (fresh import, release build, iOS Simulator, counters added temporarily to the handler): 3 645 scripts were derived during the scan; 3 348 reached the sweep and 297 — derived by 14 blocks that were applied 2–4 times each while their batch still had other blocks outstanding — were lost. The blocks that spend the coins paid to the lost addresses match only on the coins' prevout scripts (their outputs are not ours), so they were never found, requested or applied; the wallet ended the scan with 11 spent coins credited (0.11 DASH) and nothing in the engine could ever remove them: no spender record for the born-spent attribution,
observed_spent_outpointsnever saw the spend,spent_outpointsis only fed by matched transactions. The same 11 coins came back after every restart because the persister mirrors the engine (dashpay/platform#4575, dashpay/platform#4638).What was done
sync_manager.rs: settle the in-flight entry and the batch's pending count from the tracked delivery only, but collect new scripts from every delivery — into the tracked batch while it is active, else the batch covering the block, else the lowest active batch, whose commit rescans it, every later batch and the committed prefix. With no active batch the scripts stay in the durable pending-sweep set and are replayed by the next scan, as before.Rescan filtersandRescan committed filterslog lines now carry the script count, which is what made the loss visible.scripts_derived_by_a_redelivered_block_enter_the_cascadeincoinjoin_gap_discovery_tests.rs: a secondBlockProcessedfor an already-settled block must leave its scripts both in the pending-sweep set and in the batch's collected scripts. Red before the fix (the pending-sweep assertion), green after.How has this been tested
cargo test -p dash-spv --lib sync::filters: 117 passed (116 existing + the new one);cargo fmt --checkandcargo clippy --all-targetsclean fordash-spv.platform-walletFFI with this commit applied on the fix(key-wallet, dash-spv): re-emit late knowledge — record corrections, durable rescans, address-pool repair #979 compat rebase:utxo_count=0for the CoinJoin account, the SwiftData store holds 0 unspent rows, and a restart restores nothing. This matches the only earlier run of the same wallet that had converged (by timing luck).Not addressed here
InFlightre-emitsBlocksNeeded). Harmless for correctness now that every application's scripts are kept, but wasteful; worth a separate look.prune_finalized_observed_spendsbounds by the committed filter height, which runs ahead of rescan deliveries during a historical scan; with the cascade complete this no longer bites on this wallet, noted in dash-spv: the initial scan's new-script cascade never re-tests blocks that only match on the prevouts of coins discovered mid-scan, so their spends are missed and the coins stay credited #1006.🤖 Generated with Claude Code