@@ -18,6 +18,7 @@ use crate::events::{self, PaymentFailureReason};
18
18
use crate :: ln:: { PaymentHash , PaymentPreimage , PaymentSecret } ;
19
19
use crate :: ln:: channelmanager:: { ChannelDetails , EventCompletionAction , HTLCSource , PaymentId } ;
20
20
use crate :: ln:: onion_utils:: { DecodedOnionFailure , HTLCFailReason } ;
21
+ use crate :: offers:: invoice:: Bolt12Invoice ;
21
22
use crate :: routing:: router:: { InFlightHtlcs , Path , PaymentParameters , Route , RouteParameters , Router } ;
22
23
use crate :: util:: errors:: APIError ;
23
24
use crate :: util:: logger:: Logger ;
@@ -440,6 +441,14 @@ pub enum PaymentSendFailure {
440
441
} ,
441
442
}
442
443
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
+
443
452
/// Information which is provided, encrypted, to the payment recipient when sending HTLCs.
444
453
///
445
454
/// This should generally be constructed with data communicated to us from the recipient (via a
@@ -577,6 +586,8 @@ pub(super) struct SendAlongPathArgs<'a> {
577
586
pub session_priv_bytes : [ u8 ; 32 ] ,
578
587
}
579
588
589
+ const BOLT_12_INVOICE_RETRY_STRATEGY : Retry = Retry :: Attempts ( 3 ) ;
590
+
580
591
pub ( super ) struct OutboundPayments {
581
592
pub ( super ) pending_outbound_payments : Mutex < HashMap < PaymentId , PendingOutboundPayment > > ,
582
593
pub ( super ) retry_lock : Mutex < ( ) > ,
@@ -677,6 +688,45 @@ impl OutboundPayments {
677
688
}
678
689
}
679
690
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 . retry_payment_internal (
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
+
680
730
pub ( super ) fn check_retry_payments < R : Deref , ES : Deref , NS : Deref , SP , IH , FH , L : Deref > (
681
731
& self , router : & R , first_hops : FH , inflight_htlcs : IH , entropy_source : & ES , node_signer : & NS ,
682
732
best_block_height : u32 ,
@@ -902,12 +952,26 @@ impl OutboundPayments {
902
952
log_error ! ( logger, "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102" ) ;
903
953
return
904
954
} ,
905
- PendingOutboundPayment :: AwaitingInvoice { .. } |
906
- PendingOutboundPayment :: InvoiceReceived { .. } =>
907
- {
955
+ PendingOutboundPayment :: AwaitingInvoice { .. } => {
908
956
log_error ! ( logger, "Payment not yet sent" ) ;
909
957
return
910
958
} ,
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
+ } ,
911
975
PendingOutboundPayment :: Fulfilled { .. } => {
912
976
log_error ! ( logger, "Payment already completed" ) ;
913
977
return
@@ -1070,40 +1134,56 @@ impl OutboundPayments {
1070
1134
keysend_preimage : Option < PaymentPreimage > , route : & Route , retry_strategy : Option < Retry > ,
1071
1135
payment_params : Option < PaymentParameters > , entropy_source : & ES , best_block_height : u32
1072
1136
) -> 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
-
1078
1137
let mut pending_outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1079
1138
match pending_outbounds. entry ( payment_id) {
1080
1139
hash_map:: Entry :: Occupied ( _) => Err ( PaymentSendFailure :: DuplicatePayment ) ,
1081
1140
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) ;
1102
1146
Ok ( onion_session_privs)
1103
1147
} ,
1104
1148
}
1105
1149
}
1106
1150
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
+
1107
1187
#[ allow( unused) ]
1108
1188
pub ( super ) fn add_new_awaiting_invoice ( & self , payment_id : PaymentId ) -> Result < ( ) , ( ) > {
1109
1189
let mut pending_outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
0 commit comments