Merge pull request #2934 from TheBlueMatt/2023-03-no-num-traits
[rust-lightning] / lightning / src / onion_message / messenger.rs
index 0a38022dbb5883cdcf06a5e3340a68079ae9f23c..e213bcbb0e1dc50d9fda8983f164e82611db26d9 100644 (file)
@@ -28,7 +28,7 @@ use super::packet::OnionMessageContents;
 use super::packet::ParsedOnionMessageContents;
 use super::offers::OffersMessageHandler;
 use super::packet::{BIG_PACKET_HOP_DATA_LEN, ForwardControlTlvs, Packet, Payload, ReceiveControlTlvs, SMALL_PACKET_HOP_DATA_LEN};
-use crate::util::logger::Logger;
+use crate::util::logger::{Logger, WithContext};
 use crate::util::ser::Writeable;
 
 use core::fmt;
@@ -318,10 +318,10 @@ where
        ES::Target: EntropySource,
 {
        fn find_path(
-               &self, _sender: PublicKey, peers: Vec<PublicKey>, destination: Destination
+               &self, sender: PublicKey, peers: Vec<PublicKey>, destination: Destination
        ) -> Result<OnionMessagePath, ()> {
                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
                        })
@@ -358,16 +358,28 @@ where
                const MIN_PEER_CHANNELS: usize = 3;
 
                let network_graph = self.network_graph.deref().read_only();
-               let paths = peers.iter()
+               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(|pubkey|
+                       .filter_map(|pubkey|
                                network_graph
                                        .node(&NodeId::from_pubkey(pubkey))
-                                       .map(|info| &info.channels[..])
-                                       .map(|channels| channels.len() >= MIN_PEER_CHANNELS)
-                                       .unwrap_or(false)
+                                       .filter(|info| info.channels.len() >= MIN_PEER_CHANNELS)
+                                       .map(|info| (*pubkey, info.is_tor_only(), info.channels.len()))
                        )
-                       .map(|pubkey| vec![*pubkey, recipient])
+                       // Exclude Tor-only nodes when the recipient is announced.
+                       .filter(|(_, is_tor_only, _)| !(*is_tor_only && is_recipient_announced))
+                       .collect::<Vec<_>>();
+
+               // Prefer using non-Tor nodes with the most channels as the introduction node.
+               peer_info.sort_unstable_by(|(_, a_tor_only, a_channels), (_, b_tor_only, b_channels)| {
+                       a_tor_only.cmp(b_tor_only).then(a_channels.cmp(b_channels).reverse())
+               });
+
+               let paths = peer_info.into_iter()
+                       .map(|(pubkey, _, _)| vec![pubkey, recipient])
                        .map(|node_pks| BlindedPath::new_for_message(&node_pks, &*self.entropy_source, secp_ctx))
                        .take(MAX_PATHS)
                        .collect::<Result<Vec<_>, _>>();
@@ -375,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 {
@@ -413,7 +425,7 @@ impl OnionMessagePath {
 }
 
 /// The destination of an onion message.
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Hash, Debug, PartialEq, Eq)]
 pub enum Destination {
        /// We're sending this onion message to a node.
        Node(PublicKey),
@@ -440,7 +452,7 @@ impl Destination {
 /// Result of successfully [sending an onion message].
 ///
 /// [sending an onion message]: OnionMessenger::send_onion_message
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Clone, Hash, Debug, PartialEq, Eq)]
 pub enum SendSuccess {
        /// The message was buffered and will be sent once it is processed by
        /// [`OnionMessageHandler::next_onion_message_for_peer`].
@@ -453,7 +465,7 @@ pub enum SendSuccess {
 /// Errors that may occur when [sending an onion message].
 ///
 /// [sending an onion message]: OnionMessenger::send_onion_message
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Clone, Hash, Debug, PartialEq, Eq)]
 pub enum SendError {
        /// Errored computing onion message packet keys.
        Secp256k1(secp256k1::Error),
@@ -523,6 +535,7 @@ pub trait CustomOnionMessageHandler {
 
 /// A processed incoming onion message, containing either a Forward (another onion message)
 /// or a Receive payload with decrypted contents.
+#[derive(Debug)]
 pub enum PeeledOnion<T: OnionMessageContents> {
        /// Forwarded onion, with the next node id and a new onion
        Forward(PublicKey, OnionMessage),
@@ -735,25 +748,31 @@ where
                &self, contents: T, destination: Destination, reply_path: Option<BlindedPath>,
                log_suffix: fmt::Arguments
        ) -> Result<SendSuccess, SendError> {
+               let mut logger = WithContext::from(&self.logger, None, None);
                let result = self.find_path(destination)
-                       .and_then(|path| self.enqueue_onion_message(path, contents, reply_path, log_suffix));
+                       .and_then(|path| {
+                               let first_hop = path.intermediate_nodes.get(0).map(|p| *p);
+                               logger = WithContext::from(&self.logger, first_hop, None);
+                               self.enqueue_onion_message(path, contents, reply_path, log_suffix)
+                       });
 
                match result.as_ref() {
                        Err(SendError::GetNodeIdFailed) => {
-                               log_warn!(self.logger, "Unable to retrieve node id {}", log_suffix);
+                               log_warn!(logger, "Unable to retrieve node id {}", log_suffix);
                        },
                        Err(SendError::PathNotFound) => {
-                               log_trace!(self.logger, "Failed to find path {}", log_suffix);
+                               log_trace!(logger, "Failed to find path {}", log_suffix);
                        },
                        Err(e) => {
-                               log_trace!(self.logger, "Failed sending onion message {}: {:?}", log_suffix, e);
+                               log_trace!(logger, "Failed sending onion message {}: {:?}", log_suffix, e);
                        },
                        Ok(SendSuccess::Buffered) => {
-                               log_trace!(self.logger, "Buffered onion message {}", log_suffix);
+                               log_trace!(logger, "Buffered onion message {}", log_suffix);
                        },
                        Ok(SendSuccess::BufferedAwaitingConnection(node_id)) => {
                                log_trace!(
-                                       self.logger, "Buffered onion message waiting on peer connection {}: {:?}",
+                                       logger,
+                                       "Buffered onion message waiting on peer connection {}: {}",
                                        log_suffix, node_id
                                );
                        },
@@ -912,12 +931,13 @@ where
        OMH::Target: OffersMessageHandler,
        CMH::Target: CustomOnionMessageHandler,
 {
-       fn handle_onion_message(&self, _peer_node_id: &PublicKey, msg: &OnionMessage) {
+       fn handle_onion_message(&self, peer_node_id: &PublicKey, msg: &OnionMessage) {
+               let logger = WithContext::from(&self.logger, Some(*peer_node_id), None);
                match self.peel_onion_message(msg) {
                        Ok(PeeledOnion::Receive(message, path_id, reply_path)) => {
                                log_trace!(
-                                       self.logger,
-                                  "Received an onion message with path_id {:02x?} and {} reply_path: {:?}",
+                                       logger,
+                                       "Received an onion message with path_id {:02x?} and {} reply_path: {:?}",
                                        path_id, if reply_path.is_some() { "a" } else { "no" }, message);
 
                                match message {
@@ -944,7 +964,10 @@ where
                        Ok(PeeledOnion::Forward(next_node_id, onion_message)) => {
                                let mut message_recipients = self.message_recipients.lock().unwrap();
                                if outbound_buffer_full(&next_node_id, &message_recipients) {
-                                       log_trace!(self.logger, "Dropping forwarded onion message to peer {:?}: outbound buffer full", next_node_id);
+                                       log_trace!(
+                                               logger,
+                                               "Dropping forwarded onion message to peer {}: outbound buffer full",
+                                               next_node_id);
                                        return
                                }
 
@@ -958,16 +981,19 @@ where
                                                e.get(), OnionMessageRecipient::ConnectedPeer(..)
                                        ) => {
                                                e.get_mut().enqueue_message(onion_message);
-                                               log_trace!(self.logger, "Forwarding an onion message to peer {}", next_node_id);
+                                               log_trace!(logger, "Forwarding an onion message to peer {}", next_node_id);
                                        },
                                        _ => {
-                                               log_trace!(self.logger, "Dropping forwarded onion message to disconnected peer {:?}", next_node_id);
+                                               log_trace!(
+                                                       logger,
+                                                       "Dropping forwarded onion message to disconnected peer {}",
+                                                       next_node_id);
                                                return
                                        },
                                }
                        },
                        Err(e) => {
-                               log_error!(self.logger, "Failed to process onion message {:?}", e);
+                               log_error!(logger, "Failed to process onion message {:?}", e);
                        }
                }
        }