]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Expose send_payment_for_bolt12_invoice
authorJeffrey Czyz <jkczyz@gmail.com>
Tue, 21 May 2024 23:47:32 +0000 (18:47 -0500)
committerJeffrey Czyz <jkczyz@gmail.com>
Thu, 13 Jun 2024 00:38:22 +0000 (19:38 -0500)
UserConfig::manually_handle_bolt12_invoices allows deferring payment of
BOLT12 invoices by generating Event::InvoiceReceived. Expose
ChannelManager::send_payment_for_bolt12_invoice to allow users to pay
the Bolt12Invoice included in the event. While the event contains the
PaymentId for reference, that parameter is now removed from the method
in favor of extracting the PaymentId from the invoice's payer_metadata.

lightning/src/events/mod.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/outbound_payment.rs
lightning/src/util/config.rs

index d6d2da936e42927355be35c4a2453715521614d7..6212cfec5f0ae027aafc923d1fe89c9ae9625a49 100644 (file)
@@ -720,8 +720,16 @@ pub enum Event {
        /// Indicates a [`Bolt12Invoice`] in response to an [`InvoiceRequest`] or a [`Refund`] was
        /// received.
        ///
+       /// This event will only be generated if [`UserConfig::manually_handle_bolt12_invoices`] is set.
+       /// Use [`ChannelManager::send_payment_for_bolt12_invoice`] to pay the invoice or
+       /// [`ChannelManager::abandon_payment`] to abandon the associated payment. See those docs for
+       /// further details.
+       ///
        /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
        /// [`Refund`]: crate::offers::refund::Refund
+       /// [`UserConfig::manually_handle_bolt12_invoices`]: crate::util::config::UserConfig::manually_handle_bolt12_invoices
+       /// [`ChannelManager::send_payment_for_bolt12_invoice`]: crate::ln::channelmanager::ChannelManager::send_payment_for_bolt12_invoice
+       /// [`ChannelManager::abandon_payment`]: crate::ln::channelmanager::ChannelManager::abandon_payment
        InvoiceReceived {
                /// The `payment_id` associated with payment for the invoice.
                payment_id: PaymentId,
index fbff775d3613290a1147fbccf1766cacc66db4bf..ba07cd606b86acd68fba1f9670171d4e37380d6a 100644 (file)
@@ -58,7 +58,7 @@ use crate::ln::onion_utils::{HTLCFailReason, INVALID_ONION_BLINDING};
 use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
 #[cfg(test)]
 use crate::ln::outbound_payment;
-use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, PaymentAttempts, PendingOutboundPayment, SendAlongPathArgs, StaleExpiration};
+use crate::ln::outbound_payment::{OutboundPayments, PaymentAttempts, PendingOutboundPayment, SendAlongPathArgs, StaleExpiration};
 use crate::ln::wire::Encode;
 use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder, UnsignedBolt12Invoice};
 use crate::offers::invoice_error::InvoiceError;
@@ -105,7 +105,7 @@ use core::time::Duration;
 use core::ops::Deref;
 
 // Re-export this for use in the public API.
-pub use crate::ln::outbound_payment::{PaymentSendFailure, ProbeSendFailure, Retry, RetryableSendFailure, RecipientOnionFields};
+pub use crate::ln::outbound_payment::{Bolt12PaymentError, PaymentSendFailure, ProbeSendFailure, Retry, RetryableSendFailure, RecipientOnionFields};
 use crate::ln::script::ShutdownScript;
 
 // We hold various information about HTLC relay in the HTLC objects in Channel itself:
@@ -3996,7 +3996,36 @@ where
                self.pending_outbound_payments.test_set_payment_metadata(payment_id, new_payment_metadata);
        }
 
-       pub(super) fn send_payment_for_bolt12_invoice(&self, invoice: &Bolt12Invoice, payment_id: PaymentId) -> Result<(), Bolt12PaymentError> {
+       /// Pays the [`Bolt12Invoice`] associated with the `payment_id` encoded in its `payer_metadata`.
+       ///
+       /// The invoice's `payer_metadata` is used to authenticate that the invoice was indeed requested
+       /// before attempting a payment. [`Bolt12PaymentError::UnexpectedInvoice`] is returned if this
+       /// fails or if the encoded `payment_id` is not recognized. The latter may happen once the
+       /// payment is no longer tracked because the payment was attempted after:
+       /// - an invoice for the `payment_id` was already paid,
+       /// - one full [timer tick] has elapsed since initially requesting the invoice when paying an
+       ///   offer, or
+       /// - the refund corresponding to the invoice has already expired.
+       ///
+       /// To retry the payment, request another invoice using a new `payment_id`.
+       ///
+       /// Attempting to pay the same invoice twice while the first payment is still pending will
+       /// result in a [`Bolt12PaymentError::DuplicateInvoice`].
+       ///
+       /// Otherwise, either [`Event::PaymentSent`] or [`Event::PaymentFailed`] are used to indicate
+       /// whether or not the payment was successful.
+       ///
+       /// [timer tick]: Self::timer_tick_occurred
+       pub fn send_payment_for_bolt12_invoice(&self, invoice: &Bolt12Invoice) -> Result<(), Bolt12PaymentError> {
+               let secp_ctx = &self.secp_ctx;
+               let expanded_key = &self.inbound_payment_key;
+               match invoice.verify(expanded_key, secp_ctx) {
+                       Ok(payment_id) => self.send_payment_for_verified_bolt12_invoice(invoice, payment_id),
+                       Err(()) => Err(Bolt12PaymentError::UnexpectedInvoice),
+               }
+       }
+
+       fn send_payment_for_verified_bolt12_invoice(&self, invoice: &Bolt12Invoice, payment_id: PaymentId) -> Result<(), Bolt12PaymentError> {
                let best_block_height = self.best_block.read().unwrap().height;
                let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
                self.pending_outbound_payments
@@ -10287,7 +10316,7 @@ where
                                                        self.pending_events.lock().unwrap().push_back((event, None));
                                                        return ResponseInstruction::NoResponse;
                                                } else {
-                                                       self.send_payment_for_bolt12_invoice(&invoice, payment_id)
+                                                       self.send_payment_for_verified_bolt12_invoice(&invoice, payment_id)
                                                                .map_err(|e| {
                                                                        log_trace!(self.logger, "Failed paying invoice: {:?}", e);
                                                                        InvoiceError::from_string(format!("{:?}", e))
index 2a9e52c83c7b21341610994536c94788259dd6bf..3ae128cb3bbe97f37016d0447fed25384ebf3dba 100644 (file)
@@ -501,9 +501,9 @@ pub enum PaymentSendFailure {
        },
 }
 
-/// An error when attempting to pay a BOLT 12 invoice.
+/// An error when attempting to pay a [`Bolt12Invoice`].
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub(super) enum Bolt12PaymentError {
+pub enum Bolt12PaymentError {
        /// The invoice was not requested.
        UnexpectedInvoice,
        /// Payment for an invoice with the corresponding [`PaymentId`] was already initiated.
index d2e038b833d24f19f7fe6322c0f78cc5d4da772d..4e124c27fd95d4f70b83e184ed291f0e56b3e9ef 100644 (file)
@@ -859,12 +859,16 @@ pub struct UserConfig {
        /// If this is set to `true`, the user needs to manually pay [`Bolt12Invoice`]s when received.
        ///
        /// When set to `true`, [`Event::InvoiceReceived`] will be generated for each received
-       /// [`Bolt12Invoice`] instead of being automatically paid after verification.
+       /// [`Bolt12Invoice`] instead of being automatically paid after verification. Use
+       /// [`ChannelManager::send_payment_for_bolt12_invoice`] to pay the invoice or
+       /// [`ChannelManager::abandon_payment`] to abandon the associated payment.
        ///
        /// Default value: `false`
        ///
        /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
        /// [`Event::InvoiceReceived`]: crate::events::Event::InvoiceReceived
+       /// [`ChannelManager::send_payment_for_bolt12_invoice`]: crate::ln::channelmanager::ChannelManager::send_payment_for_bolt12_invoice
+       /// [`ChannelManager::abandon_payment`]: crate::ln::channelmanager::ChannelManager::abandon_payment
        pub manually_handle_bolt12_invoices: bool,
 }