From 22c9da3cfb6f624883286c84569db6639856768e Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Tue, 19 Mar 2024 14:19:59 -0500 Subject: [PATCH 1/6] Re-order imports --- lightning/src/routing/test_utils.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lightning/src/routing/test_utils.rs b/lightning/src/routing/test_utils.rs index 3c0ef85fd7e..0cc6676e5e6 100644 --- a/lightning/src/routing/test_utils.rs +++ b/lightning/src/routing/test_utils.rs @@ -9,8 +9,7 @@ use crate::routing::gossip::{NetworkGraph, NodeAlias, P2PGossipSync}; use crate::ln::features::{ChannelFeatures, NodeFeatures}; -use crate::ln::msgs::{UnsignedChannelAnnouncement, ChannelAnnouncement, RoutingMessageHandler, - NodeAnnouncement, UnsignedNodeAnnouncement, ChannelUpdate, UnsignedChannelUpdate, MAX_VALUE_MSAT}; +use crate::ln::msgs::{ChannelAnnouncement, ChannelUpdate, MAX_VALUE_MSAT, NodeAnnouncement, RoutingMessageHandler, UnsignedChannelAnnouncement, UnsignedChannelUpdate, UnsignedNodeAnnouncement}; use crate::util::test_utils; use crate::util::ser::Writeable; From dc627b371fa5dd5db5b5da65ad445bf01359ec2a Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Tue, 19 Mar 2024 14:20:55 -0500 Subject: [PATCH 2/6] Include SocketAddress in test node_announcement --- lightning/src/routing/test_utils.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lightning/src/routing/test_utils.rs b/lightning/src/routing/test_utils.rs index 0cc6676e5e6..00c5528505c 100644 --- a/lightning/src/routing/test_utils.rs +++ b/lightning/src/routing/test_utils.rs @@ -9,7 +9,7 @@ use crate::routing::gossip::{NetworkGraph, NodeAlias, P2PGossipSync}; use crate::ln::features::{ChannelFeatures, NodeFeatures}; -use crate::ln::msgs::{ChannelAnnouncement, ChannelUpdate, MAX_VALUE_MSAT, NodeAnnouncement, RoutingMessageHandler, UnsignedChannelAnnouncement, UnsignedChannelUpdate, UnsignedNodeAnnouncement}; +use crate::ln::msgs::{ChannelAnnouncement, ChannelUpdate, MAX_VALUE_MSAT, NodeAnnouncement, RoutingMessageHandler, SocketAddress, UnsignedChannelAnnouncement, UnsignedChannelUpdate, UnsignedNodeAnnouncement}; use crate::util::test_utils; use crate::util::ser::Writeable; @@ -70,7 +70,7 @@ pub(super) fn add_or_update_node( node_id, rgb: [0; 3], alias: NodeAlias([0; 32]), - addresses: Vec::new(), + addresses: vec![SocketAddress::TcpIpV4 { addr: [127, 0, 0, 1], port: 1000 }], excess_address_data: Vec::new(), excess_data: Vec::new(), }; From f2b84e05e8e0d5a2d6542dd6555a6252a800eb26 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Tue, 19 Mar 2024 16:04:43 -0500 Subject: [PATCH 3/6] Fix sender is the introduction node onion messages DefaultMessageRouter will form an OnionMessagePath from a BlindedPath where the sender is the introduction node but only if the sender is announced. If the sender is unannounced, then DefaultMessageRouter will fail. While DefaultMessageRouter will only create a blinded path with an announced introduction node, it may receive one where the introduction node is unannounced. Don't return an error in this case, as the OnionMessenger can advance the blinded path by one hop. This may occur when two nodes have an unannounced channel and one (the offer creator) wants to use it for payments without an intermediary node and without putting its node id in the offer. --- lightning/src/onion_message/messenger.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 37de5504532..15dc12f6bea 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -318,10 +318,10 @@ where ES::Target: EntropySource, { fn find_path( - &self, _sender: PublicKey, peers: Vec, destination: Destination + &self, sender: PublicKey, peers: Vec, destination: Destination ) -> Result { let first_node = destination.first_node(); - if peers.contains(&first_node) { + if peers.contains(&first_node) || sender == first_node { Ok(OnionMessagePath { intermediate_nodes: vec![], destination, first_node_addresses: None }) From 3d2a0c2832ca71e6d75d335b6e3d7490f8f220b8 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Tue, 19 Mar 2024 16:07:20 -0500 Subject: [PATCH 4/6] pub(crate) visibility for routing/test_utils.rs Give pub(crate) visibility to some routing test utilities to facilitate testing DefaultMessageRouter in functional tests. --- lightning/src/routing/mod.rs | 2 +- lightning/src/routing/test_utils.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lightning/src/routing/mod.rs b/lightning/src/routing/mod.rs index 7fff856345c..9e6d8e2afd2 100644 --- a/lightning/src/routing/mod.rs +++ b/lightning/src/routing/mod.rs @@ -14,4 +14,4 @@ pub mod gossip; pub mod router; pub mod scoring; #[cfg(test)] -mod test_utils; +pub(crate) mod test_utils; diff --git a/lightning/src/routing/test_utils.rs b/lightning/src/routing/test_utils.rs index 00c5528505c..9f03b4451ef 100644 --- a/lightning/src/routing/test_utils.rs +++ b/lightning/src/routing/test_utils.rs @@ -27,7 +27,7 @@ use crate::sync::{self, Arc}; use crate::routing::gossip::NodeId; // Using the same keys for LN and BTC ids -pub(super) fn add_channel( +pub(crate) fn add_channel( gossip_sync: &P2PGossipSync>>, Arc, Arc>, secp_ctx: &Secp256k1, node_1_privkey: &SecretKey, node_2_privkey: &SecretKey, features: ChannelFeatures, short_channel_id: u64 ) { @@ -59,7 +59,7 @@ pub(super) fn add_channel( }; } -pub(super) fn add_or_update_node( +pub(crate) fn add_or_update_node( gossip_sync: &P2PGossipSync>>, Arc, Arc>, secp_ctx: &Secp256k1, node_privkey: &SecretKey, features: NodeFeatures, timestamp: u32 ) { @@ -86,7 +86,7 @@ pub(super) fn add_or_update_node( }; } -pub(super) fn update_channel( +pub(crate) fn update_channel( gossip_sync: &P2PGossipSync>>, Arc, Arc>, secp_ctx: &Secp256k1, node_privkey: &SecretKey, update: UnsignedChannelUpdate ) { From ad3de23666383a5d11c011b62899ca663f21ce5f Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Tue, 19 Mar 2024 16:11:34 -0500 Subject: [PATCH 5/6] Use DefaultMessageRouter in functional tests This helps test cases in DefaultMessageRouter that may not be exercised now or in the future. --- .../src/onion_message/functional_tests.rs | 77 ++++++++++++------- 1 file changed, 48 insertions(+), 29 deletions(-) diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index 271b56dc0c9..31d10156905 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -11,60 +11,51 @@ use crate::blinded_path::BlindedPath; use crate::events::{Event, EventsProvider}; -use crate::ln::features::InitFeatures; -use crate::ln::msgs::{self, DecodeError, OnionMessageHandler, SocketAddress}; +use crate::ln::features::{ChannelFeatures, InitFeatures}; +use crate::ln::msgs::{self, DecodeError, OnionMessageHandler}; +use crate::routing::gossip::{NetworkGraph, P2PGossipSync}; +use crate::routing::test_utils::{add_channel, add_or_update_node}; use crate::sign::{NodeSigner, Recipient}; use crate::util::ser::{FixedLengthReader, LengthReadable, Writeable, Writer}; use crate::util::test_utils; -use super::messenger::{CustomOnionMessageHandler, Destination, MessageRouter, OnionMessagePath, OnionMessenger, PendingOnionMessage, SendError}; +use super::messenger::{CustomOnionMessageHandler, DefaultMessageRouter, Destination, OnionMessagePath, OnionMessenger, PendingOnionMessage, SendError}; use super::offers::{OffersMessage, OffersMessageHandler}; use super::packet::{OnionMessageContents, Packet}; use bitcoin::network::constants::Network; use bitcoin::hashes::hex::FromHex; -use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey, self}; +use bitcoin::secp256k1::{All, PublicKey, Secp256k1, SecretKey}; use crate::io; use crate::io_extras::read_to_end; use crate::sync::{Arc, Mutex}; +use core::ops::Deref; + use crate::prelude::*; struct MessengerNode { node_id: PublicKey, + privkey: SecretKey, entropy_source: Arc, messenger: OnionMessenger< Arc, Arc, Arc, - Arc, + Arc>>, + Arc, + Arc + >>, Arc, Arc >, custom_message_handler: Arc, -} - -struct TestMessageRouter {} - -impl MessageRouter for TestMessageRouter { - fn find_path( - &self, _sender: PublicKey, _peers: Vec, destination: Destination - ) -> Result { - Ok(OnionMessagePath { - intermediate_nodes: vec![], - destination, - first_node_addresses: - Some(vec![SocketAddress::TcpIpV4 { addr: [127, 0, 0, 1], port: 1000 }]), - }) - } - - fn create_blinded_paths< - T: secp256k1::Signing + secp256k1::Verification - >( - &self, _recipient: PublicKey, _peers: Vec, _secp_ctx: &Secp256k1, - ) -> Result, ()> { - unreachable!() - } + gossip_sync: Arc>>, + Arc, + Arc + >> } struct TestOffersMessageHandler {} @@ -171,6 +162,12 @@ fn create_nodes(num_messengers: u8) -> Vec { } fn create_nodes_using_secrets(secrets: Vec) -> Vec { + let gossip_logger = Arc::new(test_utils::TestLogger::with_id("gossip".to_string())); + let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, gossip_logger.clone())); + let gossip_sync = Arc::new( + P2PGossipSync::new(network_graph.clone(), None, gossip_logger) + ); + let mut nodes = Vec::new(); for (i, secret_key) in secrets.into_iter().enumerate() { let logger = Arc::new(test_utils::TestLogger::with_id(format!("node {}", i))); @@ -178,10 +175,13 @@ fn create_nodes_using_secrets(secrets: Vec) -> Vec { let entropy_source = Arc::new(test_utils::TestKeysInterface::new(&seed, Network::Testnet)); let node_signer = Arc::new(test_utils::TestNodeSigner::new(secret_key)); - let message_router = Arc::new(TestMessageRouter {}); + let message_router = Arc::new( + DefaultMessageRouter::new(network_graph.clone(), entropy_source.clone()) + ); let offers_message_handler = Arc::new(TestOffersMessageHandler {}); let custom_message_handler = Arc::new(TestCustomMessageHandler::new()); nodes.push(MessengerNode { + privkey: secret_key, node_id: node_signer.get_node_id(Recipient::Node).unwrap(), entropy_source: entropy_source.clone(), messenger: OnionMessenger::new( @@ -189,6 +189,7 @@ fn create_nodes_using_secrets(secrets: Vec) -> Vec { offers_message_handler, custom_message_handler.clone() ), custom_message_handler, + gossip_sync: gossip_sync.clone(), }); } for i in 0..nodes.len() - 1 { @@ -216,6 +217,20 @@ fn release_events(node: &MessengerNode) -> Vec { events.into_inner() } +fn add_channel_to_graph( + node_a: &MessengerNode, node_b: &MessengerNode, secp_ctx: &Secp256k1, short_channel_id: u64 +) { + let gossip_sync = node_a.gossip_sync.deref(); + let privkey_a = &node_a.privkey; + let privkey_b = &node_b.privkey; + let channel_features = ChannelFeatures::empty(); + let node_features_a = node_a.messenger.provided_node_features(); + let node_features_b = node_b.messenger.provided_node_features(); + add_channel(gossip_sync, secp_ctx, privkey_a, privkey_b, channel_features, short_channel_id); + add_or_update_node(gossip_sync, secp_ctx, privkey_a, node_features_a, 1); + add_or_update_node(gossip_sync, secp_ctx, privkey_b, node_features_b, 1); +} + fn pass_along_path(path: &Vec) { let mut prev_node = &path[0]; for node in path.into_iter().skip(1) { @@ -492,6 +507,8 @@ fn requests_peer_connection_for_buffered_messages() { let nodes = create_nodes(3); let message = TestCustomMessage::Request; let secp_ctx = Secp256k1::new(); + add_channel_to_graph(&nodes[0], &nodes[1], &secp_ctx, 42); + let blinded_path = BlindedPath::new_for_message( &[nodes[1].node_id, nodes[2].node_id], &*nodes[0].entropy_source, &secp_ctx ).unwrap(); @@ -527,6 +544,8 @@ fn drops_buffered_messages_waiting_for_peer_connection() { let nodes = create_nodes(3); let message = TestCustomMessage::Request; let secp_ctx = Secp256k1::new(); + add_channel_to_graph(&nodes[0], &nodes[1], &secp_ctx, 42); + let blinded_path = BlindedPath::new_for_message( &[nodes[1].node_id, nodes[2].node_id], &*nodes[0].entropy_source, &secp_ctx ).unwrap(); From 806fef5848e540b8b30ba0c374d6120942cb41c5 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Tue, 19 Mar 2024 17:04:01 -0500 Subject: [PATCH 6/6] Use OnionMessenger::send_onion_message in tests Use OnionMessenger's public interface in tests whenever possible (i.e., when not using any intermediate_nodes in an OnionMessagePath. This allows us to exercise DefaultMessageRouter, and, in particular that a path can be found for an unannounced sender when its in the introduction node. --- .../src/onion_message/functional_tests.rs | 75 +++++-------------- 1 file changed, 20 insertions(+), 55 deletions(-) diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index 31d10156905..16f0babe361 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -250,12 +250,8 @@ fn one_unblinded_hop() { let nodes = create_nodes(2); let test_msg = TestCustomMessage::Response; - let path = OnionMessagePath { - intermediate_nodes: vec![], - destination: Destination::Node(nodes[1].node_id), - first_node_addresses: None, - }; - nodes[0].messenger.send_onion_message_using_path(path, test_msg, None).unwrap(); + let destination = Destination::Node(nodes[1].node_id); + nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap(); nodes[1].custom_message_handler.expect_message(TestCustomMessage::Response); pass_along_path(&nodes); } @@ -270,6 +266,7 @@ fn two_unblinded_hops() { destination: Destination::Node(nodes[2].node_id), first_node_addresses: None, }; + nodes[0].messenger.send_onion_message_using_path(path, test_msg, None).unwrap(); nodes[2].custom_message_handler.expect_message(TestCustomMessage::Response); pass_along_path(&nodes); @@ -282,12 +279,8 @@ fn one_blinded_hop() { let secp_ctx = Secp256k1::new(); let blinded_path = BlindedPath::new_for_message(&[nodes[1].node_id], &*nodes[1].entropy_source, &secp_ctx).unwrap(); - let path = OnionMessagePath { - intermediate_nodes: vec![], - destination: Destination::BlindedPath(blinded_path), - first_node_addresses: None, - }; - nodes[0].messenger.send_onion_message_using_path(path, test_msg, None).unwrap(); + let destination = Destination::BlindedPath(blinded_path); + nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap(); nodes[1].custom_message_handler.expect_message(TestCustomMessage::Response); pass_along_path(&nodes); } @@ -317,13 +310,9 @@ fn three_blinded_hops() { let secp_ctx = Secp256k1::new(); let blinded_path = BlindedPath::new_for_message(&[nodes[1].node_id, nodes[2].node_id, nodes[3].node_id], &*nodes[3].entropy_source, &secp_ctx).unwrap(); - let path = OnionMessagePath { - intermediate_nodes: vec![], - destination: Destination::BlindedPath(blinded_path), - first_node_addresses: None, - }; + let destination = Destination::BlindedPath(blinded_path); - nodes[0].messenger.send_onion_message_using_path(path, test_msg, None).unwrap(); + nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap(); nodes[3].custom_message_handler.expect_message(TestCustomMessage::Response); pass_along_path(&nodes); } @@ -354,24 +343,16 @@ fn we_are_intro_node() { let secp_ctx = Secp256k1::new(); let blinded_path = BlindedPath::new_for_message(&[nodes[0].node_id, nodes[1].node_id, nodes[2].node_id], &*nodes[2].entropy_source, &secp_ctx).unwrap(); - let path = OnionMessagePath { - intermediate_nodes: vec![], - destination: Destination::BlindedPath(blinded_path), - first_node_addresses: None, - }; + let destination = Destination::BlindedPath(blinded_path); - nodes[0].messenger.send_onion_message_using_path(path, test_msg.clone(), None).unwrap(); + nodes[0].messenger.send_onion_message(test_msg.clone(), destination, None).unwrap(); nodes[2].custom_message_handler.expect_message(TestCustomMessage::Response); pass_along_path(&nodes); // Try with a two-hop blinded path where we are the introduction node. let blinded_path = BlindedPath::new_for_message(&[nodes[0].node_id, nodes[1].node_id], &*nodes[1].entropy_source, &secp_ctx).unwrap(); - let path = OnionMessagePath { - intermediate_nodes: vec![], - destination: Destination::BlindedPath(blinded_path), - first_node_addresses: None, - }; - nodes[0].messenger.send_onion_message_using_path(path, test_msg, None).unwrap(); + let destination = Destination::BlindedPath(blinded_path); + nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap(); nodes[1].custom_message_handler.expect_message(TestCustomMessage::Response); nodes.remove(2); pass_along_path(&nodes); @@ -387,12 +368,8 @@ fn invalid_blinded_path_error() { let secp_ctx = Secp256k1::new(); let mut blinded_path = BlindedPath::new_for_message(&[nodes[1].node_id, nodes[2].node_id], &*nodes[2].entropy_source, &secp_ctx).unwrap(); blinded_path.blinded_hops.clear(); - let path = OnionMessagePath { - intermediate_nodes: vec![], - destination: Destination::BlindedPath(blinded_path), - first_node_addresses: None, - }; - let err = nodes[0].messenger.send_onion_message_using_path(path, test_msg.clone(), None).unwrap_err(); + let destination = Destination::BlindedPath(blinded_path); + let err = nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap_err(); assert_eq!(err, SendError::TooFewBlindedHops); } @@ -419,14 +396,10 @@ fn reply_path() { // Destination::BlindedPath let blinded_path = BlindedPath::new_for_message(&[nodes[1].node_id, nodes[2].node_id, nodes[3].node_id], &*nodes[3].entropy_source, &secp_ctx).unwrap(); - let path = OnionMessagePath { - intermediate_nodes: vec![], - destination: Destination::BlindedPath(blinded_path), - first_node_addresses: None, - }; + let destination = Destination::BlindedPath(blinded_path); let reply_path = BlindedPath::new_for_message(&[nodes[2].node_id, nodes[1].node_id, nodes[0].node_id], &*nodes[0].entropy_source, &secp_ctx).unwrap(); - nodes[0].messenger.send_onion_message_using_path(path, test_msg, Some(reply_path)).unwrap(); + nodes[0].messenger.send_onion_message(test_msg, destination, Some(reply_path)).unwrap(); nodes[3].custom_message_handler.expect_message(TestCustomMessage::Request); pass_along_path(&nodes); @@ -454,12 +427,8 @@ fn invalid_custom_message_type() { } let test_msg = InvalidCustomMessage {}; - let path = OnionMessagePath { - intermediate_nodes: vec![], - destination: Destination::Node(nodes[1].node_id), - first_node_addresses: None, - }; - let err = nodes[0].messenger.send_onion_message_using_path(path, test_msg, None).unwrap_err(); + let destination = Destination::Node(nodes[1].node_id); + let err = nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap_err(); assert_eq!(err, SendError::InvalidMessage); } @@ -467,15 +436,11 @@ fn invalid_custom_message_type() { fn peer_buffer_full() { let nodes = create_nodes(2); let test_msg = TestCustomMessage::Request; - let path = OnionMessagePath { - intermediate_nodes: vec![], - destination: Destination::Node(nodes[1].node_id), - first_node_addresses: None, - }; + let destination = Destination::Node(nodes[1].node_id); for _ in 0..188 { // Based on MAX_PER_PEER_BUFFER_SIZE in OnionMessenger - nodes[0].messenger.send_onion_message_using_path(path.clone(), test_msg.clone(), None).unwrap(); + nodes[0].messenger.send_onion_message(test_msg.clone(), destination.clone(), None).unwrap(); } - let err = nodes[0].messenger.send_onion_message_using_path(path, test_msg, None).unwrap_err(); + let err = nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap_err(); assert_eq!(err, SendError::BufferFull); }