Update send_onion_message API to take new OnionMessageContents enum
authorValentine Wallace <vwallace@protonmail.com>
Tue, 18 Oct 2022 17:22:12 +0000 (13:22 -0400)
committerValentine Wallace <vwallace@protonmail.com>
Tue, 18 Oct 2022 17:28:29 +0000 (13:28 -0400)
OnionMessageContents specifies the data TLV that the sender wants in the onion
message. This enum only has one variant for now, Custom. When offers are added,
additional variants for invoice, invoice_request, and invoice_error will be
added.

This commit does not actually implement sending the custom OM contents, just
the API change.

lightning/src/onion_message/functional_tests.rs
lightning/src/onion_message/messenger.rs
lightning/src/onion_message/mod.rs
lightning/src/onion_message/packet.rs

index 1521b9d77ef6eafd6ef34325c4105b4f33b34b69..356e1f3cdafafe6fec5d25bcaeada4da7bc5cedc 100644 (file)
@@ -12,7 +12,7 @@
 use chain::keysinterface::{KeysInterface, Recipient};
 use ln::features::InitFeatures;
 use ln::msgs::{self, DecodeError, OnionMessageHandler};
-use super::{BlindedRoute, CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessenger, SendError};
+use super::{BlindedRoute, CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessageContents, OnionMessenger, SendError};
 use util::enforcing_trait_impls::EnforcingSigner;
 use util::ser::{MaybeReadableArgs, Writeable, Writer};
 use util::test_utils;
@@ -119,38 +119,42 @@ fn pass_along_path(path: &Vec<MessengerNode>, expected_path_id: Option<[u8; 32]>
 #[test]
 fn one_hop() {
        let nodes = create_nodes(2);
+       let test_msg = OnionMessageContents::Custom(TestCustomMessage {});
 
-       nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), None).unwrap();
+       nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), test_msg, None).unwrap();
        pass_along_path(&nodes, None);
 }
 
 #[test]
 fn two_unblinded_hops() {
        let nodes = create_nodes(3);
+       let test_msg = OnionMessageContents::Custom(TestCustomMessage {});
 
-       nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk()], Destination::Node(nodes[2].get_node_pk()), None).unwrap();
+       nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk()], Destination::Node(nodes[2].get_node_pk()), test_msg, None).unwrap();
        pass_along_path(&nodes, None);
 }
 
 #[test]
 fn two_unblinded_two_blinded() {
        let nodes = create_nodes(5);
+       let test_msg = OnionMessageContents::Custom(TestCustomMessage {});
 
        let secp_ctx = Secp256k1::new();
        let blinded_route = BlindedRoute::new(&[nodes[3].get_node_pk(), nodes[4].get_node_pk()], &*nodes[4].keys_manager, &secp_ctx).unwrap();
 
-       nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::BlindedRoute(blinded_route), None).unwrap();
+       nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::BlindedRoute(blinded_route), test_msg, None).unwrap();
        pass_along_path(&nodes, None);
 }
 
 #[test]
 fn three_blinded_hops() {
        let nodes = create_nodes(4);
+       let test_msg = OnionMessageContents::Custom(TestCustomMessage {});
 
        let secp_ctx = Secp256k1::new();
        let blinded_route = BlindedRoute::new(&[nodes[1].get_node_pk(), nodes[2].get_node_pk(), nodes[3].get_node_pk()], &*nodes[3].keys_manager, &secp_ctx).unwrap();
 
-       nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), None).unwrap();
+       nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), test_msg, None).unwrap();
        pass_along_path(&nodes, None);
 }
 
@@ -158,10 +162,11 @@ fn three_blinded_hops() {
 fn too_big_packet_error() {
        // Make sure we error as expected if a packet is too big to send.
        let nodes = create_nodes(2);
+       let test_msg = OnionMessageContents::Custom(TestCustomMessage {});
 
        let hop_node_id = nodes[1].get_node_pk();
        let hops = [hop_node_id; 400];
-       let err = nodes[0].messenger.send_onion_message(&hops, Destination::Node(hop_node_id), None).unwrap_err();
+       let err = nodes[0].messenger.send_onion_message(&hops, Destination::Node(hop_node_id), test_msg, None).unwrap_err();
        assert_eq!(err, SendError::TooBigPacket);
 }
 
@@ -169,30 +174,32 @@ fn too_big_packet_error() {
 fn invalid_blinded_route_error() {
        // Make sure we error as expected if a provided blinded route has 0 or 1 hops.
        let nodes = create_nodes(3);
+       let test_msg = TestCustomMessage {};
 
        // 0 hops
        let secp_ctx = Secp256k1::new();
        let mut blinded_route = BlindedRoute::new(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap();
        blinded_route.blinded_hops.clear();
-       let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), None).unwrap_err();
+       let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), OnionMessageContents::Custom(test_msg.clone()), None).unwrap_err();
        assert_eq!(err, SendError::TooFewBlindedHops);
 
        // 1 hop
        let mut blinded_route = BlindedRoute::new(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], &*nodes[2].keys_manager, &secp_ctx).unwrap();
        blinded_route.blinded_hops.remove(0);
        assert_eq!(blinded_route.blinded_hops.len(), 1);
-       let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), None).unwrap_err();
+       let err = nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), OnionMessageContents::Custom(test_msg), None).unwrap_err();
        assert_eq!(err, SendError::TooFewBlindedHops);
 }
 
 #[test]
 fn reply_path() {
        let nodes = create_nodes(4);
+       let test_msg = TestCustomMessage {};
        let secp_ctx = Secp256k1::new();
 
        // Destination::Node
        let reply_path = BlindedRoute::new(&[nodes[2].get_node_pk(), nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap();
-       nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::Node(nodes[3].get_node_pk()), Some(reply_path)).unwrap();
+       nodes[0].messenger.send_onion_message(&[nodes[1].get_node_pk(), nodes[2].get_node_pk()], Destination::Node(nodes[3].get_node_pk()), OnionMessageContents::Custom(test_msg.clone()), Some(reply_path)).unwrap();
        pass_along_path(&nodes, None);
        // Make sure the last node successfully decoded the reply path.
        nodes[3].logger.assert_log_contains(
@@ -203,7 +210,7 @@ fn reply_path() {
        let blinded_route = BlindedRoute::new(&[nodes[1].get_node_pk(), nodes[2].get_node_pk(), nodes[3].get_node_pk()], &*nodes[3].keys_manager, &secp_ctx).unwrap();
        let reply_path = BlindedRoute::new(&[nodes[2].get_node_pk(), nodes[1].get_node_pk(), nodes[0].get_node_pk()], &*nodes[0].keys_manager, &secp_ctx).unwrap();
 
-       nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), Some(reply_path)).unwrap();
+       nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route), OnionMessageContents::Custom(test_msg), Some(reply_path)).unwrap();
        pass_along_path(&nodes, None);
        nodes[3].logger.assert_log_contains(
                "lightning::onion_message::messenger".to_string(),
@@ -213,9 +220,10 @@ fn reply_path() {
 #[test]
 fn peer_buffer_full() {
        let nodes = create_nodes(2);
+       let test_msg = TestCustomMessage {};
        for _ in 0..188 { // Based on MAX_PER_PEER_BUFFER_SIZE in OnionMessenger
-               nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), None).unwrap();
+               nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), OnionMessageContents::Custom(test_msg.clone()), None).unwrap();
        }
-       let err = nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), None).unwrap_err();
+       let err = nodes[0].messenger.send_onion_message(&[], Destination::Node(nodes[1].get_node_pk()), OnionMessageContents::Custom(test_msg), None).unwrap_err();
        assert_eq!(err, SendError::BufferFull);
 }
index 9db374694366e936ceb9301a076b4939ad40048f..1f7fe53084304ad6c4d0cc023adaba1d3b2b5437 100644 (file)
@@ -21,7 +21,7 @@ use ln::msgs::{self, OnionMessageHandler};
 use ln::onion_utils;
 use ln::peer_handler::IgnoringMessageHandler;
 use super::blinded_route::{BlindedRoute, ForwardTlvs, ReceiveTlvs};
-pub use super::packet::CustomOnionMessageContents;
+pub use super::packet::{CustomOnionMessageContents, OnionMessageContents};
 use super::packet::{BIG_PACKET_HOP_DATA_LEN, ForwardControlTlvs, Packet, Payload, ReceiveControlTlvs, SMALL_PACKET_HOP_DATA_LEN};
 use super::utils;
 use util::events::OnionMessageProvider;
@@ -34,7 +34,7 @@ use prelude::*;
 
 /// A sender, receiver and forwarder of onion messages. In upcoming releases, this object will be
 /// used to retrieve invoices and fulfill invoice requests from [offers]. Currently, only sending
-/// and receiving empty onion messages is supported.
+/// and receiving custom onion messages is supported.
 ///
 /// # Example
 ///
@@ -45,7 +45,7 @@ use prelude::*;
 /// # use lightning::chain::keysinterface::{InMemorySigner, KeysManager, KeysInterface};
 /// # use lightning::ln::msgs::DecodeError;
 /// # use lightning::ln::peer_handler::IgnoringMessageHandler;
-/// # use lightning::onion_message::{BlindedRoute, CustomOnionMessageContents, Destination, OnionMessenger};
+/// # use lightning::onion_message::{BlindedRoute, CustomOnionMessageContents, Destination, OnionMessageContents, OnionMessenger};
 /// # use lightning::util::logger::{Logger, Record};
 /// # use lightning::util::ser::{MaybeReadableArgs, Writeable, Writer};
 /// # use lightning::io;
@@ -88,19 +88,24 @@ use prelude::*;
 ///            // 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;
-/// onion_messenger.send_onion_message(&intermediate_hops, Destination::Node(destination_node_id), reply_path);
+/// # let your_custom_message = YourCustomMessage {};
+/// let message = OnionMessageContents::Custom(your_custom_message);
+/// onion_messenger.send_onion_message(&intermediate_hops, Destination::Node(destination_node_id), message, reply_path);
 ///
 /// // Create a blinded route to yourself, for someone to send an onion message to.
 /// # let your_node_id = hop_node_id1;
 /// let hops = [hop_node_id3, hop_node_id4, your_node_id];
 /// let blinded_route = BlindedRoute::new(&hops, &keys_manager, &secp_ctx).unwrap();
 ///
-/// // Send an empty onion message to a blinded route.
+/// // Send a custom onion message to a blinded route.
 /// # let intermediate_hops = [hop_node_id1, hop_node_id2];
 /// let reply_path = None;
-/// onion_messenger.send_onion_message(&intermediate_hops, Destination::BlindedRoute(blinded_route), reply_path);
+/// # let your_custom_message = YourCustomMessage {};
+/// let message = OnionMessageContents::Custom(your_custom_message);
+/// onion_messenger.send_onion_message(&intermediate_hops, Destination::BlindedRoute(blinded_route), message, reply_path);
 /// ```
 ///
 /// [offers]: <https://github.com/lightning/bolts/pull/798>
@@ -192,9 +197,9 @@ impl<Signer: Sign, K: Deref, L: Deref, CMH: Deref> OnionMessenger<Signer, K, L,
                }
        }
 
-       /// Send an empty onion message to `destination`, routing it through `intermediate_nodes`.
+       /// Send an onion message with contents `message` to `destination`, routing it through `intermediate_nodes`.
        /// See [`OnionMessenger`] for example usage.
-       pub fn send_onion_message(&self, intermediate_nodes: &[PublicKey], destination: Destination, reply_path: Option<BlindedRoute>) -> Result<(), SendError> {
+       pub fn send_onion_message<T: CustomOnionMessageContents>(&self, intermediate_nodes: &[PublicKey], 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);
index b80c540a6e117f0f6aad0a7ba8eec3459e44c0cc..3c522e30c51bf367c25311b6987418f3fe802931 100644 (file)
@@ -29,5 +29,5 @@ mod functional_tests;
 
 // Re-export structs so they can be imported with just the `onion_message::` module prefix.
 pub use self::blinded_route::{BlindedRoute, BlindedHop};
-pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
+pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessageContents, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
 pub(crate) use self::packet::Packet;
index 2afdbdd6570dc63c6d050e16d8d0d33161877282..8738091a94267d959b606e88d8e6ce18202fcf16 100644 (file)
@@ -104,13 +104,34 @@ pub(super) enum Payload {
        }
 }
 
-// Coming soon:
-// enum Message {
-//     InvoiceRequest(InvoiceRequest),
-//     Invoice(Invoice),
-//     InvoiceError(InvoiceError),
-//     CustomMessage<T>,
-// }
+#[derive(Debug)]
+/// The contents of an onion message. In the context of offers, this would be the invoice, invoice
+/// request, or invoice error.
+pub enum OnionMessageContents<T> where T: CustomOnionMessageContents {
+       // Coming soon:
+       // Invoice,
+       // InvoiceRequest,
+       // InvoiceError,
+       /// A custom onion message specified by the user.
+       Custom(T),
+}
+
+impl<T> OnionMessageContents<T> where T: CustomOnionMessageContents {
+       /// Returns the type that was used to decode the message payload.
+       pub fn tlv_type(&self) -> u64 {
+               match self {
+                       &OnionMessageContents::Custom(ref msg) => msg.tlv_type(),
+               }
+       }
+}
+
+impl<T: CustomOnionMessageContents> Writeable for OnionMessageContents<T> {
+       fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+               match self {
+                       OnionMessageContents::Custom(msg) => Ok(msg.write(w)?),
+               }
+       }
+}
 
 /// The contents of a custom onion message. Must implement `MaybeReadableArgs<u64>` where the `u64`
 /// is the custom TLV type attempting to be read, and return `Ok(None)` if the TLV type is unknown.