From 8b442fe4eb80ee43121c3a0f7a364698a296b713 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Wed, 13 Sep 2023 21:19:50 -0500 Subject: [PATCH] Enqueue onion messages in handlers When constructing onion messages to send initially (opposed to replying to one from a handler), the user must construct an OnionMessagePath first before calling OnionMessener::send_onion_message. Additionally, having a reference to OnionMessener isn't always desirable. For instance, in an upcoming commit, ChannelManager will implement OffersMessageHandler, which OnionMessenger needs a reference to. If ChannelManager had a reference to OnionMessenger, too, there would be a dependency cycle. Instead, modify OffersMessageHandler and CustomOnionMessageHandler's interfaces to include a method for releasing pending onion messages. That way, ChannelManager may, for instance, construct and enqueue an InvoiceRequest for sending without needing a reference to OnionMessenger. Additionally, OnionMessenger has responsibility for path finding just as it does when replying to messages from a handler. It performs this when extracting messages from the handlers before returning the next message to send to a peer. --- fuzz/src/onion_message.rs | 5 +- lightning/src/ln/peer_handler.rs | 5 +- .../src/onion_message/functional_tests.rs | 5 +- lightning/src/onion_message/messenger.rs | 49 +++++++++++++++++-- lightning/src/onion_message/mod.rs | 2 +- lightning/src/onion_message/offers.rs | 11 +++++ 6 files changed, 70 insertions(+), 7 deletions(-) diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index 57d4f697b..6277037a1 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -14,7 +14,7 @@ use lightning::offers::invoice_request::UnsignedInvoiceRequest; use lightning::util::test_channel_signer::TestChannelSigner; use lightning::util::logger::Logger; use lightning::util::ser::{Readable, Writeable, Writer}; -use lightning::onion_message::{CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessagePath, OnionMessenger}; +use lightning::onion_message::{CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessagePath, OnionMessenger, PendingOnionMessage}; use crate::utils::test_logger; @@ -108,6 +108,9 @@ impl CustomOnionMessageHandler for TestCustomMessageHandler { buffer.read_to_end(&mut buf)?; return Ok(Some(TestCustomMessage {})) } + fn release_pending_custom_messages(&self) -> Vec> { + vec![] + } } pub struct VecWriter(pub Vec); diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 84fb9748b..fc574251f 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -29,7 +29,7 @@ use crate::util::ser::{VecWriter, Writeable, Writer}; use crate::ln::peer_channel_encryptor::{PeerChannelEncryptor,NextNoiseStep}; use crate::ln::wire; use crate::ln::wire::{Encode, Type}; -use crate::onion_message::{CustomOnionMessageHandler, OffersMessage, OffersMessageHandler, OnionMessageContents, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; +use crate::onion_message::{CustomOnionMessageHandler, OffersMessage, OffersMessageHandler, OnionMessageContents, PendingOnionMessage, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; use crate::routing::gossip::{NetworkGraph, P2PGossipSync, NodeId, NodeAlias}; use crate::util::atomic_counter::AtomicCounter; use crate::util::logger::Logger; @@ -129,6 +129,9 @@ impl CustomOnionMessageHandler for IgnoringMessageHandler { fn read_custom_message(&self, _msg_type: u64, _buffer: &mut R) -> Result, msgs::DecodeError> where Self: Sized { Ok(None) } + fn release_pending_custom_messages(&self) -> Vec> { + vec![] + } } impl OnionMessageContents for Infallible { diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index 0348e4afb..6540fc89c 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -15,7 +15,7 @@ use crate::ln::msgs::{self, DecodeError, OnionMessageHandler}; use crate::sign::{NodeSigner, Recipient}; use crate::util::ser::{FixedLengthReader, LengthReadable, Writeable, Writer}; use crate::util::test_utils; -use super::{CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessagePath, OnionMessenger, SendError}; +use super::{CustomOnionMessageHandler, Destination, MessageRouter, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessagePath, OnionMessenger, PendingOnionMessage, SendError}; use bitcoin::network::constants::Network; use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey}; @@ -148,6 +148,9 @@ impl CustomOnionMessageHandler for TestCustomMessageHandler { _ => Ok(None), } } + fn release_pending_custom_messages(&self) -> Vec> { + vec![] + } } fn create_nodes(num_messengers: u8) -> Vec { diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index d6aa5c82c..d526ba9e3 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -153,6 +153,21 @@ where custom_handler: CMH, } +/// An [`OnionMessage`] for [`OnionMessenger`] to send. +/// +/// These are obtained when released from [`OnionMessenger`]'s handlers after which they are +/// enqueued for sending. +pub struct PendingOnionMessage { + /// The message contents to send in an [`OnionMessage`]. + pub contents: T, + + /// The destination of the message. + pub destination: Destination, + + /// A reply path to include in the [`OnionMessage`] for a response. + pub reply_path: Option, +} + /// A trait defining behavior for routing an [`OnionMessage`]. pub trait MessageRouter { /// Returns a route for sending an [`OnionMessage`] to the given [`Destination`]. @@ -246,11 +261,19 @@ pub trait CustomOnionMessageHandler { type CustomMessage: OnionMessageContents; /// Called with the custom message that was received, returning a response to send, if any. + /// + /// The returned [`Self::CustomMessage`], if any, is enqueued to be sent by [`OnionMessenger`]. fn handle_custom_message(&self, msg: Self::CustomMessage) -> Option; /// Read a custom message of type `message_type` from `buffer`, returning `Ok(None)` if the /// message type is unknown. fn read_custom_message(&self, message_type: u64, buffer: &mut R) -> Result, msgs::DecodeError>; + + /// Releases any [`Self::CustomMessage`]s that need to be sent. + /// + /// Typically, this is used for messages initiating a message flow rather than in response to + /// another message. The latter should use the return value of [`Self::handle_custom_message`]. + fn release_pending_custom_messages(&self) -> Vec>; } /// A processed incoming onion message, containing either a Forward (another onion message) @@ -475,7 +498,7 @@ where match reply_path { Some(reply_path) => { self.find_path_and_enqueue_onion_message( - response, Destination::BlindedPath(reply_path), log_suffix + response, Destination::BlindedPath(reply_path), None, log_suffix ); }, None => { @@ -486,7 +509,8 @@ where } fn find_path_and_enqueue_onion_message( - &self, contents: T, destination: Destination, log_suffix: fmt::Arguments + &self, contents: T, destination: Destination, reply_path: Option, + log_suffix: fmt::Arguments ) { let sender = match self.node_signer.get_node_id(Recipient::Node) { Ok(node_id) => node_id, @@ -507,7 +531,7 @@ where log_trace!(self.logger, "Sending onion message {}", log_suffix); - if let Err(e) = self.send_onion_message(path, contents, None) { + if let Err(e) = self.send_onion_message(path, contents, reply_path) { log_trace!(self.logger, "Failed sending onion message {}: {:?}", log_suffix, e); return; } @@ -644,7 +668,26 @@ where features } + // Before returning any messages to send for the peer, this method will see if any messages were + // enqueued in the handler by users, find a path to the corresponding blinded path's introduction + // node, and then enqueue the message for sending to the first peer in the full path. fn next_onion_message_for_peer(&self, peer_node_id: PublicKey) -> Option { + // Enqueue any initiating `OffersMessage`s to send. + for message in self.offers_handler.release_pending_messages() { + let PendingOnionMessage { contents, destination, reply_path } = message; + self.find_path_and_enqueue_onion_message( + contents, destination, reply_path, format_args!("when sending OffersMessage") + ); + } + + // Enqueue any initiating `CustomMessage`s to send. + for message in self.custom_handler.release_pending_custom_messages() { + let PendingOnionMessage { contents, destination, reply_path } = message; + self.find_path_and_enqueue_onion_message( + contents, destination, reply_path, format_args!("when sending CustomMessage") + ); + } + let mut pending_msgs = self.pending_messages.lock().unwrap(); if let Some(msgs) = pending_msgs.get_mut(&peer_node_id) { return msgs.pop_front() diff --git a/lightning/src/onion_message/mod.rs b/lightning/src/onion_message/mod.rs index dd9279231..be800822e 100644 --- a/lightning/src/onion_message/mod.rs +++ b/lightning/src/onion_message/mod.rs @@ -27,7 +27,7 @@ mod packet; mod functional_tests; // Re-export structs so they can be imported with just the `onion_message::` module prefix. -pub use self::messenger::{CustomOnionMessageHandler, DefaultMessageRouter, Destination, MessageRouter, OnionMessageContents, OnionMessagePath, OnionMessenger, PeeledOnion, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; +pub use self::messenger::{CustomOnionMessageHandler, DefaultMessageRouter, Destination, MessageRouter, OnionMessageContents, OnionMessagePath, OnionMessenger, PeeledOnion, PendingOnionMessage, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; pub use self::offers::{OffersMessage, OffersMessageHandler}; pub use self::packet::{Packet, ParsedOnionMessageContents}; pub(crate) use self::packet::ControlTlvs; diff --git a/lightning/src/onion_message/offers.rs b/lightning/src/onion_message/offers.rs index f5945cd55..254db7b81 100644 --- a/lightning/src/onion_message/offers.rs +++ b/lightning/src/onion_message/offers.rs @@ -17,6 +17,7 @@ use crate::offers::invoice_request::InvoiceRequest; use crate::offers::invoice::Bolt12Invoice; use crate::offers::parse::Bolt12ParseError; use crate::onion_message::OnionMessageContents; +use crate::onion_message::messenger::PendingOnionMessage; use crate::util::logger::Logger; use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer}; @@ -33,7 +34,17 @@ const INVOICE_ERROR_TLV_TYPE: u64 = 68; pub trait OffersMessageHandler { /// Handles the given message by either responding with an [`Bolt12Invoice`], sending a payment, /// or replying with an error. + /// + /// The returned [`OffersMessage`], if any, is enqueued to be sent by [`OnionMessenger`]. + /// + /// [`OnionMessenger`]: crate::onion_message::OnionMessenger fn handle_message(&self, message: OffersMessage) -> Option; + + /// Releases any [`OffersMessage`]s that need to be sent. + /// + /// Typically, this is used for messages initiating a payment flow rather than in response to + /// another message. The latter should use the return value of [`Self::handle_message`]. + fn release_pending_messages(&self) -> Vec> { vec![] } } /// Possible BOLT 12 Offers messages sent and received via an [`OnionMessage`]. -- 2.39.5