diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 3b3fe304e29..299cd6cbc82 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, Weight}; 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<(), ()> { @@ -4382,35 +4394,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 @@ -9537,27 +9520,11 @@ 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 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/offers/flow.rs b/lightning/src/offers/flow.rs index ffbd9dd717a..e2a3d031894 100644 --- a/lightning/src/offers/flow.rs +++ b/lightning/src/offers/flow.rs @@ -134,11 +134,6 @@ 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; - /// Send payment for verified bolt12 invoice fn send_payment_for_verified_bolt12_invoice( &self, invoice: &Bolt12Invoice, payment_id: PaymentId, @@ -794,6 +789,64 @@ 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.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(()), + } + } + + /// 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. + /// + /// [`Event::PaymentSent`]: crate::events::Event::PaymentSent + /// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed + /// [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 @@ -977,11 +1030,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()));