Skip to content

Commit bf0b63a

Browse files
committed
Expand create_blinded_path Functionality for Enhanced Path Diversification
- Previously, the `create_blinded_path` function was limited to returning a single `BlindedPath`, which restricted the usage of `blinded_paths`. - This commit extends the `create_blinded_path` function to return the entire blinded path vector generated by the `MessageRouter`'s `create_blinded_paths`. - The updated functionality is integrated across the codebase, enabling the sending of Offers Response messages, such as `InvoiceRequest` (in `pay_for_offer`) and `Invoice` (in `request_refund_payment`), utilizing multiple reply paths.
1 parent 669a459 commit bf0b63a

File tree

1 file changed

+63
-42
lines changed

1 file changed

+63
-42
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 63 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -8376,8 +8376,10 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
83768376
let entropy = &*$self.entropy_source;
83778377
let secp_ctx = &$self.secp_ctx;
83788378

8379-
let path = $self.create_blinded_path_using_absolute_expiry(absolute_expiry)
8379+
let path = $self.create_blinded_paths_using_absolute_expiry(absolute_expiry)
8380+
.and_then(|paths| paths.into_iter().next().ok_or(()))
83808381
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
8382+
83818383
let builder = OfferBuilder::deriving_signing_pubkey(
83828384
node_id, expanded_key, entropy, secp_ctx
83838385
)
@@ -8448,8 +8450,10 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
84488450
let entropy = &*$self.entropy_source;
84498451
let secp_ctx = &$self.secp_ctx;
84508452

8451-
let path = $self.create_blinded_path_using_absolute_expiry(Some(absolute_expiry))
8453+
let path = $self.create_blinded_paths_using_absolute_expiry(Some(absolute_expiry))
8454+
.and_then(|paths| paths.into_iter().next().ok_or(()))
84528455
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
8456+
84538457
let builder = RefundBuilder::deriving_payer_id(
84548458
node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
84558459
)?
@@ -8470,6 +8474,13 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
84708474
}
84718475
} }
84728476

8477+
/// Defines the maximum number of [`OffersMessage`] including different reply paths to be sent
8478+
/// along different paths.
8479+
/// Sending multiple requests increases the chances of successful delivery in case some
8480+
/// paths are unavailable. However, only one invoice for a given [`PaymentId`] will be paid,
8481+
/// even if multiple invoices are received.
8482+
const OFFERS_MESSAGE_REQUEST_LIMIT: usize = 10;
8483+
84738484
impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref> ChannelManager<M, T, ES, NS, SP, F, R, L>
84748485
where
84758486
M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
@@ -8571,7 +8582,7 @@ where
85718582
Some(payer_note) => builder.payer_note(payer_note),
85728583
};
85738584
let invoice_request = builder.build_and_sign()?;
8574-
let reply_path = self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
8585+
let reply_paths = self.create_blinded_paths().map_err(|_| Bolt12SemanticError::MissingPaths)?;
85758586

85768587
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
85778588

@@ -8584,25 +8595,27 @@ where
85848595

85858596
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
85868597
if !offer.paths().is_empty() {
8587-
// Send as many invoice requests as there are paths in the offer (with an upper bound).
8588-
// Using only one path could result in a failure if the path no longer exists. But only
8589-
// one invoice for a given payment id will be paid, even if more than one is received.
8590-
const REQUEST_LIMIT: usize = 10;
8591-
for path in offer.paths().into_iter().take(REQUEST_LIMIT) {
8598+
reply_paths
8599+
.iter()
8600+
.flat_map(|reply_path| offer.paths().iter().map(move |path| (path, reply_path)))
8601+
.take(OFFERS_MESSAGE_REQUEST_LIMIT)
8602+
.for_each(|(path, reply_path)| {
8603+
let message = new_pending_onion_message(
8604+
OffersMessage::InvoiceRequest(invoice_request.clone()),
8605+
Destination::BlindedPath(path.clone()),
8606+
Some(reply_path.clone()),
8607+
);
8608+
pending_offers_messages.push(message);
8609+
});
8610+
} else if let Some(signing_pubkey) = offer.signing_pubkey() {
8611+
for reply_path in reply_paths {
85928612
let message = new_pending_onion_message(
85938613
OffersMessage::InvoiceRequest(invoice_request.clone()),
8594-
Destination::BlindedPath(path.clone()),
8595-
Some(reply_path.clone()),
8614+
Destination::Node(signing_pubkey),
8615+
Some(reply_path),
85968616
);
85978617
pending_offers_messages.push(message);
85988618
}
8599-
} else if let Some(signing_pubkey) = offer.signing_pubkey() {
8600-
let message = new_pending_onion_message(
8601-
OffersMessage::InvoiceRequest(invoice_request),
8602-
Destination::Node(signing_pubkey),
8603-
Some(reply_path),
8604-
);
8605-
pending_offers_messages.push(message);
86068619
} else {
86078620
debug_assert!(false);
86088621
return Err(Bolt12SemanticError::MissingSigningPubkey);
@@ -8671,26 +8684,32 @@ where
86718684
)?;
86728685
let builder: InvoiceBuilder<DerivedSigningPubkey> = builder.into();
86738686
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
8674-
let reply_path = self.create_blinded_path()
8687+
let reply_paths = self.create_blinded_paths()
86758688
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
86768689

86778690
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
86788691
if refund.paths().is_empty() {
8679-
let message = new_pending_onion_message(
8680-
OffersMessage::Invoice(invoice.clone()),
8681-
Destination::Node(refund.payer_id()),
8682-
Some(reply_path),
8683-
);
8684-
pending_offers_messages.push(message);
8685-
} else {
8686-
for path in refund.paths() {
8692+
for reply_path in reply_paths {
86878693
let message = new_pending_onion_message(
86888694
OffersMessage::Invoice(invoice.clone()),
8689-
Destination::BlindedPath(path.clone()),
8690-
Some(reply_path.clone()),
8695+
Destination::Node(refund.payer_id()),
8696+
Some(reply_path),
86918697
);
86928698
pending_offers_messages.push(message);
86938699
}
8700+
} else {
8701+
reply_paths
8702+
.iter()
8703+
.flat_map(|reply_path| refund.paths().iter().map(move |path| (path, reply_path)))
8704+
.take(OFFERS_MESSAGE_REQUEST_LIMIT)
8705+
.for_each(|(path, reply_path)| {
8706+
let message = new_pending_onion_message(
8707+
OffersMessage::Invoice(invoice.clone()),
8708+
Destination::BlindedPath(path.clone()),
8709+
Some(reply_path.clone()),
8710+
);
8711+
pending_offers_messages.push(message);
8712+
});
86948713
}
86958714

86968715
Ok(invoice)
@@ -8797,22 +8816,22 @@ where
87978816
inbound_payment::get_payment_preimage(payment_hash, payment_secret, &self.inbound_payment_key)
87988817
}
87998818

8800-
/// Creates a blinded path by delegating to [`MessageRouter`] based on the path's intended
8801-
/// lifetime.
8819+
/// Creates a collection of blinded paths by delegating to [`MessageRouter`] based on
8820+
/// the path's intended lifetime.
88028821
///
88038822
/// Whether or not the path is compact depends on whether the path is short-lived or long-lived,
88048823
/// respectively, based on the given `absolute_expiry` as seconds since the Unix epoch. See
88058824
/// [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`].
8806-
fn create_blinded_path_using_absolute_expiry(
8825+
fn create_blinded_paths_using_absolute_expiry(
88078826
&self, absolute_expiry: Option<Duration>
8808-
) -> Result<BlindedPath, ()> {
8827+
) -> Result<Vec<BlindedPath>, ()> {
88098828
let now = self.duration_since_epoch();
88108829
let max_short_lived_absolute_expiry = now.saturating_add(MAX_SHORT_LIVED_RELATIVE_EXPIRY);
88118830

88128831
if absolute_expiry.unwrap_or(Duration::MAX) <= max_short_lived_absolute_expiry {
8813-
self.create_compact_blinded_path()
8832+
self.create_compact_blinded_paths()
88148833
} else {
8815-
self.create_blinded_path()
8834+
self.create_blinded_paths()
88168835
}
88178836
}
88188837

@@ -8829,10 +8848,11 @@ where
88298848
now
88308849
}
88318850

8832-
/// Creates a blinded path by delegating to [`MessageRouter::create_blinded_paths`].
8851+
/// Creates a collection of blinded paths by delegating to
8852+
/// [`MessageRouter::create_blinded_paths`].
88338853
///
8834-
/// Errors if the `MessageRouter` errors or returns an empty `Vec`.
8835-
fn create_blinded_path(&self) -> Result<BlindedPath, ()> {
8854+
/// Errors if the `MessageRouter` errors.
8855+
fn create_blinded_paths(&self) -> Result<Vec<BlindedPath>, ()> {
88368856
let recipient = self.get_our_node_id();
88378857
let secp_ctx = &self.secp_ctx;
88388858

@@ -8846,13 +8866,14 @@ where
88468866

88478867
self.router
88488868
.create_blinded_paths(recipient, peers, secp_ctx)
8849-
.and_then(|paths| paths.into_iter().next().ok_or(()))
8869+
.and_then(|paths| (!paths.is_empty()).then(|| paths).ok_or(()))
88508870
}
88518871

8852-
/// Creates a blinded path by delegating to [`MessageRouter::create_compact_blinded_paths`].
8872+
/// Creates a collection of blinded paths by delegating to
8873+
/// [`MessageRouter::create_compact_blinded_paths`].
88538874
///
8854-
/// Errors if the `MessageRouter` errors or returns an empty `Vec`.
8855-
fn create_compact_blinded_path(&self) -> Result<BlindedPath, ()> {
8875+
/// Errors if the `MessageRouter` errors.
8876+
fn create_compact_blinded_paths(&self) -> Result<Vec<BlindedPath>, ()> {
88568877
let recipient = self.get_our_node_id();
88578878
let secp_ctx = &self.secp_ctx;
88588879

@@ -8873,7 +8894,7 @@ where
88738894

88748895
self.router
88758896
.create_compact_blinded_paths(recipient, peers, secp_ctx)
8876-
.and_then(|paths| paths.into_iter().next().ok_or(()))
8897+
.and_then(|paths| (!paths.is_empty()).then(|| paths).ok_or(()))
88778898
}
88788899

88798900
/// Creates multi-hop blinded payment paths for the given `amount_msats` by delegating to

0 commit comments

Comments
 (0)