From e10583365b36148f500b6c93d999c96060e44791 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Wed, 28 Feb 2024 15:58:14 -0600 Subject: [PATCH] Prefer one-hop blinded path to Tor intro nodes If a node is announced, prefer using a one-hop blinded path with it as the introduction node to using a two-hop blinded path with a Tor-only introduction node. The one-hop blinded path is more reliable, thus only use Tor-only nodes if the recipient is unannounced. And then, prefer non-Tor-only nodes. --- lightning/src/ln/offers_tests.rs | 17 ++++++++++++++++- lightning/src/onion_message/messenger.rs | 7 ++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index 6af4cb6b..e16c0ed5 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -250,7 +250,7 @@ fn prefers_non_tor_nodes_in_blinded_paths() { disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]); let tor = SocketAddress::OnionV2([255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 38, 7]); - announce_node_address(charlie, &[alice, bob, david, &nodes[4], &nodes[5]], tor); + announce_node_address(charlie, &[alice, bob, david, &nodes[4], &nodes[5]], tor.clone()); let offer = bob.node .create_offer_builder("coffee".to_string()).unwrap() @@ -259,8 +259,23 @@ fn prefers_non_tor_nodes_in_blinded_paths() { assert_ne!(offer.signing_pubkey(), bob_id); assert!(!offer.paths().is_empty()); for path in offer.paths() { + assert_ne!(path.introduction_node_id, bob_id); assert_ne!(path.introduction_node_id, charlie_id); } + + // Use a one-hop blinded path when Bob is announced and all his peers are Tor-only. + announce_node_address(&nodes[4], &[alice, bob, charlie, david, &nodes[5]], tor.clone()); + announce_node_address(&nodes[5], &[alice, bob, charlie, david, &nodes[4]], tor.clone()); + + let offer = bob.node + .create_offer_builder("coffee".to_string()).unwrap() + .amount_msats(10_000_000) + .build().unwrap(); + assert_ne!(offer.signing_pubkey(), bob_id); + assert!(!offer.paths().is_empty()); + for path in offer.paths() { + assert_eq!(path.introduction_node_id, bob_id); + } } /// Checks that blinded paths prefer an introduction node that is the most connected. diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 6987ece9..37de5504 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -358,6 +358,9 @@ where const MIN_PEER_CHANNELS: usize = 3; let network_graph = self.network_graph.deref().read_only(); + let is_recipient_announced = + network_graph.nodes().contains_key(&NodeId::from_pubkey(&recipient)); + let mut peer_info = peers.iter() // Limit to peers with announced channels .filter_map(|pubkey| @@ -366,6 +369,8 @@ where .filter(|info| info.channels.len() >= MIN_PEER_CHANNELS) .map(|info| (*pubkey, info.is_tor_only(), info.channels.len())) ) + // Exclude Tor-only nodes when the recipient is announced. + .filter(|(_, is_tor_only, _)| !(*is_tor_only && is_recipient_announced)) .collect::>(); // Prefer using non-Tor nodes with the most channels as the introduction node. @@ -382,7 +387,7 @@ where match paths { Ok(paths) if !paths.is_empty() => Ok(paths), _ => { - if network_graph.nodes().contains_key(&NodeId::from_pubkey(&recipient)) { + if is_recipient_announced { BlindedPath::one_hop_for_message(recipient, &*self.entropy_source, secp_ctx) .map(|path| vec![path]) } else { -- 2.30.2