Support onion message replies in OnionMessenger
authorJeffrey Czyz <jkczyz@gmail.com>
Sun, 19 Feb 2023 01:29:14 +0000 (19:29 -0600)
committerJeffrey Czyz <jkczyz@gmail.com>
Tue, 13 Jun 2023 18:07:47 +0000 (13:07 -0500)
Modify onion message handlers to return an optional response message for
OnionMessenger to reply with.

fuzz/src/onion_message.rs
lightning/src/ln/peer_handler.rs
lightning/src/onion_message/functional_tests.rs
lightning/src/onion_message/messenger.rs
lightning/src/onion_message/offers.rs

index fd19a6114581183560f9d7433a92baf699c374db..0e31347f5233fc6fbff9d280dfb0570c3cedc1d1 100644 (file)
@@ -68,7 +68,9 @@ impl MessageRouter for TestMessageRouter {
 struct TestOffersMessageHandler {}
 
 impl OffersMessageHandler for TestOffersMessageHandler {
-       fn handle_message(&self, _message: OffersMessage) {}
+       fn handle_message(&self, _message: OffersMessage) -> Option<OffersMessage> {
+               None
+       }
 }
 
 struct TestCustomMessage {}
@@ -92,7 +94,9 @@ struct TestCustomMessageHandler {}
 
 impl CustomOnionMessageHandler for TestCustomMessageHandler {
        type CustomMessage = TestCustomMessage;
-       fn handle_custom_message(&self, _msg: Self::CustomMessage) {}
+       fn handle_custom_message(&self, _msg: Self::CustomMessage) -> Option<Self::CustomMessage> {
+               None
+       }
        fn read_custom_message<R: io::Read>(&self, _message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, msgs::DecodeError> {
                let mut buf = Vec::new();
                buffer.read_to_end(&mut buf)?;
index 56e0a1e0a444a04f6b9521119ab304066672159f..931e8c4e4245d8485962015f9937b42f25e17de6 100644 (file)
@@ -119,11 +119,11 @@ impl OnionMessageHandler for IgnoringMessageHandler {
        }
 }
 impl OffersMessageHandler for IgnoringMessageHandler {
-       fn handle_message(&self, _msg: OffersMessage) {}
+       fn handle_message(&self, _msg: OffersMessage) -> Option<OffersMessage> { None }
 }
 impl CustomOnionMessageHandler for IgnoringMessageHandler {
        type CustomMessage = Infallible;
-       fn handle_custom_message(&self, _msg: Infallible) {
+       fn handle_custom_message(&self, _msg: Infallible) -> Option<Infallible> {
                // Since we always return `None` in the read the handle method should never be called.
                unreachable!();
        }
index a5effdd92fe49d1df9ee122b7516523c392b66cc..e6058c459eb972710a84605d30bbc69360fd976c 100644 (file)
@@ -58,8 +58,8 @@ impl MessageRouter for TestMessageRouter {
 struct TestOffersMessageHandler {}
 
 impl OffersMessageHandler for TestOffersMessageHandler {
-       fn handle_message(&self, _message: OffersMessage) {
-               todo!()
+       fn handle_message(&self, _message: OffersMessage) -> Option<OffersMessage> {
+               None
        }
 }
 
@@ -104,8 +104,9 @@ impl Drop for TestCustomMessageHandler {
 
 impl CustomOnionMessageHandler for TestCustomMessageHandler {
        type CustomMessage = TestCustomMessage;
-       fn handle_custom_message(&self, _msg: Self::CustomMessage) {
+       fn handle_custom_message(&self, _msg: Self::CustomMessage) -> Option<Self::CustomMessage> {
                self.num_messages_expected.fetch_sub(1, Ordering::SeqCst);
+               None
        }
        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 {
index 07cb0bc1e9896df5241c05a0b80a2b03e89eb995..7c259113934ca797ec211dd1bb33b8bd2f0f0d74 100644 (file)
@@ -224,8 +224,10 @@ pub trait CustomOnionMessageHandler {
        /// The message known to the handler. To support multiple message types, you may want to make this
        /// an enum with a variant for each supported message.
        type CustomMessage: CustomOnionMessageContents;
-       /// Called with the custom message that was received.
-       fn handle_custom_message(&self, msg: Self::CustomMessage);
+
+       /// Called with the custom message that was received, returning a response to send, if any.
+       fn handle_custom_message(&self, msg: Self::CustomMessage) -> Option<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>;
@@ -320,6 +322,56 @@ where
                }
        }
 
+       fn respond_with_onion_message<T: CustomOnionMessageContents>(
+               &self, response: OnionMessageContents<T>, path_id: Option<[u8; 32]>,
+               reply_path: Option<BlindedPath>
+       ) {
+               let sender = match self.node_signer.get_node_id(Recipient::Node) {
+                       Ok(node_id) => node_id,
+                       Err(_) => {
+                               log_warn!(
+                                       self.logger, "Unable to retrieve node id when responding to onion message with \
+                                       path_id {:02x?}", path_id
+                               );
+                               return;
+                       }
+               };
+
+               let peers = self.pending_messages.lock().unwrap().keys().copied().collect();
+
+               let destination = match reply_path {
+                       Some(reply_path) => Destination::BlindedPath(reply_path),
+                       None => {
+                               log_trace!(
+                                       self.logger, "Missing reply path when responding to onion message with path_id \
+                                       {:02x?}", path_id
+                               );
+                               return;
+                       },
+               };
+
+               let path = match self.message_router.find_path(sender, peers, destination) {
+                       Ok(path) => path,
+                       Err(()) => {
+                               log_trace!(
+                                       self.logger, "Failed to find path when responding to onion message with \
+                                       path_id {:02x?}", path_id
+                               );
+                               return;
+                       },
+               };
+
+               log_trace!(self.logger, "Responding to onion message with path_id {:02x?}", path_id);
+
+               if let Err(e) = self.send_onion_message(path, response, None) {
+                       log_trace!(
+                               self.logger, "Failed responding to onion message with path_id {:02x?}: {:?}",
+                               path_id, e
+                       );
+                       return;
+               }
+       }
+
        #[cfg(test)]
        pub(super) fn release_pending_msgs(&self) -> HashMap<PublicKey, VecDeque<msgs::OnionMessage>> {
                let mut pending_msgs = self.pending_messages.lock().unwrap();
@@ -403,9 +455,20 @@ where
                                log_info!(self.logger,
                                        "Received an onion message with path_id {:02x?} and {} reply_path",
                                                path_id, if reply_path.is_some() { "a" } else { "no" });
-                               match message {
-                                       OnionMessageContents::Offers(msg) => self.offers_handler.handle_message(msg),
-                                       OnionMessageContents::Custom(msg) => self.custom_handler.handle_custom_message(msg),
+
+                               let response = match message {
+                                       OnionMessageContents::Offers(msg) => {
+                                               self.offers_handler.handle_message(msg)
+                                                       .map(|msg| OnionMessageContents::Offers(msg))
+                                       },
+                                       OnionMessageContents::Custom(msg) => {
+                                               self.custom_handler.handle_custom_message(msg)
+                                                       .map(|msg| OnionMessageContents::Custom(msg))
+                                       },
+                               };
+
+                               if let Some(response) = response {
+                                       self.respond_with_onion_message(response, path_id, reply_path);
                                }
                        },
                        Ok((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {
index 98276d1bfb74d1fb617a3b8c71892a0280d2593b..f82afdd618a5bfa78ac02a7e0bfd6476cac4bbdd 100644 (file)
@@ -32,7 +32,7 @@ const INVOICE_ERROR_TLV_TYPE: u64 = 68;
 pub trait OffersMessageHandler {
        /// Handles the given message by either responding with an [`Invoice`], sending a payment, or
        /// replying with an error.
-       fn handle_message(&self, message: OffersMessage);
+       fn handle_message(&self, message: OffersMessage) -> Option<OffersMessage>;
 }
 
 /// Possible BOLT 12 Offers messages sent and received via an [`OnionMessage`].