Skip to content

Commit 1345585

Browse files
committed
refactor: move channel check to pre-setup node
1 parent ba847bf commit 1345585

1 file changed

Lines changed: 29 additions & 51 deletions

File tree

Bitkit/ViewModels/WalletViewModel.swift

Lines changed: 29 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,6 @@ class WalletViewModel: ObservableObject {
5959

6060
static var peerSimulation: BlocktankPeerSimulation = .none
6161

62-
private static let channelRecoveryRestartDelayMs: UInt64 = 500
63-
6462
@Published var isRestoringWallet = false
6563
@Published var balanceInTransferToSavings: Int = 0
6664
@Published var balanceInTransferToSpending: Int = 0
@@ -138,6 +136,21 @@ class WalletViewModel: ObservableObject {
138136
MigrationsService.shared.pendingChannelMigration = nil
139137
}
140138

139+
// If no local migration data, try fetching from RN remote backup (one-time)
140+
if channelMigration == nil {
141+
let (remoteMigration, allRetrieved) = await fetchOrphanedChannelMonitorsIfNeeded(walletIndex: walletIndex)
142+
if let remoteMigration {
143+
channelMigration = ChannelDataMigration(
144+
channelManager: [UInt8](remoteMigration.channelManager),
145+
channelMonitors: remoteMigration.channelMonitors.map { [UInt8]($0) }
146+
)
147+
MigrationsService.shared.pendingChannelMigration = nil
148+
}
149+
if allRetrieved {
150+
MigrationsService.shared.isChannelRecoveryChecked = true
151+
}
152+
}
153+
141154
await runLegacyNetworkGraphCleanupIfNeeded()
142155

143156
try await lightningService.setup(
@@ -236,77 +249,42 @@ class WalletViewModel: ObservableObject {
236249
Task { @MainActor in
237250
try await sync()
238251
}
239-
240-
// One-time check for orphaned channel monitors from RN migration
241-
Task {
242-
await checkForOrphanedChannelMonitorRecovery()
243-
}
244252
}
245253

246-
private func checkForOrphanedChannelMonitorRecovery() async {
254+
/// Fetches orphaned channel monitors from RN remote backup before LDK setup.
255+
/// Returns (migration data if found, whether all monitors were successfully retrieved).
256+
private func fetchOrphanedChannelMonitorsIfNeeded(walletIndex: Int) async -> (PendingChannelMigration?, Bool) {
247257
let migrations = MigrationsService.shared
248-
guard !migrations.isChannelRecoveryChecked else { return }
258+
guard !migrations.isChannelRecoveryChecked else { return (nil, true) }
249259

250-
Logger.info("Running one-time channel monitor recovery check", context: "WalletViewModel")
260+
Logger.info("Running pre-startup channel monitor recovery check", context: "WalletViewModel")
251261

252-
var allMonitorsRetrieved = false
253262
do {
254-
guard let mnemonic = try Keychain.loadString(key: .bip39Mnemonic(index: 0)) else {
263+
guard let mnemonic = try Keychain.loadString(key: .bip39Mnemonic(index: walletIndex)) else {
255264
Logger.debug("Channel recovery: no mnemonic, skipping", context: "WalletViewModel")
256265
migrations.isChannelRecoveryChecked = true
257-
return
266+
return (nil, true)
258267
}
259-
let passphrase = try? Keychain.loadString(key: .bip39Passphrase(index: 0))
268+
let passphrase = try? Keychain.loadString(key: .bip39Passphrase(index: walletIndex))
260269

261270
RNBackupClient.shared.reset()
262271
try await RNBackupClient.shared.setup(mnemonic: mnemonic, passphrase: passphrase)
263272

264-
let retrieved = await migrations.fetchRNRemoteLdkData()
273+
let allRetrieved = await migrations.fetchRNRemoteLdkData()
265274

266275
if let migration = migrations.pendingChannelMigration {
267-
let monitorCount = migration.channelMonitors.count
268276
Logger.info(
269-
"Found \(monitorCount) monitors on RN backup, attempting recovery",
277+
"Found \(migration.channelMonitors.count) monitors on RN backup for pre-startup recovery",
270278
context: "WalletViewModel"
271279
)
272-
273-
let channelMigration = ChannelDataMigration(
274-
channelManager: [UInt8](migration.channelManager),
275-
channelMonitors: migration.channelMonitors.map { [UInt8]($0) }
276-
)
277-
migrations.pendingChannelMigration = nil
278-
279-
// Stop and restart the lightning service directly (not via self.start())
280-
// to avoid the nodeLifecycleState guard racing with concurrent sync Tasks
281-
try await lightningService.stop()
282-
try await Task.sleep(nanoseconds: Self.channelRecoveryRestartDelayMs * 1_000_000)
283-
284-
let electrumServerUrl = electrumConfigService.getCurrentServer().fullUrl
285-
let rgsServerUrl = rgsConfigService.getCurrentServerUrl()
286-
try await lightningService.setup(
287-
walletIndex: 0,
288-
electrumServerUrl: electrumServerUrl,
289-
rgsServerUrl: rgsServerUrl.isEmpty ? nil : rgsServerUrl,
290-
channelMigration: channelMigration
291-
)
292-
try await lightningService.start()
293-
294-
nodeLifecycleState = .running
295-
syncState()
296-
Logger.info("Channel monitor recovery complete", context: "WalletViewModel")
280+
return (migration, allRetrieved)
297281
} else {
298282
Logger.info("No channel monitors found on RN backup", context: "WalletViewModel")
283+
return (nil, allRetrieved)
299284
}
300-
301-
allMonitorsRetrieved = retrieved
302285
} catch {
303-
Logger.error("Channel monitor recovery check failed: \(error)", context: "WalletViewModel")
304-
}
305-
306-
if allMonitorsRetrieved {
307-
migrations.isChannelRecoveryChecked = true
308-
} else {
309-
Logger.warn("Some monitors failed to download, will retry on next startup", context: "WalletViewModel")
286+
Logger.error("Pre-startup channel monitor fetch failed: \(error)", context: "WalletViewModel")
287+
return (nil, false)
310288
}
311289
}
312290

0 commit comments

Comments
 (0)