From f962dfba5c2e65888e54697026dae7c151e7fdbf Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Fri, 3 Mar 2023 09:38:45 -0600 Subject: [PATCH] WIP: Include blinded paths --- lightning/src/blinded_path/mod.rs | 6 ++--- lightning/src/ln/channelmanager.rs | 42 +++++++++++++++++++++++++++--- lightning/src/routing/router.rs | 12 +++++++++ 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/lightning/src/blinded_path/mod.rs b/lightning/src/blinded_path/mod.rs index 989cfbee00f..b11e3b77dab 100644 --- a/lightning/src/blinded_path/mod.rs +++ b/lightning/src/blinded_path/mod.rs @@ -64,9 +64,9 @@ impl BlindedPath { /// /// Errors if less than two hops are provided or if `node_pk`(s) are invalid. // TODO: make all payloads the same size with padding + add dummy hops - pub fn new_for_message - (node_pks: &[PublicKey], entropy_source: &ES, secp_ctx: &Secp256k1) -> Result - { + pub fn new_for_message( + node_pks: &[PublicKey], entropy_source: ES, secp_ctx: &Secp256k1 + ) -> Result where ES::Target: EntropySource { if node_pks.len() < 2 { return Err(()) } let blinding_secret_bytes = entropy_source.get_secure_random_bytes(); let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted"); diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 080249a6ae2..70a38acdb0b 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -30,6 +30,7 @@ use bitcoin::secp256k1::{SecretKey,PublicKey}; use bitcoin::secp256k1::Secp256k1; use bitcoin::{LockTime, secp256k1, Sequence}; +use crate::blinded_path::BlindedPath; use crate::chain; use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock}; use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator}; @@ -6353,6 +6354,10 @@ where /// Creates an [`OfferBuilder`] such that the [`Offer`] it builds is recognized by the /// [`ChannelManager`] when handling [`InvoiceRequest`] messages for the offer. /// + /// Uses [`Router::find_partial_paths`] to construct a [`BlindedPath`] for the offer. If one is + /// found, also uses a derived signing pubkey for recipient privacy. Otherwise, uses the node id + /// as the signing pubkey. + /// /// [`Offer`]: crate::offers::offer::Offer /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest pub fn create_offer_builder( @@ -6362,9 +6367,15 @@ where let expanded_key = &self.inbound_payment_key; let entropy = &*self.entropy_source; let secp_ctx = &self.secp_ctx; + let builder = OfferBuilder::deriving_signing_pubkey( + description, node_id, expanded_key, entropy, secp_ctx + ); - // TODO: Set blinded paths - OfferBuilder::deriving_signing_pubkey(description, node_id, expanded_key, entropy, secp_ctx) + match self.create_blinded_paths(1) { + Ok(paths) if !paths.is_empty() => builder.path(paths.into_iter().next().unwrap()), + // TODO: check if node is public? + Ok(_) | Err(_) => builder, + } } /// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the @@ -6372,6 +6383,10 @@ where /// /// The provided `payment_id` is used to ensure that only one invoice is paid for the refund. /// + /// Uses [`Router::find_partial_paths`] to construct a [`BlindedPath`] for the refund. If one is + /// found, also uses a derived payer id for sender privacy. Otherwise, uses the node id as the + /// payer id. + /// /// [`Refund`]: crate::offers::refund::Refund /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice pub fn create_refund_builder( @@ -6382,10 +6397,14 @@ where let entropy = &*self.entropy_source; let secp_ctx = &self.secp_ctx; - // TODO: Set blinded paths let builder = RefundBuilder::deriving_payer_id( description, node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id )?; + let builder = match self.create_blinded_paths(1) { + Ok(paths) if !paths.is_empty() => builder.path(paths.into_iter().next().unwrap()), + // TODO: check if node is public? + Ok(_) | Err(_) => builder, + }; self.pending_outbound_payments .add_new_awaiting_invoice(payment_id) .map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?; @@ -6518,6 +6537,23 @@ where inbound_payment::get_payment_preimage(payment_hash, payment_secret, &self.inbound_payment_key) } + /// + fn create_blinded_paths(&self, count: usize) -> Result, ()> { + let last_hops = self.per_peer_state.read().unwrap().iter() + .filter(|(_, peer)| peer.lock().unwrap().latest_features.supports_route_blinding()) + .map(|(node_id, _)| *node_id) + .collect::>(); + let entropy_source = self.entropy_source.deref(); + let secp_ctx = &self.secp_ctx; + + self.router + .find_partial_paths(self.get_our_node_id(), last_hops.as_slice())? + .into_iter() + .map(|node_pks| BlindedPath::new_for_message(&node_pks[..], entropy_source, secp_ctx)) + .take(count) + .collect() + } + /// Gets a fake short channel id for use in receiving [phantom node payments]. These fake scids /// are used when constructing the phantom invoice's route hints. /// diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 3419f122e7d..6e06cf958f1 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -90,6 +90,7 @@ pub trait Router { &self, payer: &PublicKey, route_params: &RouteParameters, first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InFlightHtlcs ) -> Result; + /// Finds a [`Route`] for a payment between the given `payer` and a payee. /// /// The `payee` and the payment's value are given in [`RouteParameters::payment_params`] @@ -104,6 +105,17 @@ pub trait Router { ) -> Result { self.find_route(payer, route_params, first_hops, inflight_htlcs) } + + /// Finds partial paths to the `recipient` node for creating `BlindedPath`s. The nodes in + /// `peers` are assumed to be direct peers with the `recipient`. + /// + /// The default implementation returns two-node paths for each node in `peers` with the + /// `recipient` node. + fn find_partial_paths( + &self, recipient: PublicKey, peers: &[PublicKey] + ) -> Result>, ()> { + Ok(peers.iter().map(|hop| vec![*hop, recipient]).collect()) + } } /// [`Score`] implementation that factors in in-flight HTLC liquidity.