Skip to content

Commit a96a510

Browse files
committed
WIP: Multi-hop blinded paths
1 parent ae2d248 commit a96a510

File tree

2 files changed

+39
-14
lines changed

2 files changed

+39
-14
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6709,8 +6709,9 @@ where
67096709
/// Creates an [`OfferBuilder`] such that the [`Offer`] it builds is recognized by the
67106710
/// [`ChannelManager`] when handling [`InvoiceRequest`] messages for the offer.
67116711
///
6712-
/// Uses a one-hop [`BlindedPath`] for the offer with [`ChannelManager::get_our_node_id`] as the
6713-
/// introduction node and a derived signing pubkey for recipient privacy.
6712+
/// Uses [`Router::find_partial_paths`] to construct a [`BlindedPath`] for the offer. If one is
6713+
/// found, also uses a derived signing pubkey for recipient privacy. Otherwise, uses the node id
6714+
/// as the signing pubkey.
67146715
///
67156716
/// [`Offer`]: crate::offers::offer::Offer
67166717
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
@@ -6725,10 +6726,10 @@ where
67256726
description, node_id, expanded_key, entropy, secp_ctx
67266727
);
67276728

6728-
match self.create_one_hop_blinded_path() {
6729-
Ok(path) => builder.path(path),
6729+
match self.create_blinded_paths(1) {
6730+
Ok(paths) if !paths.is_empty() => builder.path(paths.into_iter().next().unwrap()),
67306731
// TODO: check if node is public?
6731-
Err(_) => builder,
6732+
Ok(_) | Err(_) => builder,
67326733
}
67336734
}
67346735

@@ -6737,8 +6738,9 @@ where
67376738
///
67386739
/// The provided `payment_id` is used to ensure that only one invoice is paid for the refund.
67396740
///
6740-
/// Uses a one-hop [`BlindedPath`] for the refund with [`ChannelManager::get_our_node_id`] as
6741-
/// the introduction node and a derived payer id for sender privacy.
6741+
/// Uses [`Router::find_partial_paths`] to construct a [`BlindedPath`] for the refund. If one is
6742+
/// found, also uses a derived payer id for sender privacy. Otherwise, uses the node id as the
6743+
/// payer id.
67426744
///
67436745
/// [`Refund`]: crate::offers::refund::Refund
67446746
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
@@ -6753,10 +6755,10 @@ where
67536755
let builder = RefundBuilder::deriving_payer_id(
67546756
description, node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
67556757
)?;
6756-
let builder = match self.create_one_hop_blinded_path() {
6757-
Ok(path) => builder.path(path),
6758+
let builder = match self.create_blinded_paths(1) {
6759+
Ok(paths) if !paths.is_empty() => builder.path(paths.into_iter().next().unwrap()),
67586760
// TODO: check if node is public?
6759-
Err(_) => builder,
6761+
Ok(_) | Err(_) => builder,
67606762
};
67616763
self.pending_outbound_payments
67626764
.add_new_awaiting_invoice(payment_id, retry_strategy)
@@ -6890,13 +6892,25 @@ where
68906892
inbound_payment::get_payment_preimage(payment_hash, payment_secret, &self.inbound_payment_key)
68916893
}
68926894

6893-
/// Creates a one-hop blinded path with [`ChannelManager::get_our_node_id`] as the introduction
6894-
/// node.
6895-
fn create_one_hop_blinded_path(&self) -> Result<BlindedPath, ()> {
6895+
/// Creates `count` blinded paths using our immediate peers as the introduction nodes.
6896+
///
6897+
/// May return fewer paths if there are fewer than `count` peers that [support route blinding].
6898+
///
6899+
/// [support route blinding]: crate::ln::features::InitFeatures::supports_route_blinding
6900+
fn create_blinded_paths(&self, count: usize) -> Result<Vec<BlindedPath>, ()> {
6901+
let last_hops = self.per_peer_state.read().unwrap().iter()
6902+
.filter(|(_, peer)| peer.lock().unwrap().latest_features.supports_route_blinding())
6903+
.map(|(node_id, _)| *node_id)
6904+
.collect::<Vec<_>>();
68966905
let entropy_source = self.entropy_source.deref();
68976906
let secp_ctx = &self.secp_ctx;
6898-
BlindedPath::new_for_message(&[self.get_our_node_id()], entropy_source, secp_ctx)
68996907

6908+
self.router
6909+
.find_partial_paths(self.get_our_node_id(), last_hops.as_slice())?
6910+
.into_iter()
6911+
.map(|node_pks| BlindedPath::new_for_message(&node_pks[..], entropy_source, secp_ctx))
6912+
.take(count)
6913+
.collect()
69006914
}
69016915

69026916
/// Gets a fake short channel id for use in receiving [phantom node payments]. These fake scids

lightning/src/routing/router.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,17 @@ pub trait Router {
105105
) -> Result<Route, LightningError> {
106106
self.find_route(payer, route_params, first_hops, inflight_htlcs)
107107
}
108+
109+
/// Finds partial paths to the `recipient` node for creating `BlindedPath`s. The nodes in
110+
/// `peers` are assumed to be direct peers with the `recipient`.
111+
///
112+
/// The default implementation returns two-node paths for each node in `peers` with the
113+
/// `recipient` node.
114+
fn find_partial_paths(
115+
&self, recipient: PublicKey, peers: &[PublicKey]
116+
) -> Result<Vec<Vec<PublicKey>>, ()> {
117+
Ok(peers.iter().map(|hop| vec![*hop, recipient]).collect())
118+
}
108119
}
109120

110121
/// [`ScoreLookUp`] implementation that factors in in-flight HTLC liquidity.

0 commit comments

Comments
 (0)