fix(syncing): only gate sends during initial restore - #998
Conversation
📝 WalkthroughWalkthroughThe PR replaces the general chain-sync send block with an initial-restore synchronization gate. Core-funded sends and payment routes use the shared policy. Tests cover initial restore, completed sync, and ordinary catch-up states. ChangesInitial restore send gating
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant PaymentRoute
participant WalletSendService
participant WalletState
PaymentRoute->>WalletSendService: check initial restore sync
WalletSendService->>WalletState: read resync and chain sync state
WalletState-->>WalletSendService: return current state
WalletSendService-->>PaymentRoute: block or allow Core-funded spending
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@DashWallet/Sources/UI/Payments/InternalTransfer/InternalTransferViewModel.swift`:
- Around line 624-630: The restore marker currently bypasses monitor callbacks,
so both view models can become stale. Expose the marker through a typed
publisher, then update InternalTransferViewModel.swift:624-630 and
SendViewModel.swift:464-471 to subscribe to it and recompute their sync-blocking
state when DWRecoverWalletCommand or DWGlobalOptions.restoreToDefaults() changes
the marker; retain existing SyncingActivityMonitor updates.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: bc716ac6-485a-4e8f-a5e2-fc733c6261bd
📒 Files selected for processing (5)
DashWallet/Sources/Models/Transactions/WalletSendService.swiftDashWallet/Sources/UI/Payments/InternalTransfer/InternalTransferViewModel.swiftDashWallet/Sources/UI/Payments/Pay/SendScreen.swiftDashWallet/Sources/UI/Payments/Pay/SendViewModel.swiftDashWalletTests/PassiveWalletStateUITailTests.swift
| /// Only Core-funded routes during a restored wallet's first sync block. | ||
| var isBlockedBySync: Bool { | ||
| switch route { | ||
| case .coreToShielded, .coreToPlatform: | ||
| return !isChainSynced | ||
| return WalletSendService.isBlockedByInitialRestoreSync( | ||
| isResyncingWallet: DWGlobalOptions.sharedInstance().isResyncingWallet, | ||
| isChainSynced: isChainSynced) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 6 '\bisResyncingWallet\b' \
--glob '*.swift' --glob '*.m' --glob '*.mm' --glob '*.h'
rg -n -C 5 \
-e 'objectWillChange' \
-e 'NotificationCenter.*restore' \
-e 'NotificationCenter.*resync' \
-e 'publisher\(for:' \
--glob '*.swift' --glob '*.m' --glob '*.mm' --glob '*.h'Repository: dashpay/dashwallet-ios
Length of output: 160
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- target files ---'
git ls-files '*InternalTransferViewModel.swift' '*SendViewModel.swift' '*DWGlobalOptions*'
printf '%s\n' '--- restore-marker references ---'
rg -n -C 8 'isResyncingWallet|DWGlobalOptions' \
DashWallet/Sources/UI/Payments/InternalTransfer/InternalTransferViewModel.swift \
DashWallet/Sources/UI/Payments/Pay/SendViewModel.swift \
--glob '*.swift' --glob '*.m' --glob '*.mm' --glob '*.h' || true
printf '%s\n' '--- publication and observation in target files ---'
rg -n -C 5 'ObservableObject|objectWillChange|`@Published`|publisher\(for:|NotificationCenter|SyncingActivityMonitor|syncDone|init\(|deinit|sink\(' \
DashWallet/Sources/UI/Payments/InternalTransfer/InternalTransferViewModel.swift \
DashWallet/Sources/UI/Payments/Pay/SendViewModel.swift \
--glob '*.swift' || true
printf '%s\n' '--- marker definition and mutation sites ---'
rg -n -C 10 'isResyncingWallet' . \
--glob '*.swift' --glob '*.m' --glob '*.mm' --glob '*.h' || trueRepository: dashpay/dashwallet-ios
Length of output: 50378
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- direct marker assignments ---'
rg -n -C 4 '(\bisResyncingWallet\b|\bresyncingWallet\b)\s*=' \
--glob '*.swift' --glob '*.m' --glob '*.mm' --glob '*.h' . || true
printf '%s\n' '--- global-options implementation ---'
cat -n DashWallet/Sources/Models/DWGlobalOptions.h | sed -n '1,90p'
cat -n DashWallet/Sources/Models/DWGlobalOptions.m | sed -n '1,180p'
printf '%s\n' '--- monitor state transitions ---'
cat -n 'DashWallet/Sources/Application/Syncyng Activity Monitor/SyncingActivityMonitor.swift' | sed -n '110,180p'
printf '%s\n' '--- restore/resync lifecycle references ---'
rg -n -C 6 'resync|restore|syncDone|syncStateChangedNotification' \
--glob '*.swift' --glob '*.m' --glob '*.mm' --glob '*.h' \
DashWallet/Sources | head -n 500Repository: dashpay/dashwallet-ios
Length of output: 50378
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- recovery command lifecycle ---'
cat -n DashWallet/Sources/UI/Setup/RecoverWallet/DWRecoverWalletCommand.m | sed -n '1,130p'
printf '%s\n' '--- restoreToDefaults callers ---'
rg -n -C 8 'DWGlobalOptions.*restoreToDefaults|restoreToDefaults\s*\(' \
--glob '*.swift' --glob '*.m' --glob '*.mm' --glob '*.h' \
DashWallet/Sources | head -n 300
printf '%s\n' '--- monitor initialization and state updates ---'
cat -n 'DashWallet/Sources/Application/Syncyng Activity Monitor/SyncingActivityMonitor.swift' | sed -n '180,330p'
cat -n 'DashWallet/Sources/Application/Syncyng Activity Monitor/SyncingActivityMonitor.swift' | sed -n '330,460p'
printf '%s\n' '--- payment view-model construction and lifetime anchors ---'
rg -n -C 5 'InternalTransferViewModel\(|SendViewModel\(' \
--glob '*.swift' DashWallet/Sources/UI | head -n 400Repository: dashpay/dashwallet-ios
Length of output: 24799
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- recovery command call sites ---'
rg -n -C 10 'DWRecoverWalletCommand|recoverWalletWithPhrase|recoverWallet' \
--glob '*.swift' --glob '*.m' --glob '*.mm' --glob '*.h' \
DashWallet/Sources | head -n 500
printf '%s\n' '--- exact view-model initialization paths ---'
cat -n DashWallet/Sources/UI/Payments/InternalTransfer/InternalTransferViewModel.swift | sed -n '540,590p'
cat -n DashWallet/Sources/UI/Payments/Pay/SendViewModel.swift | sed -n '90,155p'
printf '%s\n' '--- all writes to the sync monitor state ---'
rg -n -C 3 '\bstate\s*=' \
'DashWallet/Sources/Application/Syncyng Activity Monitor/SyncingActivityMonitor.swift' \
--glob '*.swift'Repository: dashpay/dashwallet-ios
Length of output: 44018
Publish restore-marker changes to both view models.
DWRecoverWalletCommand changes the marker without changing SyncingActivityMonitor.state. DWGlobalOptions.restoreToDefaults() also changes it without a monitor callback. Expose the marker through a typed publisher and update both InternalTransferViewModel and SendViewModel.
📍 Affects 2 files
DashWallet/Sources/UI/Payments/InternalTransfer/InternalTransferViewModel.swift#L624-L630(this comment)DashWallet/Sources/UI/Payments/Pay/SendViewModel.swift#L464-L471
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@DashWallet/Sources/UI/Payments/InternalTransfer/InternalTransferViewModel.swift`
around lines 624 - 630, The restore marker currently bypasses monitor callbacks,
so both view models can become stale. Expose the marker through a typed
publisher, then update InternalTransferViewModel.swift:624-630 and
SendViewModel.swift:464-471 to subscribe to it and recompute their sync-blocking
state when DWRecoverWalletCommand or DWGlobalOptions.restoreToDefaults() changes
the marker; retain existing SyncingActivityMonitor updates.
Summary
Validation
git diff --checkpassedv4.2-devcontains merged platform #4381 and rust-dashcore revision36b49cb7f9c07ce8f2ed63f965489c50968d19f7Out of scope
Summary by CodeRabbit
Improvements
Tests