@@ -18,6 +18,7 @@ use crate::events::{self, PaymentFailureReason};
1818use crate :: ln:: { PaymentHash , PaymentPreimage , PaymentSecret } ;
1919use crate :: ln:: channelmanager:: { ChannelDetails , EventCompletionAction , HTLCSource , PaymentId } ;
2020use crate :: ln:: onion_utils:: { DecodedOnionFailure , HTLCFailReason } ;
21+ use crate :: offers:: invoice:: Bolt12Invoice ;
2122use crate :: routing:: router:: { InFlightHtlcs , Path , PaymentParameters , Route , RouteParameters , Router } ;
2223use crate :: util:: errors:: APIError ;
2324use crate :: util:: logger:: Logger ;
@@ -440,6 +441,14 @@ pub enum PaymentSendFailure {
440441 } ,
441442}
442443
444+ /// An error when attempting to pay a BOLT 12 invoice.
445+ pub ( super ) enum Bolt12PaymentError {
446+ /// The invoice was not requested.
447+ UnexpectedInvoice ,
448+ /// Payment for an invoice with the corresponding [`PaymentId`] was already initiated.
449+ DuplicateInvoice ,
450+ }
451+
443452/// Information which is provided, encrypted, to the payment recipient when sending HTLCs.
444453///
445454/// This should generally be constructed with data communicated to us from the recipient (via a
@@ -577,6 +586,8 @@ pub(super) struct SendAlongPathArgs<'a> {
577586 pub session_priv_bytes : [ u8 ; 32 ] ,
578587}
579588
589+ const BOLT_12_INVOICE_RETRY_STRATEGY : Retry = Retry :: Attempts ( 3 ) ;
590+
580591pub ( super ) struct OutboundPayments {
581592 pub ( super ) pending_outbound_payments : Mutex < HashMap < PaymentId , PendingOutboundPayment > > ,
582593 pub ( super ) retry_lock : Mutex < ( ) > ,
@@ -677,6 +688,45 @@ impl OutboundPayments {
677688 }
678689 }
679690
691+ #[ allow( unused) ]
692+ pub ( super ) fn send_payment_for_bolt12_invoice < R : Deref , ES : Deref , NS : Deref , IH , SP , L : Deref > (
693+ & self , invoice : & Bolt12Invoice , payment_id : PaymentId , router : & R ,
694+ first_hops : Vec < ChannelDetails > , inflight_htlcs : IH , entropy_source : & ES , node_signer : & NS ,
695+ best_block_height : u32 , logger : & L ,
696+ pending_events : & Mutex < VecDeque < ( events:: Event , Option < EventCompletionAction > ) > > ,
697+ send_payment_along_path : SP ,
698+ ) -> Result < ( ) , Bolt12PaymentError >
699+ where
700+ R :: Target : Router ,
701+ ES :: Target : EntropySource ,
702+ NS :: Target : NodeSigner ,
703+ L :: Target : Logger ,
704+ IH : Fn ( ) -> InFlightHtlcs ,
705+ SP : Fn ( SendAlongPathArgs ) -> Result < ( ) , APIError > ,
706+ {
707+ let payment_hash = invoice. payment_hash ( ) ;
708+ match self . pending_outbound_payments . lock ( ) . unwrap ( ) . entry ( payment_id) {
709+ hash_map:: Entry :: Occupied ( entry) if entry. get ( ) . is_awaiting_invoice ( ) => {
710+ * entry. into_mut ( ) = PendingOutboundPayment :: InvoiceReceived { payment_hash } ;
711+ } ,
712+ hash_map:: Entry :: Occupied ( _) => return Err ( Bolt12PaymentError :: DuplicateInvoice ) ,
713+ hash_map:: Entry :: Vacant ( _) => return Err ( Bolt12PaymentError :: UnexpectedInvoice ) ,
714+ } ;
715+
716+ let route_params = RouteParameters {
717+ payment_params : PaymentParameters :: from_bolt12_invoice ( & invoice) ,
718+ final_value_msat : invoice. amount_msats ( ) ,
719+ } ;
720+
721+ self . find_route_and_send_payment (
722+ payment_hash, payment_id, route_params, router, first_hops, & inflight_htlcs,
723+ entropy_source, node_signer, best_block_height, logger, pending_events,
724+ & send_payment_along_path
725+ ) ;
726+
727+ Ok ( ( ) )
728+ }
729+
680730 pub ( super ) fn check_retry_payments < R : Deref , ES : Deref , NS : Deref , SP , IH , FH , L : Deref > (
681731 & self , router : & R , first_hops : FH , inflight_htlcs : IH , entropy_source : & ES , node_signer : & NS ,
682732 best_block_height : u32 ,
@@ -902,12 +952,26 @@ impl OutboundPayments {
902952 log_error ! ( logger, "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102" ) ;
903953 return
904954 } ,
905- PendingOutboundPayment :: AwaitingInvoice { .. } |
906- PendingOutboundPayment :: InvoiceReceived { .. } =>
907- {
955+ PendingOutboundPayment :: AwaitingInvoice { .. } => {
908956 log_error ! ( logger, "Payment not yet sent" ) ;
909957 return
910958 } ,
959+ PendingOutboundPayment :: InvoiceReceived { payment_hash } => {
960+ let total_amount = route_params. final_value_msat ;
961+ let recipient_onion = RecipientOnionFields {
962+ payment_secret : None ,
963+ payment_metadata : None ,
964+ custom_tlvs : vec ! [ ] ,
965+ } ;
966+ let retry_strategy = Some ( BOLT_12_INVOICE_RETRY_STRATEGY ) ;
967+ let payment_params = Some ( route_params. payment_params . clone ( ) ) ;
968+ let ( retryable_payment, onion_session_privs) = self . create_pending_payment (
969+ * payment_hash, recipient_onion. clone ( ) , None , & route,
970+ retry_strategy, payment_params, entropy_source, best_block_height
971+ ) ;
972+ * payment. into_mut ( ) = retryable_payment;
973+ ( total_amount, recipient_onion, None , onion_session_privs)
974+ } ,
911975 PendingOutboundPayment :: Fulfilled { .. } => {
912976 log_error ! ( logger, "Payment already completed" ) ;
913977 return
@@ -1070,40 +1134,56 @@ impl OutboundPayments {
10701134 keysend_preimage : Option < PaymentPreimage > , route : & Route , retry_strategy : Option < Retry > ,
10711135 payment_params : Option < PaymentParameters > , entropy_source : & ES , best_block_height : u32
10721136 ) -> Result < Vec < [ u8 ; 32 ] > , PaymentSendFailure > where ES :: Target : EntropySource {
1073- let mut onion_session_privs = Vec :: with_capacity ( route. paths . len ( ) ) ;
1074- for _ in 0 ..route. paths . len ( ) {
1075- onion_session_privs. push ( entropy_source. get_secure_random_bytes ( ) ) ;
1076- }
1077-
10781137 let mut pending_outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
10791138 match pending_outbounds. entry ( payment_id) {
10801139 hash_map:: Entry :: Occupied ( _) => Err ( PaymentSendFailure :: DuplicatePayment ) ,
10811140 hash_map:: Entry :: Vacant ( entry) => {
1082- let payment = entry. insert ( PendingOutboundPayment :: Retryable {
1083- retry_strategy,
1084- attempts : PaymentAttempts :: new ( ) ,
1085- payment_params,
1086- session_privs : HashSet :: new ( ) ,
1087- pending_amt_msat : 0 ,
1088- pending_fee_msat : Some ( 0 ) ,
1089- payment_hash,
1090- payment_secret : recipient_onion. payment_secret ,
1091- payment_metadata : recipient_onion. payment_metadata ,
1092- keysend_preimage,
1093- custom_tlvs : recipient_onion. custom_tlvs ,
1094- starting_block_height : best_block_height,
1095- total_msat : route. get_total_amount ( ) ,
1096- } ) ;
1097-
1098- for ( path, session_priv_bytes) in route. paths . iter ( ) . zip ( onion_session_privs. iter ( ) ) {
1099- assert ! ( payment. insert( * session_priv_bytes, path) ) ;
1100- }
1101-
1141+ let ( payment, onion_session_privs) = self . create_pending_payment (
1142+ payment_hash, recipient_onion, keysend_preimage, route, retry_strategy,
1143+ payment_params, entropy_source, best_block_height
1144+ ) ;
1145+ entry. insert ( payment) ;
11021146 Ok ( onion_session_privs)
11031147 } ,
11041148 }
11051149 }
11061150
1151+ fn create_pending_payment < ES : Deref > (
1152+ & self , payment_hash : PaymentHash , recipient_onion : RecipientOnionFields ,
1153+ keysend_preimage : Option < PaymentPreimage > , route : & Route , retry_strategy : Option < Retry > ,
1154+ payment_params : Option < PaymentParameters > , entropy_source : & ES , best_block_height : u32
1155+ ) -> ( PendingOutboundPayment , Vec < [ u8 ; 32 ] > )
1156+ where
1157+ ES :: Target : EntropySource ,
1158+ {
1159+ let mut onion_session_privs = Vec :: with_capacity ( route. paths . len ( ) ) ;
1160+ for _ in 0 ..route. paths . len ( ) {
1161+ onion_session_privs. push ( entropy_source. get_secure_random_bytes ( ) ) ;
1162+ }
1163+
1164+ let mut payment = PendingOutboundPayment :: Retryable {
1165+ retry_strategy,
1166+ attempts : PaymentAttempts :: new ( ) ,
1167+ payment_params,
1168+ session_privs : HashSet :: new ( ) ,
1169+ pending_amt_msat : 0 ,
1170+ pending_fee_msat : Some ( 0 ) ,
1171+ payment_hash,
1172+ payment_secret : recipient_onion. payment_secret ,
1173+ payment_metadata : recipient_onion. payment_metadata ,
1174+ keysend_preimage,
1175+ custom_tlvs : recipient_onion. custom_tlvs ,
1176+ starting_block_height : best_block_height,
1177+ total_msat : route. get_total_amount ( ) ,
1178+ } ;
1179+
1180+ for ( path, session_priv_bytes) in route. paths . iter ( ) . zip ( onion_session_privs. iter ( ) ) {
1181+ assert ! ( payment. insert( * session_priv_bytes, path) ) ;
1182+ }
1183+
1184+ ( payment, onion_session_privs)
1185+ }
1186+
11071187 #[ allow( unused) ]
11081188 pub ( super ) fn add_new_awaiting_invoice ( & self , payment_id : PaymentId ) -> Result < ( ) , ( ) > {
11091189 let mut pending_outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
0 commit comments