Skip to content

Commit 082f6e9

Browse files
committed
WIP: Include blinded paths
1 parent cf883b5 commit 082f6e9

File tree

3 files changed

+55
-6
lines changed

3 files changed

+55
-6
lines changed

lightning/src/blinded_path/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub(crate) mod utils;
1515

1616
use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
1717

18+
use core::ops::Deref;
1819
use crate::sign::EntropySource;
1920
use crate::ln::msgs::DecodeError;
2021
use crate::util::ser::{Readable, Writeable, Writer};
@@ -60,9 +61,9 @@ impl BlindedPath {
6061
///
6162
/// Errors if less than two hops are provided or if `node_pk`(s) are invalid.
6263
// TODO: make all payloads the same size with padding + add dummy hops
63-
pub fn new_for_message<ES: EntropySource, T: secp256k1::Signing + secp256k1::Verification>
64-
(node_pks: &[PublicKey], entropy_source: &ES, secp_ctx: &Secp256k1<T>) -> Result<Self, ()>
65-
{
64+
pub fn new_for_message<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
65+
node_pks: &[PublicKey], entropy_source: ES, secp_ctx: &Secp256k1<T>
66+
) -> Result<Self, ()> where ES::Target: EntropySource {
6667
if node_pks.len() < 2 { return Err(()) }
6768
let blinding_secret_bytes = entropy_source.get_secure_random_bytes();
6869
let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted");

lightning/src/ln/channelmanager.rs

Lines changed: 39 additions & 3 deletions
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};
@@ -6585,6 +6586,10 @@ where
65856586
/// Creates an [`OfferBuilder`] such that the [`Offer`] it builds is recognized by the
65866587
/// [`ChannelManager`] when handling [`InvoiceRequest`] messages for the offer.
65876588
///
6589+
/// Uses [`Router::find_partial_paths`] to construct a [`BlindedPath`] for the offer. If one is
6590+
/// found, also uses a derived signing pubkey for recipient privacy. Otherwise, uses the node id
6591+
/// as the signing pubkey.
6592+
///
65886593
/// [`Offer`]: crate::offers::offer::Offer
65896594
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
65906595
pub fn create_offer_builder(
@@ -6594,16 +6599,26 @@ where
65946599
let expanded_key = &self.inbound_payment_key;
65956600
let entropy = &*self.entropy_source;
65966601
let secp_ctx = &self.secp_ctx;
6602+
let builder = OfferBuilder::deriving_signing_pubkey(
6603+
description, node_id, expanded_key, entropy, secp_ctx
6604+
);
65976605

6598-
// TODO: Set blinded paths
6599-
OfferBuilder::deriving_signing_pubkey(description, node_id, expanded_key, entropy, secp_ctx)
6606+
match self.create_blinded_paths(1) {
6607+
Ok(paths) if !paths.is_empty() => builder.path(paths.into_iter().next().unwrap()),
6608+
// TODO: check if node is public?
6609+
Ok(_) | Err(_) => builder,
6610+
}
66006611
}
66016612

66026613
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
66036614
/// [`ChannelManager`] when handling [`Bolt12Invoice`] messages for the refund.
66046615
///
66056616
/// The provided `payment_id` is used to ensure that only one invoice is paid for the refund.
66066617
///
6618+
/// Uses [`Router::find_partial_paths`] to construct a [`BlindedPath`] for the refund. If one is
6619+
/// found, also uses a derived payer id for sender privacy. Otherwise, uses the node id as the
6620+
/// payer id.
6621+
///
66076622
/// [`Refund`]: crate::offers::refund::Refund
66086623
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
66096624
pub fn create_refund_builder(
@@ -6614,10 +6629,14 @@ where
66146629
let entropy = &*self.entropy_source;
66156630
let secp_ctx = &self.secp_ctx;
66166631

6617-
// TODO: Set blinded paths
66186632
let builder = RefundBuilder::deriving_payer_id(
66196633
description, node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
66206634
)?;
6635+
let builder = match self.create_blinded_paths(1) {
6636+
Ok(paths) if !paths.is_empty() => builder.path(paths.into_iter().next().unwrap()),
6637+
// TODO: check if node is public?
6638+
Ok(_) | Err(_) => builder,
6639+
};
66216640
self.pending_outbound_payments
66226641
.add_new_awaiting_invoice(payment_id)
66236642
.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
@@ -6750,6 +6769,23 @@ where
67506769
inbound_payment::get_payment_preimage(payment_hash, payment_secret, &self.inbound_payment_key)
67516770
}
67526771

6772+
///
6773+
fn create_blinded_paths(&self, count: usize) -> Result<Vec<BlindedPath>, ()> {
6774+
let last_hops = self.per_peer_state.read().unwrap().iter()
6775+
.filter(|(_, peer)| peer.lock().unwrap().latest_features.supports_route_blinding())
6776+
.map(|(node_id, _)| *node_id)
6777+
.collect::<Vec<_>>();
6778+
let entropy_source = self.entropy_source.deref();
6779+
let secp_ctx = &self.secp_ctx;
6780+
6781+
self.router
6782+
.find_partial_paths(self.get_our_node_id(), last_hops.as_slice())?
6783+
.into_iter()
6784+
.map(|node_pks| BlindedPath::new_for_message(&node_pks[..], entropy_source, secp_ctx))
6785+
.take(count)
6786+
.collect()
6787+
}
6788+
67536789
/// Gets a fake short channel id for use in receiving [phantom node payments]. These fake scids
67546790
/// are used when constructing the phantom invoice's route hints.
67556791
///

lightning/src/routing/router.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ pub trait Router {
9090
&self, payer: &PublicKey, route_params: &RouteParameters,
9191
first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InFlightHtlcs
9292
) -> Result<Route, LightningError>;
93+
9394
/// Finds a [`Route`] for a payment between the given `payer` and a payee.
9495
///
9596
/// The `payee` and the payment's value are given in [`RouteParameters::payment_params`]
@@ -104,6 +105,17 @@ pub trait Router {
104105
) -> Result<Route, LightningError> {
105106
self.find_route(payer, route_params, first_hops, inflight_htlcs)
106107
}
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+
}
107119
}
108120

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

0 commit comments

Comments
 (0)