Skip to content

Commit 98f0198

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 035579b commit 98f0198

File tree

2 files changed

+54
-28
lines changed

2 files changed

+54
-28
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12263,7 +12263,12 @@ where
1226312263

1226412264
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
1226512265

12266-
self.flow.enqueue_invoice(invoice.clone(), refund, self.get_peers_for_blinded_path())?;
12266+
if refund.paths().is_empty() {
12267+
self.flow.enqueue_invoice_using_node_id(invoice.clone(), refund.payer_signing_pubkey(), self.get_peers_for_blinded_path())?;
12268+
} else {
12269+
self.flow.enqueue_invoice_using_reply_paths(invoice.clone(), refund.paths(), self.get_peers_for_blinded_path())?;
12270+
}
12271+
1226712272
Ok(invoice)
1226812273
}
1226912274

lightning/src/offers/flow.rs

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,22 +1118,23 @@ where
11181118
Ok(())
11191119
}
11201120

1121-
/// Enqueues the created [`Bolt12Invoice`] corresponding to a [`Refund`] to be sent
1122-
/// to the counterparty.
1121+
/// Enqueues the provided [`Bolt12Invoice`] to be sent directly to the specified
1122+
/// [`PublicKey`] `destination`.
11231123
///
1124-
/// # Peers
1124+
/// This method should be used when there are no available [`BlindedMessagePath`]s
1125+
/// for routing the [`Bolt12Invoice`] and the counterparty’s node ID is known.
11251126
///
1126-
/// The user must provide a list of [`MessageForwardNode`] that will be used to generate valid
1127-
/// reply paths for the counterparty to send back the corresponding [`InvoiceError`] if we fail
1128-
/// to create blinded reply paths
1127+
/// # Reply Path Requirement
1128+
///
1129+
/// Reply paths are generated from the given `peers` to allow the counterparty to return
1130+
/// an [`InvoiceError`] in case they fail to process the invoice. If valid reply paths
1131+
/// cannot be constructed, this method returns a [`Bolt12SemanticError::MissingPaths`].
11291132
///
11301133
/// [`InvoiceError`]: crate::offers::invoice_error::InvoiceError
1131-
/// [`supports_onion_messages`]: crate::types::features::Features::supports_onion_messages
1132-
pub fn enqueue_invoice(
1133-
&self, invoice: Bolt12Invoice, refund: &Refund, peers: Vec<MessageForwardNode>,
1134+
pub fn enqueue_invoice_using_node_id(
1135+
&self, invoice: Bolt12Invoice, destination: PublicKey, peers: Vec<MessageForwardNode>,
11341136
) -> Result<(), Bolt12SemanticError> {
11351137
let payment_hash = invoice.payment_hash();
1136-
11371138
let context = MessageContext::Offers(OffersContext::InboundPayment { payment_hash });
11381139

11391140
let reply_paths = self
@@ -1142,28 +1143,48 @@ where
11421143

11431144
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
11441145

1145-
if refund.paths().is_empty() {
1146-
for reply_path in reply_paths {
1147-
let instructions = MessageSendInstructions::WithSpecifiedReplyPath {
1148-
destination: Destination::Node(refund.payer_signing_pubkey()),
1149-
reply_path,
1150-
};
1151-
let message = OffersMessage::Invoice(invoice.clone());
1152-
pending_offers_messages.push((message, instructions));
1153-
}
1154-
} else {
1155-
let message = OffersMessage::Invoice(invoice);
1156-
enqueue_onion_message_with_reply_paths(
1157-
message,
1158-
refund.paths(),
1159-
reply_paths,
1160-
&mut pending_offers_messages,
1161-
);
1146+
for reply_path in reply_paths {
1147+
let instructions = MessageSendInstructions::WithSpecifiedReplyPath {
1148+
destination: Destination::Node(destination),
1149+
reply_path,
1150+
};
1151+
let message = OffersMessage::Invoice(invoice.clone());
1152+
pending_offers_messages.push((message, instructions));
11621153
}
11631154

11641155
Ok(())
11651156
}
11661157

1158+
/// Similar to [`Self::enqueue_invoice_using_node_id`], but uses [`BlindedMessagePath`]s
1159+
/// for routing the [`Bolt12Invoice`] instead of a direct node ID.
1160+
///
1161+
/// Useful when the counterparty expects to receive invoices through onion-routed paths
1162+
/// for privacy or anonymity.
1163+
///
1164+
/// For reply path requirements see [`Self::enqueue_invoice_using_node_id`].
1165+
pub fn enqueue_invoice_using_reply_paths(
1166+
&self, invoice: Bolt12Invoice, paths: &[BlindedMessagePath], peers: Vec<MessageForwardNode>,
1167+
) -> Result<(), Bolt12SemanticError> {
1168+
let payment_hash = invoice.payment_hash();
1169+
let context = MessageContext::Offers(OffersContext::InboundPayment { payment_hash });
1170+
1171+
let reply_paths = self
1172+
.create_blinded_paths(peers, context)
1173+
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
1174+
1175+
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
1176+
1177+
let message = OffersMessage::Invoice(invoice);
1178+
enqueue_onion_message_with_reply_paths(
1179+
message,
1180+
paths,
1181+
reply_paths,
1182+
&mut pending_offers_messages,
1183+
);
1184+
1185+
Ok(())
1186+
}
1187+
11671188
/// Forwards a [`StaticInvoice`] over the provided [`Responder`] in response to an
11681189
/// [`InvoiceRequest`] that we as a static invoice server received on behalf of an often-offline
11691190
/// recipient.

0 commit comments

Comments
 (0)