Skip to content

Commit e3fec6e

Browse files
committed
WIP: Include blinded paths
1 parent e9315bf commit e3fec6e

File tree

3 files changed

+57
-9
lines changed

3 files changed

+57
-9
lines changed

lightning/src/blinded_path/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ impl BlindedPath {
6464
///
6565
/// Errors if less than two hops are provided or if `node_pk`(s) are invalid.
6666
// TODO: make all payloads the same size with padding + add dummy hops
67-
pub fn new_for_message<ES: EntropySource, T: secp256k1::Signing + secp256k1::Verification>
68-
(node_pks: &[PublicKey], entropy_source: &ES, secp_ctx: &Secp256k1<T>) -> Result<Self, ()>
69-
{
67+
pub fn new_for_message<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
68+
node_pks: &[PublicKey], entropy_source: ES, secp_ctx: &Secp256k1<T>
69+
) -> Result<Self, ()> where ES::Target: EntropySource {
7070
if node_pks.len() < 2 { return Err(()) }
7171
let blinding_secret_bytes = entropy_source.get_secure_random_bytes();
7272
let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted");

lightning/src/ln/channelmanager.rs

+42-6
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use bitcoin::secp256k1::{SecretKey,PublicKey};
3030
use bitcoin::secp256k1::Secp256k1;
3131
use bitcoin::{LockTime, secp256k1, Sequence};
3232

33+
use crate::blinded_path::BlindedPath;
3334
use crate::chain;
3435
use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock};
3536
use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator};
@@ -6086,6 +6087,10 @@ where
60866087
/// Creates an [`OfferBuilder`] such that the [`Offer`] it builds is recognized by the
60876088
/// [`OnionMessenger`] when handling [`InvoiceRequest`] messages for the offer.
60886089
///
6090+
/// Uses [`Router::find_partial_paths`] to construct a [`BlindedPath`] for the offer. If one is
6091+
/// found, also uses a derived signing pubkey for recipient privacy. Otherwise, uses the node id
6092+
/// as the signing pubkey.
6093+
///
60896094
/// [`Offer`]: crate::offers::offer::Offer
60906095
/// [`OnionMessenger`]: crate::onion_message::OnionMessenger
60916096
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
@@ -6096,14 +6101,24 @@ where
60966101
let expanded_key = &self.inbound_payment_key;
60976102
let entropy = &*self.entropy_source;
60986103
let secp_ctx = &self.secp_ctx;
6104+
let builder = OfferBuilder::deriving_signing_pubkey(
6105+
description, node_id, expanded_key, entropy, secp_ctx
6106+
);
60996107

6100-
// TODO: Set blinded paths
6101-
OfferBuilder::deriving_signing_pubkey(description, node_id, expanded_key, entropy, secp_ctx)
6108+
match self.create_blinded_paths(1) {
6109+
Ok(paths) if !paths.is_empty() => builder.path(paths.into_iter().next().unwrap()),
6110+
// TODO: check if node is public?
6111+
Ok(_) | Err(_) => builder,
6112+
}
61026113
}
61036114

61046115
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
61056116
/// [`OnionMessenger`] when handling [`Invoice`] messages for the refund.
61066117
///
6118+
/// Uses [`Router::find_partial_paths`] to construct a [`BlindedPath`] for the refund. If one is
6119+
/// found, also uses a derived payer id for sender privacy. Otherwise, uses the node id as the
6120+
/// payer id.
6121+
///
61076122
/// [`Refund`]: crate::offers::refund::Refund
61086123
/// [`OnionMessenger`]: crate::onion_message::OnionMessenger
61096124
/// [`Invoice`]: crate::offers::invoice::Invoice
@@ -6114,11 +6129,15 @@ where
61146129
let expanded_key = &self.inbound_payment_key;
61156130
let entropy = &*self.entropy_source;
61166131
let secp_ctx = &self.secp_ctx;
6117-
6118-
// TODO: Set blinded paths
6119-
RefundBuilder::deriving_payer_id(
6132+
let builder = RefundBuilder::deriving_payer_id(
61206133
description, node_id, expanded_key, entropy, secp_ctx, amount_msats
6121-
)
6134+
)?;
6135+
6136+
match self.create_blinded_paths(1) {
6137+
Ok(paths) if !paths.is_empty() => Ok(builder.path(paths.into_iter().next().unwrap())),
6138+
// TODO: check if node is public?
6139+
Ok(_) | Err(_) => Ok(builder),
6140+
}
61226141
}
61236142

61246143
/// Creates an [`InvoiceRequestBuilder`] such that the [`InvoiceRequest`] it builds is
@@ -6237,6 +6256,23 @@ where
62376256
inbound_payment::get_payment_preimage(payment_hash, payment_secret, &self.inbound_payment_key)
62386257
}
62396258

6259+
///
6260+
fn create_blinded_paths(&self, count: usize) -> Result<Vec<BlindedPath>, ()> {
6261+
let last_hops = self.per_peer_state.read().unwrap().iter()
6262+
.filter(|(_, peer)| peer.lock().unwrap().latest_features.supports_route_blinding())
6263+
.map(|(node_id, _)| *node_id)
6264+
.collect::<Vec<_>>();
6265+
let entropy_source = self.entropy_source.deref();
6266+
let secp_ctx = &self.secp_ctx;
6267+
6268+
self.router
6269+
.find_partial_paths(self.get_our_node_id(), last_hops.as_slice())?
6270+
.into_iter()
6271+
.map(|node_pks| BlindedPath::new_for_message(&node_pks[..], entropy_source, secp_ctx))
6272+
.take(count)
6273+
.collect()
6274+
}
6275+
62406276
/// Gets a fake short channel id for use in receiving [phantom node payments]. These fake scids
62416277
/// are used when constructing the phantom invoice's route hints.
62426278
///

lightning/src/routing/router.rs

+12
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ pub trait Router {
8787
&self, payer: &PublicKey, route_params: &RouteParameters,
8888
first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: &InFlightHtlcs
8989
) -> Result<Route, LightningError>;
90+
9091
/// Finds a [`Route`] between `payer` and `payee` for a payment with the given values. Includes
9192
/// `PaymentHash` and `PaymentId` to be able to correlate the request with a specific payment.
9293
fn find_route_with_id(
@@ -96,6 +97,17 @@ pub trait Router {
9697
) -> Result<Route, LightningError> {
9798
self.find_route(payer, route_params, first_hops, inflight_htlcs)
9899
}
100+
101+
/// Finds partial paths to the `recipient` node for creating `BlindedPath`s. The nodes in
102+
/// `peers` are assumed to be direct peers with the `recipient`.
103+
///
104+
/// The default implementation returns two-node paths for each node in `peers` with the
105+
/// `recipient` node.
106+
fn find_partial_paths(
107+
&self, recipient: PublicKey, peers: &[PublicKey]
108+
) -> Result<Vec<Vec<PublicKey>>, ()> {
109+
Ok(peers.iter().map(|hop| vec![*hop, recipient]).collect())
110+
}
99111
}
100112

101113
/// [`Score`] implementation that factors in in-flight HTLC liquidity.

0 commit comments

Comments
 (0)