@@ -151,6 +151,8 @@ class Ldk: NSObject {
151151 var currentNetwork : NSString ?
152152 var currentBlockchainTipHash : NSString ?
153153 var currentBlockchainHeight : NSInteger ?
154+ var currentScorerDownloadUrl : NSString ?
155+ var currentRapidGossipSyncUrl : NSString ?
154156
155157 // Peer connection checks
156158 var backgroundedAt : Date ? = nil
@@ -259,6 +261,8 @@ class Ldk: NSObject {
259261 guard let accountStoragePath = Ldk . accountStoragePath else {
260262 return handleReject ( reject, . init_storage_path)
261263 }
264+
265+ currentScorerDownloadUrl = scorerSyncUrl
262266
263267 let destinationFile = accountStoragePath. appendingPathComponent ( LdkFileNames . scorer. rawValue)
264268
@@ -299,6 +303,8 @@ class Ldk: NSObject {
299303 guard let accountStoragePath = Ldk . accountStoragePath else {
300304 return handleReject ( reject, . init_storage_path)
301305 }
306+
307+ currentRapidGossipSyncUrl = rapidGossipSyncUrl
302308
303309 let networkGraphStoragePath = accountStoragePath. appendingPathComponent ( LdkFileNames . network_graph. rawValue) . standardizedFileURL
304310
@@ -1062,29 +1068,110 @@ class Ldk: NSObject {
10621068
10631069 return resolve ( invoice. asJson) // Invoice class extended in Helpers file
10641070 }
1071+
1072+ //Called when a payment fails but we want to reset graph and channel manager so if they try again it might work
1073+ func resetGraphAndScorerAndRetryPayment( orginalError: LdkErrors , paymentRequest: NSString , amountSats: NSInteger , timeoutSeconds: NSInteger , resolve: @escaping RCTPromiseResolveBlock , reject: @escaping RCTPromiseRejectBlock ) {
1074+ guard let accountStoragePath = Ldk . accountStoragePath else {
1075+ LdkEventEmitter . shared. send ( withEvent: . native_log, body: " Failed to reset graph: account storage path not set " )
1076+ return handleReject ( reject, orginalError)
1077+ }
1078+
1079+ let fileManager = FileManager . default
1080+ let scorerPath = accountStoragePath. appendingPathComponent ( LdkFileNames . scorer. rawValue)
1081+ let networkGraphPath = accountStoragePath. appendingPathComponent ( LdkFileNames . network_graph. rawValue)
1082+
1083+ // Delete scorer if exists
1084+ if fileManager. fileExists ( atPath: scorerPath. path) {
1085+ do {
1086+ try fileManager. removeItem ( at: scorerPath)
1087+ LdkEventEmitter . shared. send ( withEvent: . native_log, body: " Deleted scorer file " )
1088+ } catch {
1089+ LdkEventEmitter . shared. send ( withEvent: . native_log, body: " Failed to delete scorer file: \( error. localizedDescription) " )
1090+ }
1091+ }
1092+
1093+ // Delete network graph if exists
1094+ if fileManager. fileExists ( atPath: networkGraphPath. path) {
1095+ do {
1096+ try fileManager. removeItem ( at: networkGraphPath)
1097+ LdkEventEmitter . shared. send ( withEvent: . native_log, body: " Deleted network graph file " )
1098+ networkGraph = nil
1099+ } catch {
1100+ LdkEventEmitter . shared. send ( withEvent: . native_log, body: " Failed to delete network graph file: \( error. localizedDescription) " )
1101+ }
1102+ }
1103+
1104+ guard let currentScorerDownloadUrl, let currentRapidGossipSyncUrl, let currentNetwork else {
1105+ return handleReject ( reject, orginalError)
1106+ }
1107+
1108+ LdkEventEmitter . shared. send ( withEvent: . native_log, body: " Deleted scorer and network graph, resyncing from scratch so we can retry payment " )
1109+
1110+ //Download everything again and retry
1111+ self . downloadScorer ( currentScorerDownloadUrl, skipHoursThreshold: 1 ) { _ in
1112+ self . initNetworkGraph ( currentNetwork, rapidGossipSyncUrl: currentRapidGossipSyncUrl, skipHoursThreshold: 1 , resolve: { _ in
1113+ self . restart { _ in
1114+ let ( paymentId2, error2) = self . handlePayment ( paymentRequest: paymentRequest, amountSats: amountSats, timeoutSeconds: timeoutSeconds)
1115+ if let error2 {
1116+ return handleReject ( reject, error2)
1117+ }
1118+
1119+ //2nd attempt found a path with fresh graph
1120+ return resolve ( paymentId2)
1121+ } reject: { _, _, _ in
1122+ return handleReject ( reject, orginalError)
1123+ }
1124+ } , reject: { _, _, _ in
1125+ return handleReject ( reject, orginalError)
1126+ } )
1127+ } reject: { _, _, _ in
1128+ return handleReject ( reject, orginalError)
1129+ }
1130+ }
10651131
10661132 @objc
10671133 func pay( _ paymentRequest: NSString , amountSats: NSInteger , timeoutSeconds: NSInteger , resolve: @escaping RCTPromiseResolveBlock , reject: @escaping RCTPromiseRejectBlock ) {
1134+ let ( paymentId, error) = handlePayment ( paymentRequest: paymentRequest, amountSats: amountSats, timeoutSeconds: timeoutSeconds)
1135+ if let error {
1136+ //If error is route not found, maybe a problem with the graph, so reset it, download all again and try payment one more time
1137+ if error == . invoice_payment_fail_route_not_found {
1138+ return resetGraphAndScorerAndRetryPayment (
1139+ orginalError: error,
1140+ paymentRequest: paymentRequest,
1141+ amountSats: amountSats,
1142+ timeoutSeconds: timeoutSeconds,
1143+ resolve: resolve,
1144+ reject: reject
1145+ )
1146+ }
1147+
1148+ return handleReject ( reject, error)
1149+ }
1150+
1151+ return resolve ( paymentId)
1152+ }
1153+
1154+ func handlePayment( paymentRequest: NSString , amountSats: NSInteger , timeoutSeconds: NSInteger ) -> ( String ? , LdkErrors ? ) {
10681155 guard let channelManager = channelManager else {
1069- return handleReject ( reject , . init_channel_manager)
1156+ return ( nil , . init_channel_manager)
10701157 }
1071-
1158+
10721159 guard let invoice = Bolt11Invoice . fromStr ( s: String ( paymentRequest) ) . getValue ( ) else {
1073- return handleReject ( reject , . decode_invoice_fail)
1160+ return ( nil , . decode_invoice_fail)
10741161 }
10751162
10761163 let isZeroValueInvoice = invoice. amountMilliSatoshis ( ) == nil
10771164
10781165 // If it's a zero invoice and we don't have an amount then don't proceed
10791166 guard !( isZeroValueInvoice && amountSats == 0 ) else {
1080- return handleReject ( reject , . invoice_payment_fail_must_specify_amount)
1167+ return ( nil , . invoice_payment_fail_must_specify_amount)
10811168 }
10821169
10831170 // Amount was set but not allowed to set own amount
10841171 guard !( amountSats > 0 && !isZeroValueInvoice) else {
1085- return handleReject ( reject , . invoice_payment_fail_must_not_specify_amount)
1172+ return ( nil , . invoice_payment_fail_must_not_specify_amount)
10861173 }
1087-
1174+
10881175 let paymentId = invoice. paymentHash ( ) !
10891176 let ( paymentHash, recipientOnion, routeParameters) = isZeroValueInvoice ? Bindings . paymentParametersFromZeroAmountInvoice ( invoice: invoice, amountMsat: UInt64 ( amountSats * 1000 ) ) . getValue ( ) ! : Bindings . paymentParametersFromInvoice ( invoice: invoice) . getValue ( ) !
10901177
@@ -1101,22 +1188,26 @@ class Ldk: NSObject {
11011188 ] )
11021189
11031190 if res. isOk ( ) {
1104- return resolve ( paymentId)
1191+ return ( Data ( paymentId) . hexEncodedString ( ) , nil )
11051192 }
11061193
11071194 guard let error = res. getError ( ) else {
1108- return handleReject ( reject , . invoice_payment_fail_unknown)
1195+ return ( nil , . invoice_payment_fail_unknown)
11091196 }
11101197
11111198 switch error {
11121199 case . DuplicatePayment:
1113- return handleReject ( reject , . invoice_payment_fail_duplicate_payment)
1200+ return ( nil , . invoice_payment_fail_duplicate_payment)
11141201 case . PaymentExpired:
1115- return handleReject ( reject , . invoice_payment_fail_payment_expired)
1202+ return ( nil , . invoice_payment_fail_payment_expired)
11161203 case . RouteNotFound:
1117- return handleReject ( reject, . invoice_payment_fail_route_not_found)
1204+ //Delete scorer
1205+ //Delete graph
1206+ //Download and update graph again
1207+ //Retry payment
1208+ return ( nil , . invoice_payment_fail_route_not_found)
11181209 @unknown default :
1119- return handleReject ( reject , . invoice_payment_fail_unknown)
1210+ return ( nil , . invoice_payment_fail_unknown)
11201211 }
11211212 }
11221213
0 commit comments