]> git.bitcoin.ninja Git - rust-lightning/commitdiff
OffersMessageHandler trait for OnionMessenger
authorJeffrey Czyz <jkczyz@gmail.com>
Wed, 15 Feb 2023 22:10:59 +0000 (16:10 -0600)
committerJeffrey Czyz <jkczyz@gmail.com>
Tue, 13 Jun 2023 18:07:47 +0000 (13:07 -0500)
Add a trait for handling BOLT 12 Offers messages to OnionMessenger and a
skeleton implementation of it for ChannelManager. This allows users to
either provide their own custom handling Offers messages or rely on a
version provided by LDK using stateless verification.

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/mod.rs
lightning/src/onion_message/offers.rs
lightning/src/onion_message/packet.rs

index 5fb2122ced4a5485c6169111cda9a0d3b0aceae5..ec467e22dda5dd86d0c654a863f557093bae74cb 100644 (file)
@@ -11,7 +11,7 @@ use lightning::ln::script::ShutdownScript;
 use lightning::util::enforcing_trait_impls::EnforcingSigner;
 use lightning::util::logger::Logger;
 use lightning::util::ser::{Readable, Writeable, Writer};
-use lightning::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, OnionMessenger};
+use lightning::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, OffersMessage, OffersMessageHandler, OnionMessenger};
 
 use crate::utils::test_logger;
 
@@ -29,8 +29,11 @@ pub fn do_test<L: Logger>(data: &[u8], logger: &L) {
                        node_secret: secret,
                        counter: AtomicU64::new(0),
                };
+               let offers_msg_handler = TestOffersMessageHandler {};
                let custom_msg_handler = TestCustomMessageHandler {};
-               let onion_messenger = OnionMessenger::new(&keys_manager, &keys_manager, logger, &custom_msg_handler);
+               let onion_messenger = OnionMessenger::new(
+                       &keys_manager, &keys_manager, logger, &offers_msg_handler, &custom_msg_handler
+               );
                let mut pk = [2; 33]; pk[1] = 0xff;
                let peer_node_id_not_used = PublicKey::from_slice(&pk).unwrap();
                onion_messenger.handle_onion_message(&peer_node_id_not_used, &msg);
@@ -50,6 +53,12 @@ pub extern "C" fn onion_message_run(data: *const u8, datalen: usize) {
        do_test(unsafe { std::slice::from_raw_parts(data, datalen) }, &logger);
 }
 
+struct TestOffersMessageHandler {}
+
+impl OffersMessageHandler for TestOffersMessageHandler {
+       fn handle_message(&self, _message: OffersMessage) {}
+}
+
 struct TestCustomMessage {}
 
 const CUSTOM_MESSAGE_TYPE: u64 = 4242;
index 06c6932cce36bb814ff591f40b4455fa11560693..f5c6341bb3ebde548c907636336d3edf90606cc0 100644 (file)
@@ -28,7 +28,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::{CustomOnionMessageContents, CustomOnionMessageHandler, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
+use crate::onion_message::{CustomOnionMessageContents, CustomOnionMessageHandler, OffersMessage, OffersMessageHandler, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
 use crate::routing::gossip::{NetworkGraph, P2PGossipSync, NodeId, NodeAlias};
 use crate::util::atomic_counter::AtomicCounter;
 use crate::util::logger::Logger;
@@ -118,6 +118,9 @@ impl OnionMessageHandler for IgnoringMessageHandler {
                InitFeatures::empty()
        }
 }
+impl OffersMessageHandler for IgnoringMessageHandler {
+       fn handle_message(&self, _msg: OffersMessage) {}
+}
 impl CustomOnionMessageHandler for IgnoringMessageHandler {
        type CustomMessage = Infallible;
        fn handle_custom_message(&self, _msg: Infallible) {
index 96e0c44b2ce8f31f77d1c5fcd936998b229be1eb..cc83f2d2c9e2b17e47c6c2758ade3310154fb710 100644 (file)
@@ -13,7 +13,7 @@ use crate::blinded_path::BlindedPath;
 use crate::sign::{NodeSigner, Recipient};
 use crate::ln::features::InitFeatures;
 use crate::ln::msgs::{self, DecodeError, OnionMessageHandler};
-use super::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessageContents, OnionMessenger, SendError};
+use super::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OffersMessage, OffersMessageHandler, OnionMessageContents, OnionMessenger, SendError};
 use crate::util::ser::{Writeable, Writer};
 use crate::util::test_utils;
 
@@ -27,7 +27,7 @@ use crate::sync::Arc;
 
 struct MessengerNode {
        keys_manager: Arc<test_utils::TestKeysInterface>,
-       messenger: OnionMessenger<Arc<test_utils::TestKeysInterface>, Arc<test_utils::TestKeysInterface>, Arc<test_utils::TestLogger>, Arc<TestCustomMessageHandler>>,
+       messenger: OnionMessenger<Arc<test_utils::TestKeysInterface>, Arc<test_utils::TestKeysInterface>, Arc<test_utils::TestLogger>, Arc<TestOffersMessageHandler>, Arc<TestCustomMessageHandler>>,
        custom_message_handler: Arc<TestCustomMessageHandler>,
        logger: Arc<test_utils::TestLogger>,
 }
@@ -38,6 +38,14 @@ impl MessengerNode {
        }
 }
 
+struct TestOffersMessageHandler {}
+
+impl OffersMessageHandler for TestOffersMessageHandler {
+       fn handle_message(&self, _message: OffersMessage) {
+               todo!()
+       }
+}
+
 #[derive(Clone)]
 struct TestCustomMessage {}
 
@@ -98,10 +106,11 @@ fn create_nodes(num_messengers: u8) -> Vec<MessengerNode> {
                let logger = Arc::new(test_utils::TestLogger::with_id(format!("node {}", i)));
                let seed = [i as u8; 32];
                let keys_manager = Arc::new(test_utils::TestKeysInterface::new(&seed, Network::Testnet));
+               let offers_message_handler = Arc::new(TestOffersMessageHandler {});
                let custom_message_handler = Arc::new(TestCustomMessageHandler::new());
                nodes.push(MessengerNode {
                        keys_manager: keys_manager.clone(),
-                       messenger: OnionMessenger::new(keys_manager.clone(), keys_manager.clone(), logger.clone(), custom_message_handler.clone()),
+                       messenger: OnionMessenger::new(keys_manager.clone(), keys_manager, logger.clone(), offers_message_handler, custom_message_handler.clone()),
                        custom_message_handler,
                        logger,
                });
index dbfa0bc636a3de78ac0cdf5f87ab6f31960583c8..23c9db0c45b073f3ff4c6cd7aab310f87a8db8fa 100644 (file)
@@ -23,6 +23,7 @@ use crate::ln::msgs::{self, OnionMessageHandler};
 use crate::ln::onion_utils;
 use crate::ln::peer_handler::IgnoringMessageHandler;
 pub use super::packet::{CustomOnionMessageContents, OnionMessageContents};
+use super::offers::OffersMessageHandler;
 use super::packet::{BIG_PACKET_HOP_DATA_LEN, ForwardControlTlvs, Packet, Payload, ReceiveControlTlvs, SMALL_PACKET_HOP_DATA_LEN};
 use crate::util::logger::Logger;
 use crate::util::ser::Writeable;
@@ -63,10 +64,11 @@ use crate::prelude::*;
 /// # let hop_node_id1 = PublicKey::from_secret_key(&secp_ctx, &node_secret);
 /// # let (hop_node_id2, hop_node_id3, hop_node_id4) = (hop_node_id1, hop_node_id1, hop_node_id1);
 /// # let destination_node_id = hop_node_id1;
-/// # let your_custom_message_handler = IgnoringMessageHandler {};
+/// # let custom_message_handler = IgnoringMessageHandler {};
+/// # let offers_message_handler = IgnoringMessageHandler {};
 /// // Create the onion messenger. This must use the same `keys_manager` as is passed to your
 /// // ChannelManager.
-/// let onion_messenger = OnionMessenger::new(&keys_manager, &keys_manager, logger, &your_custom_message_handler);
+/// let onion_messenger = OnionMessenger::new(&keys_manager, &keys_manager, logger, &offers_message_handler, &custom_message_handler);
 ///
 /// # struct YourCustomMessage {}
 /// impl Writeable for YourCustomMessage {
@@ -103,20 +105,21 @@ use crate::prelude::*;
 ///
 /// [offers]: <https://github.com/lightning/bolts/pull/798>
 /// [`OnionMessenger`]: crate::onion_message::OnionMessenger
-pub struct OnionMessenger<ES: Deref, NS: Deref, L: Deref, CMH: Deref>
-       where ES::Target: EntropySource,
-                 NS::Target: NodeSigner,
-                 L::Target: Logger,
-                 CMH:: Target: CustomOnionMessageHandler,
+pub struct OnionMessenger<ES: Deref, NS: Deref, L: Deref, OMH: Deref, CMH: Deref>
+where
+       ES::Target: EntropySource,
+       NS::Target: NodeSigner,
+       L::Target: Logger,
+       OMH::Target: OffersMessageHandler,
+       CMH:: Target: CustomOnionMessageHandler,
 {
        entropy_source: ES,
        node_signer: NS,
        logger: L,
        pending_messages: Mutex<HashMap<PublicKey, VecDeque<msgs::OnionMessage>>>,
        secp_ctx: Secp256k1<secp256k1::All>,
+       offers_handler: OMH,
        custom_handler: CMH,
-       // Coming soon:
-       // invoice_handler: InvoiceHandler,
 }
 
 /// The destination of an onion message.
@@ -187,15 +190,19 @@ pub trait CustomOnionMessageHandler {
        fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, msgs::DecodeError>;
 }
 
-impl<ES: Deref, NS: Deref, L: Deref, CMH: Deref> OnionMessenger<ES, NS, L, CMH>
-       where ES::Target: EntropySource,
-                 NS::Target: NodeSigner,
-                 L::Target: Logger,
-                 CMH::Target: CustomOnionMessageHandler,
+impl<ES: Deref, NS: Deref, L: Deref, OMH: Deref, CMH: Deref> OnionMessenger<ES, NS, L, OMH, CMH>
+where
+       ES::Target: EntropySource,
+       NS::Target: NodeSigner,
+       L::Target: Logger,
+       OMH::Target: OffersMessageHandler,
+       CMH::Target: CustomOnionMessageHandler,
 {
        /// Constructs a new `OnionMessenger` to send, forward, and delegate received onion messages to
        /// their respective handlers.
-       pub fn new(entropy_source: ES, node_signer: NS, logger: L, custom_handler: CMH) -> Self {
+       pub fn new(
+               entropy_source: ES, node_signer: NS, logger: L, offers_handler: OMH, custom_handler: CMH
+       ) -> Self {
                let mut secp_ctx = Secp256k1::new();
                secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes());
                OnionMessenger {
@@ -204,6 +211,7 @@ impl<ES: Deref, NS: Deref, L: Deref, CMH: Deref> OnionMessenger<ES, NS, L, CMH>
                        pending_messages: Mutex::new(HashMap::new()),
                        secp_ctx,
                        logger,
+                       offers_handler,
                        custom_handler,
                }
        }
@@ -298,11 +306,14 @@ fn outbound_buffer_full(peer_node_id: &PublicKey, buffer: &HashMap<PublicKey, Ve
        false
 }
 
-impl<ES: Deref, NS: Deref, L: Deref, CMH: Deref> OnionMessageHandler for OnionMessenger<ES, NS, L, CMH>
-       where ES::Target: EntropySource,
-                 NS::Target: NodeSigner,
-                 L::Target: Logger + Sized,
-                 CMH::Target: CustomOnionMessageHandler + Sized,
+impl<ES: Deref, NS: Deref, L: Deref, OMH: Deref, CMH: Deref> OnionMessageHandler
+for OnionMessenger<ES, NS, L, OMH, CMH>
+where
+       ES::Target: EntropySource,
+       NS::Target: NodeSigner,
+       L::Target: Logger,
+       OMH::Target: OffersMessageHandler,
+       CMH::Target: CustomOnionMessageHandler + Sized,
 {
        /// Handle an incoming onion message. Currently, if a message was destined for us we will log, but
        /// soon we'll delegate the onion message to a handler that can generate invoices or send
@@ -342,7 +353,7 @@ impl<ES: Deref, NS: Deref, L: Deref, CMH: Deref> OnionMessageHandler for OnionMe
                                        "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) => todo!(),
+                                       OnionMessageContents::Offers(msg) => self.offers_handler.handle_message(msg),
                                        OnionMessageContents::Custom(msg) => self.custom_handler.handle_custom_message(msg),
                                }
                        },
@@ -445,11 +456,14 @@ impl<ES: Deref, NS: Deref, L: Deref, CMH: Deref> OnionMessageHandler for OnionMe
        }
 }
 
-impl<ES: Deref, NS: Deref, L: Deref, CMH: Deref> OnionMessageProvider for OnionMessenger<ES, NS, L, CMH>
-       where ES::Target: EntropySource,
-                 NS::Target: NodeSigner,
-                 L::Target: Logger,
-                 CMH::Target: CustomOnionMessageHandler,
+impl<ES: Deref, NS: Deref, L: Deref, OMH: Deref, CMH: Deref> OnionMessageProvider
+for OnionMessenger<ES, NS, L, OMH, CMH>
+where
+       ES::Target: EntropySource,
+       NS::Target: NodeSigner,
+       L::Target: Logger,
+       OMH::Target: OffersMessageHandler,
+       CMH::Target: CustomOnionMessageHandler,
 {
        fn next_onion_message_for_peer(&self, peer_node_id: PublicKey) -> Option<msgs::OnionMessage> {
                let mut pending_msgs = self.pending_messages.lock().unwrap();
@@ -469,7 +483,14 @@ impl<ES: Deref, NS: Deref, L: Deref, CMH: Deref> OnionMessageProvider for OnionM
 ///
 /// [`SimpleArcChannelManager`]: crate::ln::channelmanager::SimpleArcChannelManager
 /// [`SimpleArcPeerManager`]: crate::ln::peer_handler::SimpleArcPeerManager
-pub type SimpleArcOnionMessenger<L> = OnionMessenger<Arc<KeysManager>, Arc<KeysManager>, Arc<L>, IgnoringMessageHandler>;
+pub type SimpleArcOnionMessenger<L> = OnionMessenger<
+       Arc<KeysManager>,
+       Arc<KeysManager>,
+       Arc<L>,
+       IgnoringMessageHandler,
+       IgnoringMessageHandler
+>;
+
 /// Useful for simplifying the parameters of [`SimpleRefChannelManager`] and
 /// [`SimpleRefPeerManager`]. See their docs for more details.
 ///
@@ -477,7 +498,13 @@ pub type SimpleArcOnionMessenger<L> = OnionMessenger<Arc<KeysManager>, Arc<KeysM
 ///
 /// [`SimpleRefChannelManager`]: crate::ln::channelmanager::SimpleRefChannelManager
 /// [`SimpleRefPeerManager`]: crate::ln::peer_handler::SimpleRefPeerManager
-pub type SimpleRefOnionMessenger<'a, 'b, L> = OnionMessenger<&'a KeysManager, &'a KeysManager, &'b L, IgnoringMessageHandler>;
+pub type SimpleRefOnionMessenger<'a, 'b, L> = OnionMessenger<
+       &'a KeysManager,
+       &'a KeysManager,
+       &'b L,
+       IgnoringMessageHandler,
+       IgnoringMessageHandler
+>;
 
 /// Construct onion packet payloads and keys for sending an onion message along the given
 /// `unblinded_path` to the given `destination`.
index 0fcf3cc791bc68d6b1f83fd15c0898a83701bae4..e0b3f5001954a052f2d14c989ef18dac96ec8282 100644 (file)
@@ -28,4 +28,5 @@ mod functional_tests;
 
 // Re-export structs so they can be imported with just the `onion_message::` module prefix.
 pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, Destination, OnionMessageContents, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
+pub use self::offers::{OffersMessage, OffersMessageHandler};
 pub(crate) use self::packet::{ControlTlvs, Packet};
index 36363c90a629032c6a514347d9d9889e1959ac20..98276d1bfb74d1fb617a3b8c71892a0280d2593b 100644 (file)
@@ -26,6 +26,15 @@ const INVOICE_REQUEST_TLV_TYPE: u64 = 64;
 const INVOICE_TLV_TYPE: u64 = 66;
 const INVOICE_ERROR_TLV_TYPE: u64 = 68;
 
+/// A handler for an [`OnionMessage`] containing a BOLT 12 Offers message as its payload.
+///
+/// [`OnionMessage`]: crate::ln::msgs::OnionMessage
+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);
+}
+
 /// Possible BOLT 12 Offers messages sent and received via an [`OnionMessage`].
 ///
 /// [`OnionMessage`]: crate::ln::msgs::OnionMessage
@@ -82,7 +91,7 @@ impl Writeable for OffersMessage {
        }
 }
 
-impl<L: Logger> ReadableArgs<(u64, &L)> for OffersMessage {
+impl<L: Logger + ?Sized> ReadableArgs<(u64, &L)> for OffersMessage {
        fn read<R: Read>(r: &mut R, read_args: (u64, &L)) -> Result<Self, DecodeError> {
                let (tlv_type, logger) = read_args;
                if tlv_type == INVOICE_ERROR_TLV_TYPE {
index e5fb93f4501ec5e175039c4385518c2230449b3c..663a0b0cdc703a923c75781522a8fc7a0c6520d5 100644 (file)
@@ -203,7 +203,7 @@ impl<T: CustomOnionMessageContents> Writeable for (Payload<T>, [u8; 32]) {
 }
 
 // Uses the provided secret to simultaneously decode and decrypt the control TLVs and data TLV.
-impl<H: CustomOnionMessageHandler, L: Logger>
+impl<H: CustomOnionMessageHandler, L: Logger + ?Sized>
 ReadableArgs<(SharedSecret, &H, &L)> for Payload<<H as CustomOnionMessageHandler>::CustomMessage> {
        fn read<R: Read>(r: &mut R, args: (SharedSecret, &H, &L)) -> Result<Self, DecodeError> {
                let (encrypted_tlvs_ss, handler, logger) = args;