mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-01-19 05:43:55 +01:00
Multi-hop blinded paths in ChannelManager
When constructing blinded paths for Offer and Refund, delegate to MessageRouter::create_blinded_paths which may produce multi-hop blinded paths. Fallback to one-hop blinded paths if the MessageRouter fails or returns no paths. Likewise, do the same for InvoiceRequest and Bolt12Invoice reply paths.
This commit is contained in:
parent
dcd8d58346
commit
606304aa32
@ -65,7 +65,7 @@ use crate::offers::merkle::SignError;
|
|||||||
use crate::offers::offer::{DerivedMetadata, Offer, OfferBuilder};
|
use crate::offers::offer::{DerivedMetadata, Offer, OfferBuilder};
|
||||||
use crate::offers::parse::Bolt12SemanticError;
|
use crate::offers::parse::Bolt12SemanticError;
|
||||||
use crate::offers::refund::{Refund, RefundBuilder};
|
use crate::offers::refund::{Refund, RefundBuilder};
|
||||||
use crate::onion_message::{Destination, OffersMessage, OffersMessageHandler, PendingOnionMessage, new_pending_onion_message};
|
use crate::onion_message::{Destination, MessageRouter, OffersMessage, OffersMessageHandler, PendingOnionMessage, new_pending_onion_message};
|
||||||
use crate::sign::{EntropySource, KeysManager, NodeSigner, Recipient, SignerProvider};
|
use crate::sign::{EntropySource, KeysManager, NodeSigner, Recipient, SignerProvider};
|
||||||
use crate::sign::ecdsa::WriteableEcdsaChannelSigner;
|
use crate::sign::ecdsa::WriteableEcdsaChannelSigner;
|
||||||
use crate::util::config::{UserConfig, ChannelConfig, ChannelConfigUpdate};
|
use crate::util::config::{UserConfig, ChannelConfig, ChannelConfigUpdate};
|
||||||
@ -7483,32 +7483,43 @@ where
|
|||||||
///
|
///
|
||||||
/// # Privacy
|
/// # Privacy
|
||||||
///
|
///
|
||||||
/// Uses a one-hop [`BlindedPath`] for the offer with [`ChannelManager::get_our_node_id`] as the
|
/// Uses [`MessageRouter::create_blinded_paths`] to construct a [`BlindedPath`] for the offer.
|
||||||
/// introduction node and a derived signing pubkey for recipient privacy. As such, currently,
|
/// However, if one is not found, uses a one-hop [`BlindedPath`] with
|
||||||
/// the node must be announced. Otherwise, there is no way to find a path to the introduction
|
/// [`ChannelManager::get_our_node_id`] as the introduction node instead. In the latter case,
|
||||||
/// node in order to send the [`InvoiceRequest`].
|
/// the node must be announced, otherwise, there is no way to find a path to the introduction in
|
||||||
|
/// order to send the [`InvoiceRequest`].
|
||||||
|
///
|
||||||
|
/// Also, uses a derived signing pubkey in the offer for recipient privacy.
|
||||||
///
|
///
|
||||||
/// # Limitations
|
/// # Limitations
|
||||||
///
|
///
|
||||||
/// Requires a direct connection to the introduction node in the responding [`InvoiceRequest`]'s
|
/// Requires a direct connection to the introduction node in the responding [`InvoiceRequest`]'s
|
||||||
/// reply path.
|
/// reply path.
|
||||||
///
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Errors if the parameterized [`Router`] is unable to create a blinded path for the offer.
|
||||||
|
///
|
||||||
/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
|
/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
|
||||||
///
|
///
|
||||||
/// [`Offer`]: crate::offers::offer::Offer
|
/// [`Offer`]: crate::offers::offer::Offer
|
||||||
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
|
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
|
||||||
pub fn create_offer_builder(
|
pub fn create_offer_builder(
|
||||||
&self, description: String
|
&self, description: String
|
||||||
) -> OfferBuilder<DerivedMetadata, secp256k1::All> {
|
) -> Result<OfferBuilder<DerivedMetadata, secp256k1::All>, Bolt12SemanticError> {
|
||||||
let node_id = self.get_our_node_id();
|
let node_id = self.get_our_node_id();
|
||||||
let expanded_key = &self.inbound_payment_key;
|
let expanded_key = &self.inbound_payment_key;
|
||||||
let entropy = &*self.entropy_source;
|
let entropy = &*self.entropy_source;
|
||||||
let secp_ctx = &self.secp_ctx;
|
let secp_ctx = &self.secp_ctx;
|
||||||
let path = self.create_one_hop_blinded_path();
|
|
||||||
|
|
||||||
OfferBuilder::deriving_signing_pubkey(description, node_id, expanded_key, entropy, secp_ctx)
|
let path = self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
|
||||||
|
let builder = OfferBuilder::deriving_signing_pubkey(
|
||||||
|
description, node_id, expanded_key, entropy, secp_ctx
|
||||||
|
)
|
||||||
.chain_hash(self.chain_hash)
|
.chain_hash(self.chain_hash)
|
||||||
.path(path)
|
.path(path);
|
||||||
|
|
||||||
|
Ok(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
|
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
|
||||||
@ -7533,10 +7544,13 @@ where
|
|||||||
///
|
///
|
||||||
/// # Privacy
|
/// # Privacy
|
||||||
///
|
///
|
||||||
/// Uses a one-hop [`BlindedPath`] for the refund with [`ChannelManager::get_our_node_id`] as
|
/// Uses [`MessageRouter::create_blinded_paths`] to construct a [`BlindedPath`] for the refund.
|
||||||
/// the introduction node and a derived payer id for payer privacy. As such, currently, the
|
/// However, if one is not found, uses a one-hop [`BlindedPath`] with
|
||||||
/// node must be announced. Otherwise, there is no way to find a path to the introduction node
|
/// [`ChannelManager::get_our_node_id`] as the introduction node instead. In the latter case,
|
||||||
/// in order to send the [`Bolt12Invoice`].
|
/// the node must be announced, otherwise, there is no way to find a path to the introduction in
|
||||||
|
/// order to send the [`Bolt12Invoice`].
|
||||||
|
///
|
||||||
|
/// Also, uses a derived payer id in the refund for payer privacy.
|
||||||
///
|
///
|
||||||
/// # Limitations
|
/// # Limitations
|
||||||
///
|
///
|
||||||
@ -7545,8 +7559,10 @@ where
|
|||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Errors if a duplicate `payment_id` is provided given the caveats in the aforementioned link
|
/// Errors if:
|
||||||
/// or if `amount_msats` is invalid.
|
/// - a duplicate `payment_id` is provided given the caveats in the aforementioned link,
|
||||||
|
/// - `amount_msats` is invalid, or
|
||||||
|
/// - the parameterized [`Router`] is unable to create a blinded path for the refund.
|
||||||
///
|
///
|
||||||
/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
|
/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
|
||||||
///
|
///
|
||||||
@ -7561,8 +7577,8 @@ where
|
|||||||
let expanded_key = &self.inbound_payment_key;
|
let expanded_key = &self.inbound_payment_key;
|
||||||
let entropy = &*self.entropy_source;
|
let entropy = &*self.entropy_source;
|
||||||
let secp_ctx = &self.secp_ctx;
|
let secp_ctx = &self.secp_ctx;
|
||||||
let path = self.create_one_hop_blinded_path();
|
|
||||||
|
|
||||||
|
let path = self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
|
||||||
let builder = RefundBuilder::deriving_payer_id(
|
let builder = RefundBuilder::deriving_payer_id(
|
||||||
description, node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
|
description, node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
|
||||||
)?
|
)?
|
||||||
@ -7620,8 +7636,11 @@ where
|
|||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Errors if a duplicate `payment_id` is provided given the caveats in the aforementioned link
|
/// Errors if:
|
||||||
/// or if the provided parameters are invalid for the offer.
|
/// - a duplicate `payment_id` is provided given the caveats in the aforementioned link,
|
||||||
|
/// - the provided parameters are invalid for the offer,
|
||||||
|
/// - the parameterized [`Router`] is unable to create a blinded reply path for the invoice
|
||||||
|
/// request.
|
||||||
///
|
///
|
||||||
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
|
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
|
||||||
/// [`InvoiceRequest::quantity`]: crate::offers::invoice_request::InvoiceRequest::quantity
|
/// [`InvoiceRequest::quantity`]: crate::offers::invoice_request::InvoiceRequest::quantity
|
||||||
@ -7654,9 +7673,8 @@ where
|
|||||||
None => builder,
|
None => builder,
|
||||||
Some(payer_note) => builder.payer_note(payer_note),
|
Some(payer_note) => builder.payer_note(payer_note),
|
||||||
};
|
};
|
||||||
|
|
||||||
let invoice_request = builder.build_and_sign()?;
|
let invoice_request = builder.build_and_sign()?;
|
||||||
let reply_path = self.create_one_hop_blinded_path();
|
let reply_path = self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
|
||||||
|
|
||||||
let expiration = StaleExpiration::TimerTicks(1);
|
let expiration = StaleExpiration::TimerTicks(1);
|
||||||
self.pending_outbound_payments
|
self.pending_outbound_payments
|
||||||
@ -7732,7 +7750,8 @@ where
|
|||||||
payment_paths, payment_hash, created_at, expanded_key, entropy
|
payment_paths, payment_hash, created_at, expanded_key, entropy
|
||||||
)?;
|
)?;
|
||||||
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
|
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
|
||||||
let reply_path = self.create_one_hop_blinded_path();
|
let reply_path = self.create_blinded_path()
|
||||||
|
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
|
||||||
|
|
||||||
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
|
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
|
||||||
if refund.paths().is_empty() {
|
if refund.paths().is_empty() {
|
||||||
@ -7859,12 +7878,23 @@ where
|
|||||||
inbound_payment::get_payment_preimage(payment_hash, payment_secret, &self.inbound_payment_key)
|
inbound_payment::get_payment_preimage(payment_hash, payment_secret, &self.inbound_payment_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a one-hop blinded path with [`ChannelManager::get_our_node_id`] as the introduction
|
/// Creates a blinded path by delegating to [`MessageRouter::create_blinded_paths`].
|
||||||
/// node.
|
///
|
||||||
fn create_one_hop_blinded_path(&self) -> BlindedPath {
|
/// Errors if the `MessageRouter` errors or returns an empty `Vec`.
|
||||||
|
fn create_blinded_path(&self) -> Result<BlindedPath, ()> {
|
||||||
|
let recipient = self.get_our_node_id();
|
||||||
let entropy_source = self.entropy_source.deref();
|
let entropy_source = self.entropy_source.deref();
|
||||||
let secp_ctx = &self.secp_ctx;
|
let secp_ctx = &self.secp_ctx;
|
||||||
BlindedPath::one_hop_for_message(self.get_our_node_id(), entropy_source, secp_ctx).unwrap()
|
|
||||||
|
let peers = self.per_peer_state.read().unwrap()
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, peer)| peer.lock().unwrap().latest_features.supports_onion_messages())
|
||||||
|
.map(|(node_id, _)| *node_id)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
self.router
|
||||||
|
.create_blinded_paths(recipient, peers, entropy_source, secp_ctx)
|
||||||
|
.and_then(|paths| paths.into_iter().next().ok_or(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a one-hop blinded payment path with [`ChannelManager::get_our_node_id`] as the
|
/// Creates a one-hop blinded payment path with [`ChannelManager::get_our_node_id`] as the
|
||||||
|
Loading…
Reference in New Issue
Block a user