@@ -14,7 +14,7 @@ use bitcoin::hashes::sha256::Hash as Sha256;
1414use bitcoin:: secp256k1:: { self , Secp256k1 , SecretKey } ;
1515
1616use crate :: chain:: keysinterface:: { EntropySource , NodeSigner , Recipient } ;
17- use crate :: events;
17+ use crate :: events:: { self , PaymentFailureReason } ;
1818use crate :: ln:: { PaymentHash , PaymentPreimage , PaymentSecret } ;
1919use crate :: ln:: channelmanager:: { ChannelDetails , HTLCSource , IDEMPOTENCY_TIMEOUT_TICKS , PaymentId } ;
2020use crate :: ln:: onion_utils:: HTLCFailReason ;
@@ -68,6 +68,8 @@ pub(crate) enum PendingOutboundPayment {
6868 Abandoned {
6969 session_privs : HashSet < [ u8 ; 32 ] > ,
7070 payment_hash : PaymentHash ,
71+ /// Will be `None` if the payment was serialized before 0.0.115.
72+ reason : Option < PaymentFailureReason > ,
7173 } ,
7274}
7375
@@ -145,21 +147,22 @@ impl PendingOutboundPayment {
145147 * self = PendingOutboundPayment :: Fulfilled { session_privs, payment_hash, timer_ticks_without_htlcs : 0 } ;
146148 }
147149
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 {
152152 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 ( ( ) )
159163 } ,
160- } ) ;
161- * self = PendingOutboundPayment :: Abandoned { session_privs, payment_hash : our_payment_hash } ;
162- Ok ( ( ) )
164+ PendingOutboundPayment :: Abandoned { .. } => Ok ( ( ) ) ,
165+ }
163166 }
164167
165168 /// panics if path is None and !self.is_fulfilled
@@ -546,10 +549,12 @@ impl OutboundPayments {
546549 outbounds. retain ( |pmt_id, pmt| {
547550 let mut retain = true ;
548551 if !pmt. is_auto_retryable_now ( ) && pmt. remaining_parts ( ) == 0 {
549- if pmt. mark_abandoned ( ) . is_ok ( ) {
552+ let _ = pmt. mark_abandoned ( PaymentFailureReason :: RetriesExhausted ) ;
553+ if let PendingOutboundPayment :: Abandoned { payment_hash, reason, .. } = pmt {
550554 pending_events. lock ( ) . unwrap ( ) . push ( events:: Event :: PaymentFailed {
551555 payment_id : * pmt_id,
552- payment_hash : pmt. payment_hash ( ) . expect ( "PendingOutboundPayments::Retryable always has a payment hash set" ) ,
556+ payment_hash : * payment_hash,
557+ reason : * reason,
553558 } ) ;
554559 retain = false ;
555560 }
@@ -629,7 +634,7 @@ impl OutboundPayments {
629634 #[ cfg( feature = "std" ) ] {
630635 if has_expired ( & route_params) {
631636 log_error ! ( logger, "Payment params expired on retry, abandoning payment {}" , log_bytes!( payment_id. 0 ) ) ;
632- self . abandon_payment ( payment_id, pending_events) ;
637+ self . abandon_payment ( payment_id, PaymentFailureReason :: PaymentExpired , pending_events) ;
633638 return
634639 }
635640 }
@@ -642,14 +647,14 @@ impl OutboundPayments {
642647 Ok ( route) => route,
643648 Err ( e) => {
644649 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) ;
650+ self . abandon_payment ( payment_id, PaymentFailureReason :: RouteNotFound , pending_events) ;
646651 return
647652 }
648653 } ;
649654 for path in route. paths . iter ( ) {
650655 if path. len ( ) == 0 {
651656 log_error ! ( logger, "length-0 path in route" ) ;
652- self . abandon_payment ( payment_id, pending_events) ;
657+ self . abandon_payment ( payment_id, PaymentFailureReason :: UnexpectedError , pending_events) ;
653658 return
654659 }
655660 }
@@ -661,13 +666,17 @@ impl OutboundPayments {
661666 }
662667
663668 macro_rules! abandon_with_entry {
664- ( $payment: expr) => {
665- if $payment. get_mut( ) . mark_abandoned( ) . is_ok( ) && $payment. get( ) . remaining_parts( ) == 0 {
666- pending_events. lock( ) . unwrap( ) . push( events:: Event :: PaymentFailed {
667- payment_id,
668- payment_hash,
669- } ) ;
670- $payment. remove( ) ;
669+ ( $payment: expr, $reason: expr) => {
670+ let _ = $payment. get_mut( ) . mark_abandoned( $reason) ;
671+ if let PendingOutboundPayment :: Abandoned { reason, .. } = $payment. get( ) {
672+ if $payment. get( ) . remaining_parts( ) == 0 {
673+ pending_events. lock( ) . unwrap( ) . push( events:: Event :: PaymentFailed {
674+ payment_id,
675+ payment_hash,
676+ reason: * reason,
677+ } ) ;
678+ $payment. remove( ) ;
679+ }
671680 }
672681 }
673682 }
@@ -682,7 +691,7 @@ impl OutboundPayments {
682691 let retry_amt_msat: u64 = route. paths . iter ( ) . map ( |path| path. last ( ) . unwrap ( ) . fee_msat ) . sum ( ) ;
683692 if retry_amt_msat + * pending_amt_msat > * total_msat * ( 100 + RETRY_OVERFLOW_PERCENTAGE ) / 100 {
684693 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) ;
694+ abandon_with_entry ! ( payment, PaymentFailureReason :: UnexpectedError ) ;
686695 return
687696 }
688697 ( * total_msat, * payment_secret, * keysend_preimage)
@@ -702,7 +711,7 @@ impl OutboundPayments {
702711 } ;
703712 if !payment. get ( ) . is_retryable_now ( ) {
704713 log_error ! ( logger, "Retries exhausted for payment id {}" , log_bytes!( payment_id. 0 ) ) ;
705- abandon_with_entry ! ( payment) ;
714+ abandon_with_entry ! ( payment, PaymentFailureReason :: RetriesExhausted ) ;
706715 return
707716 }
708717 payment. get_mut ( ) . increment_attempts ( ) ;
@@ -759,12 +768,13 @@ impl OutboundPayments {
759768 // initial HTLC-Add messages yet.
760769 } ,
761770 PaymentSendFailure :: PathParameterError ( results) => {
771+ log_error ! ( logger, "Failed to send to route due to parameter error in a single path. Your router is buggy" ) ;
762772 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) ;
773+ self . abandon_payment ( payment_id, PaymentFailureReason :: UnexpectedError , pending_events) ;
764774 } ,
765775 PaymentSendFailure :: ParameterError ( e) => {
766776 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) ;
777+ self . abandon_payment ( payment_id, PaymentFailureReason :: UnexpectedError , pending_events) ;
768778 } ,
769779 PaymentSendFailure :: DuplicatePayment => debug_assert ! ( false ) , // unreachable
770780 }
@@ -1167,15 +1177,21 @@ impl OutboundPayments {
11671177 }
11681178
11691179 if payment_is_probe || !is_retryable_now || !payment_retryable {
1170- let _ = payment. get_mut ( ) . mark_abandoned ( ) ; // we'll only Err if it's a legacy payment
1180+ let reason = if !payment_retryable {
1181+ PaymentFailureReason :: RecipientRejected
1182+ } else {
1183+ PaymentFailureReason :: RetriesExhausted
1184+ } ;
1185+ let _ = payment. get_mut ( ) . mark_abandoned ( reason) ; // we'll only Err if it's a legacy payment
11711186 is_retryable_now = false ;
11721187 }
11731188 if payment. get ( ) . remaining_parts ( ) == 0 {
1174- if payment. get ( ) . abandoned ( ) {
1189+ if let PendingOutboundPayment :: Abandoned { payment_hash , reason , .. } = payment. get ( ) {
11751190 if !payment_is_probe {
11761191 full_failure_ev = Some ( events:: Event :: PaymentFailed {
11771192 payment_id : * payment_id,
1178- payment_hash : payment. get ( ) . payment_hash ( ) . expect ( "PendingOutboundPayments::RetriesExceeded always has a payment hash set" ) ,
1193+ payment_hash : * payment_hash,
1194+ reason : * reason,
11791195 } ) ;
11801196 }
11811197 payment. remove ( ) ;
@@ -1233,15 +1249,17 @@ impl OutboundPayments {
12331249 }
12341250
12351251 pub ( super ) fn abandon_payment (
1236- & self , payment_id : PaymentId , pending_events : & Mutex < Vec < events:: Event > >
1252+ & self , payment_id : PaymentId , reason : PaymentFailureReason , pending_events : & Mutex < Vec < events:: Event > >
12371253 ) {
12381254 let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
12391255 if let hash_map:: Entry :: Occupied ( mut payment) = outbounds. entry ( payment_id) {
1240- if let Ok ( ( ) ) = payment. get_mut ( ) . mark_abandoned ( ) {
1256+ let _ = payment. get_mut ( ) . mark_abandoned ( reason) ;
1257+ if let PendingOutboundPayment :: Abandoned { payment_hash, reason, .. } = payment. get ( ) {
12411258 if payment. get ( ) . remaining_parts ( ) == 0 {
12421259 pending_events. lock ( ) . unwrap ( ) . push ( events:: Event :: PaymentFailed {
12431260 payment_id,
1244- payment_hash : payment. get ( ) . payment_hash ( ) . expect ( "PendingOutboundPayments::RetriesExceeded always has a payment hash set" ) ,
1261+ payment_hash : * payment_hash,
1262+ reason : * reason,
12451263 } ) ;
12461264 payment. remove ( ) ;
12471265 }
@@ -1303,6 +1321,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
13031321 } ,
13041322 ( 3 , Abandoned ) => {
13051323 ( 0 , session_privs, required) ,
1324+ ( 1 , reason, option) ,
13061325 ( 2 , payment_hash, required) ,
13071326 } ,
13081327) ;
@@ -1312,7 +1331,7 @@ mod tests {
13121331 use bitcoin:: network:: constants:: Network ;
13131332 use bitcoin:: secp256k1:: { PublicKey , Secp256k1 , SecretKey } ;
13141333
1315- use crate :: events:: { Event , PathFailure } ;
1334+ use crate :: events:: { Event , PathFailure , PaymentFailureReason } ;
13161335 use crate :: ln:: PaymentHash ;
13171336 use crate :: ln:: channelmanager:: PaymentId ;
13181337 use crate :: ln:: features:: { ChannelFeatures , NodeFeatures } ;
@@ -1360,7 +1379,9 @@ mod tests {
13601379 & pending_events, & |_, _, _, _, _, _, _, _| Ok ( ( ) ) ) ;
13611380 let events = pending_events. lock ( ) . unwrap ( ) ;
13621381 assert_eq ! ( events. len( ) , 1 ) ;
1363- if let Event :: PaymentFailed { .. } = events[ 0 ] { } else { panic ! ( "Unexpected event" ) ; }
1382+ if let Event :: PaymentFailed { ref reason, .. } = events[ 0 ] {
1383+ assert_eq ! ( reason. unwrap( ) , PaymentFailureReason :: PaymentExpired ) ;
1384+ } else { panic ! ( "Unexpected event" ) ; }
13641385 } else {
13651386 let err = outbound_payments. send_payment (
13661387 PaymentHash ( [ 0 ; 32 ] ) , & None , PaymentId ( [ 0 ; 32 ] ) , Retry :: Attempts ( 0 ) , expired_route_params,
0 commit comments