Skip to content

Commit 8defec2

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 ea7af69 commit 8defec2

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
@@ -13119,7 +13119,20 @@ where
1311913119

1312013120
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
1312113121

13122-
self.flow.enqueue_invoice(invoice.clone(), refund, self.get_peers_for_blinded_path())?;
13122+
if refund.paths().is_empty() {
13123+
self.flow.enqueue_invoice_using_node_id(
13124+
invoice.clone(),
13125+
refund.payer_signing_pubkey(),
13126+
self.get_peers_for_blinded_path(),
13127+
)?;
13128+
} else {
13129+
self.flow.enqueue_invoice_using_reply_paths(
13130+
invoice.clone(),
13131+
refund.paths(),
13132+
self.get_peers_for_blinded_path(),
13133+
)?;
13134+
}
13135+
1312313136
Ok(invoice)
1312413137
}
1312513138

lightning/src/offers/flow.rs

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,22 +1169,23 @@ where
11691169
Ok(())
11701170
}
11711171

1172-
/// Enqueues the created [`Bolt12Invoice`] corresponding to a [`Refund`] to be sent
1173-
/// to the counterparty.
1172+
/// Enqueues the provided [`Bolt12Invoice`] to be sent directly to the specified
1173+
/// [`PublicKey`] `destination`.
11741174
///
1175-
/// # Peers
1175+
/// This method should be used when there are no available [`BlindedMessagePath`]s
1176+
/// for routing the [`Bolt12Invoice`] and the counterparty’s node ID is known.
1177+
///
1178+
/// # Reply Path Requirement
11761179
///
1177-
/// The user must provide a list of [`MessageForwardNode`] that will be used to generate valid
1178-
/// reply paths for the counterparty to send back the corresponding [`InvoiceError`] if we fail
1179-
/// to create blinded reply paths
1180+
/// Reply paths are generated from the given `peers` to allow the counterparty to return
1181+
/// an [`InvoiceError`] in case they fail to process the invoice. If valid reply paths
1182+
/// cannot be constructed, this method returns a [`Bolt12SemanticError::MissingPaths`].
11801183
///
11811184
/// [`InvoiceError`]: crate::offers::invoice_error::InvoiceError
1182-
/// [`supports_onion_messages`]: crate::types::features::Features::supports_onion_messages
1183-
pub fn enqueue_invoice(
1184-
&self, invoice: Bolt12Invoice, refund: &Refund, peers: Vec<MessageForwardNode>,
1185+
pub fn enqueue_invoice_using_node_id(
1186+
&self, invoice: Bolt12Invoice, destination: PublicKey, peers: Vec<MessageForwardNode>,
11851187
) -> Result<(), Bolt12SemanticError> {
11861188
let payment_hash = invoice.payment_hash();
1187-
11881189
let context = MessageContext::Offers(OffersContext::InboundPayment { payment_hash });
11891190

11901191
let reply_paths = self
@@ -1193,28 +1194,48 @@ where
11931194

11941195
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
11951196

1196-
if refund.paths().is_empty() {
1197-
for reply_path in reply_paths {
1198-
let instructions = MessageSendInstructions::WithSpecifiedReplyPath {
1199-
destination: Destination::Node(refund.payer_signing_pubkey()),
1200-
reply_path,
1201-
};
1202-
let message = OffersMessage::Invoice(invoice.clone());
1203-
pending_offers_messages.push((message, instructions));
1204-
}
1205-
} else {
1206-
let message = OffersMessage::Invoice(invoice);
1207-
enqueue_onion_message_with_reply_paths(
1208-
message,
1209-
refund.paths(),
1210-
reply_paths,
1211-
&mut pending_offers_messages,
1212-
);
1197+
for reply_path in reply_paths {
1198+
let instructions = MessageSendInstructions::WithSpecifiedReplyPath {
1199+
destination: Destination::Node(destination),
1200+
reply_path,
1201+
};
1202+
let message = OffersMessage::Invoice(invoice.clone());
1203+
pending_offers_messages.push((message, instructions));
12131204
}
12141205

12151206
Ok(())
12161207
}
12171208

1209+
/// Similar to [`Self::enqueue_invoice_using_node_id`], but uses [`BlindedMessagePath`]s
1210+
/// for routing the [`Bolt12Invoice`] instead of a direct node ID.
1211+
///
1212+
/// Useful when the counterparty expects to receive invoices through onion-routed paths
1213+
/// for privacy or anonymity.
1214+
///
1215+
/// For reply path requirements see [`Self::enqueue_invoice_using_node_id`].
1216+
pub fn enqueue_invoice_using_reply_paths(
1217+
&self, invoice: Bolt12Invoice, paths: &[BlindedMessagePath], peers: Vec<MessageForwardNode>,
1218+
) -> Result<(), Bolt12SemanticError> {
1219+
let payment_hash = invoice.payment_hash();
1220+
let context = MessageContext::Offers(OffersContext::InboundPayment { payment_hash });
1221+
1222+
let reply_paths = self
1223+
.create_blinded_paths(peers, context)
1224+
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
1225+
1226+
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
1227+
1228+
let message = OffersMessage::Invoice(invoice);
1229+
enqueue_onion_message_with_reply_paths(
1230+
message,
1231+
paths,
1232+
reply_paths,
1233+
&mut pending_offers_messages,
1234+
);
1235+
1236+
Ok(())
1237+
}
1238+
12181239
/// Forwards a [`StaticInvoice`] over the provided [`Responder`] in response to an
12191240
/// [`InvoiceRequest`] that we as a static invoice server received on behalf of an often-offline
12201241
/// recipient.

0 commit comments

Comments
 (0)