From 6bfac3b564dfbffd62e8badc44c9d4299cd57e43 Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 24 Jan 2024 15:32:30 +0200 Subject: [PATCH 1/7] chore: cleanup old backup functions --- example/ios/Podfile.lock | 4 +- .../Classes/LdkChannelManagerPersister.swift | 4 +- lib/ios/Classes/LdkPersist.swift | 1 - lib/ios/Ldk.swift | 1 - lib/package.json | 2 +- lib/src/lightning-manager.ts | 219 ++---------------- lib/src/utils/types.ts | 18 +- 7 files changed, 22 insertions(+), 227 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 524f4c6d..3ce70f19 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -375,7 +375,7 @@ PODS: - React-jsinspector (0.72.4) - React-logger (0.72.4): - glog - - react-native-ldk (0.0.125): + - react-native-ldk (0.0.127): - React - react-native-randombytes (3.6.1): - React-Core @@ -723,7 +723,7 @@ SPEC CHECKSUMS: React-jsiexecutor: c7f826e40fa9cab5d37cab6130b1af237332b594 React-jsinspector: aaed4cf551c4a1c98092436518c2d267b13a673f React-logger: da1ebe05ae06eb6db4b162202faeafac4b435e77 - react-native-ldk: c78b18c8c8fe218481721f7083e3e0f825aa957e + react-native-ldk: 4ab3d26d5e1356313c572814289cc516dc18dd88 react-native-randombytes: 421f1c7d48c0af8dbcd471b0324393ebf8fe7846 react-native-tcp-socket: c1b7297619616b4c9caae6889bcb0aba78086989 React-NativeModulesApple: edb5ace14f73f4969df6e7b1f3e41bef0012740f diff --git a/lib/ios/Classes/LdkChannelManagerPersister.swift b/lib/ios/Classes/LdkChannelManagerPersister.swift index 7f0e232a..67eab5fc 100644 --- a/lib/ios/Classes/LdkChannelManagerPersister.swift +++ b/lib/ios/Classes/LdkChannelManagerPersister.swift @@ -320,9 +320,7 @@ class LdkChannelManagerPersister: Persister, ExtendedChannelManagerPersister { try Data(channelManager.write()).write(to: managerStorage) LdkEventEmitter.shared.send(withEvent: .native_log, body: "Persisted channel manager to disk") - - LdkEventEmitter.shared.send(withEvent: .backup, body: "") - + return Result_NoneIOErrorZ.initWithOk() } catch { LdkEventEmitter.shared.send(withEvent: .native_log, body: "Error. Failed to persist channel manager to disk Error \(error.localizedDescription).") diff --git a/lib/ios/Classes/LdkPersist.swift b/lib/ios/Classes/LdkPersist.swift index cd7e3d2d..24063c3a 100644 --- a/lib/ios/Classes/LdkPersist.swift +++ b/lib/ios/Classes/LdkPersist.swift @@ -39,7 +39,6 @@ class LdkPersister: Persist { 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: \(updateId.hash())") - LdkEventEmitter.shared.send(withEvent: .backup, body: "") //TODO remove after old backup is deprecated } } diff --git a/lib/ios/Ldk.swift b/lib/ios/Ldk.swift index f66369d2..be0fa093 100644 --- a/lib/ios/Ldk.swift +++ b/lib/ios/Ldk.swift @@ -8,7 +8,6 @@ enum EventTypes: String, CaseIterable { case register_tx = "register_tx" case register_output = "register_output" case broadcast_transaction = "broadcast_transaction" - case backup = "backup" case channel_manager_funding_generation_ready = "channel_manager_funding_generation_ready" case channel_manager_payment_claimable = "channel_manager_payment_claimable" case channel_manager_payment_sent = "channel_manager_payment_sent" diff --git a/lib/package.json b/lib/package.json index 560f6a56..a9419d9c 100644 --- a/lib/package.json +++ b/lib/package.json @@ -1,7 +1,7 @@ { "name": "@synonymdev/react-native-ldk", "title": "React Native LDK", - "version": "0.0.126", + "version": "0.0.127", "description": "React Native wrapper for LDK", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/lib/src/lightning-manager.ts b/lib/src/lightning-manager.ts index e68b146b..e600a57d 100644 --- a/lib/src/lightning-manager.ts +++ b/lib/src/lightning-manager.ts @@ -1,7 +1,6 @@ import ldk from './ldk'; import { Err, err, ok, Result } from './utils/result'; import { - DefaultLdkDataShape, DefaultTransactionDataShape, EEventTypes, ELdkData, @@ -41,7 +40,6 @@ import { TLdkBroadcastedTransactions, TChannelUpdate, TPaymentReq, - TPaymentTimeoutReq, TLdkPaymentIds, TNetworkGraphUpdated, TGetTransactionPosition, @@ -111,11 +109,6 @@ class LightningManager { name: '', seed: '', }; - backupSubscriptions: { - [id: string]: (backup: Result) => void; - } = {}; - backupSubscriptionsId = 0; - backupSubscriptionsDebounceTimer: NodeJS.Timeout | undefined = undefined; getTransactionData: TGetTransactionData = async (): Promise => DefaultTransactionDataShape; getTransactionPosition: TGetTransactionPosition = @@ -171,9 +164,6 @@ class LightningManager { EEventTypes.broadcast_transaction, this.onBroadcastTransaction.bind(this), ); - - ldk.onEvent(EEventTypes.backup, this.onLdkBackupEvent.bind(this)); - //Channel manager handle events: ldk.onEvent( EEventTypes.channel_manager_funding_generation_ready, @@ -938,10 +928,10 @@ class LightningManager { getPeers = async (): Promise => { const res = await ldk.readFromFile({ fileName: ELdkFiles.peers }); if (res.isOk()) { - return parseData(res.value.content, DefaultLdkDataShape.peers); + return parseData(res.value.content, []); } - return DefaultLdkDataShape.peers; + return []; }; /** @@ -1156,112 +1146,6 @@ class LightningManager { } }; - /** - * Used to back up the data that corresponds with the provided account. - * @param {TAccount} account - * @param {boolean} includeTransactionHistory - * @returns {TAccountBackup} This object can be stringified and used to import/restore this LDK account via importAccount. - */ - backupAccount = async ({ - account, - includeTransactionHistory = false, - }: { - account: TAccount; - includeTransactionHistory?: boolean; - }): Promise> => { - console.warn( - 'backupAccount() is deprecated and will be removed in future versions. Use remote backup server instead.', - ); - if (!this.baseStoragePath) { - return err( - 'baseStoragePath required for wallet persistence. Call setBaseStoragePath(path) first.', - ); - } - - try { - if (!account || !this?.account) { - return err( - 'No account provided. Please pass an account object containing the name & seed to the start method and try again.', - ); - } - if (!account) { - account = this.account; - } - if (!account?.name || !account?.seed) { - return err( - 'No account name or seed provided. Please pass an account object containing the name & seed to the start method and try again.', - ); - } - - const accountPath = appendPath(this.baseStoragePath, account.name); - - //Get serialised channel manager - const channelManagerRes = await ldk.readFromFile({ - fileName: ELdkFiles.channel_manager, - path: accountPath, - format: 'hex', - }); - if (channelManagerRes.isErr()) { - return err(channelManagerRes.error); - } - - //Get serialised channels - const listChannelsRes = await ldk.listChannelFiles(); - if (listChannelsRes.isErr()) { - return err(listChannelsRes.error); - } - - let channel_monitors: { [key: string]: string } = {}; - for (let index = 0; index < listChannelsRes.value.length; index++) { - const fileName = listChannelsRes.value[index]; - - const serialisedChannelRes = await ldk.readFromFile({ - fileName, - path: appendPath(accountPath, ELdkFiles.channels), - format: 'hex', - }); - if (serialisedChannelRes.isErr()) { - return err(serialisedChannelRes.error); - } - - channel_monitors[fileName.replace('.bin', '')] = - serialisedChannelRes.value.content; - } - - const accountBackup: TAccountBackup = { - account, - data: { - channel_manager: channelManagerRes.value.content, - channel_monitors: channel_monitors, - peers: await this.getPeers(), - unconfirmed_transactions: await this.getLdkUnconfirmedTxs(), - broadcasted_transactions: await this.getLdkBroadcastedTxs(), - payment_ids: await this.getLdkPaymentIds(), - spendable_outputs: await this.getLdkSpendableOutputs(), - payments_claimed: [], - payments_sent: [], - bolt11_invoices: [], - timestamp: Date.now(), - }, - package_version: require('../package.json').version, - network: this.network, - }; - - //Backups can become large, so we only include transaction history if requested. - if (includeTransactionHistory) { - accountBackup.data = { - ...accountBackup.data, - payments_claimed: await this.getLdkPaymentsClaimed(), - payments_sent: await this.getLdkPaymentsSent(), - bolt11_invoices: await this.getBolt11Invoices(), - }; - } - return ok(accountBackup); - } catch (e) { - return err(e); - } - }; - payWithTimeout = async ({ paymentRequest, amountSats, @@ -1348,62 +1232,6 @@ class LightningManager { this.paymentSentSubscription && this.paymentSentSubscription.remove(); }; - /** - * Subscribe to back up events and receive full backups to callback passed - * @param callback - * @returns {string} - */ - subscribeToBackups( - callback: (backup: Result) => void, - ): string { - console.warn( - 'subscribeToBackups() is deprecated, use backup server instead.', - ); - this.backupSubscriptionsId++; - const id = `${this.backupSubscriptionsId}`; - this.backupSubscriptions[id] = callback; - return id; - } - - /** - * Unsubscribe from backup events - * @param id - */ - unsubscribeFromBackups(id: string): void { - console.warn( - 'unsubscribeFromBackups() is deprecated, use backup server instead.', - ); - if (this.backupSubscriptions[id]) { - delete this.backupSubscriptions[id]; - } - } - - /** - * Handle native events triggering backups by debouncing and fetching data after - * a timeout to avoid too many backup events being triggered right after each other. - * @returns {Promise} - */ - private async onLdkBackupEvent(): Promise { - if (this.backupsServerSetup) { - return; - } - if (this.backupSubscriptionsDebounceTimer) { - clearTimeout(this.backupSubscriptionsDebounceTimer); - } - - this.backupSubscriptionsDebounceTimer = setTimeout(async () => { - const backupRes = await this.backupAccount({ account: this.account }); - - //Process all subscriptions - Object.keys(this.backupSubscriptions).forEach((id) => { - const callback = this.backupSubscriptions[id]; - if (callback) { - callback(backupRes); - } - }); - }, 250); - } - /** * Returns change destination script for the provided address. * @param {string} address @@ -1478,12 +1306,9 @@ class LightningManager { fileName: ELdkFiles.unconfirmed_transactions, }); if (res.isOk()) { - return parseData( - res.value.content, - DefaultLdkDataShape.unconfirmed_transactions, - ); + return parseData(res.value.content, []); } - return DefaultLdkDataShape.unconfirmed_transactions; + return []; }; private getLdkPaymentIds = async (): Promise => { @@ -1491,10 +1316,7 @@ class LightningManager { fileName: ELdkFiles.payment_ids, }); if (res.isOk()) { - let parsed = parseData( - res.value.content, - DefaultLdkDataShape.payment_ids, - ); + let parsed = parseData(res.value.content, []); //Temp patch for wallets with incorrectly written payment ID file formats. Can be removed after a few releases. if (parsed.length === 64 && res.value.content.length === 66) { @@ -1503,7 +1325,7 @@ class LightningManager { return parsed; } - return DefaultLdkDataShape.payment_ids; + return []; }; private removeLdkPaymentId = async (paymentId: string): Promise => { @@ -1543,9 +1365,9 @@ class LightningManager { fileName: ELdkFiles.payments_claimed, }); if (res.isOk()) { - return parseData(res.value.content, DefaultLdkDataShape.payments_claimed); + return parseData(res.value.content, []); } - return DefaultLdkDataShape.payments_claimed; + return []; }; /** @@ -1557,9 +1379,9 @@ class LightningManager { fileName: ELdkFiles.payments_sent, }); if (res.isOk()) { - return parseData(res.value.content, DefaultLdkDataShape.payments_sent); + return parseData(res.value.content, []); } - return DefaultLdkDataShape.payments_sent; + return []; }; //TODO Remove any stale payments from storage if stuck for 60min. No payment claim should be stuck that long. @@ -1573,14 +1395,11 @@ class LightningManager { fileName: ELdkFiles.bolt11_invoices, }); if (res.isOk()) { - let parsed = parseData( - res.value.content, - DefaultLdkDataShape.bolt11_invoices, - ); + let parsed = parseData(res.value.content, []); return parsed; } - return DefaultLdkDataShape.bolt11_invoices; + return []; }; appendBolt11Invoice = async (bolt11: string): Promise => { @@ -1637,12 +1456,9 @@ class LightningManager { fileName: ELdkFiles.spendable_outputs, }); if (res.isOk()) { - return parseData( - res.value.content, - DefaultLdkDataShape.spendable_outputs, - ); + return parseData(res.value.content, []); } - return DefaultLdkDataShape.spendable_outputs; + return []; }; /** @@ -1654,12 +1470,9 @@ class LightningManager { fileName: ELdkFiles.broadcasted_transactions, }); if (res.isOk()) { - return parseData( - res.value.content, - DefaultLdkDataShape.broadcasted_transactions, - ); + return parseData(res.value.content, []); } - return DefaultLdkDataShape.broadcasted_transactions; + return []; } async rebroadcastAllKnownTransactions(): Promise { diff --git a/lib/src/utils/types.ts b/lib/src/utils/types.ts index 89830195..229805a0 100644 --- a/lib/src/utils/types.ts +++ b/lib/src/utils/types.ts @@ -17,7 +17,6 @@ export enum EEventTypes { register_tx = 'register_tx', register_output = 'register_output', broadcast_transaction = 'broadcast_transaction', - backup = 'backup', channel_manager_funding_generation_ready = 'channel_manager_funding_generation_ready', channel_manager_payment_claimable = 'channel_manager_payment_claimable', channel_manager_payment_sent = 'channel_manager_payment_sent', @@ -34,7 +33,6 @@ export enum EEventTypes { new_channel = 'new_channel', network_graph_updated = 'network_graph_updated', channel_manager_restarted = 'channel_manager_restarted', - backup_failed = 'backup_failed', } //LDK event responses @@ -493,6 +491,7 @@ export enum ELdkData { bolt11_invoices = 'bolt11_invoices', } +//Can be removed after importAccount is officially removed export type TLdkData = { [ELdkData.channel_manager]: string; [ELdkData.channel_monitors]: { [key: string]: string }; @@ -507,6 +506,7 @@ export type TLdkData = { [ELdkData.bolt11_invoices]: TBolt11Invoices; }; +//Can be removed after importAccount is officially removed export type TAccountBackup = { account: TAccount; package_version: string; @@ -531,20 +531,6 @@ export type TBolt11Invoices = string[]; export type TLdkSpendableOutputs = string[]; -export const DefaultLdkDataShape: TLdkData = { - [ELdkData.channel_manager]: '', - [ELdkData.channel_monitors]: {}, - [ELdkData.peers]: [], - [ELdkData.unconfirmed_transactions]: [], - [ELdkData.broadcasted_transactions]: [], - [ELdkData.payment_ids]: [], - [ELdkData.timestamp]: 0, - [ELdkData.spendable_outputs]: [], - [ELdkData.payments_claimed]: [], - [ELdkData.payments_sent]: [], - [ELdkData.bolt11_invoices]: [], -}; - export type TAccount = { name: string; seed: string; From 206e063fc0b4691e09bef8df1841ff7282a3ca91 Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 24 Jan 2024 16:08:31 +0200 Subject: [PATCH 2/7] feat: move backup setup outside of start method --- example/ldk/index.ts | 10 +++++++++- lib/src/ldk.ts | 2 +- lib/src/lightning-manager.ts | 15 +++------------ lib/src/utils/types.ts | 2 +- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/example/ldk/index.ts b/example/ldk/index.ts index f8172152..e574356c 100644 --- a/example/ldk/index.ts +++ b/example/ldk/index.ts @@ -109,6 +109,15 @@ export const setupLdk = async ( return err(storageRes.error); } + const res = await ldk.backupSetup({ + network: ldkNetwork(selectedNetwork), + seed: account.seed, + details: backupServerDetails!, + }); + if (res.isErr()) { + return err(res.error); + } + const lmStart = await lm.start({ getBestBlock, account, @@ -140,7 +149,6 @@ export const setupLdk = async ( manually_accept_inbound_channels: true, }, trustedZeroConfPeers: [peers.lnd.pubKey], - backupServerDetails, }); if (lmStart.isErr()) { diff --git a/lib/src/ldk.ts b/lib/src/ldk.ts index 137d6250..23e057c5 100644 --- a/lib/src/ldk.ts +++ b/lib/src/ldk.ts @@ -1294,7 +1294,7 @@ class LDK { /** * Runs a self check by creating random string, encrypting, backing up, fetching, decrypting and validating content. */ - async backupSelfCheck(): Promise> { + async backupSelfCheck(): Promise> { try { const res = await NativeLDK.backupSelfCheck(); return ok(res); diff --git a/lib/src/lightning-manager.ts b/lib/src/lightning-manager.ts index e600a57d..fc8a1f7b 100644 --- a/lib/src/lightning-manager.ts +++ b/lib/src/lightning-manager.ts @@ -146,8 +146,6 @@ class LightningManager { private pendingStartPromises: Array<(result: Result) => void> = []; private previousAccountName: string = ''; - private backupsServerSetup = false; - constructor() { // Step 0: Subscribe to all events ldk.onEvent(EEventTypes.native_log, (line) => { @@ -291,8 +289,8 @@ class LightningManager { forceCloseOnStartup, userConfig = defaultUserConfig, trustedZeroConfPeers = [], - backupServerDetails, skipParamCheck = false, + skipRemoteBackups = false, }: TLdkStart): Promise> { if (!account) { return err( @@ -456,15 +454,8 @@ class LightningManager { ); } - if (backupServerDetails) { - promises.push( - ldk.backupSetup({ - seed: account.seed, - network: this.network, - details: backupServerDetails, - }), - ); - this.backupsServerSetup = true; + if (!skipRemoteBackups) { + promises.push(ldk.backupSelfCheck()); } // Check for any errors before starting channel manager. diff --git a/lib/src/utils/types.ts b/lib/src/utils/types.ts index 229805a0..21ca7d52 100644 --- a/lib/src/utils/types.ts +++ b/lib/src/utils/types.ts @@ -556,8 +556,8 @@ export type TLdkStart = { forceCloseOnStartup?: TForceCloseOnStartup; userConfig?: TUserConfig; trustedZeroConfPeers?: string[]; - backupServerDetails?: TBackupServerDetails; skipParamCheck?: boolean; + skipRemoteBackups?: boolean; }; export interface IAddress { From 814f3e35b98c03188c0a502440d68a150d48b46b Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 24 Jan 2024 17:50:20 +0200 Subject: [PATCH 3/7] feat: ios allow any file to be remotely backed up and retrieved --- backup-server/src/server.js | 11 ++++- example/Dev.tsx | 40 +++++++++++++++++++ example/ldk/index.ts | 1 + lib/ios/Classes/BackupClient.swift | 11 ++--- .../Classes/LdkChannelManagerPersister.swift | 10 +++-- lib/ios/Classes/LdkPersist.swift | 12 ++++-- lib/ios/Ldk.m | 8 +++- lib/ios/Ldk.swift | 37 +++++++++++++++++ lib/src/ldk.ts | 18 +++++++++ 9 files changed, 135 insertions(+), 13 deletions(-) diff --git a/backup-server/src/server.js b/backup-server/src/server.js index 35307e8c..15ede721 100644 --- a/backup-server/src/server.js +++ b/backup-server/src/server.js @@ -16,7 +16,7 @@ const challenges = new Map(); // pubkey -> {challenge, expires} const signedMessagePrefix = 'react-native-ldk backup server auth:'; -let labels = [ +const ldkLabels = [ 'ping', 'channel_manager', 'channel_monitor', @@ -29,6 +29,15 @@ let labels = [ 'payments_sent', 'bolt11_invoices', ]; +const bitkitLabels = [ + 'bitkit_settings', + 'bitkit_widgets', + 'bitkit_metadata', + 'bitkit_blocktank_orders', + 'bitkit_slashtags_contacts', +]; +const labels = [...ldkLabels, ...bitkitLabels]; + let networks = ['bitcoin', 'testnet', 'regtest', 'signet']; const version = 'v1'; diff --git a/example/Dev.tsx b/example/Dev.tsx index bbe08573..e189f77d 100644 --- a/example/Dev.tsx +++ b/example/Dev.tsx @@ -645,6 +645,46 @@ const Dev = (): ReactElement => { setMessage(res.value); }} /> + +