Merge pull request #1791 from valentinewallace/2022-10-we-are-intro-node
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Tue, 1 Nov 2022 21:12:30 +0000 (21:12 +0000)
committerGitHub <noreply@github.com>
Tue, 1 Nov 2022 21:12:30 +0000 (21:12 +0000)
Onion messages: fix edge case where we are the intro node

1  2 
lightning/src/onion_message/functional_tests.rs
lightning/src/onion_message/messenger.rs

index d1e892de016c35ef48b74c9ff844c2ebdb9ea526,81826a62cc375cc9bf3f4fbf60dbe84406a1e008..bd0a884a811afac547aa030f693d864774304132
@@@ -14,7 -14,7 +14,7 @@@ use crate::ln::features::InitFeatures
  use crate::ln::msgs::{self, DecodeError, OnionMessageHandler};
  use super::{BlindedRoute, CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessageContents, OnionMessenger, SendError};
  use crate::util::enforcing_trait_impls::EnforcingSigner;
 -use crate::util::ser::{MaybeReadableArgs, Writeable, Writer};
 +use crate::util::ser::{ Writeable, Writer};
  use crate::util::test_utils;
  
  use bitcoin::network::constants::Network;
@@@ -54,12 -54,8 +54,12 @@@ impl Writeable for TestCustomMessage 
        }
  }
  
 -impl MaybeReadableArgs<u64> for TestCustomMessage {
 -      fn read<R: io::Read>(buffer: &mut R, message_type: u64) -> Result<Option<Self>, DecodeError> where Self: Sized {
 +struct TestCustomMessageHandler {}
 +
 +impl CustomOnionMessageHandler for TestCustomMessageHandler {
 +      type CustomMessage = TestCustomMessage;
 +      fn handle_custom_message(&self, _msg: Self::CustomMessage) {}
 +      fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, DecodeError> where Self: Sized {
                if message_type == CUSTOM_MESSAGE_TYPE {
                        let mut buf = Vec::new();
                        buffer.read_to_end(&mut buf)?;
        }
  }
  
 -struct TestCustomMessageHandler {}
 -
 -impl CustomOnionMessageHandler for TestCustomMessageHandler {
 -      type CustomMessage = TestCustomMessage;
 -      fn handle_custom_message(&self, _msg: Self::CustomMessage) {}
 -}
 -
  fn create_nodes(num_messengers: u8) -> Vec<MessengerNode> {
        let mut nodes = Vec::new();
        for i in 0..num_messengers {
@@@ -167,6 -170,26 +167,26 @@@ fn too_big_packet_error() 
        assert_eq!(err, SendError::TooBigPacket);
  }
  
+ #[test]
+ fn we_are_intro_node() {
+       // If we are sending straight to a blinded route and we are the introduction node, we need to
+       // advance the blinded route by 1 hop so the second hop is the new introduction node.
+       let mut nodes = create_nodes(3);
+       let test_msg = TestCustomMessage {};
+       let secp_ctx = Secp256k1::new();
+       let blinded_route = BlindedRoute::new(&[nodes[0].get_node_pk(), nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap();
+       nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), OnionMessageContents::Custom(test_msg.clone()), None).unwrap();
+       pass_along_path(&nodes, None);
+       // Try with a two-hop blinded route where we are the introduction node.
+       let blinded_route = BlindedRoute::new(&[nodes[0].get_node_pk(), nodes[1].get_node_pk()], &*nodes[1].keys_manager, &secp_ctx).unwrap();
+       nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), OnionMessageContents::Custom(test_msg), None).unwrap();
+       nodes.remove(2);
+       pass_along_path(&nodes, None);
+ }
  #[test]
  fn invalid_blinded_route_error() {
        // Make sure we error as expected if a provided blinded route has 0 or 1 hops.
@@@ -230,6 -253,12 +250,6 @@@ fn invalid_custom_message_type() 
                fn write<W: Writer>(&self, _w: &mut W) -> Result<(), io::Error> { unreachable!() }
        }
  
 -      impl MaybeReadableArgs<u64> for InvalidCustomMessage {
 -              fn read<R: io::Read>(_buffer: &mut R, _message_type: u64) -> Result<Option<Self>, DecodeError> where Self: Sized {
 -                      unreachable!()
 -              }
 -      }
 -
        let test_msg = OnionMessageContents::Custom(InvalidCustomMessage {});
        let err = nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), test_msg, None).unwrap_err();
        assert_eq!(err, SendError::InvalidMessage);
index a80715e16f092362473b16b7dd1fb5fb5d251346,70a0842c7710be9bf4ad86f4f6d76dd9be292322..a09c942be61fbfcb75da606e6b440bfffa37bdbc
@@@ -29,7 -29,6 +29,7 @@@ use crate::util::logger::Logger
  use crate::util::ser::Writeable;
  
  use core::ops::Deref;
 +use crate::io;
  use crate::sync::{Arc, Mutex};
  use crate::prelude::*;
  
@@@ -48,7 -47,7 +48,7 @@@
  /// # use lightning::ln::peer_handler::IgnoringMessageHandler;
  /// # use lightning::onion_message::{BlindedRoute, CustomOnionMessageContents, Destination, OnionMessageContents, OnionMessenger};
  /// # use lightning::util::logger::{Logger, Record};
 -/// # use lightning::util::ser::{MaybeReadableArgs, Writeable, Writer};
 +/// # use lightning::util::ser::{Writeable, Writer};
  /// # use lightning::io;
  /// # use std::sync::Arc;
  /// # struct FakeLogger {};
  ///           your_custom_message_type
  ///   }
  /// }
 -/// impl MaybeReadableArgs<u64> for YourCustomMessage {
 -///   fn read<R: io::Read>(r: &mut R, message_type: u64) -> Result<Option<Self>, DecodeError> {
 -///           # unreachable!()
 -///           // Read your custom onion message of type `message_type` from `r`, or return `None`
 -///           // if the message type is unknown
 -///   }
 -/// }
  /// // Send a custom onion message to a node id.
  /// let intermediate_hops = [hop_node_id1, hop_node_id2];
  /// let reply_path = None;
@@@ -154,6 -160,15 +154,15 @@@ pub enum SendError 
        InvalidMessage,
        /// Our next-hop peer's buffer was full or our total outbound buffer was full.
        BufferFull,
+       /// Failed to retrieve our node id from the provided [`KeysInterface`].
+       ///
+       /// [`KeysInterface`]: crate::chain::keysinterface::KeysInterface
+       GetNodeIdFailed,
+       /// We attempted to send to a blinded route where we are the introduction node, and failed to
+       /// advance the blinded route to make the second hop the new introduction node. Either
+       /// [`KeysInterface::ecdh`] failed, we failed to tweak the current blinding point to get the
+       /// new blinding point, or we were attempting to send to ourselves.
+       BlindedRouteAdvanceFailed,
  }
  
  /// Handler for custom onion messages. If you are using [`SimpleArcOnionMessenger`],
@@@ -172,9 -187,6 +181,9 @@@ pub trait CustomOnionMessageHandler 
        type CustomMessage: CustomOnionMessageContents;
        /// Called with the custom message that was received.
        fn handle_custom_message(&self, msg: Self::CustomMessage);
 +      /// Read a custom message of type `message_type` from `buffer`, returning `Ok(None)` if the
 +      /// message type is unknown.
 +      fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, msgs::DecodeError>;
  }
  
  impl<Signer: Sign, K: Deref, L: Deref, CMH: Deref> OnionMessenger<Signer, K, L, CMH>
  
        /// Send an onion message with contents `message` to `destination`, routing it through `intermediate_nodes`.
        /// See [`OnionMessenger`] for example usage.
-       pub fn send_onion_message<T: CustomOnionMessageContents>(&self, intermediate_nodes: &[PublicKey], destination: Destination, message: OnionMessageContents<T>, reply_path: Option<BlindedRoute>) -> Result<(), SendError> {
+       pub fn send_onion_message<T: CustomOnionMessageContents>(&self, intermediate_nodes: &[PublicKey], mut destination: Destination, message: OnionMessageContents<T>, reply_path: Option<BlindedRoute>) -> Result<(), SendError> {
                if let Destination::BlindedRoute(BlindedRoute { ref blinded_hops, .. }) = destination {
                        if blinded_hops.len() < 2 {
                                return Err(SendError::TooFewBlindedHops);
                let OnionMessageContents::Custom(ref msg) = message;
                if msg.tlv_type() < 64 { return Err(SendError::InvalidMessage) }
  
+               // If we are sending straight to a blinded route and we are the introduction node, we need to
+               // advance the blinded route by 1 hop so the second hop is the new introduction node.
+               if intermediate_nodes.len() == 0 {
+                       if let Destination::BlindedRoute(ref mut blinded_route) = destination {
+                               let our_node_id = self.keys_manager.get_node_id(Recipient::Node)
+                                       .map_err(|()| SendError::GetNodeIdFailed)?;
+                               if blinded_route.introduction_node_id == our_node_id {
+                                       blinded_route.advance_by_one(&self.keys_manager, &self.secp_ctx)
+                                               .map_err(|()| SendError::BlindedRouteAdvanceFailed)?;
+                               }
+                       }
+               }
                let blinding_secret_bytes = self.keys_manager.get_secure_random_bytes();
                let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted");
                let (introduction_node_id, blinding_point) = if intermediate_nodes.len() != 0 {
@@@ -276,7 -301,7 +298,7 @@@ fn outbound_buffer_full(peer_node_id: &
  impl<Signer: Sign, K: Deref, L: Deref, CMH: Deref> OnionMessageHandler for OnionMessenger<Signer, K, L, CMH>
        where K::Target: KeysInterface<Signer = Signer>,
              L::Target: Logger,
 -            CMH::Target: CustomOnionMessageHandler,
 +            CMH::Target: CustomOnionMessageHandler + Sized,
  {
        /// Handle an incoming onion message. Currently, if a message was destined for us we will log, but
        /// soon we'll delegate the onion message to a handler that can generate invoices or send
                                }
                        }
                };
 -              match onion_utils::decode_next_hop(onion_decode_ss, &msg.onion_routing_packet.hop_data[..],
 -                      msg.onion_routing_packet.hmac, control_tlvs_ss)
 +              match onion_utils::decode_next_untagged_hop(onion_decode_ss, &msg.onion_routing_packet.hop_data[..],
 +                      msg.onion_routing_packet.hmac, (control_tlvs_ss, &*self.custom_handler))
                {
                        Ok((Payload::Receive::<<<CMH as Deref>::Target as CustomOnionMessageHandler>::CustomMessage> {
                                message, control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id }), reply_path,
@@@ -488,12 -513,8 +510,8 @@@ fn packet_payloads_and_keys<T: CustomOn
                                        next_blinding_override: Some(blinding_pt),
                                })), control_tlvs_ss));
                        }
-                       if let Some(encrypted_payload) = enc_payload_opt {
-                               payloads.push((Payload::Forward(ForwardControlTlvs::Blinded(encrypted_payload)),
-                                       control_tlvs_ss));
-                       } else { debug_assert!(false); }
-                       blinded_path_idx += 1;
-               } else if blinded_path_idx < num_blinded_hops - 1 && enc_payload_opt.is_some() {
+               }
+               if blinded_path_idx < num_blinded_hops.saturating_sub(1) && enc_payload_opt.is_some() {
                        payloads.push((Payload::Forward(ForwardControlTlvs::Blinded(enc_payload_opt.unwrap())),
                                control_tlvs_ss));
                        blinded_path_idx += 1;