@@ -313,9 +313,44 @@ impl<T: Time> Display for PaymentAttemptsUsingTime<T> {
313
313
}
314
314
}
315
315
316
- /// If a payment fails to send, it can be in one of several states. This enum is returned as the
317
- /// Err() type describing which state the payment is in, see the description of individual enum
318
- /// states for more.
316
+ /// If a payment fails to send with [`ChannelManager::send_payment_with_retry`], it can be in one of
317
+ /// several states. This enum is returned as the Err() type describing which state the payment is
318
+ /// in, see the description of individual enum states for more.
319
+ ///
320
+ /// [`ChannelManager::send_payment_with_retry`]: crate::ln::channelmanager::ChannelManager::send_payment_with_retry
321
+ #[ derive( Clone , Debug ) ]
322
+ pub enum RetryableSendFailure {
323
+ /// A parameter which was passed to send_payment was invalid, preventing us from attempting to
324
+ /// send the payment at all.
325
+ ///
326
+ /// You can freely resend the payment in full (with the parameter error fixed).
327
+ ParameterError ( APIError ) ,
328
+ /// A parameter in a single path which was passed to send_payment was invalid, preventing us
329
+ /// from attempting to send the payment at all.
330
+ ///
331
+ /// You can freely resend the payment in full (with the parameter error fixed).
332
+ ///
333
+ /// The results here are ordered the same as the paths in the route object which was passed to
334
+ /// send_payment.
335
+ PathParameterError ( Vec < Result < ( ) , APIError > > ) ,
336
+ /// All paths which were attempted failed to send, with no channel state change taking place.
337
+ /// You can freely resend the payment in full (though you probably want to do so over different
338
+ /// paths than the ones selected).
339
+ AllFailedResendSafe ( Vec < APIError > ) ,
340
+ /// Indicates that a payment for the provided [`PaymentId`] is already in-flight and has not
341
+ /// yet completed (i.e. generated an [`Event::PaymentSent`] or [`Event::PaymentFailed`]).
342
+ ///
343
+ /// [`PaymentId`]: crate::ln::channelmanager::PaymentId
344
+ /// [`Event::PaymentSent`]: crate::util::events::Event::PaymentSent
345
+ /// [`Event::PaymentFailed`]: crate::util::events::Event::PaymentFailed
346
+ DuplicatePayment ,
347
+ }
348
+
349
+ /// If a payment fails to send with [`ChannelManager::send_payment`], it can be in one of several
350
+ /// states. This enum is returned as the Err() type describing which state the payment is in, see
351
+ /// the description of individual enum states for more.
352
+ ///
353
+ /// [`ChannelManager::send_payment`]: crate::ln::channelmanager::ChannelManager::send_payment
319
354
#[ derive( Clone , Debug ) ]
320
355
pub enum PaymentSendFailure {
321
356
/// A parameter which was passed to send_payment was invalid, preventing us from attempting to
@@ -379,7 +414,7 @@ impl OutboundPayments {
379
414
retry_strategy : Retry , route_params : RouteParameters , router : & R ,
380
415
first_hops : Vec < ChannelDetails > , inflight_htlcs : InFlightHtlcs , entropy_source : & ES ,
381
416
node_signer : & NS , best_block_height : u32 , logger : & L , send_payment_along_path : F ,
382
- ) -> Result < ( ) , PaymentSendFailure >
417
+ ) -> Result < ( ) , RetryableSendFailure >
383
418
where
384
419
R :: Target : Router ,
385
420
ES :: Target : EntropySource ,
@@ -388,10 +423,18 @@ impl OutboundPayments {
388
423
F : Fn ( & Vec < RouteHop > , & Option < PaymentParameters > , & PaymentHash , & Option < PaymentSecret > , u64 ,
389
424
u32 , PaymentId , & Option < PaymentPreimage > , [ u8 ; 32 ] ) -> Result < ( ) , APIError > ,
390
425
{
391
- self . pay_internal ( payment_id, Some ( ( payment_hash, payment_secret, None , retry_strategy) ) ,
426
+ let res = self . pay_internal ( payment_id, Some ( ( payment_hash, payment_secret, None , retry_strategy) ) ,
392
427
route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer,
393
428
best_block_height, logger, & send_payment_along_path)
394
- . map_err ( |e| { self . remove_outbound_if_all_failed ( payment_id, & e) ; e } )
429
+ . map_err ( |e| { self . remove_outbound_if_all_failed ( payment_id, & e) ; e } ) ;
430
+ match res {
431
+ Err ( PaymentSendFailure :: ParameterError ( e) ) => Err ( RetryableSendFailure :: ParameterError ( e) ) ,
432
+ Err ( PaymentSendFailure :: PathParameterError ( e) ) => Err ( RetryableSendFailure :: PathParameterError ( e) ) ,
433
+ Err ( PaymentSendFailure :: AllFailedResendSafe ( e) ) => Err ( RetryableSendFailure :: AllFailedResendSafe ( e) ) ,
434
+ Err ( PaymentSendFailure :: DuplicatePayment ) => Err ( RetryableSendFailure :: DuplicatePayment ) ,
435
+ Err ( PaymentSendFailure :: PartialFailure { .. } ) => Ok ( ( ) ) ,
436
+ Ok ( ( ) ) => Ok ( ( ) )
437
+ }
395
438
}
396
439
397
440
pub ( super ) fn send_payment_with_route < ES : Deref , NS : Deref , F > (
@@ -416,7 +459,7 @@ impl OutboundPayments {
416
459
retry_strategy : Retry , route_params : RouteParameters , router : & R ,
417
460
first_hops : Vec < ChannelDetails > , inflight_htlcs : InFlightHtlcs , entropy_source : & ES ,
418
461
node_signer : & NS , best_block_height : u32 , logger : & L , send_payment_along_path : F
419
- ) -> Result < PaymentHash , PaymentSendFailure >
462
+ ) -> Result < PaymentHash , RetryableSendFailure >
420
463
where
421
464
R :: Target : Router ,
422
465
ES :: Target : EntropySource ,
@@ -428,11 +471,18 @@ impl OutboundPayments {
428
471
let preimage = payment_preimage
429
472
. unwrap_or_else ( || PaymentPreimage ( entropy_source. get_secure_random_bytes ( ) ) ) ;
430
473
let payment_hash = PaymentHash ( Sha256 :: hash ( & preimage. 0 ) . into_inner ( ) ) ;
431
- self . pay_internal ( payment_id, Some ( ( payment_hash, & None , Some ( preimage) , retry_strategy) ) ,
474
+ let res = self . pay_internal ( payment_id, Some ( ( payment_hash, & None , Some ( preimage) , retry_strategy) ) ,
432
475
route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer,
433
476
best_block_height, logger, & send_payment_along_path)
434
- . map ( |( ) | payment_hash)
435
- . map_err ( |e| { self . remove_outbound_if_all_failed ( payment_id, & e) ; e } )
477
+ . map_err ( |e| { self . remove_outbound_if_all_failed ( payment_id, & e) ; e } ) ;
478
+ match res {
479
+ Err ( PaymentSendFailure :: ParameterError ( e) ) => Err ( RetryableSendFailure :: ParameterError ( e) ) ,
480
+ Err ( PaymentSendFailure :: PathParameterError ( e) ) => Err ( RetryableSendFailure :: PathParameterError ( e) ) ,
481
+ Err ( PaymentSendFailure :: AllFailedResendSafe ( e) ) => Err ( RetryableSendFailure :: AllFailedResendSafe ( e) ) ,
482
+ Err ( PaymentSendFailure :: DuplicatePayment ) => Err ( RetryableSendFailure :: DuplicatePayment ) ,
483
+ Err ( PaymentSendFailure :: PartialFailure { .. } ) => Ok ( payment_hash) ,
484
+ Ok ( ( ) ) => Ok ( payment_hash) ,
485
+ }
436
486
}
437
487
438
488
pub ( super ) fn send_spontaneous_payment_with_route < ES : Deref , NS : Deref , F > (
@@ -1222,19 +1272,22 @@ mod tests {
1222
1272
final_value_msat : 0 ,
1223
1273
final_cltv_expiry_delta : 0 ,
1224
1274
} ;
1225
- let err = if on_retry {
1226
- outbound_payments. pay_internal (
1275
+ if on_retry {
1276
+ let err = outbound_payments. pay_internal (
1227
1277
PaymentId ( [ 0 ; 32 ] ) , None , expired_route_params, & & router, vec ! [ ] , InFlightHtlcs :: new ( ) ,
1228
- & & keys_manager, & & keys_manager, 0 , & & logger, & |_, _, _, _, _, _, _, _, _| Ok ( ( ) ) ) . unwrap_err ( )
1278
+ & & keys_manager, & & keys_manager, 0 , & & logger, & |_, _, _, _, _, _, _, _, _| Ok ( ( ) ) ) . unwrap_err ( ) ;
1279
+ if let PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError { err } ) = err {
1280
+ assert ! ( err. contains( "Invoice expired" ) ) ;
1281
+ } else { panic ! ( "Unexpected error" ) ; }
1229
1282
} else {
1230
- outbound_payments. send_payment (
1283
+ let err = outbound_payments. send_payment (
1231
1284
PaymentHash ( [ 0 ; 32 ] ) , & None , PaymentId ( [ 0 ; 32 ] ) , Retry :: Attempts ( 0 ) , expired_route_params,
1232
1285
& & router, vec ! [ ] , InFlightHtlcs :: new ( ) , & & keys_manager, & & keys_manager, 0 , & & logger,
1233
- |_, _, _, _, _, _, _, _, _| Ok ( ( ) ) ) . unwrap_err ( )
1234
- } ;
1235
- if let PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError { err } ) = err {
1236
- assert ! ( err . contains ( "Invoice expired" ) ) ;
1237
- } else { panic ! ( "Unexpected error" ) ; }
1286
+ |_, _, _, _, _, _, _, _, _| Ok ( ( ) ) ) . unwrap_err ( ) ;
1287
+ if let RetryableSendFailure :: ParameterError ( APIError :: APIMisuseError { err } ) = err {
1288
+ assert ! ( err. contains ( "Invoice expired" ) ) ;
1289
+ } else { panic ! ( "Unexpected error" ) ; }
1290
+ }
1238
1291
}
1239
1292
1240
1293
#[ test]
@@ -1261,22 +1314,25 @@ mod tests {
1261
1314
router. expect_find_route ( route_params. clone ( ) ,
1262
1315
Err ( LightningError { err : String :: new ( ) , action : ErrorAction :: IgnoreError } ) ) ;
1263
1316
1264
- let err = if on_retry {
1317
+ if on_retry {
1265
1318
outbound_payments. add_new_pending_payment ( PaymentHash ( [ 0 ; 32 ] ) , None , PaymentId ( [ 0 ; 32 ] ) , None ,
1266
1319
& Route { paths : vec ! [ ] , payment_params : None } , Some ( Retry :: Attempts ( 1 ) ) ,
1267
1320
Some ( route_params. payment_params . clone ( ) ) , & & keys_manager, 0 ) . unwrap ( ) ;
1268
- outbound_payments. pay_internal (
1321
+ let err = outbound_payments. pay_internal (
1269
1322
PaymentId ( [ 0 ; 32 ] ) , None , route_params, & & router, vec ! [ ] , InFlightHtlcs :: new ( ) ,
1270
- & & keys_manager, & & keys_manager, 0 , & & logger, & |_, _, _, _, _, _, _, _, _| Ok ( ( ) ) ) . unwrap_err ( )
1323
+ & & keys_manager, & & keys_manager, 0 , & & logger, & |_, _, _, _, _, _, _, _, _| Ok ( ( ) ) ) . unwrap_err ( ) ;
1324
+ if let PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError { err } ) = err {
1325
+ assert ! ( err. contains( "Failed to find a route" ) ) ;
1326
+ } else { panic ! ( "Unexpected error" ) ; }
1271
1327
} else {
1272
- outbound_payments. send_payment (
1328
+ let err = outbound_payments. send_payment (
1273
1329
PaymentHash ( [ 0 ; 32 ] ) , & None , PaymentId ( [ 0 ; 32 ] ) , Retry :: Attempts ( 0 ) , route_params,
1274
1330
& & router, vec ! [ ] , InFlightHtlcs :: new ( ) , & & keys_manager, & & keys_manager, 0 , & & logger,
1275
- |_, _, _, _, _, _, _, _, _| Ok ( ( ) ) ) . unwrap_err ( )
1276
- } ;
1277
- if let PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError { err } ) = err {
1278
- assert ! ( err . contains ( "Failed to find a route" ) ) ;
1279
- } else { panic ! ( "Unexpected error" ) ; }
1331
+ |_, _, _, _, _, _, _, _, _| Ok ( ( ) ) ) . unwrap_err ( ) ;
1332
+ if let RetryableSendFailure :: ParameterError ( APIError :: APIMisuseError { err } ) = err {
1333
+ assert ! ( err. contains ( "Failed to find a route" ) ) ;
1334
+ } else { panic ! ( "Unexpected error" ) ; }
1335
+ }
1280
1336
}
1281
1337
1282
1338
#[ test]
0 commit comments