Skip to content

Commit

Permalink
Move pay_for_offer to flow.rs
Browse files Browse the repository at this point in the history
Move pay_for_offer documentation to flow.rs
  • Loading branch information
shaavan committed Nov 18, 2024
1 parent 839e69a commit 734b58f
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 129 deletions.
174 changes: 68 additions & 106 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ use crate::events::{Event, EventHandler, EventsProvider, MessageSendEvent, Messa
// construct one themselves.
use crate::ln::inbound_payment;
use crate::ln::types::ChannelId;
use crate::offers::offer::Offer;
use crate::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
use crate::ln::channel::{self, Channel, ChannelPhase, ChannelError, ChannelUpdateStatus, ShutdownResult, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel, WithChannelContext};
use crate::ln::channel_state::ChannelDetails;
Expand All @@ -67,7 +68,6 @@ use crate::ln::wire::Encode;
use crate::offers::invoice::{Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, InvoiceBuilder};
use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestBuilder};
use crate::offers::nonce::Nonce;
use crate::offers::offer::Offer;
use crate::offers::parse::Bolt12SemanticError;
use crate::offers::refund::Refund;
use crate::offers::signer;
Expand Down Expand Up @@ -1996,57 +1996,6 @@ where
///
/// ## BOLT 12 Offers
///
/// Use [`pay_for_offer`] to initiated payment, which sends an [`InvoiceRequest`] for an [`Offer`]
/// and pays the [`Bolt12Invoice`] response.
///
/// ```
/// # use lightning::events::{Event, EventsProvider};
/// # use lightning::ln::channelmanager::{AChannelManager, OffersMessageCommons, PaymentId, RecentPaymentDetails, Retry};
/// # use lightning::offers::offer::Offer;
/// #
/// # fn example<T: AChannelManager>(
/// # channel_manager: T, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
/// # payer_note: Option<String>, retry: Retry, max_total_routing_fee_msat: Option<u64>
/// # ) {
/// # let channel_manager = channel_manager.get_cm();
/// let payment_id = PaymentId([42; 32]);
/// match channel_manager.pay_for_offer(
/// offer, quantity, amount_msats, payer_note, payment_id, retry, max_total_routing_fee_msat
/// ) {
/// Ok(()) => println!("Requesting invoice for offer"),
/// Err(e) => println!("Unable to request invoice for offer: {:?}", e),
/// }
///
/// // First the payment will be waiting on an invoice
/// let expected_payment_id = payment_id;
/// assert!(
/// channel_manager.list_recent_payments().iter().find(|details| matches!(
/// details,
/// RecentPaymentDetails::AwaitingInvoice { payment_id: expected_payment_id }
/// )).is_some()
/// );
///
/// // Once the invoice is received, a payment will be sent
/// assert!(
/// channel_manager.list_recent_payments().iter().find(|details| matches!(
/// details,
/// RecentPaymentDetails::Pending { payment_id: expected_payment_id, .. }
/// )).is_some()
/// );
///
/// // On the event processing thread
/// channel_manager.process_pending_events(&|event| {
/// match event {
/// Event::PaymentSent { payment_id: Some(payment_id), .. } => println!("Paid {}", payment_id),
/// Event::PaymentFailed { payment_id, .. } => println!("Failed paying {}", payment_id),
/// // ...
/// # _ => {},
/// }
/// Ok(())
/// });
/// # }
/// ```
///
/// ## BOLT 12 Refunds
///
/// Use [`request_refund_payment`] to send a [`Bolt12Invoice`] for receiving the refund. Similar to
Expand Down Expand Up @@ -2173,7 +2122,7 @@ where
/// [`claim_funds`]: Self::claim_funds
/// [`send_payment`]: Self::send_payment
/// [`offers`]: crate::offers
/// [`pay_for_offer`]: Self::pay_for_offer
/// [`Offer`]: crate::offers::offer
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
/// [`request_refund_payment`]: Self::request_refund_payment
/// [`peer_disconnected`]: msgs::ChannelMessageHandler::peer_disconnected
Expand Down Expand Up @@ -2685,6 +2634,8 @@ const MAX_NO_CHANNEL_PEERS: usize = 250;
/// Using compact [`BlindedMessagePath`]s may provide better privacy as the [`MessageRouter`] could select
/// more hops. However, since they use short channel ids instead of pubkeys, they are more likely to
/// become invalid over time as channels are closed. Thus, they are only suitable for short-term use.
///
/// [`Offer`]: crate::offers::offer
pub const MAX_SHORT_LIVED_RELATIVE_EXPIRY: Duration = Duration::from_secs(60 * 60 * 24);

/// Used by [`ChannelManager::list_recent_payments`] to express the status of recent payments.
Expand All @@ -2693,8 +2644,10 @@ pub const MAX_SHORT_LIVED_RELATIVE_EXPIRY: Duration = Duration::from_secs(60 * 6
pub enum RecentPaymentDetails {
/// When an invoice was requested and thus a payment has not yet been sent.
AwaitingInvoice {
/// A user-provided identifier in [`ChannelManager::pay_for_offer`] used to uniquely identify a
/// 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,
},
/// When a payment is still being sent and awaiting successful delivery.
Expand All @@ -2703,7 +2656,7 @@ pub enum RecentPaymentDetails {
/// identify a payment and ensure idempotency in LDK.
///
/// [`send_payment`]: crate::ln::channelmanager::ChannelManager::send_payment
/// [`pay_for_offer`]: crate::ln::channelmanager::ChannelManager::pay_for_offer
/// [`pay_for_offer`]: crate::offers::flow::OffersMessageFlow::pay_for_offer
payment_id: PaymentId,
/// Hash of the payment that is currently being sent but has yet to be fulfilled or
/// abandoned.
Expand All @@ -2720,7 +2673,7 @@ pub enum RecentPaymentDetails {
/// identify a payment and ensure idempotency in LDK.
///
/// [`send_payment`]: crate::ln::channelmanager::ChannelManager::send_payment
/// [`pay_for_offer`]: crate::ln::channelmanager::ChannelManager::pay_for_offer
/// [`pay_for_offer`]: crate::offers::flow::OffersMessageFlow::pay_for_offer
payment_id: PaymentId,
/// Hash of the payment that was claimed. `None` for serializations of [`ChannelManager`]
/// made before LDK version 0.0.104.
Expand All @@ -2734,7 +2687,7 @@ pub enum RecentPaymentDetails {
/// identify a payment and ensure idempotency in LDK.
///
/// [`send_payment`]: crate::ln::channelmanager::ChannelManager::send_payment
/// [`pay_for_offer`]: crate::ln::channelmanager::ChannelManager::pay_for_offer
/// [`pay_for_offer`]: crate::offers::flow::OffersMessageFlow::pay_for_offer
payment_id: PaymentId,
/// Hash of the payment that we have given up trying to send.
payment_hash: PaymentHash,
Expand Down Expand Up @@ -4608,7 +4561,7 @@ where
///
/// # Requested Invoices
///
/// In the case of paying a [`Bolt12Invoice`] via [`ChannelManager::pay_for_offer`], abandoning
/// In the case of paying a [`Bolt12Invoice`] via [`OffersMessageFlow::pay_for_offer`], abandoning
/// the payment prior to receiving the invoice will result in an [`Event::PaymentFailed`] and
/// prevent any attempts at paying it once received.
///
Expand All @@ -4618,6 +4571,7 @@ where
/// [`ChannelManager`], another [`Event::PaymentFailed`] may be generated.
///
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
/// [`OffersMessageFlow::pay_for_offer`]: crate::offers::flow::OffersMessageFlow::pay_for_offer
pub fn abandon_payment(&self, payment_id: PaymentId) {
self.abandon_payment_with_reason(payment_id, PaymentFailureReason::UserAbandoned)
}
Expand Down Expand Up @@ -9346,6 +9300,13 @@ pub trait OffersMessageCommons {
///
/// [`Event::PaymentSent`]: events::Event::PaymentSent
fn list_recent_payments(&self) -> Vec<RecentPaymentDetails>;

/// Internal pay_for_offer
fn pay_for_offer_intern<CPP: FnOnce(&InvoiceRequest, Nonce) -> Result<(), Bolt12SemanticError>> (
&self, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
payer_note: Option<String>, payment_id: PaymentId,
human_readable_name: Option<HumanReadableName>, create_pending_payment: CPP,
) -> Result<(), Bolt12SemanticError>;
}

impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, MR: Deref, L: Deref> OffersMessageCommons for ChannelManager<M, T, ES, NS, SP, F, R, MR, L>
Expand Down Expand Up @@ -9519,7 +9480,6 @@ where
}

fn add_new_awaiting_invoice(&self, payment_id: PaymentId, expiration: StaleExpiration, retry_strategy: Retry, max_total_routing_fee_msat: Option<u64>, retryable_invoice_request: Option<RetryableInvoiceRequest>) -> Result<(), ()> {
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
self.pending_outbound_payments.add_new_awaiting_invoice (
payment_id, expiration, retry_strategy, max_total_routing_fee_msat, retryable_invoice_request,
)
Expand Down Expand Up @@ -9555,6 +9515,53 @@ where
})
.collect()
}

fn pay_for_offer_intern<CPP: FnOnce(&InvoiceRequest, Nonce) -> Result<(), Bolt12SemanticError>>(
&self, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
payer_note: Option<String>, payment_id: PaymentId,
human_readable_name: Option<HumanReadableName>, create_pending_payment: CPP,
) -> Result<(), Bolt12SemanticError> {
let expanded_key = &self.inbound_payment_key;
let entropy = &*self.entropy_source;
let secp_ctx = &self.secp_ctx;

let nonce = Nonce::from_entropy_source(entropy);
let builder: InvoiceRequestBuilder<secp256k1::All> = offer
.request_invoice(expanded_key, nonce, secp_ctx, payment_id)?
.into();
let builder = builder.chain_hash(self.chain_hash)?;

let builder = match quantity {
None => builder,
Some(quantity) => builder.quantity(quantity)?,
};
let builder = match amount_msats {
None => builder,
Some(amount_msats) => builder.amount_msats(amount_msats)?,
};
let builder = match payer_note {
None => builder,
Some(payer_note) => builder.payer_note(payer_note),
};
let builder = match human_readable_name {
None => builder,
Some(hrn) => builder.sourced_from_human_readable_name(hrn),
};
let invoice_request = builder.build_and_sign()?;

let hmac = payment_id.hmac_for_offer_payment(nonce, expanded_key);
let context = MessageContext::Offers(
OffersContext::OutboundPayment { payment_id, nonce, hmac: Some(hmac) }
);
let reply_paths = self.create_blinded_paths(context)
.map_err(|_| Bolt12SemanticError::MissingPaths)?;

let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);

create_pending_payment(&invoice_request, nonce)?;

self.enqueue_invoice_request(invoice_request, reply_paths)
}
}

/// Defines the maximum number of [`OffersMessage`] including different reply paths to be sent
Expand Down Expand Up @@ -9649,53 +9656,6 @@ where
})
}

fn pay_for_offer_intern<CPP: FnOnce(&InvoiceRequest, Nonce) -> Result<(), Bolt12SemanticError>>(
&self, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
payer_note: Option<String>, payment_id: PaymentId,
human_readable_name: Option<HumanReadableName>, create_pending_payment: CPP,
) -> Result<(), Bolt12SemanticError> {
let expanded_key = &self.inbound_payment_key;
let entropy = &*self.entropy_source;
let secp_ctx = &self.secp_ctx;

let nonce = Nonce::from_entropy_source(entropy);
let builder: InvoiceRequestBuilder<secp256k1::All> = offer
.request_invoice(expanded_key, nonce, secp_ctx, payment_id)?
.into();
let builder = builder.chain_hash(self.chain_hash)?;

let builder = match quantity {
None => builder,
Some(quantity) => builder.quantity(quantity)?,
};
let builder = match amount_msats {
None => builder,
Some(amount_msats) => builder.amount_msats(amount_msats)?,
};
let builder = match payer_note {
None => builder,
Some(payer_note) => builder.payer_note(payer_note),
};
let builder = match human_readable_name {
None => builder,
Some(hrn) => builder.sourced_from_human_readable_name(hrn),
};
let invoice_request = builder.build_and_sign()?;

let hmac = payment_id.hmac_for_offer_payment(nonce, expanded_key);
let context = MessageContext::Offers(
OffersContext::OutboundPayment { payment_id, nonce, hmac: Some(hmac) }
);
let reply_paths = self.create_blinded_paths(context)
.map_err(|_| Bolt12SemanticError::MissingPaths)?;

let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);

create_pending_payment(&invoice_request, nonce)?;

self.enqueue_invoice_request(invoice_request, reply_paths)
}

/// Creates a [`Bolt12Invoice`] for a [`Refund`] and enqueues it to be sent via an onion
/// message.
///
Expand Down Expand Up @@ -12240,6 +12200,8 @@ where
pub router: R,
/// The [`MessageRouter`] used for constructing [`BlindedMessagePath`]s for [`Offer`]s,
/// [`Refund`]s, and any reply paths.
///
/// [`Offer`]: crate::offers::offer
pub message_router: MR,
/// The Logger for use in the ChannelManager and which may be used to log information during
/// deserialization.
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/ln/max_payment_path_len_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ fn bolt12_invoice_too_large_blinded_paths() {

let offer = nodes[1].offers_handler.create_offer_builder(None).unwrap().build().unwrap();
let payment_id = PaymentId([1; 32]);
nodes[0].node.pay_for_offer(&offer, None, Some(5000), None, payment_id, Retry::Attempts(0), None).unwrap();
nodes[0].offers_handler.pay_for_offer(&offer, None, Some(5000), None, payment_id, Retry::Attempts(0), None).unwrap();
let invreq_om = nodes[0].onion_messenger.next_onion_message_for_peer(nodes[1].node.get_our_node_id()).unwrap();
nodes[1].onion_messenger.handle_onion_message(nodes[0].node.get_our_node_id(), &invreq_om);

Expand Down
Loading

0 comments on commit 734b58f

Please sign in to comment.