Component
packages/rs-sdk — dash_sdk::platform::address_sync
Mechanism
sync_address_balances (packages/rs-sdk/src/platform/address_sync/mod.rs) builds a key_to_tag lookup once from a single provider.pending_addresses() snapshot and passes it by immutable reference into the private incremental_catch_up. In both the compacted apply loop and the recent apply loop the predicate if let Some(&(tag, address)) = address_lookup.get(&addr_bytes) had no else branch: any balance change the platform returns for an address absent from the frozen snapshot was dropped with no log, metric, or error. Unlike the tree-scan path, incremental_catch_up never re-polled pending_addresses() (contrast after_branch_iteration, which does refresh during the branch loop).
Repro
Within one sync pass, derive a fresh receive address A after the pass's snapshot is taken (routine under concurrent multi-identity funding), fund A, let it chain-confirm. The recent/compacted balance-changes RPC returns A's balance but the SDK discards it: result.found never gets A, on_address_found is never called, and the wallet's local sync map shows A empty. On single-threaded runs the derive usually precedes the snapshot, hiding the bug — hence "flaky", not "always red", in live e2e.
Impact
Root cause of repeated e2e flakes in the rs-platform-wallet suite: TK-001 / TK-007 / TK-013 / TK-014 / id_005, all funding-gate Found-025 under parallel multi-identity churn.
Fix (implemented)
PR #PLACEHOLDER on v3.1-dev:
- Extract the two inline apply loops into a pure
pub(crate) apply_address_changes seam (no Sdk/network/async) that returns applied updates plus the addresses absent from the snapshot.
apply_block_changes re-polls pending_addresses() when an unknown address appears (mirroring the tree-scan refresh) and replays only the previously-unknown subset, so a freshly-derived address is recovered and known-address AddToCredits deltas are never double-counted.
- Addresses still unknown after the refresh are logged at
warn (observable, never silently dropped).
- Known-address behavior is byte-for-byte identical.
- Three deterministic
#[cfg(test)] regression guards on the pure seam (red on pre-fix logic, green post-fix).
Deterministic-test enablement
The extracted pub(crate) pure seam makes the discard a pure-data assertion (no Sdk/proof) that is pinned in rs-sdk's own test module.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
Component
packages/rs-sdk—dash_sdk::platform::address_syncMechanism
sync_address_balances(packages/rs-sdk/src/platform/address_sync/mod.rs) builds akey_to_taglookup once from a singleprovider.pending_addresses()snapshot and passes it by immutable reference into the privateincremental_catch_up. In both the compacted apply loop and the recent apply loop the predicateif let Some(&(tag, address)) = address_lookup.get(&addr_bytes)had noelsebranch: any balance change the platform returns for an address absent from the frozen snapshot was dropped with no log, metric, or error. Unlike the tree-scan path,incremental_catch_upnever re-polledpending_addresses()(contrastafter_branch_iteration, which does refresh during the branch loop).Repro
Within one sync pass, derive a fresh receive address
Aafter the pass's snapshot is taken (routine under concurrent multi-identity funding), fundA, let it chain-confirm. The recent/compacted balance-changes RPC returnsA's balance but the SDK discards it:result.foundnever getsA,on_address_foundis never called, and the wallet's local sync map showsAempty. On single-threaded runs the derive usually precedes the snapshot, hiding the bug — hence "flaky", not "always red", in live e2e.Impact
Root cause of repeated e2e flakes in the rs-platform-wallet suite: TK-001 / TK-007 / TK-013 / TK-014 / id_005, all funding-gate Found-025 under parallel multi-identity churn.
Fix (implemented)
PR #PLACEHOLDER on
v3.1-dev:pub(crate) apply_address_changesseam (noSdk/network/async) that returns applied updates plus the addresses absent from the snapshot.apply_block_changesre-pollspending_addresses()when an unknown address appears (mirroring the tree-scan refresh) and replays only the previously-unknown subset, so a freshly-derived address is recovered and known-addressAddToCreditsdeltas are never double-counted.warn(observable, never silently dropped).#[cfg(test)]regression guards on the pure seam (red on pre-fix logic, green post-fix).Deterministic-test enablement
The extracted
pub(crate)pure seam makes the discard a pure-data assertion (noSdk/proof) that is pinned inrs-sdk's own test module.Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com