+ match self.payment_cache.lock().unwrap().entry(payment_hash) {
+ hash_map::Entry::Occupied(_) => return Err(PaymentError::Invoice("payment pending")),
+ hash_map::Entry::Vacant(entry) => entry.insert(0),
+ };
+
+ let payment_secret = Some(invoice.payment_secret().clone());
+ let mut payee = Payee::from_node_id(invoice.recover_payee_pub_key())
+ .with_expiry_time(expiry_time_from_unix_epoch(&invoice).as_secs())
+ .with_route_hints(invoice.route_hints());
+ if let Some(features) = invoice.features() {
+ payee = payee.with_features(features.clone());
+ }
+ let params = RouteParameters {
+ payee,
+ final_value_msat: invoice.amount_milli_satoshis().or(amount_msats).unwrap(),
+ final_cltv_expiry_delta: invoice.min_final_cltv_expiry() as u32,
+ };
+
+ let send_payment = |route: &Route| {
+ self.payer.send_payment(route, payment_hash, &payment_secret)
+ };
+ self.pay_internal(¶ms, payment_hash, send_payment)
+ .map_err(|e| { self.payment_cache.lock().unwrap().remove(&payment_hash); e })
+ }
+
+ /// Pays `pubkey` an amount using the hash of the given preimage, caching it for later use in
+ /// case a retry is needed.
+ ///
+ /// You should ensure that `payment_preimage` is unique and that its `payment_hash` has never
+ /// been paid before. Because [`InvoicePayer`] is stateless no effort is made to do so for you.
+ pub fn pay_pubkey(
+ &self, pubkey: PublicKey, payment_preimage: PaymentPreimage, amount_msats: u64,
+ final_cltv_expiry_delta: u32
+ ) -> Result<PaymentId, PaymentError> {
+ let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
+ match self.payment_cache.lock().unwrap().entry(payment_hash) {
+ hash_map::Entry::Occupied(_) => return Err(PaymentError::Invoice("payment pending")),
+ hash_map::Entry::Vacant(entry) => entry.insert(0),
+ };
+
+ let params = RouteParameters {
+ payee: Payee::for_keysend(pubkey),
+ final_value_msat: amount_msats,
+ final_cltv_expiry_delta,
+ };
+
+ let send_payment = |route: &Route| {
+ self.payer.send_spontaneous_payment(route, payment_preimage)
+ };
+ self.pay_internal(¶ms, payment_hash, send_payment)
+ .map_err(|e| { self.payment_cache.lock().unwrap().remove(&payment_hash); e })
+ }
+
+ fn pay_internal<F: FnOnce(&Route) -> Result<PaymentId, PaymentSendFailure> + Copy>(
+ &self, params: &RouteParameters, payment_hash: PaymentHash, send_payment: F,
+ ) -> Result<PaymentId, PaymentError> {
+ if has_expired(params) {
+ log_trace!(self.logger, "Invoice expired prior to send for payment {}", log_bytes!(payment_hash.0));