Skip to content

Commit

Permalink
Expand create_blinded_path Functionality for Enhanced Path Diversif…
Browse files Browse the repository at this point in the history
…ication

- 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.
  • Loading branch information
shaavan committed Jun 10, 2024
1 parent 1d0c6c6 commit b6e38c2
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 33 deletions.
82 changes: 52 additions & 30 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8285,8 +8285,11 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
let entropy = &*$self.entropy_source;
let secp_ctx = &$self.secp_ctx;

// TODO: Introduce a parameter to allow adding more paths to the created Offer.
let path = $self.create_blinded_path_using_absolute_expiry(absolute_expiry)
.and_then(|paths| paths.into_iter().next().ok_or(()))
.map_err(|_| Bolt12SemanticError::MissingPaths)?;

let builder = OfferBuilder::deriving_signing_pubkey(
node_id, expanded_key, entropy, secp_ctx
)
Expand Down Expand Up @@ -8357,8 +8360,11 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
let entropy = &*$self.entropy_source;
let secp_ctx = &$self.secp_ctx;

// TODO: Introduce a parameter to allow adding more paths to the created Refund.
let path = $self.create_blinded_path_using_absolute_expiry(Some(absolute_expiry))
.and_then(|paths| paths.into_iter().next().ok_or(()))
.map_err(|_| Bolt12SemanticError::MissingPaths)?;

let builder = RefundBuilder::deriving_payer_id(
node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
)?
Expand Down Expand Up @@ -8480,7 +8486,7 @@ where
Some(payer_note) => builder.payer_note(payer_note),
};
let invoice_request = builder.build_and_sign()?;
let reply_path = self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
let reply_paths = self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;

let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);

Expand All @@ -8493,25 +8499,32 @@ where

let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
if !offer.paths().is_empty() {
// Send as many invoice requests as there are paths in the offer (with an upper bound).
// Using only one path could result in a failure if the path no longer exists. But only
// one invoice for a given payment id will be paid, even if more than one is received.
// Send as many invoice requests as there are paths in the offer using as many different
// reply_paths possible (with an upper bound).
// Using only one path could result in a failure if the path no longer exists.
// But only one invoice for a given payment ID will be paid, even if more than one is received.
const REQUEST_LIMIT: usize = 10;
for path in offer.paths().into_iter().take(REQUEST_LIMIT) {
reply_paths
.iter()
.flat_map(|reply_path| offer.paths().iter().map(move |path| (path, reply_path)))
.take(REQUEST_LIMIT)
.for_each(|(path, reply_path)| {
let message = new_pending_onion_message(
OffersMessage::InvoiceRequest(invoice_request.clone()),
Destination::BlindedPath(path.clone()),
Some(reply_path.clone()),
);
pending_offers_messages.push(message);
});
} else if let Some(signing_pubkey) = offer.signing_pubkey() {
for reply_path in reply_paths {
let message = new_pending_onion_message(
OffersMessage::InvoiceRequest(invoice_request.clone()),
Destination::BlindedPath(path.clone()),
Some(reply_path.clone()),
Destination::Node(signing_pubkey),
Some(reply_path),
);
pending_offers_messages.push(message);
}
} else if let Some(signing_pubkey) = offer.signing_pubkey() {
let message = new_pending_onion_message(
OffersMessage::InvoiceRequest(invoice_request),
Destination::Node(signing_pubkey),
Some(reply_path),
);
pending_offers_messages.push(message);
} else {
debug_assert!(false);
return Err(Bolt12SemanticError::MissingSigningPubkey);
Expand Down Expand Up @@ -8580,26 +8593,37 @@ where
)?;
let builder: InvoiceBuilder<DerivedSigningPubkey> = builder.into();
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
let reply_path = self.create_blinded_path()
let reply_paths = self.create_blinded_path()
.map_err(|_| Bolt12SemanticError::MissingPaths)?;

let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
if refund.paths().is_empty() {
let message = new_pending_onion_message(
OffersMessage::Invoice(invoice.clone()),
Destination::Node(refund.payer_id()),
Some(reply_path),
);
pending_offers_messages.push(message);
} else {
for path in refund.paths() {
for reply_path in reply_paths {
let message = new_pending_onion_message(
OffersMessage::Invoice(invoice.clone()),
Destination::BlindedPath(path.clone()),
Some(reply_path.clone()),
Destination::Node(refund.payer_id()),
Some(reply_path),
);
pending_offers_messages.push(message);
}
} else {
// Send as many BOLT12Invoices as there are paths in the refund using as many different
// reply_paths possible (with an upper bound).
// Using only one path could result in a failure if the path no longer exists.
// But only one invoice for a given payment ID will be paid, even if more than one is received.
const REQUEST_LIMIT: usize = 10;
reply_paths
.iter()
.flat_map(|reply_path| refund.paths().iter().map(move |path| (path, reply_path)))
.take(REQUEST_LIMIT)
.for_each(|(path, reply_path)| {
let message = new_pending_onion_message(
OffersMessage::Invoice(invoice.clone()),
Destination::BlindedPath(path.clone()),
Some(reply_path.clone()),
);
pending_offers_messages.push(message);
});
}

Ok(invoice)
Expand Down Expand Up @@ -8714,7 +8738,7 @@ where
/// [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`].
fn create_blinded_path_using_absolute_expiry(
&self, absolute_expiry: Option<Duration>
) -> Result<BlindedPath, ()> {
) -> Result<Vec<BlindedPath>, ()> {
let now = self.duration_since_epoch();
let max_short_lived_absolute_expiry = now.saturating_add(MAX_SHORT_LIVED_RELATIVE_EXPIRY);

Expand All @@ -8741,7 +8765,7 @@ where
/// Creates a blinded path by delegating to [`MessageRouter::create_blinded_paths`].
///
/// Errors if the `MessageRouter` errors or returns an empty `Vec`.
fn create_blinded_path(&self) -> Result<BlindedPath, ()> {
fn create_blinded_path(&self) -> Result<Vec<BlindedPath>, ()> {
let recipient = self.get_our_node_id();
let secp_ctx = &self.secp_ctx;

Expand All @@ -8755,13 +8779,12 @@ where

self.router
.create_blinded_paths(recipient, peers, secp_ctx)
.and_then(|paths| paths.into_iter().next().ok_or(()))
}

/// Creates a blinded path by delegating to [`MessageRouter::create_compact_blinded_paths`].
///
/// Errors if the `MessageRouter` errors or returns an empty `Vec`.
fn create_compact_blinded_path(&self) -> Result<BlindedPath, ()> {
fn create_compact_blinded_path(&self) -> Result<Vec<BlindedPath>, ()> {
let recipient = self.get_our_node_id();
let secp_ctx = &self.secp_ctx;

Expand All @@ -8782,7 +8805,6 @@ where

self.router
.create_compact_blinded_paths(recipient, peers, secp_ctx)
.and_then(|paths| paths.into_iter().next().ok_or(()))
}

/// Creates multi-hop blinded payment paths for the given `amount_msats` by delegating to
Expand Down
7 changes: 4 additions & 3 deletions lightning/src/onion_message/messenger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1127,7 +1127,7 @@ where
.map_err(|_| SendError::PathNotFound)
}

fn create_blinded_path(&self) -> Result<BlindedPath, SendError> {
fn create_blinded_path(&self) -> Result<Vec<BlindedPath>, SendError> {
let recipient = self.node_signer
.get_node_id(Recipient::Node)
.map_err(|_| SendError::GetNodeIdFailed)?;
Expand All @@ -1141,7 +1141,6 @@ where

self.message_router
.create_blinded_paths(recipient, peers, secp_ctx)
.and_then(|paths| paths.into_iter().next().ok_or(()))
.map_err(|_| SendError::PathNotFound)
}

Expand Down Expand Up @@ -1237,7 +1236,9 @@ where

let message_type = response.message.msg_type();
let reply_path = if create_reply_path {
match self.create_blinded_path() {
match self.create_blinded_path().and_then(
|paths| paths.into_iter().next().ok_or(SendError::PathNotFound)
) {
Ok(reply_path) => Some(reply_path),
Err(err) => {
log_trace!(
Expand Down

0 comments on commit b6e38c2

Please sign in to comment.