Onion messages: fix edge case where we are the introduction node
[rust-lightning] / lightning / src / onion_message / messenger.rs
index ff20f19a7fc16a6bfea57e59f1b00eca27dc1d77..4eb0ada38399a40da8fb2c3b7a29d3f05cec445f 100644 (file)
@@ -160,6 +160,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`],
@@ -201,7 +210,7 @@ impl<Signer: Sign, K: Deref, L: Deref, CMH: Deref> OnionMessenger<Signer, K, L,
 
        /// 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);
@@ -210,6 +219,19 @@ impl<Signer: Sign, K: Deref, L: Deref, CMH: Deref> OnionMessenger<Signer, K, L,
                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 {