-
Notifications
You must be signed in to change notification settings - Fork 16
fix: persist channel locally in case remote backup fails #294
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,39 +27,69 @@ class LdkPersister: Persist { | |
| } | ||
|
|
||
| let isNew = !FileManager().fileExists(atPath: channelStoragePath.path) | ||
| let serialized = Data(data.write()) | ||
|
|
||
| // If we're not remotely backing up no need to update status later | ||
| if BackupClient.skipRemoteBackup { | ||
| try Data(data.write()).write(to: channelStoragePath) | ||
| try serialized.write(to: channelStoragePath) | ||
| if isNew { | ||
| LdkEventEmitter.shared.send(withEvent: .new_channel, body: body) | ||
| } | ||
| return ChannelMonitorUpdateStatus.Completed | ||
| } | ||
|
|
||
| BackupClient.addToPersistQueue(.channelMonitor(id: channelIdHex), data.write()) { error in | ||
|
|
||
| // For new channels: write locally first to prevent loss if app is killed during backup | ||
| // Then try remote backup asynchronously | ||
| if isNew { | ||
| try serialized.write(to: channelStoragePath) | ||
|
|
||
| // Notify chain monitor on main thread | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't need to call channelMonitorUpdated on main thread. Not sure it matters if you do but it shouldn't be required.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If main thread is needed then do the same below for the other call to channelMonitorUpdated
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The threading wrapper is indeed necessary, after another test. It only coincidentally works in the Short write-up by the agent: The Crash occurred in Call Stack:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I updated the other call to |
||
| DispatchQueue.main.async { | ||
ovitrif marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| let res = Ldk.chainMonitor?.channelMonitorUpdated( | ||
| fundingTxo: channelFundingOutpoint, | ||
| completedUpdateId: data.getLatestUpdateId() | ||
| ) | ||
| if let error = res?.getError() { | ||
| LdkEventEmitter.shared.send(withEvent: .native_log, body: "Error. Failed to update chain monitor for channel (\(channelIdHex)) Error \(error.getValueType()).") | ||
| } else { | ||
| LdkEventEmitter.shared.send(withEvent: .native_log, body: "Persisted channel \(channelIdHex). Update ID: \(data.getLatestUpdateId())") | ||
| LdkEventEmitter.shared.send(withEvent: .new_channel, body: body) | ||
| } | ||
| } | ||
|
|
||
| // Kick off remote backup asynchronously (non-blocking) | ||
| BackupClient.addToPersistQueue(.channelMonitor(id: channelIdHex), [UInt8](serialized)) { error in | ||
| if let error { | ||
| LdkEventEmitter.shared.send(withEvent: .native_log, body: "Warning. Remote backup failed for new channel (\(channelIdHex)), but channel was persisted locally. \(error.localizedDescription)") | ||
| } | ||
| } | ||
|
|
||
| return ChannelMonitorUpdateStatus.Completed | ||
| } | ||
|
|
||
| // For updates: try remote backup first, then write locally on success (original behavior) | ||
| BackupClient.addToPersistQueue(.channelMonitor(id: channelIdHex), [UInt8](serialized)) { error in | ||
| if let error { | ||
| LdkEventEmitter.shared.send(withEvent: .native_log, body: "Error. Failed persist channel on remote server (\(channelIdHex)). \(error.localizedDescription)") | ||
| return | ||
| } | ||
|
|
||
| // Callback for when the persist queue queue entry is processed | ||
| // Callback for when the persist queue entry is processed | ||
| do { | ||
| try Data(data.write()).write(to: channelStoragePath) | ||
| try serialized.write(to: channelStoragePath) | ||
| } catch { | ||
| // If this fails we can't do much but LDK will retry on startup | ||
| LdkEventEmitter.shared.send(withEvent: .native_log, body: "Error. Failed to locally persist channel (\(channelIdHex)). \(error.localizedDescription)") | ||
| return | ||
| } | ||
|
|
||
| // Update chainmonitor with successful persist | ||
| let res = Ldk.chainMonitor?.channelMonitorUpdated(fundingTxo: channelFundingOutpoint, completedUpdateId: data.getLatestUpdateId()) | ||
| if let error = res?.getError() { | ||
| LdkEventEmitter.shared.send(withEvent: .native_log, body: "Error. Failed to update chain monitor for channel (\(channelIdHex)) Error \(error.getValueType()).") | ||
| } else { | ||
| LdkEventEmitter.shared.send(withEvent: .native_log, body: "Persisted channel \(channelIdHex). Update ID: \(data.getLatestUpdateId())") | ||
| if isNew { | ||
| LdkEventEmitter.shared.send(withEvent: .new_channel, body: body) | ||
| // Update chainmonitor with successful persist on main thread | ||
| DispatchQueue.main.async { | ||
| let res = Ldk.chainMonitor?.channelMonitorUpdated(fundingTxo: channelFundingOutpoint, completedUpdateId: data.getLatestUpdateId()) | ||
| if let error = res?.getError() { | ||
| LdkEventEmitter.shared.send(withEvent: .native_log, body: "Error. Failed to update chain monitor for channel (\(channelIdHex)) Error \(error.getValueType()).") | ||
| } else { | ||
| LdkEventEmitter.shared.send(withEvent: .native_log, body: "Persisted channel \(channelIdHex). Update ID: \(data.getLatestUpdateId())") | ||
| } | ||
| } | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.