@@ -8621,8 +8621,10 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
8621
8621
let entropy = &*$self.entropy_source;
8622
8622
let secp_ctx = &$self.secp_ctx;
8623
8623
8624
- let path = $self.create_blinded_path_using_absolute_expiry(OffersContext::Unknown {}, absolute_expiry)
8624
+ let path = $self.create_blinded_paths_using_absolute_expiry(OffersContext::Unknown {}, absolute_expiry)
8625
+ .and_then(|paths| paths.into_iter().next().ok_or(()))
8625
8626
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
8627
+
8626
8628
let builder = OfferBuilder::deriving_signing_pubkey(
8627
8629
node_id, expanded_key, entropy, secp_ctx
8628
8630
)
@@ -8694,8 +8696,10 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
8694
8696
let secp_ctx = &$self.secp_ctx;
8695
8697
8696
8698
let context = OffersContext::OutboundPayment { payment_id };
8697
- let path = $self.create_blinded_path_using_absolute_expiry(context, Some(absolute_expiry))
8699
+ let path = $self.create_blinded_paths_using_absolute_expiry(context, Some(absolute_expiry))
8700
+ .and_then(|paths| paths.into_iter().next().ok_or(()))
8698
8701
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
8702
+
8699
8703
let builder = RefundBuilder::deriving_payer_id(
8700
8704
node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
8701
8705
)?
@@ -8716,6 +8720,13 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
8716
8720
}
8717
8721
} }
8718
8722
8723
+ /// Defines the maximum number of [`OffersMessage`] including different reply paths to be sent
8724
+ /// along different paths.
8725
+ /// Sending multiple requests increases the chances of successful delivery in case some
8726
+ /// paths are unavailable. However, only one invoice for a given [`PaymentId`] will be paid,
8727
+ /// even if multiple invoices are received.
8728
+ const OFFERS_MESSAGE_REQUEST_LIMIT: usize = 10;
8729
+
8719
8730
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>
8720
8731
where
8721
8732
M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
@@ -8819,7 +8830,7 @@ where
8819
8830
let invoice_request = builder.build_and_sign()?;
8820
8831
8821
8832
let context = OffersContext::OutboundPayment { payment_id };
8822
- let reply_path = self.create_blinded_path (context).map_err(|_| Bolt12SemanticError::MissingPaths)?;
8833
+ let reply_paths = self.create_blinded_paths (context).map_err(|_| Bolt12SemanticError::MissingPaths)?;
8823
8834
8824
8835
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
8825
8836
@@ -8832,25 +8843,27 @@ where
8832
8843
8833
8844
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
8834
8845
if !offer.paths().is_empty() {
8835
- // Send as many invoice requests as there are paths in the offer (with an upper bound).
8836
- // Using only one path could result in a failure if the path no longer exists. But only
8837
- // one invoice for a given payment id will be paid, even if more than one is received.
8838
- const REQUEST_LIMIT: usize = 10;
8839
- for path in offer.paths().into_iter().take(REQUEST_LIMIT) {
8846
+ reply_paths
8847
+ .iter()
8848
+ .flat_map(|reply_path| offer.paths().iter().map(move |path| (path, reply_path)))
8849
+ .take(OFFERS_MESSAGE_REQUEST_LIMIT)
8850
+ .for_each(|(path, reply_path)| {
8851
+ let message = new_pending_onion_message(
8852
+ OffersMessage::InvoiceRequest(invoice_request.clone()),
8853
+ Destination::BlindedPath(path.clone()),
8854
+ Some(reply_path.clone()),
8855
+ );
8856
+ pending_offers_messages.push(message);
8857
+ });
8858
+ } else if let Some(signing_pubkey) = offer.signing_pubkey() {
8859
+ for reply_path in reply_paths {
8840
8860
let message = new_pending_onion_message(
8841
8861
OffersMessage::InvoiceRequest(invoice_request.clone()),
8842
- Destination::BlindedPath(path.clone() ),
8843
- Some(reply_path.clone() ),
8862
+ Destination::Node(signing_pubkey ),
8863
+ Some(reply_path),
8844
8864
);
8845
8865
pending_offers_messages.push(message);
8846
8866
}
8847
- } else if let Some(signing_pubkey) = offer.signing_pubkey() {
8848
- let message = new_pending_onion_message(
8849
- OffersMessage::InvoiceRequest(invoice_request),
8850
- Destination::Node(signing_pubkey),
8851
- Some(reply_path),
8852
- );
8853
- pending_offers_messages.push(message);
8854
8867
} else {
8855
8868
debug_assert!(false);
8856
8869
return Err(Bolt12SemanticError::MissingSigningPubkey);
@@ -8919,26 +8932,32 @@ where
8919
8932
)?;
8920
8933
let builder: InvoiceBuilder<DerivedSigningPubkey> = builder.into();
8921
8934
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
8922
- let reply_path = self.create_blinded_path (OffersContext::Unknown {})
8935
+ let reply_paths = self.create_blinded_paths (OffersContext::Unknown {})
8923
8936
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
8924
8937
8925
8938
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
8926
8939
if refund.paths().is_empty() {
8927
- let message = new_pending_onion_message(
8928
- OffersMessage::Invoice(invoice.clone()),
8929
- Destination::Node(refund.payer_id()),
8930
- Some(reply_path),
8931
- );
8932
- pending_offers_messages.push(message);
8933
- } else {
8934
- for path in refund.paths() {
8940
+ for reply_path in reply_paths {
8935
8941
let message = new_pending_onion_message(
8936
8942
OffersMessage::Invoice(invoice.clone()),
8937
- Destination::BlindedPath(path.clone ()),
8938
- Some(reply_path.clone() ),
8943
+ Destination::Node(refund.payer_id ()),
8944
+ Some(reply_path),
8939
8945
);
8940
8946
pending_offers_messages.push(message);
8941
8947
}
8948
+ } else {
8949
+ reply_paths
8950
+ .iter()
8951
+ .flat_map(|reply_path| refund.paths().iter().map(move |path| (path, reply_path)))
8952
+ .take(OFFERS_MESSAGE_REQUEST_LIMIT)
8953
+ .for_each(|(path, reply_path)| {
8954
+ let message = new_pending_onion_message(
8955
+ OffersMessage::Invoice(invoice.clone()),
8956
+ Destination::BlindedPath(path.clone()),
8957
+ Some(reply_path.clone()),
8958
+ );
8959
+ pending_offers_messages.push(message);
8960
+ });
8942
8961
}
8943
8962
8944
8963
Ok(invoice)
@@ -9045,22 +9064,22 @@ where
9045
9064
inbound_payment::get_payment_preimage(payment_hash, payment_secret, &self.inbound_payment_key)
9046
9065
}
9047
9066
9048
- /// Creates a blinded path by delegating to [`MessageRouter`] based on the path's intended
9049
- /// lifetime.
9067
+ /// Creates a collection of blinded paths by delegating to [`MessageRouter`] based on
9068
+ /// the path's intended lifetime.
9050
9069
///
9051
9070
/// Whether or not the path is compact depends on whether the path is short-lived or long-lived,
9052
9071
/// respectively, based on the given `absolute_expiry` as seconds since the Unix epoch. See
9053
9072
/// [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`].
9054
- fn create_blinded_path_using_absolute_expiry (
9073
+ fn create_blinded_paths_using_absolute_expiry (
9055
9074
&self, context: OffersContext, absolute_expiry: Option<Duration>,
9056
- ) -> Result<BlindedPath, ()> {
9075
+ ) -> Result<Vec< BlindedPath> , ()> {
9057
9076
let now = self.duration_since_epoch();
9058
9077
let max_short_lived_absolute_expiry = now.saturating_add(MAX_SHORT_LIVED_RELATIVE_EXPIRY);
9059
9078
9060
9079
if absolute_expiry.unwrap_or(Duration::MAX) <= max_short_lived_absolute_expiry {
9061
- self.create_compact_blinded_path (context)
9080
+ self.create_compact_blinded_paths (context)
9062
9081
} else {
9063
- self.create_blinded_path (context)
9082
+ self.create_blinded_paths (context)
9064
9083
}
9065
9084
}
9066
9085
@@ -9077,10 +9096,11 @@ where
9077
9096
now
9078
9097
}
9079
9098
9080
- /// Creates a blinded path by delegating to [`MessageRouter::create_blinded_paths`].
9099
+ /// Creates a collection of blinded paths by delegating to
9100
+ /// [`MessageRouter::create_blinded_paths`].
9081
9101
///
9082
- /// Errors if the `MessageRouter` errors or returns an empty `Vec` .
9083
- fn create_blinded_path (&self, context: OffersContext) -> Result<BlindedPath, ()> {
9102
+ /// Errors if the `MessageRouter` errors.
9103
+ fn create_blinded_paths (&self, context: OffersContext) -> Result<Vec< BlindedPath> , ()> {
9084
9104
let recipient = self.get_our_node_id();
9085
9105
let secp_ctx = &self.secp_ctx;
9086
9106
@@ -9094,13 +9114,14 @@ where
9094
9114
9095
9115
self.router
9096
9116
.create_blinded_paths(recipient, MessageContext::Offers(context), peers, secp_ctx)
9097
- .and_then(|paths| paths.into_iter().next( ).ok_or(()))
9117
+ .and_then(|paths| (! paths.is_empty()).then(|| paths ).ok_or(()))
9098
9118
}
9099
9119
9100
- /// Creates a blinded path by delegating to [`MessageRouter::create_compact_blinded_paths`].
9120
+ /// Creates a collection of blinded paths by delegating to
9121
+ /// [`MessageRouter::create_compact_blinded_paths`].
9101
9122
///
9102
- /// Errors if the `MessageRouter` errors or returns an empty `Vec` .
9103
- fn create_compact_blinded_path (&self, context: OffersContext) -> Result<BlindedPath, ()> {
9123
+ /// Errors if the `MessageRouter` errors.
9124
+ fn create_compact_blinded_paths (&self, context: OffersContext) -> Result<Vec< BlindedPath> , ()> {
9104
9125
let recipient = self.get_our_node_id();
9105
9126
let secp_ctx = &self.secp_ctx;
9106
9127
@@ -9121,7 +9142,7 @@ where
9121
9142
9122
9143
self.router
9123
9144
.create_compact_blinded_paths(recipient, MessageContext::Offers(context), peers, secp_ctx)
9124
- .and_then(|paths| paths.into_iter().next( ).ok_or(()))
9145
+ .and_then(|paths| (! paths.is_empty()).then(|| paths ).ok_or(()))
9125
9146
}
9126
9147
9127
9148
/// Creates multi-hop blinded payment paths for the given `amount_msats` by delegating to
0 commit comments