@@ -16,7 +16,7 @@ use bitcoin::secp256k1::{self, Secp256k1, SecretKey};
1616use  crate :: sign:: { EntropySource ,  NodeSigner ,  Recipient } ; 
1717use  crate :: events:: { self ,  PaymentFailureReason } ; 
1818use  crate :: ln:: { PaymentHash ,  PaymentPreimage ,  PaymentSecret } ; 
19- use  crate :: ln:: channelmanager:: { ChannelDetails ,  EventCompletionAction ,  HTLCSource ,  IDEMPOTENCY_TIMEOUT_TICKS ,  PaymentId } ; 
19+ use  crate :: ln:: channelmanager:: { ChannelDetails ,  EventCompletionAction ,  HTLCSource ,  IDEMPOTENCY_TIMEOUT_TICKS ,  INVOICE_REQUEST_TIMEOUT_TICKS ,   PaymentId } ; 
2020use  crate :: ln:: onion_utils:: HTLCFailReason ; 
2121use  crate :: routing:: router:: { InFlightHtlcs ,  Path ,  PaymentParameters ,  Route ,  RouteParameters ,  Router } ; 
2222use  crate :: util:: errors:: APIError ; 
@@ -38,6 +38,9 @@ pub(crate) enum PendingOutboundPayment {
3838	Legacy  { 
3939		session_privs :  HashSet < [ u8 ;  32 ] > , 
4040	} , 
41+ 	AwaitingInvoice  { 
42+ 		timer_ticks_without_response :  u8 , 
43+ 	} , 
4144	Retryable  { 
4245		retry_strategy :  Option < Retry > , 
4346		attempts :  PaymentAttempts , 
@@ -107,6 +110,12 @@ impl PendingOutboundPayment {
107110			params. previously_failed_channels . push ( scid) ; 
108111		} 
109112	} 
113+ 	fn  is_awaiting_invoice ( & self )  -> bool  { 
114+ 		match  self  { 
115+ 			PendingOutboundPayment :: AwaitingInvoice  {  .. }  => true , 
116+ 			_ => false , 
117+ 		} 
118+ 	} 
110119	pub ( super )  fn  is_fulfilled ( & self )  -> bool  { 
111120		match  self  { 
112121			PendingOutboundPayment :: Fulfilled  {  .. }  => true , 
@@ -129,6 +138,7 @@ impl PendingOutboundPayment {
129138	fn  payment_hash ( & self )  -> Option < PaymentHash >  { 
130139		match  self  { 
131140			PendingOutboundPayment :: Legacy  {  .. }  => None , 
141+ 			PendingOutboundPayment :: AwaitingInvoice  {  .. }  => None , 
132142			PendingOutboundPayment :: Retryable  {  payment_hash,  .. }  => Some ( * payment_hash) , 
133143			PendingOutboundPayment :: Fulfilled  {  payment_hash,  .. }  => * payment_hash, 
134144			PendingOutboundPayment :: Abandoned  {  payment_hash,  .. }  => Some ( * payment_hash) , 
@@ -141,8 +151,8 @@ impl PendingOutboundPayment {
141151			PendingOutboundPayment :: Legacy  {  session_privs }  |
142152				PendingOutboundPayment :: Retryable  {  session_privs,  .. }  |
143153				PendingOutboundPayment :: Fulfilled  {  session_privs,  .. }  |
144- 				PendingOutboundPayment :: Abandoned  {  session_privs,  .. } 
145- 			=> session_privs , 
154+ 				PendingOutboundPayment :: Abandoned  {  session_privs,  .. }  => session_privs , 
155+ 			PendingOutboundPayment :: AwaitingInvoice   {  ..  }   => return , 
146156		} ) ; 
147157		let  payment_hash = self . payment_hash ( ) ; 
148158		* self  = PendingOutboundPayment :: Fulfilled  {  session_privs,  payment_hash,  timer_ticks_without_htlcs :  0  } ; 
@@ -168,7 +178,8 @@ impl PendingOutboundPayment {
168178				PendingOutboundPayment :: Fulfilled  {  session_privs,  .. }  |
169179				PendingOutboundPayment :: Abandoned  {  session_privs,  .. }  => { 
170180					session_privs. remove ( session_priv) 
171- 				} 
181+ 				} , 
182+ 			PendingOutboundPayment :: AwaitingInvoice  {  .. }  => false , 
172183		} ; 
173184		if  remove_res { 
174185			if  let  PendingOutboundPayment :: Retryable  {  ref  mut  pending_amt_msat,  ref  mut  pending_fee_msat,  .. }  = self  { 
@@ -188,6 +199,7 @@ impl PendingOutboundPayment {
188199				PendingOutboundPayment :: Retryable  {  session_privs,  .. }  => { 
189200					session_privs. insert ( session_priv) 
190201				} 
202+ 			PendingOutboundPayment :: AwaitingInvoice  {  .. }  => false , 
191203			PendingOutboundPayment :: Fulfilled  {  .. }  => false , 
192204			PendingOutboundPayment :: Abandoned  {  .. }  => false , 
193205		} ; 
@@ -209,7 +221,8 @@ impl PendingOutboundPayment {
209221				PendingOutboundPayment :: Fulfilled  {  session_privs,  .. }  |
210222				PendingOutboundPayment :: Abandoned  {  session_privs,  .. }  => { 
211223					session_privs. len ( ) 
212- 				} 
224+ 				} , 
225+ 			PendingOutboundPayment :: AwaitingInvoice  {  .. }  => 0 , 
213226		} 
214227	} 
215228} 
@@ -626,7 +639,7 @@ impl OutboundPayments {
626639		let  mut  outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ; 
627640		outbounds. retain ( |pmt_id,  pmt| { 
628641			let  mut  retain = true ; 
629- 			if  !pmt. is_auto_retryable_now ( )  && pmt. remaining_parts ( )  == 0  { 
642+ 			if  !pmt. is_auto_retryable_now ( )  && pmt. remaining_parts ( )  == 0  && !pmt . is_awaiting_invoice ( )   { 
630643				pmt. mark_abandoned ( PaymentFailureReason :: RetriesExhausted ) ; 
631644				if  let  PendingOutboundPayment :: Abandoned  {  payment_hash,  reason,  .. }  = pmt { 
632645					pending_events. lock ( ) . unwrap ( ) . push_back ( ( events:: Event :: PaymentFailed  { 
@@ -644,7 +657,8 @@ impl OutboundPayments {
644657	pub ( super )  fn  needs_abandon ( & self )  -> bool  { 
645658		let  outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ; 
646659		outbounds. iter ( ) . any ( |( _,  pmt) |
647- 			!pmt. is_auto_retryable_now ( )  && pmt. remaining_parts ( )  == 0  && !pmt. is_fulfilled ( ) ) 
660+ 			!pmt. is_auto_retryable_now ( )  && pmt. remaining_parts ( )  == 0  && !pmt. is_fulfilled ( )  &&
661+ 			!pmt. is_awaiting_invoice ( ) ) 
648662	} 
649663
650664	/// Errors immediately on [`RetryableSendFailure`] error conditions. Otherwise, further errors may 
@@ -779,6 +793,10 @@ impl OutboundPayments {
779793							log_error ! ( logger,  "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102" ) ; 
780794							return 
781795						} , 
796+ 						PendingOutboundPayment :: AwaitingInvoice  {  .. }  => { 
797+ 							log_error ! ( logger,  "Payment not yet sent" ) ; 
798+ 							return 
799+ 						} , 
782800						PendingOutboundPayment :: Fulfilled  {  .. }  => { 
783801							log_error ! ( logger,  "Payment already completed" ) ; 
784802							return 
@@ -951,35 +969,57 @@ impl OutboundPayments {
951969		keysend_preimage :  Option < PaymentPreimage > ,  route :  & Route ,  retry_strategy :  Option < Retry > , 
952970		payment_params :  Option < PaymentParameters > ,  entropy_source :  & ES ,  best_block_height :  u32 
953971	)  -> Result < Vec < [ u8 ;  32 ] > ,  PaymentSendFailure >  where  ES :: Target :  EntropySource  { 
972+ 		let  mut  pending_outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ; 
973+ 		let  entry = pending_outbounds. entry ( payment_id) ; 
974+ 		if  let  hash_map:: Entry :: Occupied ( entry)  = & entry { 
975+ 			if  let  PendingOutboundPayment :: AwaitingInvoice  {  .. }  = entry. get ( )  {  }  else  { 
976+ 				return  Err ( PaymentSendFailure :: DuplicatePayment ) 
977+ 			} 
978+ 		} 
979+ 
954980		let  mut  onion_session_privs = Vec :: with_capacity ( route. paths . len ( ) ) ; 
955981		for  _ in  0 ..route. paths . len ( )  { 
956982			onion_session_privs. push ( entropy_source. get_secure_random_bytes ( ) ) ; 
957983		} 
958984
985+ 		let  mut  payment = PendingOutboundPayment :: Retryable  { 
986+ 			retry_strategy, 
987+ 			attempts :  PaymentAttempts :: new ( ) , 
988+ 			payment_params, 
989+ 			session_privs :  HashSet :: new ( ) , 
990+ 			pending_amt_msat :  0 , 
991+ 			pending_fee_msat :  Some ( 0 ) , 
992+ 			payment_hash, 
993+ 			payment_secret :  recipient_onion. payment_secret , 
994+ 			payment_metadata :  recipient_onion. payment_metadata , 
995+ 			keysend_preimage, 
996+ 			starting_block_height :  best_block_height, 
997+ 			total_msat :  route. get_total_amount ( ) , 
998+ 		} ; 
999+ 
1000+ 		for  ( path,  session_priv_bytes)  in  route. paths . iter ( ) . zip ( onion_session_privs. iter ( ) )  { 
1001+ 			assert ! ( payment. insert( * session_priv_bytes,  path) ) ; 
1002+ 		} 
1003+ 
1004+ 		match  entry { 
1005+ 			hash_map:: Entry :: Occupied ( mut  entry)  => {  entry. insert ( payment) ;  } , 
1006+ 			hash_map:: Entry :: Vacant ( entry)  => {  entry. insert ( payment) ;  } , 
1007+ 		} 
1008+ 
1009+ 		Ok ( onion_session_privs) 
1010+ 	} 
1011+ 
1012+ 	#[ allow( unused) ]  
1013+ 	pub ( super )  fn  add_new_awaiting_invoice ( & self ,  payment_id :  PaymentId )  -> Result < ( ) ,  ( ) >  { 
9591014		let  mut  pending_outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ; 
9601015		match  pending_outbounds. entry ( payment_id)  { 
961- 			hash_map:: Entry :: Occupied ( _)  => Err ( PaymentSendFailure :: DuplicatePayment ) , 
1016+ 			hash_map:: Entry :: Occupied ( _)  => Err ( ( ) ) , 
9621017			hash_map:: Entry :: Vacant ( entry)  => { 
963- 				let  payment = entry. insert ( PendingOutboundPayment :: Retryable  { 
964- 					retry_strategy, 
965- 					attempts :  PaymentAttempts :: new ( ) , 
966- 					payment_params, 
967- 					session_privs :  HashSet :: new ( ) , 
968- 					pending_amt_msat :  0 , 
969- 					pending_fee_msat :  Some ( 0 ) , 
970- 					payment_hash, 
971- 					payment_secret :  recipient_onion. payment_secret , 
972- 					payment_metadata :  recipient_onion. payment_metadata , 
973- 					keysend_preimage, 
974- 					starting_block_height :  best_block_height, 
975- 					total_msat :  route. get_total_amount ( ) , 
1018+ 				entry. insert ( PendingOutboundPayment :: AwaitingInvoice  { 
1019+ 					timer_ticks_without_response :  0 , 
9761020				} ) ; 
9771021
978- 				for  ( path,  session_priv_bytes)  in  route. paths . iter ( ) . zip ( onion_session_privs. iter ( ) )  { 
979- 					assert ! ( payment. insert( * session_priv_bytes,  path) ) ; 
980- 				} 
981- 
982- 				Ok ( onion_session_privs) 
1022+ 				Ok ( ( ) ) 
9831023			} , 
9841024		} 
9851025	} 
@@ -1188,19 +1228,19 @@ impl OutboundPayments {
11881228		} 
11891229	} 
11901230
1191- 	pub ( super )  fn  remove_stale_resolved_payments ( & self , 
1192- 		pending_events :  & Mutex < VecDeque < ( events:: Event ,  Option < EventCompletionAction > ) > > ) 
1231+ 	pub ( super )  fn  remove_stale_payments ( 
1232+ 		& self ,   pending_events :  & Mutex < VecDeque < ( events:: Event ,  Option < EventCompletionAction > ) > > ) 
11931233	{ 
1194- 		// If an outbound payment was completed, and no pending HTLCs remain, we should remove it 
1195- 		// from the map. However, if we did that immediately when the last payment HTLC is claimed, 
1196- 		// this could race the user making a duplicate send_payment call and our idempotency 
1197- 		// guarantees would be violated. Instead, we wait a few timer ticks to do the actual 
1198- 		// removal. This should be more than sufficient to ensure the idempotency of any 
1199- 		// `send_payment` calls that were made at the same time the `PaymentSent` event was being 
1200- 		// processed. 
12011234		let  mut  pending_outbound_payments = self . pending_outbound_payments . lock ( ) . unwrap ( ) ; 
1202- 		let  pending_events = pending_events. lock ( ) . unwrap ( ) ; 
1235+ 		let  mut   pending_events = pending_events. lock ( ) . unwrap ( ) ; 
12031236		pending_outbound_payments. retain ( |payment_id,  payment| { 
1237+ 			// If an outbound payment was completed, and no pending HTLCs remain, we should remove it 
1238+ 			// from the map. However, if we did that immediately when the last payment HTLC is claimed, 
1239+ 			// this could race the user making a duplicate send_payment call and our idempotency 
1240+ 			// guarantees would be violated. Instead, we wait a few timer ticks to do the actual 
1241+ 			// removal. This should be more than sufficient to ensure the idempotency of any 
1242+ 			// `send_payment` calls that were made at the same time the `PaymentSent` event was being 
1243+ 			// processed. 
12041244			if  let  PendingOutboundPayment :: Fulfilled  {  session_privs,  timer_ticks_without_htlcs,  .. }  = payment { 
12051245				let  mut  no_remaining_entries = session_privs. is_empty ( ) ; 
12061246				if  no_remaining_entries { 
@@ -1225,6 +1265,16 @@ impl OutboundPayments {
12251265					* timer_ticks_without_htlcs = 0 ; 
12261266					true 
12271267				} 
1268+ 			}  else  if  let  PendingOutboundPayment :: AwaitingInvoice  {  timer_ticks_without_response,  .. }  = payment { 
1269+ 				* timer_ticks_without_response += 1 ; 
1270+ 				if  * timer_ticks_without_response <= INVOICE_REQUEST_TIMEOUT_TICKS  { 
1271+ 					true 
1272+ 				}  else  { 
1273+ 					pending_events. push_back ( 
1274+ 						( events:: Event :: InvoiceRequestFailed  {  payment_id :  * payment_id } ,  None ) 
1275+ 					) ; 
1276+ 					false 
1277+ 				} 
12281278			}  else  {  true  } 
12291279		} ) ; 
12301280	} 
@@ -1429,6 +1479,9 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
14291479		( 1 ,  reason,  option) , 
14301480		( 2 ,  payment_hash,  required) , 
14311481	} , 
1482+ 	( 5 ,  AwaitingInvoice )  => { 
1483+ 		( 0 ,  timer_ticks_without_response,  required) , 
1484+ 	} , 
14321485) ; 
14331486
14341487#[ cfg( test) ]  
0 commit comments