@@ -489,7 +489,8 @@ impl OutboundPayments {
489
489
490
490
pub ( super ) fn check_retry_payments < R : Deref , ES : Deref , NS : Deref , SP , IH , FH , L : Deref > (
491
491
& self , router : & R , first_hops : FH , inflight_htlcs : IH , entropy_source : & ES , node_signer : & NS ,
492
- best_block_height : u32 , logger : & L , send_payment_along_path : SP ,
492
+ best_block_height : u32 , pending_events : & Mutex < Vec < events:: Event > > , logger : & L ,
493
+ send_payment_along_path : SP ,
493
494
)
494
495
where
495
496
R :: Target : Router ,
@@ -523,10 +524,14 @@ impl OutboundPayments {
523
524
}
524
525
}
525
526
}
527
+ core:: mem:: drop ( outbounds) ;
526
528
if let Some ( ( payment_id, route_params) ) = retry_id_route_params {
527
- core:: mem:: drop ( outbounds) ;
528
529
if let Err ( e) = self . pay_internal ( payment_id, None , route_params, router, first_hops ( ) , inflight_htlcs ( ) , entropy_source, node_signer, best_block_height, logger, & send_payment_along_path) {
529
530
log_info ! ( logger, "Errored retrying payment: {:?}" , e) ;
531
+ // If we error on retry, there is no chance of the payment succeeding and no HTLCs have
532
+ // been irrevocably committed to, so we can safely abandon. See docs on `pay_internal` for
533
+ // more information.
534
+ self . abandon_payment ( payment_id, pending_events) ;
530
535
}
531
536
} else { break }
532
537
}
@@ -1205,18 +1210,19 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
1205
1210
1206
1211
#[ cfg( test) ]
1207
1212
mod tests {
1213
+ use super :: * ;
1208
1214
use bitcoin:: blockdata:: constants:: genesis_block;
1209
1215
use bitcoin:: network:: constants:: Network ;
1210
1216
use bitcoin:: secp256k1:: { PublicKey , Secp256k1 , SecretKey } ;
1211
1217
1212
1218
use crate :: ln:: PaymentHash ;
1213
1219
use crate :: ln:: channelmanager:: { PaymentId , PaymentSendFailure } ;
1214
1220
use crate :: ln:: msgs:: { ErrorAction , LightningError } ;
1215
- use crate :: ln:: outbound_payment:: { OutboundPayments , Retry } ;
1216
1221
use crate :: routing:: gossip:: NetworkGraph ;
1217
1222
use crate :: routing:: router:: { InFlightHtlcs , PaymentParameters , Route , RouteParameters } ;
1218
1223
use crate :: sync:: Arc ;
1219
1224
use crate :: util:: errors:: APIError ;
1225
+ use crate :: util:: events:: Event ;
1220
1226
use crate :: util:: test_utils;
1221
1227
1222
1228
#[ test]
@@ -1301,4 +1307,53 @@ mod tests {
1301
1307
assert ! ( err. contains( "Failed to find a route" ) ) ;
1302
1308
} else { panic ! ( "Unexpected error" ) ; }
1303
1309
}
1310
+
1311
+ #[ test]
1312
+ fn fail_on_retry_error ( ) {
1313
+ let outbound_payments = OutboundPayments :: new ( ) ;
1314
+ let logger = test_utils:: TestLogger :: new ( ) ;
1315
+ let genesis_hash = genesis_block ( Network :: Testnet ) . header . block_hash ( ) ;
1316
+ let network_graph = Arc :: new ( NetworkGraph :: new ( genesis_hash, & logger) ) ;
1317
+ let router = test_utils:: TestRouter :: new ( network_graph) ;
1318
+ let secp_ctx = Secp256k1 :: new ( ) ;
1319
+ let session_priv = [ 42 ; 32 ] ;
1320
+ let keys_manager = test_utils:: TestKeysInterface :: new ( & [ 0 ; 32 ] , Network :: Testnet ) ;
1321
+ {
1322
+ let mut random_bytes_override = keys_manager. override_random_bytes . lock ( ) . unwrap ( ) ;
1323
+ * random_bytes_override = Some ( session_priv) ;
1324
+ }
1325
+
1326
+ let payment_params = PaymentParameters :: from_node_id (
1327
+ PublicKey :: from_secret_key ( & secp_ctx, & SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) ) , 0 ) ;
1328
+ let route_params = RouteParameters {
1329
+ payment_params,
1330
+ final_value_msat : 1000 ,
1331
+ final_cltv_expiry_delta : 0 ,
1332
+ } ;
1333
+ router. expect_find_route ( route_params. clone ( ) ,
1334
+ Err ( LightningError { err : String :: new ( ) , action : ErrorAction :: IgnoreError } ) ) ;
1335
+ let our_payment_id = PaymentId ( [ 0 ; 32 ] ) ;
1336
+ let our_payment_hash = PaymentHash ( [ 0 ; 32 ] ) ;
1337
+ outbound_payments. add_new_pending_payment ( our_payment_hash, None , our_payment_id, None ,
1338
+ & Route { paths : vec ! [ ] , payment_params : None } , Some ( Retry :: Attempts ( 1 ) ) ,
1339
+ Some ( route_params. payment_params . clone ( ) ) , & & keys_manager, 0 ) . unwrap ( ) ;
1340
+ {
1341
+ let mut pending_outbounds = outbound_payments. pending_outbound_payments . lock ( ) . unwrap ( ) ;
1342
+ if let Some ( PendingOutboundPayment :: Retryable { ref mut total_msat, .. } ) = pending_outbounds. get_mut ( & our_payment_id) {
1343
+ * total_msat += 1000 ;
1344
+ }
1345
+ }
1346
+
1347
+ let pending_events_mtx = Mutex :: new ( vec ! [ ] ) ;
1348
+ outbound_payments. check_retry_payments ( & & router, || vec ! [ ] , || InFlightHtlcs :: new ( ) , & & keys_manager, & & keys_manager, 0 , & pending_events_mtx, & & logger, |_, _, _, _, _, _, _, _, _| Ok ( ( ) ) ) ;
1349
+ let pending_events = pending_events_mtx. lock ( ) . unwrap ( ) ;
1350
+ assert_eq ! ( pending_events. len( ) , 1 ) ;
1351
+ match pending_events[ 0 ] {
1352
+ Event :: PaymentFailed { payment_id, payment_hash } => {
1353
+ assert_eq ! ( payment_id, our_payment_id) ;
1354
+ assert_eq ! ( payment_hash, our_payment_hash) ;
1355
+ } ,
1356
+ _ => panic ! ( )
1357
+ }
1358
+ }
1304
1359
}
0 commit comments