From ec538d181677bdd4a9dd7b29f619fff032fc2120 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Tue, 18 Oct 2022 13:22:12 -0400 Subject: [PATCH] Update send_onion_message API to take new OnionMessageContents enum 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. --- .../src/onion_message/functional_tests.rs | 32 ++++++++++------- lightning/src/onion_message/messenger.rs | 21 ++++++----- lightning/src/onion_message/mod.rs | 2 +- lightning/src/onion_message/packet.rs | 35 +++++++++++++++---- 4 files changed, 62 insertions(+), 28 deletions(-) diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index 1521b9d7..356e1f3c 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -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, 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); } diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 9db37469..1f7fe530 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -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]: @@ -192,9 +197,9 @@ impl OnionMessenger) -> Result<(), SendError> { + pub fn send_onion_message(&self, intermediate_nodes: &[PublicKey], destination: Destination, message: OnionMessageContents, reply_path: Option) -> Result<(), SendError> { if let Destination::BlindedRoute(BlindedRoute { ref blinded_hops, .. }) = destination { if blinded_hops.len() < 2 { return Err(SendError::TooFewBlindedHops); diff --git a/lightning/src/onion_message/mod.rs b/lightning/src/onion_message/mod.rs index b80c540a..3c522e30 100644 --- a/lightning/src/onion_message/mod.rs +++ b/lightning/src/onion_message/mod.rs @@ -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; diff --git a/lightning/src/onion_message/packet.rs b/lightning/src/onion_message/packet.rs index 2afdbdd6..8738091a 100644 --- a/lightning/src/onion_message/packet.rs +++ b/lightning/src/onion_message/packet.rs @@ -104,13 +104,34 @@ pub(super) enum Payload { } } -// Coming soon: -// enum Message { -// InvoiceRequest(InvoiceRequest), -// Invoice(Invoice), -// InvoiceError(InvoiceError), -// CustomMessage, -// } +#[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 where T: CustomOnionMessageContents { + // Coming soon: + // Invoice, + // InvoiceRequest, + // InvoiceError, + /// A custom onion message specified by the user. + Custom(T), +} + +impl OnionMessageContents 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 Writeable for OnionMessageContents { + fn write(&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` where the `u64` /// is the custom TLV type attempting to be read, and return `Ok(None)` if the TLV type is unknown. -- 2.30.2