@@ -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 ;
@@ -68,6 +68,8 @@ pub(crate) enum PendingOutboundPayment {
68
68
Abandoned {
69
69
session_privs : HashSet < [ u8 ; 32 ] > ,
70
70
payment_hash : PaymentHash ,
71
+ /// Will be `None` if the payment was serialized before 0.0.115.
72
+ reason : Option < PaymentFailureReason > ,
71
73
} ,
72
74
}
73
75
@@ -145,21 +147,22 @@ impl PendingOutboundPayment {
145
147
* self = PendingOutboundPayment :: Fulfilled { session_privs, payment_hash, timer_ticks_without_htlcs : 0 } ;
146
148
}
147
149
148
- fn mark_abandoned ( & mut self ) -> Result < ( ) , ( ) > {
149
- let mut session_privs = HashSet :: new ( ) ;
150
- let our_payment_hash;
151
- core:: mem:: swap ( & mut session_privs, match self {
150
+ fn mark_abandoned ( & mut self , reason : PaymentFailureReason ) -> Result < ( ) , ( ) > {
151
+ match self {
152
152
PendingOutboundPayment :: Legacy { .. } |
153
- PendingOutboundPayment :: Fulfilled { .. } =>
154
- return Err ( ( ) ) ,
155
- PendingOutboundPayment :: Retryable { session_privs, payment_hash, .. } |
156
- PendingOutboundPayment :: Abandoned { session_privs, payment_hash, .. } => {
157
- our_payment_hash = * payment_hash;
158
- session_privs
153
+ PendingOutboundPayment :: Fulfilled { .. } => Err ( ( ) ) ,
154
+ PendingOutboundPayment :: Retryable { session_privs, payment_hash, .. } => {
155
+ let mut our_session_privs = HashSet :: new ( ) ;
156
+ core:: mem:: swap ( & mut our_session_privs, session_privs) ;
157
+ * self = PendingOutboundPayment :: Abandoned {
158
+ session_privs : our_session_privs,
159
+ payment_hash : * payment_hash,
160
+ reason : Some ( reason)
161
+ } ;
162
+ Ok ( ( ) )
159
163
} ,
160
- } ) ;
161
- * self = PendingOutboundPayment :: Abandoned { session_privs, payment_hash : our_payment_hash } ;
162
- Ok ( ( ) )
164
+ PendingOutboundPayment :: Abandoned { .. } => Ok ( ( ) ) ,
165
+ }
163
166
}
164
167
165
168
/// panics if path is None and !self.is_fulfilled
@@ -588,10 +591,12 @@ impl OutboundPayments {
588
591
outbounds. retain ( |pmt_id, pmt| {
589
592
let mut retain = true ;
590
593
if !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 {
591
- if pmt. mark_abandoned ( ) . is_ok ( ) {
594
+ let _ = pmt. mark_abandoned ( PaymentFailureReason :: RetriesExhausted ) ;
595
+ if let PendingOutboundPayment :: Abandoned { payment_hash, reason, .. } = pmt {
592
596
pending_events. lock ( ) . unwrap ( ) . push ( events:: Event :: PaymentFailed {
593
597
payment_id : * pmt_id,
594
- payment_hash : pmt. payment_hash ( ) . expect ( "PendingOutboundPayments::Retryable always has a payment hash set" ) ,
598
+ payment_hash : * payment_hash,
599
+ reason : * reason,
595
600
} ) ;
596
601
retain = false ;
597
602
}
@@ -671,7 +676,7 @@ impl OutboundPayments {
671
676
#[ cfg( feature = "std" ) ] {
672
677
if has_expired ( & route_params) {
673
678
log_error ! ( logger, "Payment params expired on retry, abandoning payment {}" , log_bytes!( payment_id. 0 ) ) ;
674
- self . abandon_payment ( payment_id, pending_events) ;
679
+ self . abandon_payment ( payment_id, PaymentFailureReason :: PaymentExpired , pending_events) ;
675
680
return
676
681
}
677
682
}
@@ -684,14 +689,14 @@ impl OutboundPayments {
684
689
Ok ( route) => route,
685
690
Err ( e) => {
686
691
log_error ! ( logger, "Failed to find a route on retry, abandoning payment {}: {:#?}" , log_bytes!( payment_id. 0 ) , e) ;
687
- self . abandon_payment ( payment_id, pending_events) ;
692
+ self . abandon_payment ( payment_id, PaymentFailureReason :: RouteNotFound , pending_events) ;
688
693
return
689
694
}
690
695
} ;
691
696
for path in route. paths . iter ( ) {
692
697
if path. len ( ) == 0 {
693
698
log_error ! ( logger, "length-0 path in route" ) ;
694
- self . abandon_payment ( payment_id, pending_events) ;
699
+ self . abandon_payment ( payment_id, PaymentFailureReason :: UnexpectedError , pending_events) ;
695
700
return
696
701
}
697
702
}
@@ -703,13 +708,17 @@ impl OutboundPayments {
703
708
}
704
709
705
710
macro_rules! abandon_with_entry {
706
- ( $payment: expr) => {
707
- if $payment. get_mut( ) . mark_abandoned( ) . is_ok( ) && $payment. get( ) . remaining_parts( ) == 0 {
708
- pending_events. lock( ) . unwrap( ) . push( events:: Event :: PaymentFailed {
709
- payment_id,
710
- payment_hash,
711
- } ) ;
712
- $payment. remove( ) ;
711
+ ( $payment: expr, $reason: expr) => {
712
+ let _ = $payment. get_mut( ) . mark_abandoned( $reason) ;
713
+ if let PendingOutboundPayment :: Abandoned { reason, .. } = $payment. get( ) {
714
+ if $payment. get( ) . remaining_parts( ) == 0 {
715
+ pending_events. lock( ) . unwrap( ) . push( events:: Event :: PaymentFailed {
716
+ payment_id,
717
+ payment_hash,
718
+ reason: * reason,
719
+ } ) ;
720
+ $payment. remove( ) ;
721
+ }
713
722
}
714
723
}
715
724
}
@@ -724,7 +733,7 @@ impl OutboundPayments {
724
733
let retry_amt_msat: u64 = route. paths . iter ( ) . map ( |path| path. last ( ) . unwrap ( ) . fee_msat ) . sum ( ) ;
725
734
if retry_amt_msat + * pending_amt_msat > * total_msat * ( 100 + RETRY_OVERFLOW_PERCENTAGE ) / 100 {
726
735
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) ;
727
- abandon_with_entry ! ( payment) ;
736
+ abandon_with_entry ! ( payment, PaymentFailureReason :: UnexpectedError ) ;
728
737
return
729
738
}
730
739
( * total_msat, RecipientOnionFields {
@@ -746,7 +755,7 @@ impl OutboundPayments {
746
755
} ;
747
756
if !payment. get ( ) . is_retryable_now ( ) {
748
757
log_error ! ( logger, "Retries exhausted for payment id {}" , log_bytes!( payment_id. 0 ) ) ;
749
- abandon_with_entry ! ( payment) ;
758
+ abandon_with_entry ! ( payment, PaymentFailureReason :: RetriesExhausted ) ;
750
759
return
751
760
}
752
761
payment. get_mut ( ) . increment_attempts ( ) ;
@@ -803,12 +812,13 @@ impl OutboundPayments {
803
812
// initial HTLC-Add messages yet.
804
813
} ,
805
814
PaymentSendFailure :: PathParameterError ( results) => {
815
+ log_error ! ( logger, "Failed to send to route due to parameter error in a single path. Your router is buggy" ) ;
806
816
Self :: push_path_failed_evs_and_scids ( payment_id, payment_hash, & mut route_params, route. paths , results. into_iter ( ) , pending_events) ;
807
- self . abandon_payment ( payment_id, pending_events) ;
817
+ self . abandon_payment ( payment_id, PaymentFailureReason :: UnexpectedError , pending_events) ;
808
818
} ,
809
819
PaymentSendFailure :: ParameterError ( e) => {
810
820
log_error ! ( logger, "Failed to send to route due to parameter error: {:?}. Your router is buggy" , e) ;
811
- self . abandon_payment ( payment_id, pending_events) ;
821
+ self . abandon_payment ( payment_id, PaymentFailureReason :: UnexpectedError , pending_events) ;
812
822
} ,
813
823
PaymentSendFailure :: DuplicatePayment => debug_assert ! ( false ) , // unreachable
814
824
}
@@ -1216,15 +1226,21 @@ impl OutboundPayments {
1216
1226
}
1217
1227
1218
1228
if payment_is_probe || !is_retryable_now || !payment_retryable {
1219
- let _ = payment. get_mut ( ) . mark_abandoned ( ) ; // we'll only Err if it's a legacy payment
1229
+ let reason = if !payment_retryable {
1230
+ PaymentFailureReason :: RecipientRejected
1231
+ } else {
1232
+ PaymentFailureReason :: RetriesExhausted
1233
+ } ;
1234
+ let _ = payment. get_mut ( ) . mark_abandoned ( reason) ; // we'll only Err if it's a legacy payment
1220
1235
is_retryable_now = false ;
1221
1236
}
1222
1237
if payment. get ( ) . remaining_parts ( ) == 0 {
1223
- if payment. get ( ) . abandoned ( ) {
1238
+ if let PendingOutboundPayment :: Abandoned { payment_hash , reason , .. } = payment. get ( ) {
1224
1239
if !payment_is_probe {
1225
1240
full_failure_ev = Some ( events:: Event :: PaymentFailed {
1226
1241
payment_id : * payment_id,
1227
- payment_hash : payment. get ( ) . payment_hash ( ) . expect ( "PendingOutboundPayments::RetriesExceeded always has a payment hash set" ) ,
1242
+ payment_hash : * payment_hash,
1243
+ reason : * reason,
1228
1244
} ) ;
1229
1245
}
1230
1246
payment. remove ( ) ;
@@ -1282,15 +1298,17 @@ impl OutboundPayments {
1282
1298
}
1283
1299
1284
1300
pub ( super ) fn abandon_payment (
1285
- & self , payment_id : PaymentId , pending_events : & Mutex < Vec < events:: Event > >
1301
+ & self , payment_id : PaymentId , reason : PaymentFailureReason , pending_events : & Mutex < Vec < events:: Event > >
1286
1302
) {
1287
1303
let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1288
1304
if let hash_map:: Entry :: Occupied ( mut payment) = outbounds. entry ( payment_id) {
1289
- if let Ok ( ( ) ) = payment. get_mut ( ) . mark_abandoned ( ) {
1305
+ let _ = payment. get_mut ( ) . mark_abandoned ( reason) ;
1306
+ if let PendingOutboundPayment :: Abandoned { payment_hash, reason, .. } = payment. get ( ) {
1290
1307
if payment. get ( ) . remaining_parts ( ) == 0 {
1291
1308
pending_events. lock ( ) . unwrap ( ) . push ( events:: Event :: PaymentFailed {
1292
1309
payment_id,
1293
- payment_hash : payment. get ( ) . payment_hash ( ) . expect ( "PendingOutboundPayments::RetriesExceeded always has a payment hash set" ) ,
1310
+ payment_hash : * payment_hash,
1311
+ reason : * reason,
1294
1312
} ) ;
1295
1313
payment. remove ( ) ;
1296
1314
}
@@ -1352,6 +1370,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
1352
1370
} ,
1353
1371
( 3 , Abandoned ) => {
1354
1372
( 0 , session_privs, required) ,
1373
+ ( 1 , reason, option) ,
1355
1374
( 2 , payment_hash, required) ,
1356
1375
} ,
1357
1376
) ;
@@ -1361,7 +1380,7 @@ mod tests {
1361
1380
use bitcoin:: network:: constants:: Network ;
1362
1381
use bitcoin:: secp256k1:: { PublicKey , Secp256k1 , SecretKey } ;
1363
1382
1364
- use crate :: events:: { Event , PathFailure } ;
1383
+ use crate :: events:: { Event , PathFailure , PaymentFailureReason } ;
1365
1384
use crate :: ln:: PaymentHash ;
1366
1385
use crate :: ln:: channelmanager:: { PaymentId , RecipientOnionFields } ;
1367
1386
use crate :: ln:: features:: { ChannelFeatures , NodeFeatures } ;
@@ -1410,7 +1429,9 @@ mod tests {
1410
1429
& pending_events, & |_, _, _, _, _, _, _, _| Ok ( ( ) ) ) ;
1411
1430
let events = pending_events. lock ( ) . unwrap ( ) ;
1412
1431
assert_eq ! ( events. len( ) , 1 ) ;
1413
- if let Event :: PaymentFailed { .. } = events[ 0 ] { } else { panic ! ( "Unexpected event" ) ; }
1432
+ if let Event :: PaymentFailed { ref reason, .. } = events[ 0 ] {
1433
+ assert_eq ! ( reason. unwrap( ) , PaymentFailureReason :: PaymentExpired ) ;
1434
+ } else { panic ! ( "Unexpected event" ) ; }
1414
1435
} else {
1415
1436
let err = outbound_payments. send_payment (
1416
1437
PaymentHash ( [ 0 ; 32 ] ) , RecipientOnionFields :: spontaneous_empty ( ) , PaymentId ( [ 0 ; 32 ] ) ,
0 commit comments