@@ -14,7 +14,7 @@ use bitcoin::hashes::sha256::Hash as Sha256;
14
14
use bitcoin:: secp256k1:: { self , Secp256k1 , SecretKey } ;
15
15
16
16
use crate :: chain:: keysinterface:: { EntropySource , NodeSigner , Recipient } ;
17
- use crate :: events;
17
+ use crate :: events:: { self , PaymentFailureReason } ;
18
18
use crate :: ln:: { PaymentHash , PaymentPreimage , PaymentSecret } ;
19
19
use crate :: ln:: channelmanager:: { ChannelDetails , HTLCSource , IDEMPOTENCY_TIMEOUT_TICKS , PaymentId } ;
20
20
use crate :: ln:: onion_utils:: HTLCFailReason ;
@@ -550,6 +550,7 @@ impl OutboundPayments {
550
550
pending_events. lock ( ) . unwrap ( ) . push ( events:: Event :: PaymentFailed {
551
551
payment_id : * pmt_id,
552
552
payment_hash : pmt. payment_hash ( ) . expect ( "PendingOutboundPayments::Retryable always has a payment hash set" ) ,
553
+ reason : Some ( events:: PaymentFailureReason :: ExhaustedRetryAttempts ) ,
553
554
} ) ;
554
555
retain = false ;
555
556
}
@@ -629,7 +630,7 @@ impl OutboundPayments {
629
630
#[ cfg( feature = "std" ) ] {
630
631
if has_expired ( & route_params) {
631
632
log_error ! ( logger, "Payment params expired on retry, abandoning payment {}" , log_bytes!( payment_id. 0 ) ) ;
632
- self . abandon_payment ( payment_id, pending_events) ;
633
+ self . abandon_payment ( payment_id, PaymentFailureReason :: PaymentExpired , pending_events) ;
633
634
return
634
635
}
635
636
}
@@ -642,14 +643,14 @@ impl OutboundPayments {
642
643
Ok ( route) => route,
643
644
Err ( e) => {
644
645
log_error ! ( logger, "Failed to find a route on retry, abandoning payment {}: {:#?}" , log_bytes!( payment_id. 0 ) , e) ;
645
- self . abandon_payment ( payment_id, pending_events) ;
646
+ self . abandon_payment ( payment_id, PaymentFailureReason :: FailedRoutingRetry , pending_events) ;
646
647
return
647
648
}
648
649
} ;
649
650
for path in route. paths . iter ( ) {
650
651
if path. len ( ) == 0 {
651
652
log_error ! ( logger, "length-0 path in route" ) ;
652
- self . abandon_payment ( payment_id, pending_events) ;
653
+ self . abandon_payment ( payment_id, PaymentFailureReason :: FailedRoutingRetry , pending_events) ;
653
654
return
654
655
}
655
656
}
@@ -661,11 +662,12 @@ impl OutboundPayments {
661
662
}
662
663
663
664
macro_rules! abandon_with_entry {
664
- ( $payment: expr) => {
665
+ ( $payment: expr, $reason : expr ) => {
665
666
if $payment. get_mut( ) . mark_abandoned( ) . is_ok( ) && $payment. get( ) . remaining_parts( ) == 0 {
666
667
pending_events. lock( ) . unwrap( ) . push( events:: Event :: PaymentFailed {
667
668
payment_id,
668
669
payment_hash,
670
+ reason: Some ( $reason) ,
669
671
} ) ;
670
672
$payment. remove( ) ;
671
673
}
@@ -682,7 +684,7 @@ impl OutboundPayments {
682
684
let retry_amt_msat: u64 = route. paths . iter ( ) . map ( |path| path. last ( ) . unwrap ( ) . fee_msat ) . sum ( ) ;
683
685
if retry_amt_msat + * pending_amt_msat > * total_msat * ( 100 + RETRY_OVERFLOW_PERCENTAGE ) / 100 {
684
686
log_error ! ( logger, "retry_amt_msat of {} will put pending_amt_msat (currently: {}) more than 10% over total_payment_amt_msat of {}" , retry_amt_msat, pending_amt_msat, total_msat) ;
685
- abandon_with_entry ! ( payment) ;
687
+ abandon_with_entry ! ( payment, PaymentFailureReason :: UnexpectedError ) ;
686
688
return
687
689
}
688
690
( * total_msat, * payment_secret, * keysend_preimage)
@@ -702,7 +704,7 @@ impl OutboundPayments {
702
704
} ;
703
705
if !payment. get ( ) . is_retryable_now ( ) {
704
706
log_error ! ( logger, "Retries exhausted for payment id {}" , log_bytes!( payment_id. 0 ) ) ;
705
- abandon_with_entry ! ( payment) ;
707
+ abandon_with_entry ! ( payment, PaymentFailureReason :: ExhaustedRetryAttempts ) ;
706
708
return
707
709
}
708
710
payment. get_mut ( ) . increment_attempts ( ) ;
@@ -760,11 +762,11 @@ impl OutboundPayments {
760
762
} ,
761
763
PaymentSendFailure :: PathParameterError ( results) => {
762
764
Self :: push_path_failed_evs_and_scids ( payment_id, payment_hash, & mut route_params, route. paths , results. into_iter ( ) , pending_events) ;
763
- self . abandon_payment ( payment_id, pending_events) ;
765
+ self . abandon_payment ( payment_id, PaymentFailureReason :: UnexpectedError , pending_events) ;
764
766
} ,
765
767
PaymentSendFailure :: ParameterError ( e) => {
766
768
log_error ! ( logger, "Failed to send to route due to parameter error: {:?}. Your router is buggy" , e) ;
767
- self . abandon_payment ( payment_id, pending_events) ;
769
+ self . abandon_payment ( payment_id, PaymentFailureReason :: UnexpectedError , pending_events) ;
768
770
} ,
769
771
PaymentSendFailure :: DuplicatePayment => debug_assert ! ( false ) , // unreachable
770
772
}
@@ -1176,6 +1178,11 @@ impl OutboundPayments {
1176
1178
full_failure_ev = Some ( events:: Event :: PaymentFailed {
1177
1179
payment_id : * payment_id,
1178
1180
payment_hash : payment. get ( ) . payment_hash ( ) . expect ( "PendingOutboundPayments::RetriesExceeded always has a payment hash set" ) ,
1181
+ reason : Some ( if payment_retryable {
1182
+ PaymentFailureReason :: FailedAlongPath
1183
+ } else {
1184
+ PaymentFailureReason :: RecipientRejected
1185
+ } ) ,
1179
1186
} ) ;
1180
1187
}
1181
1188
payment. remove ( ) ;
@@ -1233,7 +1240,7 @@ impl OutboundPayments {
1233
1240
}
1234
1241
1235
1242
pub ( super ) fn abandon_payment (
1236
- & self , payment_id : PaymentId , pending_events : & Mutex < Vec < events:: Event > >
1243
+ & self , payment_id : PaymentId , reason : PaymentFailureReason , pending_events : & Mutex < Vec < events:: Event > >
1237
1244
) {
1238
1245
let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1239
1246
if let hash_map:: Entry :: Occupied ( mut payment) = outbounds. entry ( payment_id) {
@@ -1242,6 +1249,7 @@ impl OutboundPayments {
1242
1249
pending_events. lock ( ) . unwrap ( ) . push ( events:: Event :: PaymentFailed {
1243
1250
payment_id,
1244
1251
payment_hash : payment. get ( ) . payment_hash ( ) . expect ( "PendingOutboundPayments::RetriesExceeded always has a payment hash set" ) ,
1252
+ reason : Some ( reason) ,
1245
1253
} ) ;
1246
1254
payment. remove ( ) ;
1247
1255
}
@@ -1312,7 +1320,7 @@ mod tests {
1312
1320
use bitcoin:: network:: constants:: Network ;
1313
1321
use bitcoin:: secp256k1:: { PublicKey , Secp256k1 , SecretKey } ;
1314
1322
1315
- use crate :: events:: { Event , PathFailure } ;
1323
+ use crate :: events:: { Event , PathFailure , PaymentFailureReason } ;
1316
1324
use crate :: ln:: PaymentHash ;
1317
1325
use crate :: ln:: channelmanager:: PaymentId ;
1318
1326
use crate :: ln:: features:: { ChannelFeatures , NodeFeatures } ;
@@ -1332,6 +1340,7 @@ mod tests {
1332
1340
}
1333
1341
#[ cfg( feature = "std" ) ]
1334
1342
fn do_fails_paying_after_expiration ( on_retry : bool ) {
1343
+
1335
1344
let outbound_payments = OutboundPayments :: new ( ) ;
1336
1345
let logger = test_utils:: TestLogger :: new ( ) ;
1337
1346
let network_graph = Arc :: new ( NetworkGraph :: new ( Network :: Testnet , & logger) ) ;
@@ -1360,7 +1369,9 @@ mod tests {
1360
1369
& pending_events, & |_, _, _, _, _, _, _, _| Ok ( ( ) ) ) ;
1361
1370
let events = pending_events. lock ( ) . unwrap ( ) ;
1362
1371
assert_eq ! ( events. len( ) , 1 ) ;
1363
- if let Event :: PaymentFailed { .. } = events[ 0 ] { } else { panic ! ( "Unexpected event" ) ; }
1372
+ if let Event :: PaymentFailed { ref reason, .. } = events[ 0 ] {
1373
+ assert_eq ! ( reason. unwrap( ) , PaymentFailureReason :: PaymentExpired ) ;
1374
+ } else { panic ! ( "Unexpected event" ) ; }
1364
1375
} else {
1365
1376
let err = outbound_payments. send_payment (
1366
1377
PaymentHash ( [ 0 ; 32 ] ) , & None , PaymentId ( [ 0 ; 32 ] ) , Retry :: Attempts ( 0 ) , expired_route_params,
0 commit comments