Skip to content

Commit

Permalink
Move send_payment_for_bolt12_invoice to flow.rs
Browse files Browse the repository at this point in the history
  • Loading branch information
shaavan committed Nov 30, 2024
1 parent e15d10a commit d5c244a
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 67 deletions.
4 changes: 2 additions & 2 deletions lightning/src/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -871,7 +871,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.
///
Expand All @@ -882,7 +882,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.
Expand Down
70 changes: 16 additions & 54 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -438,11 +438,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<Sha256>;

/// 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<Sha256>, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey,
) -> Result<(), ()>;
Expand All @@ -451,6 +455,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<Sha256> {
Expand All @@ -459,6 +465,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<Sha256>, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey,
) -> Result<(), ()> {
Expand Down Expand Up @@ -499,6 +507,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<Sha256> {
Expand All @@ -507,6 +517,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<Sha256>, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey,
) -> Result<(), ()> {
Expand Down Expand Up @@ -4376,35 +4388,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
Expand Down Expand Up @@ -9528,15 +9511,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<MessageForwardNode>;

/// Verify bolt12 invoice
fn verify_bolt12_invoice(
&self, invoice: &Bolt12Invoice, context: Option<&OffersContext>,
) -> Result<PaymentId, ()>;

/// 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
Expand Down Expand Up @@ -9658,31 +9636,15 @@ where
.collect::<Vec<_>>()
}

fn verify_bolt12_invoice(
&self, invoice: &Bolt12Invoice, context: Option<&OffersContext>,
) -> Result<PaymentId, ()> {
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,
Expand Down
8 changes: 4 additions & 4 deletions lightning/src/ln/offers_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
);

Expand All @@ -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),
);

Expand All @@ -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),
);
}
Expand Down
65 changes: 60 additions & 5 deletions lightning/src/offers/flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,62 @@ where
}
}

impl<ES: Deref, OMC: Deref, MR: Deref, L: Deref> OffersMessageFlow<ES, OMC, MR, L>
where
ES::Target: EntropySource,
OMC::Target: OffersMessageCommons,
MR::Target: MessageRouter,
L::Target: Logger,
{
fn verify_bolt12_invoice(
&self, invoice: &Bolt12Invoice, context: Option<&OffersContext>,
) -> Result<PaymentId, ()> {
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<ES: Deref, OMC: Deref, MR: Deref, L: Deref> OffersMessageHandler
for OffersMessageFlow<ES, OMC, MR, L>
where
Expand Down Expand Up @@ -833,11 +889,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()));
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/util/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down

0 comments on commit d5c244a

Please sign in to comment.