Refactor MessageRouter::create_blinded_paths
authorJeffrey Czyz <jkczyz@gmail.com>
Wed, 22 May 2024 20:32:32 +0000 (15:32 -0500)
committerJeffrey Czyz <jkczyz@gmail.com>
Wed, 5 Jun 2024 22:52:30 +0000 (17:52 -0500)
Using compact blinded paths isn't always necessary or desirable. For
instance, reply paths are communicated via onion messages where space
isn't a premium unlike in QR codes. Additionally, long-lived paths could
become invalid if the channel associated with the SCID is closed.
Refactor MessageRouter::create_blinded_paths into two methods: one for
compact blinded paths and one for normal blinded paths.

fuzz/src/chanmon_consistency.rs
fuzz/src/full_stack.rs
fuzz/src/onion_message.rs
lightning/src/ln/channelmanager.rs
lightning/src/onion_message/messenger.rs
lightning/src/routing/router.rs
lightning/src/util/test_utils.rs

index 1bcba1fbf378db62bde396740006bf50b9ca0e4e..1cdf617fa078ba60c87efa971888b98201e1142d 100644 (file)
@@ -34,7 +34,6 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash;
 use bitcoin::hash_types::BlockHash;
 
 use lightning::blinded_path::BlindedPath;
-use lightning::blinded_path::message::ForwardNode;
 use lightning::blinded_path::payment::ReceiveTlvs;
 use lightning::chain;
 use lightning::chain::{BestBlock, ChannelMonitorUpdateStatus, chainmonitor, channelmonitor, Confirm, Watch};
@@ -124,7 +123,7 @@ impl MessageRouter for FuzzRouter {
        }
 
        fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
-               &self, _recipient: PublicKey, _peers: Vec<ForwardNode>, _secp_ctx: &Secp256k1<T>,
+               &self, _recipient: PublicKey, _peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
        ) -> Result<Vec<BlindedPath>, ()> {
                unreachable!()
        }
index 2ae5ba2225d1e1c421739423189a8f413a52fe16..bdd29be9129f9a66a494ba428771c539edebb6f8 100644 (file)
@@ -31,7 +31,6 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash;
 use bitcoin::hash_types::{Txid, BlockHash};
 
 use lightning::blinded_path::BlindedPath;
-use lightning::blinded_path::message::ForwardNode;
 use lightning::blinded_path::payment::ReceiveTlvs;
 use lightning::chain;
 use lightning::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen};
@@ -162,7 +161,7 @@ impl MessageRouter for FuzzRouter {
        }
 
        fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
-               &self, _recipient: PublicKey, _peers: Vec<ForwardNode>, _secp_ctx: &Secp256k1<T>,
+               &self, _recipient: PublicKey, _peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
        ) -> Result<Vec<BlindedPath>, ()> {
                unreachable!()
        }
index 4c1c5ac1122b286689b97bcf7f0980981d37dc7e..371a9421fc7fea7d3348eb4304136ca49a357aa6 100644 (file)
@@ -7,7 +7,6 @@ use bitcoin::secp256k1::ecdsa::RecoverableSignature;
 use bitcoin::secp256k1::schnorr;
 
 use lightning::blinded_path::{BlindedPath, EmptyNodeIdLookUp};
-use lightning::blinded_path::message::ForwardNode;
 use lightning::ln::features::InitFeatures;
 use lightning::ln::msgs::{self, DecodeError, OnionMessageHandler};
 use lightning::ln::script::ShutdownScript;
@@ -89,7 +88,7 @@ impl MessageRouter for TestMessageRouter {
        }
 
        fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
-               &self, _recipient: PublicKey, _peers: Vec<ForwardNode>, _secp_ctx: &Secp256k1<T>,
+               &self, _recipient: PublicKey, _peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
        ) -> Result<Vec<BlindedPath>, ()> {
                unreachable!()
        }
index e3f7243cd3f0bea9030fad8e6c160c874a04befa..69139194194af0b7bb1863b3420f63058ba59b40 100644 (file)
@@ -8245,8 +8245,8 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
        ///
        /// # Privacy
        ///
-       /// Uses [`MessageRouter::create_blinded_paths`] to construct a [`BlindedPath`] for the offer.
-       /// However, if one is not found, uses a one-hop [`BlindedPath`] with
+       /// Uses [`MessageRouter::create_compact_blinded_paths`] to construct a [`BlindedPath`] for the
+       /// offer. However, if one is not found, uses a one-hop [`BlindedPath`] with
        /// [`ChannelManager::get_our_node_id`] as the introduction node instead. In the latter case,
        /// the node must be announced, otherwise, there is no way to find a path to the introduction in
        /// order to send the [`InvoiceRequest`].
@@ -8304,8 +8304,8 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
        ///
        /// # Privacy
        ///
-       /// Uses [`MessageRouter::create_blinded_paths`] to construct a [`BlindedPath`] for the refund.
-       /// However, if one is not found, uses a one-hop [`BlindedPath`] with
+       /// Uses [`MessageRouter::create_compact_blinded_paths`] to construct a [`BlindedPath`] for the
+       /// refund. However, if one is not found, uses a one-hop [`BlindedPath`] with
        /// [`ChannelManager::get_our_node_id`] as the introduction node instead. In the latter case,
        /// the node must be announced, otherwise, there is no way to find a path to the introduction in
        /// order to send the [`Bolt12Invoice`].
@@ -8686,7 +8686,7 @@ where
                inbound_payment::get_payment_preimage(payment_hash, payment_secret, &self.inbound_payment_key)
        }
 
-       /// Creates a blinded path by delegating to [`MessageRouter::create_blinded_paths`].
+       /// Creates a blinded path by delegating to [`MessageRouter::create_compact_blinded_paths`].
        ///
        /// Errors if the `MessageRouter` errors or returns an empty `Vec`.
        fn create_blinded_path(&self) -> Result<BlindedPath, ()> {
@@ -8708,7 +8708,7 @@ where
                        .collect::<Vec<_>>();
 
                self.router
-                       .create_blinded_paths(recipient, peers, secp_ctx)
+                       .create_compact_blinded_paths(recipient, peers, secp_ctx)
                        .and_then(|paths| paths.into_iter().next().ok_or(()))
        }
 
index 5004986632567f10f1b2f37321e2ca5932a8c8fa..5ceb0683c57203396da6612a6e2e7835c4c2f8bc 100644 (file)
@@ -162,7 +162,7 @@ for OnionMessenger<ES, NS, L, NL, MR, OMH, CMH> where
 /// #         })
 /// #     }
 /// #     fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
-/// #         &self, _recipient: PublicKey, _peers: Vec<ForwardNode>, _secp_ctx: &Secp256k1<T>
+/// #         &self, _recipient: PublicKey, _peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>
 /// #     ) -> Result<Vec<BlindedPath>, ()> {
 /// #         unreachable!()
 /// #     }
@@ -426,8 +426,33 @@ pub trait MessageRouter {
        fn create_blinded_paths<
                T: secp256k1::Signing + secp256k1::Verification
        >(
-               &self, recipient: PublicKey, peers: Vec<ForwardNode>, secp_ctx: &Secp256k1<T>,
+               &self, recipient: PublicKey, peers: Vec<PublicKey>, secp_ctx: &Secp256k1<T>,
        ) -> Result<Vec<BlindedPath>, ()>;
+
+       /// Creates compact [`BlindedPath`]s to the `recipient` node. The nodes in `peers` are assumed
+       /// to be direct peers with the `recipient`.
+       ///
+       /// 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 a
+       /// [`ForwardNode`] but may be `None` for graceful degradation.
+       ///
+       /// Implementations using additional intermediate nodes are responsible for using a
+       /// [`ForwardNode`] with `Some` short channel id, if possible. Similarly, implementations should
+       /// call [`BlindedPath::use_compact_introduction_node`].
+       ///
+       /// The provided implementation simply delegates to [`MessageRouter::create_blinded_paths`],
+       /// ignoring the short channel ids.
+       fn create_compact_blinded_paths<
+               T: secp256k1::Signing + secp256k1::Verification
+       >(
+               &self, recipient: PublicKey, peers: Vec<ForwardNode>, secp_ctx: &Secp256k1<T>,
+       ) -> Result<Vec<BlindedPath>, ()> {
+               let peers = peers
+                       .into_iter()
+                       .map(|ForwardNode { node_id, short_channel_id: _ }| node_id)
+                       .collect();
+               self.create_blinded_paths(recipient, peers, secp_ctx)
+       }
 }
 
 /// A [`MessageRouter`] that can only route to a directly connected [`Destination`].
@@ -454,7 +479,7 @@ where
                I: Iterator<Item = ForwardNode>,
                T: secp256k1::Signing + secp256k1::Verification
        >(
-               &self, recipient: PublicKey, peers: I, secp_ctx: &Secp256k1<T>,
+               &self, recipient: PublicKey, peers: I, secp_ctx: &Secp256k1<T>, compact_paths: bool
        ) -> Result<Vec<BlindedPath>, ()> {
                // Limit the number of blinded paths that are computed.
                const MAX_PATHS: usize = 3;
@@ -502,8 +527,11 @@ where
                                }
                        },
                }?;
-               for path in &mut paths {
-                       path.use_compact_introduction_node(&network_graph);
+
+               if compact_paths {
+                       for path in &mut paths {
+                               path.use_compact_introduction_node(&network_graph);
+                       }
                }
 
                Ok(paths)
@@ -550,10 +578,21 @@ where
 
        fn create_blinded_paths<
                T: secp256k1::Signing + secp256k1::Verification
+       >(
+               &self, recipient: PublicKey, peers: Vec<PublicKey>, secp_ctx: &Secp256k1<T>,
+       ) -> Result<Vec<BlindedPath>, ()> {
+               let peers = peers
+                       .into_iter()
+                       .map(|node_id| ForwardNode { node_id, short_channel_id: None });
+               self.create_blinded_paths_from_iter(recipient, peers, secp_ctx, false)
+       }
+
+       fn create_compact_blinded_paths<
+               T: secp256k1::Signing + secp256k1::Verification
        >(
                &self, recipient: PublicKey, peers: Vec<ForwardNode>, secp_ctx: &Secp256k1<T>,
        ) -> Result<Vec<BlindedPath>, ()> {
-               self.create_blinded_paths_from_iter(recipient, peers.into_iter(), secp_ctx)
+               self.create_blinded_paths_from_iter(recipient, peers.into_iter(), secp_ctx, true)
        }
 }
 
@@ -1090,10 +1129,7 @@ where
                let peers = self.message_recipients.lock().unwrap()
                        .iter()
                        .filter(|(_, peer)| matches!(peer, OnionMessageRecipient::ConnectedPeer(_)))
-                       .map(|(node_id, _ )| ForwardNode {
-                               node_id: *node_id,
-                               short_channel_id: None,
-                       })
+                       .map(|(node_id, _ )| *node_id)
                        .collect::<Vec<_>>();
 
                self.message_router
index e1b5b655719401e7670134ae3a59403d2569cb07..c105e914679c05f147ee9f477a4a55dc60a6a7b9 100644 (file)
@@ -173,10 +173,18 @@ impl< G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, ES: Deref, S: Deref,
        fn create_blinded_paths<
                T: secp256k1::Signing + secp256k1::Verification
        > (
-               &self, recipient: PublicKey, peers: Vec<message::ForwardNode>, secp_ctx: &Secp256k1<T>,
+               &self, recipient: PublicKey, peers: Vec<PublicKey>, secp_ctx: &Secp256k1<T>,
        ) -> Result<Vec<BlindedPath>, ()> {
                self.message_router.create_blinded_paths(recipient, peers, secp_ctx)
        }
+
+       fn create_compact_blinded_paths<
+               T: secp256k1::Signing + secp256k1::Verification
+       > (
+               &self, recipient: PublicKey, peers: Vec<message::ForwardNode>, secp_ctx: &Secp256k1<T>,
+       ) -> Result<Vec<BlindedPath>, ()> {
+               self.message_router.create_compact_blinded_paths(recipient, peers, secp_ctx)
+       }
 }
 
 /// A trait defining behavior for routing a payment.
index a5363d32c76296f2e62bea89243e971df0388fa0..f6616a8e5d2449391c2beb68d08e93c295127cee 100644 (file)
@@ -250,10 +250,18 @@ impl<'a> MessageRouter for TestRouter<'a> {
        fn create_blinded_paths<
                T: secp256k1::Signing + secp256k1::Verification
        >(
-               &self, recipient: PublicKey, peers: Vec<ForwardNode>, secp_ctx: &Secp256k1<T>,
+               &self, recipient: PublicKey, peers: Vec<PublicKey>, secp_ctx: &Secp256k1<T>,
        ) -> Result<Vec<BlindedPath>, ()> {
                self.router.create_blinded_paths(recipient, peers, secp_ctx)
        }
+
+       fn create_compact_blinded_paths<
+               T: secp256k1::Signing + secp256k1::Verification
+       >(
+               &self, recipient: PublicKey, peers: Vec<ForwardNode>, secp_ctx: &Secp256k1<T>,
+       ) -> Result<Vec<BlindedPath>, ()> {
+               self.router.create_compact_blinded_paths(recipient, peers, secp_ctx)
+       }
 }
 
 impl<'a> Drop for TestRouter<'a> {
@@ -285,10 +293,16 @@ impl<'a> MessageRouter for TestMessageRouter<'a> {
        }
 
        fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
-               &self, recipient: PublicKey, peers: Vec<ForwardNode>, secp_ctx: &Secp256k1<T>,
+               &self, recipient: PublicKey, peers: Vec<PublicKey>, secp_ctx: &Secp256k1<T>,
        ) -> Result<Vec<BlindedPath>, ()> {
                self.inner.create_blinded_paths(recipient, peers, secp_ctx)
        }
+
+       fn create_compact_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
+               &self, recipient: PublicKey, peers: Vec<ForwardNode>, secp_ctx: &Secp256k1<T>,
+       ) -> Result<Vec<BlindedPath>, ()> {
+               self.inner.create_compact_blinded_paths(recipient, peers, secp_ctx)
+       }
 }
 
 pub struct OnlyReadsKeysInterface {}