Skip to content

Commit

Permalink
Introduce a Unified Function Flow for Creating Blinded Paths
Browse files Browse the repository at this point in the history
This refactor simplifies the codebase while ensuring that
the existing functionality is maintained.
  • Loading branch information
shaavan committed Sep 19, 2024
1 parent 9a981c1 commit 4014246
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 172 deletions.
8 changes: 5 additions & 3 deletions fuzz/src/chanmon_consistency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ use lightning::ln::script::ShutdownScript;
use lightning::ln::types::{ChannelId, PaymentHash, PaymentPreimage, PaymentSecret};
use lightning::offers::invoice::UnsignedBolt12Invoice;
use lightning::offers::invoice_request::UnsignedInvoiceRequest;
use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath};
use lightning::onion_message::messenger::{
BlindedPathType, Destination, MessageRouter, OnionMessagePath,
};
use lightning::routing::router::{InFlightHtlcs, Path, Route, RouteHop, RouteParameters, Router};
use lightning::sign::{
EntropySource, InMemorySigner, KeyMaterial, NodeSigner, Recipient, SignerProvider,
Expand Down Expand Up @@ -141,8 +143,8 @@ impl MessageRouter for FuzzRouter {
}

fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
_secp_ctx: &Secp256k1<T>,
&self, _recipient: PublicKey, _context: MessageContext, _blinded_path: BlindedPathType,
_peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedMessagePath>, ()> {
unreachable!()
}
Expand Down
8 changes: 5 additions & 3 deletions fuzz/src/full_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ use lightning::ln::script::ShutdownScript;
use lightning::ln::types::{ChannelId, PaymentHash, PaymentPreimage, PaymentSecret};
use lightning::offers::invoice::UnsignedBolt12Invoice;
use lightning::offers::invoice_request::UnsignedInvoiceRequest;
use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath};
use lightning::onion_message::messenger::{
BlindedPathType, Destination, MessageRouter, OnionMessagePath,
};
use lightning::routing::gossip::{NetworkGraph, P2PGossipSync};
use lightning::routing::router::{
InFlightHtlcs, PaymentParameters, Route, RouteParameters, Router,
Expand Down Expand Up @@ -176,8 +178,8 @@ impl MessageRouter for FuzzRouter {
}

fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
_secp_ctx: &Secp256k1<T>,
&self, _recipient: PublicKey, _context: MessageContext, _blinded_path: BlindedPathType,
_peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedMessagePath>, ()> {
unreachable!()
}
Expand Down
8 changes: 4 additions & 4 deletions fuzz/src/onion_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ use lightning::onion_message::async_payments::{
AsyncPaymentsMessageHandler, HeldHtlcAvailable, ReleaseHeldHtlc,
};
use lightning::onion_message::messenger::{
CustomOnionMessageHandler, Destination, MessageRouter, MessageSendInstructions,
OnionMessagePath, OnionMessenger, Responder, ResponseInstruction,
BlindedPathType, CustomOnionMessageHandler, Destination, MessageRouter,
MessageSendInstructions, OnionMessagePath, OnionMessenger, Responder, ResponseInstruction,
};
use lightning::onion_message::offers::{OffersMessage, OffersMessageHandler};
use lightning::onion_message::packet::OnionMessageContents;
Expand Down Expand Up @@ -98,8 +98,8 @@ impl MessageRouter for TestMessageRouter {
}

fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
_secp_ctx: &Secp256k1<T>,
&self, _recipient: PublicKey, _context: MessageContext, _blinded_path: BlindedPathType,
_peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedMessagePath>, ()> {
unreachable!()
}
Expand Down
98 changes: 27 additions & 71 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2554,9 +2554,7 @@ const MAX_NO_CHANNEL_PEERS: usize = 250;
/// short-lived, while anything with a greater expiration is considered long-lived.
///
/// Using [`ChannelManager::create_offer_builder`] or [`ChannelManager::create_refund_builder`],
/// will included a [`BlindedMessagePath`] created using:
/// - [`MessageRouter::create_compact_blinded_paths`] when short-lived, and
/// - [`MessageRouter::create_blinded_paths`] when long-lived.
/// will included a [`BlindedMessagePath`] created using [`MessageRouter::create_blinded_paths`].
///
/// Using compact [`BlindedMessagePath`]s may provide better privacy as the [`MessageRouter`] could select
/// more hops. However, since they use short channel ids instead of pubkeys, they are more likely to
Expand Down Expand Up @@ -9042,21 +9040,9 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
let nonce = Nonce::from_entropy_source(entropy);
let context = OffersContext::InvoiceRequest { nonce };
let builder = match blinded_path {
Some(BlindedPathType::Compact) => {
Some(blinded_path) => {
let path = $self
.create_compact_blinded_paths(context)
.and_then(|paths| paths.into_iter().next().ok_or(()))
.map_err(|_| Bolt12SemanticError::MissingPaths)?;

OfferBuilder::deriving_signing_pubkey(node_id, expanded_key, nonce, secp_ctx)
.chain_hash($self.chain_hash)
.path(path)
}

Some(BlindedPathType::Full) => {
let context = MessageContext::Offers(context);
let path = $self
.create_blinded_paths(context)
.create_blinded_paths(context, blinded_path)
.and_then(|paths| paths.into_iter().next().ok_or(()))
.map_err(|_| Bolt12SemanticError::MissingPaths)?;

Expand Down Expand Up @@ -9132,25 +9118,9 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
let context = OffersContext::OutboundPayment { payment_id, nonce, hmac: None };

let builder = match blinded_path {
Some(BlindedPathType::Compact) => {
let path = $self
.create_compact_blinded_paths(context)
.and_then(|paths| paths.into_iter().next().ok_or(()))
.map_err(|_| Bolt12SemanticError::MissingPaths)?;

RefundBuilder::deriving_signing_pubkey(
node_id, expanded_key, nonce, secp_ctx,
amount_msats, payment_id,
)?
.chain_hash($self.chain_hash)
.absolute_expiry(absolute_expiry)
.path(path)
}

Some(BlindedPathType::Full) => {
let context = MessageContext::Offers(context);
Some(blinded_path) => {
let path = $self
.create_blinded_paths(context)
.create_blinded_paths(context, blinded_path)
.and_then(|paths| paths.into_iter().next().ok_or(()))
.map_err(|_| Bolt12SemanticError::MissingPaths)?;

Expand Down Expand Up @@ -9299,7 +9269,7 @@ where
let context = MessageContext::Offers(
OffersContext::OutboundPayment { payment_id, nonce, hmac: Some(hmac) }
);
let reply_paths = self.create_blinded_paths(context)
let reply_paths = self.create_blinded_paths(context, BlindedPathType::Full)
.map_err(|_| Bolt12SemanticError::MissingPaths)?;

let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
Expand Down Expand Up @@ -9421,7 +9391,7 @@ where
let context = MessageContext::Offers(OffersContext::InboundPayment {
payment_hash: invoice.payment_hash(), nonce, hmac
});
let reply_paths = self.create_blinded_paths(context)
let reply_paths = self.create_blinded_paths(context, BlindedPathType::Full)
.map_err(|_| Bolt12SemanticError::MissingPaths)?;

let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
Expand Down Expand Up @@ -9571,7 +9541,7 @@ where
/// [`MessageRouter::create_blinded_paths`].
///
/// Errors if the `MessageRouter` errors.
fn create_blinded_paths(&self, context: MessageContext) -> Result<Vec<BlindedMessagePath>, ()> {
fn create_blinded_paths(&self, context: MessageContext, blinded_path: BlindedPathType) -> Result<Vec<BlindedMessagePath>, ()> {
let recipient = self.get_our_node_id();
let secp_ctx = &self.secp_ctx;

Expand All @@ -9580,44 +9550,30 @@ where
.map(|(node_id, peer_state)| (node_id, peer_state.lock().unwrap()))
.filter(|(_, peer)| peer.is_connected)
.filter(|(_, peer)| peer.latest_features.supports_onion_messages())
.map(|(node_id, _)| {
MessageForwardNode {
node_id: *node_id,
short_channel_id: None,
.map(|(node_id, peer)| {
match blinded_path {
BlindedPathType::Full => {
MessageForwardNode {
node_id: *node_id,
short_channel_id: None,
}
}
BlindedPathType::Compact => {
MessageForwardNode {
node_id: *node_id,
short_channel_id: peer.channel_by_id
.iter()
.filter(|(_, channel)| channel.context().is_usable())
.min_by_key(|(_, channel)| channel.context().channel_creation_height)
.and_then(|(_, channel)| channel.context().get_short_channel_id()),
}
}
}
})
.collect::<Vec<_>>();

self.router
.create_blinded_paths(recipient, context, peers, secp_ctx)
.and_then(|paths| (!paths.is_empty()).then(|| paths).ok_or(()))
}

/// Creates a collection of blinded paths by delegating to
/// [`MessageRouter::create_compact_blinded_paths`].
///
/// Errors if the `MessageRouter` errors.
fn create_compact_blinded_paths(&self, context: OffersContext) -> Result<Vec<BlindedMessagePath>, ()> {
let recipient = self.get_our_node_id();
let secp_ctx = &self.secp_ctx;

let peers = self.per_peer_state.read().unwrap()
.iter()
.map(|(node_id, peer_state)| (node_id, peer_state.lock().unwrap()))
.filter(|(_, peer)| peer.is_connected)
.filter(|(_, peer)| peer.latest_features.supports_onion_messages())
.map(|(node_id, peer)| MessageForwardNode {
node_id: *node_id,
short_channel_id: peer.channel_by_id
.iter()
.filter(|(_, channel)| channel.context().is_usable())
.min_by_key(|(_, channel)| channel.context().channel_creation_height)
.and_then(|(_, channel)| channel.context().get_short_channel_id()),
})
.collect::<Vec<_>>();

self.router
.create_compact_blinded_paths(recipient, MessageContext::Offers(context), peers, secp_ctx)
.create_blinded_paths(recipient, MessageContext::Offers(context), blinded_path, peers, secp_ctx)
.and_then(|paths| (!paths.is_empty()).then(|| paths).ok_or(()))
}

Expand Down
81 changes: 22 additions & 59 deletions lightning/src/onion_message/messenger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ for OnionMessenger<ES, NS, L, NL, MR, OMH, APH, CMH> where
/// # use lightning::blinded_path::message::{BlindedMessagePath, MessageForwardNode, MessageContext};
/// # use lightning::sign::{EntropySource, KeysManager};
/// # use lightning::ln::peer_handler::IgnoringMessageHandler;
/// # use lightning::onion_message::messenger::{Destination, MessageRouter, MessageSendInstructions, OnionMessagePath, OnionMessenger};
/// # use lightning::onion_message::messenger::{BlindedPathType, Destination, MessageRouter, MessageSendInstructions, OnionMessagePath, OnionMessenger};
/// # use lightning::onion_message::packet::OnionMessageContents;
/// # use lightning::util::logger::{Logger, Record};
/// # use lightning::util::ser::{Writeable, Writer};
Expand All @@ -175,7 +175,7 @@ for OnionMessenger<ES, NS, L, NL, MR, OMH, APH, CMH> where
/// # })
/// # }
/// # fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
/// # &self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<MessageForwardNode>, _secp_ctx: &Secp256k1<T>
/// # &self, _recipient: PublicKey, _context: MessageContext, _blinded_path: BlindedPathType, _peers: Vec<MessageForwardNode>, _secp_ctx: &Secp256k1<T>
/// # ) -> Result<Vec<BlindedMessagePath>, ()> {
/// # unreachable!()
/// # }
Expand Down Expand Up @@ -449,14 +449,9 @@ pub trait MessageRouter {

/// Creates [`BlindedMessagePath`]s to the `recipient` node. The nodes in `peers` are assumed to
/// be direct peers with the `recipient`.
fn create_blinded_paths<
T: secp256k1::Signing + secp256k1::Verification
>(
&self, recipient: PublicKey, context: MessageContext, peers: Vec<MessageForwardNode>, secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedMessagePath>, ()>;

/// Creates compact [`BlindedMessagePath`]s to the `recipient` node. The nodes in `peers` are
/// assumed to be direct peers with the `recipient`.
///
/// # Note of compact blinded path:
/// User can decide to create compact blinded path by specifying the appropirate [`BlindedPathType`].
///
/// Compact blinded paths use short channel ids instead of pubkeys for a smaller serialization,
/// which is beneficial when a QR code is used to transport the data. The SCID is passed using
Expand All @@ -465,24 +460,12 @@ pub trait MessageRouter {
/// Implementations using additional intermediate nodes are responsible for using a
/// [`MessageForwardNode`] with `Some` short channel id, if possible. Similarly, implementations
/// should call [`BlindedMessagePath::use_compact_introduction_node`].
///
/// The provided implementation simply delegates to [`MessageRouter::create_blinded_paths`],
/// ignoring the short channel ids.
fn create_compact_blinded_paths<
fn create_blinded_paths<
T: secp256k1::Signing + secp256k1::Verification
>(
&self, recipient: PublicKey, context: MessageContext,
&self, recipient: PublicKey, context: MessageContext, blinded_path: BlindedPathType,
peers: Vec<MessageForwardNode>, secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedMessagePath>, ()> {
let peers = peers
.into_iter()
.map(|mut node| {
node.short_channel_id = None;
node
})
.collect();
self.create_blinded_paths(recipient, context, peers, secp_ctx)
}
) -> Result<Vec<BlindedMessagePath>, ()>;
}

/// A [`MessageRouter`] that can only route to a directly connected [`Destination`].
Expand Down Expand Up @@ -516,8 +499,8 @@ where
I: ExactSizeIterator<Item = MessageForwardNode>,
T: secp256k1::Signing + secp256k1::Verification
>(
network_graph: &G, recipient: PublicKey, context: MessageContext, peers: I,
entropy_source: &ES, secp_ctx: &Secp256k1<T>, compact_paths: bool,
network_graph: &G, recipient: PublicKey, context: MessageContext, blinded_path: BlindedPathType,
peers: I, entropy_source: &ES, secp_ctx: &Secp256k1<T>
) -> Result<Vec<BlindedMessagePath>, ()> {
// Limit the number of blinded paths that are computed.
const MAX_PATHS: usize = 3;
Expand Down Expand Up @@ -573,10 +556,13 @@ where
},
}?;

if compact_paths {
for path in &mut paths {
path.use_compact_introduction_node(&network_graph);
match blinded_path {
BlindedPathType::Compact => {
for path in &mut paths {
path.use_compact_introduction_node(&network_graph);
}
}
BlindedPathType::Full => {}
}

Ok(paths)
Expand Down Expand Up @@ -618,25 +604,10 @@ where
pub(crate) fn create_blinded_paths<
T: secp256k1::Signing + secp256k1::Verification
>(
network_graph: &G, recipient: PublicKey, context: MessageContext,
network_graph: &G, recipient: PublicKey, context: MessageContext, blinded_path: BlindedPathType,
peers: Vec<MessageForwardNode>, entropy_source: &ES, secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedMessagePath>, ()> {
let peers = peers
.into_iter()
.map(|mut node| {
node.short_channel_id = None;
node
});
Self::create_blinded_paths_from_iter(network_graph, recipient, context, peers.into_iter(), entropy_source, secp_ctx, false)
}

pub(crate) fn create_compact_blinded_paths<
T: secp256k1::Signing + secp256k1::Verification
>(
network_graph: &G, recipient: PublicKey, context: MessageContext,
peers: Vec<MessageForwardNode>, entropy_source: &ES, secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedMessagePath>, ()> {
Self::create_blinded_paths_from_iter(network_graph, recipient, context, peers.into_iter(), entropy_source, secp_ctx, true)
Self::create_blinded_paths_from_iter(network_graph, recipient, context, blinded_path, peers.into_iter(), entropy_source, secp_ctx)
}
}

Expand All @@ -654,19 +625,11 @@ where
fn create_blinded_paths<
T: secp256k1::Signing + secp256k1::Verification
>(
&self, recipient: PublicKey, context: MessageContext, peers: Vec<MessageForwardNode>, secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedMessagePath>, ()> {
Self::create_blinded_paths(&self.network_graph, recipient, context, peers, &self.entropy_source, secp_ctx)
}

fn create_compact_blinded_paths<
T: secp256k1::Signing + secp256k1::Verification
>(
&self, recipient: PublicKey, context: MessageContext, peers: Vec<MessageForwardNode>, secp_ctx: &Secp256k1<T>,
&self, recipient: PublicKey, context: MessageContext, blinded_path: BlindedPathType,
peers: Vec<MessageForwardNode>, secp_ctx: &Secp256k1<T>,
) -> Result<Vec<BlindedMessagePath>, ()> {
Self::create_compact_blinded_paths(&self.network_graph, recipient, context, peers, &self.entropy_source, secp_ctx)
Self::create_blinded_paths(&self.network_graph, recipient, context, blinded_path, peers, &self.entropy_source, secp_ctx)
}

}

/// A path for sending an [`OnionMessage`].
Expand Down Expand Up @@ -1270,7 +1233,7 @@ where
.collect::<Vec<_>>();

self.message_router
.create_blinded_paths(recipient, context, peers, secp_ctx)
.create_blinded_paths(recipient, context, BlindedPathType::Full, peers, secp_ctx)
.and_then(|paths| paths.into_iter().next().ok_or(()))
.map_err(|_| SendError::PathNotFound)
}
Expand Down
Loading

0 comments on commit 4014246

Please sign in to comment.