Skip to content

Commit a88fef6

Browse files
committed
Split enqueue_invoice into destination-specific variants
Previously, the `enqueue_invoice` function in the `Flow` component accepted a `Refund` as input and dispatched the invoice either directly to a known `PublicKey` or via `BlindedMessagePath`s, depending on what was available within the `Refund`. While this worked for the refund-based flow, it tightly coupled invoice dispatch logic to the `Refund` abstraction, limiting its general usability outside of that context. The upcoming commits will introduce support for constructing and enqueuing invoices from manually handled `InvoiceRequest`s—decoupled from the `Refund` flow. To enable this, we are preemptively introducing more flexible, destination-specific variants of the enqueue function. Specifically, the `Flow` now exposes two dedicated methods: - `enqueue_invoice_using_node_id`: For sending an invoice directly to a known `PublicKey`. - `enqueue_invoice_using_reply_paths`: For sending an invoice over a set of explicitly provided `BlindedMessagePath`s. This separation improves clarity, enables reuse in broader contexts, and lays the groundwork for more composable invoice handling across the Offers/Refund flow.
1 parent 457d57a commit a88fef6

File tree

2 files changed

+62
-28
lines changed

2 files changed

+62
-28
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13170,7 +13170,20 @@ where
1317013170

1317113171
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
1317213172

13173-
self.flow.enqueue_invoice(invoice.clone(), refund, self.get_peers_for_blinded_path())?;
13173+
if refund.paths().is_empty() {
13174+
self.flow.enqueue_invoice_using_node_id(
13175+
invoice.clone(),
13176+
refund.payer_signing_pubkey(),
13177+
self.get_peers_for_blinded_path(),
13178+
)?;
13179+
} else {
13180+
self.flow.enqueue_invoice_using_reply_paths(
13181+
invoice.clone(),
13182+
refund.paths(),
13183+
self.get_peers_for_blinded_path(),
13184+
)?;
13185+
}
13186+
1317413187
Ok(invoice)
1317513188
}
1317613189

lightning/src/offers/flow.rs

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,22 +1152,23 @@ where
11521152
Ok(())
11531153
}
11541154

1155-
/// Enqueues the created [`Bolt12Invoice`] corresponding to a [`Refund`] to be sent
1156-
/// to the counterparty.
1155+
/// Enqueues the provided [`Bolt12Invoice`] to be sent directly to the specified
1156+
/// [`PublicKey`] `destination`.
11571157
///
1158-
/// # Peers
1158+
/// This method should be used when there are no available [`BlindedMessagePath`]s
1159+
/// for routing the [`Bolt12Invoice`] and the counterparty’s node ID is known.
1160+
///
1161+
/// # Reply Path Requirement
11591162
///
1160-
/// The user must provide a list of [`MessageForwardNode`] that will be used to generate valid
1161-
/// reply paths for the counterparty to send back the corresponding [`InvoiceError`] if we fail
1162-
/// to create blinded reply paths
1163+
/// Reply paths are generated from the given `peers` to allow the counterparty to return
1164+
/// an [`InvoiceError`] in case they fail to process the invoice. If valid reply paths
1165+
/// cannot be constructed, this method returns a [`Bolt12SemanticError::MissingPaths`].
11631166
///
11641167
/// [`InvoiceError`]: crate::offers::invoice_error::InvoiceError
1165-
/// [`supports_onion_messages`]: crate::types::features::Features::supports_onion_messages
1166-
pub fn enqueue_invoice(
1167-
&self, invoice: Bolt12Invoice, refund: &Refund, peers: Vec<MessageForwardNode>,
1168+
pub fn enqueue_invoice_using_node_id(
1169+
&self, invoice: Bolt12Invoice, destination: PublicKey, peers: Vec<MessageForwardNode>,
11681170
) -> Result<(), Bolt12SemanticError> {
11691171
let payment_hash = invoice.payment_hash();
1170-
11711172
let context = MessageContext::Offers(OffersContext::InboundPayment { payment_hash });
11721173

11731174
let reply_paths = self
@@ -1176,28 +1177,48 @@ where
11761177

11771178
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
11781179

1179-
if refund.paths().is_empty() {
1180-
for reply_path in reply_paths {
1181-
let instructions = MessageSendInstructions::WithSpecifiedReplyPath {
1182-
destination: Destination::Node(refund.payer_signing_pubkey()),
1183-
reply_path,
1184-
};
1185-
let message = OffersMessage::Invoice(invoice.clone());
1186-
pending_offers_messages.push((message, instructions));
1187-
}
1188-
} else {
1189-
let message = OffersMessage::Invoice(invoice);
1190-
enqueue_onion_message_with_reply_paths(
1191-
message,
1192-
refund.paths(),
1193-
reply_paths,
1194-
&mut pending_offers_messages,
1195-
);
1180+
for reply_path in reply_paths {
1181+
let instructions = MessageSendInstructions::WithSpecifiedReplyPath {
1182+
destination: Destination::Node(destination),
1183+
reply_path,
1184+
};
1185+
let message = OffersMessage::Invoice(invoice.clone());
1186+
pending_offers_messages.push((message, instructions));
11961187
}
11971188

11981189
Ok(())
11991190
}
12001191

1192+
/// Similar to [`Self::enqueue_invoice_using_node_id`], but uses [`BlindedMessagePath`]s
1193+
/// for routing the [`Bolt12Invoice`] instead of a direct node ID.
1194+
///
1195+
/// Useful when the counterparty expects to receive invoices through onion-routed paths
1196+
/// for privacy or anonymity.
1197+
///
1198+
/// For reply path requirements see [`Self::enqueue_invoice_using_node_id`].
1199+
pub fn enqueue_invoice_using_reply_paths(
1200+
&self, invoice: Bolt12Invoice, paths: &[BlindedMessagePath], peers: Vec<MessageForwardNode>,
1201+
) -> Result<(), Bolt12SemanticError> {
1202+
let payment_hash = invoice.payment_hash();
1203+
let context = MessageContext::Offers(OffersContext::InboundPayment { payment_hash });
1204+
1205+
let reply_paths = self
1206+
.create_blinded_paths(peers, context)
1207+
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
1208+
1209+
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
1210+
1211+
let message = OffersMessage::Invoice(invoice);
1212+
enqueue_onion_message_with_reply_paths(
1213+
message,
1214+
paths,
1215+
reply_paths,
1216+
&mut pending_offers_messages,
1217+
);
1218+
1219+
Ok(())
1220+
}
1221+
12011222
/// Forwards a [`StaticInvoice`] over the provided [`Responder`] in response to an
12021223
/// [`InvoiceRequest`] that we as a static invoice server received on behalf of an often-offline
12031224
/// recipient.

0 commit comments

Comments
 (0)