diff --git a/Bitkit.xcodeproj/project.pbxproj b/Bitkit.xcodeproj/project.pbxproj index 3b930521..d6e4a2ee 100644 --- a/Bitkit.xcodeproj/project.pbxproj +++ b/Bitkit.xcodeproj/project.pbxproj @@ -928,7 +928,7 @@ repositoryURL = "https://github.com/synonymdev/ldk-node"; requirement = { kind = revision; - revision = c5698d00066e0e50f33696afc562d71023da2373; + revision = ae38eadab70fceb5dbe242bc02bf895581cb7c3f; }; }; 96DEA0382DE8BBA1009932BF /* XCRemoteSwiftPackageReference "bitkit-core" */ = { diff --git a/Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index e14c1eae..b1ca3574 100644 --- a/Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -24,7 +24,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/synonymdev/ldk-node", "state" : { - "revision" : "c5698d00066e0e50f33696afc562d71023da2373" + "revision" : "ae38eadab70fceb5dbe242bc02bf895581cb7c3f" } }, { diff --git a/Bitkit/Services/LightningService.swift b/Bitkit/Services/LightningService.swift index 2bfa4a27..357287e2 100644 --- a/Bitkit/Services/LightningService.swift +++ b/Bitkit/Services/LightningService.swift @@ -95,7 +95,8 @@ class LightningService { onchainWalletSyncIntervalSecs: Env.walletSyncIntervalSecs, lightningWalletSyncIntervalSecs: Env.walletSyncIntervalSecs, feeRateCacheUpdateIntervalSecs: Env.walletSyncIntervalSecs - ) + ), + connectionTimeoutSecs: 10 ) builder.setChainSourceElectrum(serverUrl: resolvedElectrumServerUrl, config: electrumConfig) @@ -124,19 +125,46 @@ class LightningService { builder.setEntropyBip39Mnemonic(mnemonic: mnemonic, passphrase: passphrase) try await ServiceQueue.background(.ldk) { - if !lnurlAuthServerUrl.isEmpty { - self.node = try builder.buildWithVssStore( - vssUrl: vssUrl, - storeId: storeId, - lnurlAuthServerUrl: lnurlAuthServerUrl, - fixedHeaders: [:] - ) - } else { - self.node = try builder.buildWithVssStoreAndFixedHeaders( - vssUrl: vssUrl, - storeId: storeId, - fixedHeaders: [:] + do { + if !lnurlAuthServerUrl.isEmpty { + self.node = try builder.buildWithVssStore( + vssUrl: vssUrl, + storeId: storeId, + lnurlAuthServerUrl: lnurlAuthServerUrl, + fixedHeaders: [:] + ) + } else { + self.node = try builder.buildWithVssStoreAndFixedHeaders( + vssUrl: vssUrl, + storeId: storeId, + fixedHeaders: [:] + ) + } + } catch let error as BuildError { + guard case .DangerousValue = error else { throw error } + + // Stale ChannelMonitor vs ChannelManager — retry with accept_stale to recover. + Logger.warn( + "Build failed with DangerousValue. Retrying with accept_stale_channel_monitors for recovery.", + context: "Recovery" ) + builder.setAcceptStaleChannelMonitors(accept: true) + + if !lnurlAuthServerUrl.isEmpty { + self.node = try builder.buildWithVssStore( + vssUrl: vssUrl, + storeId: storeId, + lnurlAuthServerUrl: lnurlAuthServerUrl, + fixedHeaders: [:] + ) + } else { + self.node = try builder.buildWithVssStoreAndFixedHeaders( + vssUrl: vssUrl, + storeId: storeId, + fixedHeaders: [:] + ) + } + Logger.info("Stale monitor recovery: build succeeded with accept_stale", context: "Recovery") } } diff --git a/Bitkit/Utilities/Errors.swift b/Bitkit/Utilities/Errors.swift index e4b1f62d..6630577f 100644 --- a/Bitkit/Utilities/Errors.swift +++ b/Bitkit/Utilities/Errors.swift @@ -185,6 +185,9 @@ struct AppError: LocalizedError { case let .ReadFailed(message: ldkMessage): message = "Read failed" debugMessage = ldkMessage + case let .DangerousValue(message: ldkMessage): + message = "Dangerous value" + debugMessage = ldkMessage case let .WriteFailed(message: ldkMessage): message = "Write failed" debugMessage = ldkMessage diff --git a/Bitkit/ViewModels/WalletViewModel.swift b/Bitkit/ViewModels/WalletViewModel.swift index 1949c215..da0b7aae 100644 --- a/Bitkit/ViewModels/WalletViewModel.swift +++ b/Bitkit/ViewModels/WalletViewModel.swift @@ -137,7 +137,7 @@ class WalletViewModel: ObservableObject { MigrationsService.shared.pendingChannelMigration = nil } - // If no local migration data, try fetching from RN remote backup (one-time) + // // If no local migration data, try fetching from RN remote backup (one-time) // if channelMigration == nil { // let (remoteMigration, allRetrieved) = await fetchOrphanedChannelMonitorsIfNeeded(walletIndex: walletIndex) // if let remoteMigration {