diff --git a/lightning/src/events/mod.rs b/lightning/src/events/mod.rs index d40e4e63d98..2a4a1c0347b 100644 --- a/lightning/src/events/mod.rs +++ b/lightning/src/events/mod.rs @@ -857,7 +857,7 @@ pub enum Event { /// 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 + /// Use [`OffersMessageFlow::send_payment_for_bolt12_invoice`] to pay the invoice or /// [`ChannelManager::abandon_payment`] to abandon the associated payment. See those docs for /// further details. /// @@ -868,7 +868,7 @@ pub enum Event { /// [`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 + /// [`OffersMessageFlow::send_payment_for_bolt12_invoice`]: crate::offers::flow::OffersMessageFlow::send_payment_for_bolt12_invoice /// [`ChannelManager::abandon_payment`]: crate::ln::channelmanager::ChannelManager::abandon_payment InvoiceReceived { /// The `payment_id` associated with payment for the invoice. diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 9e0220f8ad4..28443bb0935 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -33,7 +33,7 @@ use bitcoin::secp256k1::Secp256k1; use bitcoin::{secp256k1, Sequence}; use crate::events::FundingInfo; -use crate::blinded_path::message::{AsyncPaymentsContext, MessageContext, MessageForwardNode, OffersContext}; +use crate::blinded_path::message::{AsyncPaymentsContext, MessageContext, MessageForwardNode}; use crate::blinded_path::NodeIdLookUp; use crate::blinded_path::message::BlindedMessagePath; use crate::blinded_path::payment::{BlindedPaymentPath, PaymentConstraints, PaymentContext, ReceiveTlvs}; @@ -439,11 +439,15 @@ impl Ord for ClaimableHTLC { pub trait Verification { /// Constructs an HMAC to include in [`OffersContext`] for the data along with the given /// [`Nonce`]. + /// + /// [`OffersContext`]: crate::blinded_path::message::OffersContext fn hmac_for_offer_payment( &self, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey, ) -> Hmac; /// Authenticates the data using an HMAC and a [`Nonce`] taken from an [`OffersContext`]. + /// + /// [`OffersContext`]: crate::blinded_path::message::OffersContext fn verify_for_offer_payment( &self, hmac: Hmac, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey, ) -> Result<(), ()>; @@ -452,6 +456,8 @@ pub trait Verification { impl Verification for PaymentHash { /// Constructs an HMAC to include in [`OffersContext::InboundPayment`] for the payment hash /// along with the given [`Nonce`]. + /// + /// [`OffersContext::InboundPayment`]: crate::blinded_path::message::OffersContext::InboundPayment fn hmac_for_offer_payment( &self, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey, ) -> Hmac { @@ -460,6 +466,8 @@ impl Verification for PaymentHash { /// Authenticates the payment id using an HMAC and a [`Nonce`] taken from an /// [`OffersContext::InboundPayment`]. + /// + /// [`OffersContext::InboundPayment`]: crate::blinded_path::message::OffersContext::InboundPayment fn verify_for_offer_payment( &self, hmac: Hmac, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey, ) -> Result<(), ()> { @@ -500,6 +508,8 @@ impl PaymentId { impl Verification for PaymentId { /// Constructs an HMAC to include in [`OffersContext::OutboundPayment`] for the payment id /// along with the given [`Nonce`]. + /// + /// [`OffersContext::OutboundPayment`]: crate::blinded_path::message::OffersContext::OutboundPayment fn hmac_for_offer_payment( &self, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey, ) -> Hmac { @@ -508,6 +518,8 @@ impl Verification for PaymentId { /// Authenticates the payment id using an HMAC and a [`Nonce`] taken from an /// [`OffersContext::OutboundPayment`]. + /// + /// [`OffersContext::OutboundPayment`]: crate::blinded_path::message::OffersContext::OutboundPayment fn verify_for_offer_payment( &self, hmac: Hmac, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey, ) -> Result<(), ()> { @@ -1997,11 +2009,11 @@ where /// For details on initiating payments for offers, see [`pay_for_offer`]. /// /// ## BOLT 12 Refunds -/// +/// /// For more information on creating refunds, see [`create_refund_builder`]. /// /// For requesting refund payments, see [`request_refund_payment`]. -/// +/// /// # Persistence /// /// Implements [`Writeable`] to write out all channel state to disk. Implies [`peer_disconnected`] for @@ -2572,7 +2584,7 @@ pub enum RecentPaymentDetails { AwaitingInvoice { /// A user-provided identifier in [`OffersMessageFlow::pay_for_offer`] used to uniquely identify a /// payment and ensure idempotency in LDK. - /// + /// /// [`OffersMessageFlow::pay_for_offer`]: crate::offers::flow::OffersMessageFlow::pay_for_offer payment_id: PaymentId, }, @@ -4390,35 +4402,6 @@ where self.pending_outbound_payments.test_set_payment_metadata(payment_id, new_payment_metadata); } - /// 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, context: Option<&OffersContext>, - ) -> Result<(), Bolt12PaymentError> { - match self.verify_bolt12_invoice(invoice, context) { - Ok(payment_id) => self.send_payment_for_verified_bolt12_invoice(invoice, payment_id), - Err(()) => Err(Bolt12PaymentError::UnexpectedInvoice), - } - } - #[cfg(async_payments)] fn initiate_async_payment( &self, invoice: &StaticInvoice, payment_id: PaymentId @@ -9217,15 +9200,10 @@ pub trait OffersMessageCommons { /// Get the vector of peers that can be used for a blinded path fn get_peer_for_blinded_path(&self) -> Vec; - /// Verify bolt12 invoice - fn verify_bolt12_invoice( - &self, invoice: &Bolt12Invoice, context: Option<&OffersContext>, - ) -> Result; - /// Gets the current configuration applied to all new channels. fn get_current_default_configuration(&self) -> &UserConfig; - /// Send payment for verified bolt12 invoice + /// Send Payment for verified BOLT12 Invoice fn send_payment_for_verified_bolt12_invoice(&self, invoice: &Bolt12Invoice, payment_id: PaymentId) -> Result<(), Bolt12PaymentError>; /// Add new pending event @@ -9347,31 +9325,15 @@ where .collect::>() } - fn verify_bolt12_invoice( - &self, invoice: &Bolt12Invoice, context: Option<&OffersContext>, - ) -> Result { - let secp_ctx = &self.secp_ctx; - let expanded_key = &self.inbound_payment_key; - - match context { - None if invoice.is_for_refund_without_paths() => { - invoice.verify_using_metadata(expanded_key, secp_ctx) - }, - Some(&OffersContext::OutboundPayment { payment_id, nonce, .. }) => { - invoice.verify_using_payer_data(payment_id, nonce, expanded_key, secp_ctx) - }, - _ => Err(()), - } - } - fn get_current_default_configuration(&self) -> &UserConfig { &self.default_configuration } 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); let features = self.bolt12_invoice_features(); + let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self); + self.pending_outbound_payments .send_payment_for_bolt12_invoice( invoice, payment_id, &self.router, self.list_usable_channels(), features, diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index 144edf336b2..e7ad78eba95 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -1201,9 +1201,9 @@ fn pays_bolt12_invoice_asynchronously() { assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id)); } - assert!(bob.node.send_payment_for_bolt12_invoice(&invoice, context.as_ref()).is_ok()); + assert!(bob.offers_handler.send_payment_for_bolt12_invoice(&invoice, context.as_ref()).is_ok()); assert_eq!( - bob.node.send_payment_for_bolt12_invoice(&invoice, context.as_ref()), + bob.offers_handler.send_payment_for_bolt12_invoice(&invoice, context.as_ref()), Err(Bolt12PaymentError::DuplicateInvoice), ); @@ -1214,7 +1214,7 @@ fn pays_bolt12_invoice_asynchronously() { expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id); assert_eq!( - bob.node.send_payment_for_bolt12_invoice(&invoice, context.as_ref()), + bob.offers_handler.send_payment_for_bolt12_invoice(&invoice, context.as_ref()), Err(Bolt12PaymentError::DuplicateInvoice), ); @@ -1223,7 +1223,7 @@ fn pays_bolt12_invoice_asynchronously() { } assert_eq!( - bob.node.send_payment_for_bolt12_invoice(&invoice, context.as_ref()), + bob.offers_handler.send_payment_for_bolt12_invoice(&invoice, context.as_ref()), Err(Bolt12PaymentError::UnexpectedInvoice), ); } diff --git a/lightning/src/offers/flow.rs b/lightning/src/offers/flow.rs index 118759095dd..85c2254c4a7 100644 --- a/lightning/src/offers/flow.rs +++ b/lightning/src/offers/flow.rs @@ -648,6 +648,62 @@ where } } +impl OffersMessageFlow +where + ES::Target: EntropySource, + OMC::Target: OffersMessageCommons, + MR::Target: MessageRouter, + L::Target: Logger, +{ + fn verify_bolt12_invoice( + &self, invoice: &Bolt12Invoice, context: Option<&OffersContext>, + ) -> Result { + let secp_ctx = &self.secp_ctx; + let expanded_key = &self.commons.get_expanded_key(); + + match context { + None if invoice.is_for_refund_without_paths() => { + invoice.verify_using_metadata(expanded_key, secp_ctx) + }, + Some(&OffersContext::OutboundPayment { payment_id, nonce, .. }) => { + invoice.verify_using_payer_data(payment_id, nonce, expanded_key, secp_ctx) + }, + _ => Err(()), + } + } + + /// 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]: crate::ln::channelmanager::ChannelManager::timer_tick_occurred + pub fn send_payment_for_bolt12_invoice( + &self, invoice: &Bolt12Invoice, context: Option<&OffersContext>, + ) -> Result<(), Bolt12PaymentError> { + match self.verify_bolt12_invoice(invoice, context) { + Ok(payment_id) => { + self.commons.send_payment_for_verified_bolt12_invoice(invoice, payment_id) + }, + Err(()) => Err(Bolt12PaymentError::UnexpectedInvoice), + } + } +} + impl OffersMessageHandler for OffersMessageFlow where @@ -831,11 +887,10 @@ where } }, OffersMessage::Invoice(invoice) => { - let payment_id = - match self.commons.verify_bolt12_invoice(&invoice, context.as_ref()) { - Ok(payment_id) => payment_id, - Err(()) => return None, - }; + let payment_id = match self.verify_bolt12_invoice(&invoice, context.as_ref()) { + Ok(payment_id) => payment_id, + Err(()) => return None, + }; let logger = WithContext::from(&self.logger, None, None, Some(invoice.payment_hash())); diff --git a/lightning/src/util/config.rs b/lightning/src/util/config.rs index 14529327ef2..72d70ba8533 100644 --- a/lightning/src/util/config.rs +++ b/lightning/src/util/config.rs @@ -859,14 +859,14 @@ pub struct UserConfig { /// /// When set to `true`, [`Event::InvoiceReceived`] will be generated for each received /// [`Bolt12Invoice`] instead of being automatically paid after verification. Use - /// [`ChannelManager::send_payment_for_bolt12_invoice`] to pay the invoice or + /// [`OffersMessageFlow::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 + /// [`OffersMessageFlow::send_payment_for_bolt12_invoice`]: crate::offers::flow::OffersMessageFlow::send_payment_for_bolt12_invoice /// [`ChannelManager::abandon_payment`]: crate::ln::channelmanager::ChannelManager::abandon_payment pub manually_handle_bolt12_invoices: bool, }