From 54fdb31fdbf59811915ce83c7c4327c74f401196 Mon Sep 17 00:00:00 2001 From: bfoss765 Date: Sat, 11 Jul 2026 06:41:32 -0400 Subject: [PATCH] feat(key-wallet): widen DEFAULT_COINJOIN_GAP_LIMIT 30 -> 100 for dashj parity Proposal: align the CoinJoin address discovery window with dashj's `DeterministicKeyChain` lookahead (`DEFAULT_LOOKAHEAD_SIZE = 100`), the effective window dashj-core watches for CoinJoin keychains. This is window dimensioning, not a scan-algorithm fix. The gap limit only bounds the largest run of consecutive UNUSED CoinJoin addresses the wallet can bridge before discovery stalls; the progressive rescan-to-quiescence algorithm in dash-spv + key-wallet is already correct at gap 30 for any spray whose unused runs are <= 30. See PR description for the two-sided evidence and the reference to the ongoing team discussion. Refs: dashpay/platform#4074, dashpay/dash-wallet#1507 Co-Authored-By: Claude Fable 5 --- key-wallet/src/gap_limit.rs | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/key-wallet/src/gap_limit.rs b/key-wallet/src/gap_limit.rs index 9d4d5b088..7eaefc99c 100644 --- a/key-wallet/src/gap_limit.rs +++ b/key-wallet/src/gap_limit.rs @@ -16,8 +16,31 @@ pub const DEFAULT_EXTERNAL_GAP_LIMIT: u32 = 30; /// Standard gap limit for internal (change) addresses pub const DEFAULT_INTERNAL_GAP_LIMIT: u32 = 30; -/// Standard gap limit for CoinJoin addresses -pub const DEFAULT_COINJOIN_GAP_LIMIT: u32 = 30; +/// Standard gap limit for CoinJoin addresses. +/// +/// Set to match dashj's `DeterministicKeyChain` lookahead +/// (`DEFAULT_LOOKAHEAD_SIZE = 100`), which is the effective discovery window +/// dashj-core (the reference wallet, `org.dashj:dashj-core:22.x`) watches for +/// CoinJoin keychains. Address discovery here is dynamic — the pool watches +/// `highest_used + gap_limit` addresses — so this bounds the largest run of +/// UNUSED CoinJoin addresses the wallet can bridge during a filter/rescan +/// before discovery stalls. +/// +/// The previous value of 30 starved heavy mixers: DIP-9 CoinJoin mixing +/// sprays denominations across many sequential addresses, and a run wider +/// than 30 consecutive unused addresses caused the SDK to stop discovering — +/// it then missed both the txs that CREATED far-index UTXOs and the txs that +/// SPENT nearer ones, leaving a persistent balance mismatch vs dashj that +/// survived a clean re-creation + full rescan (dashpay/platform#4074, +/// dashpay/dash-wallet#1507). 100 restores parity with dashj's window so the +/// SDK discovers every CoinJoin tx dashj does. +/// +/// Cost is modest: the CoinJoin account watches two pools (external + +/// internal), so this pre-derives and filter-matches ~200 CoinJoin addresses +/// per account instead of ~60. BIP158 filter matching is a set intersection, +/// so the extra scripts add negligible per-block work; the derivation is a +/// one-time keychain expansion. +pub const DEFAULT_COINJOIN_GAP_LIMIT: u32 = 100; /// Standard gap limit for special purpose keys (identity, provider keys) pub const DEFAULT_SPECIAL_GAP_LIMIT: u32 = 5;