]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Update handle_message to accept OffersContext data as an input field
authorshaavan <shaavan.github@gmail.com>
Sat, 15 Jun 2024 13:52:28 +0000 (19:22 +0530)
committershaavan <shaavan.github@gmail.com>
Tue, 9 Jul 2024 11:57:08 +0000 (17:27 +0530)
1. Handling Offers Data:
   - Updated `handle_message` to accept `OffersContext` data as an input field.
   - If it is present, it will be utilized by the handler to
     abandon outbound payments that have failed for any reason.

2. Consistency in Custom Message Handling:
   - Updated `handle_custom_message` to accept optional custom data.
     for consistency.
   - Note: `custom_data` will remain unused in this PR.

fuzz/src/onion_message.rs
lightning/src/ln/channelmanager.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 8e71a41f9586e70ce8787fdf592dec572e92a327..e7f2c8daa818d33405c327242dc26bb1f26cc549 100644 (file)
@@ -6,6 +6,7 @@ use bitcoin::secp256k1::ecdsa::RecoverableSignature;
 use bitcoin::secp256k1::schnorr;
 use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey};
 
+use lightning::blinded_path::message::{MessageContext, OffersContext};
 use lightning::blinded_path::{BlindedPath, EmptyNodeIdLookUp};
 use lightning::ln::features::InitFeatures;
 use lightning::ln::msgs::{self, DecodeError, OnionMessageHandler};
@@ -104,7 +105,7 @@ struct TestOffersMessageHandler {}
 
 impl OffersMessageHandler for TestOffersMessageHandler {
        fn handle_message(
-               &self, _message: OffersMessage, _responder: Option<Responder>,
+               &self, _message: OffersMessage, _context: OffersContext, _responder: Option<Responder>,
        ) -> ResponseInstruction<OffersMessage> {
                ResponseInstruction::NoResponse
        }
@@ -152,7 +153,8 @@ struct TestCustomMessageHandler {}
 impl CustomOnionMessageHandler for TestCustomMessageHandler {
        type CustomMessage = TestCustomMessage;
        fn handle_custom_message(
-               &self, message: Self::CustomMessage, responder: Option<Responder>,
+               &self, message: Self::CustomMessage, _context: Option<Vec<u8>>,
+               responder: Option<Responder>,
        ) -> ResponseInstruction<Self::CustomMessage> {
                match responder {
                        Some(responder) => responder.respond(message),
@@ -342,9 +344,14 @@ mod tests {
                super::do_test(&<Vec<u8>>::from_hex(one_hop_om).unwrap(), &logger);
                {
                        let log_entries = logger.lines.lock().unwrap();
-                       assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(),
-                                               "Received an onion message with path_id None and a reply_path: Custom(TestCustomMessage)"
-                                               .to_string())), Some(&1));
+                       assert_eq!(
+                               log_entries.get(&(
+                                       "lightning::onion_message::messenger".to_string(),
+                                       "Received an onion message with a reply_path: Custom(TestCustomMessage)"
+                                               .to_string()
+                               )),
+                               Some(&1)
+                       );
                        assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(),
                                                "Constructing onion message when responding with Custom Message to an onion message: TestCustomMessage".to_string())), Some(&1));
                        assert_eq!(log_entries.get(&("lightning::onion_message::messenger".to_string(),
index 807dce7cd4536c2307f74df5190445549a0ebdac..a5c32897d383f176657c0383b810cdfe169a3ef3 100644 (file)
@@ -31,6 +31,7 @@ use bitcoin::secp256k1::{SecretKey,PublicKey};
 use bitcoin::secp256k1::Secp256k1;
 use bitcoin::{secp256k1, Sequence};
 
+use crate::blinded_path::message::OffersContext;
 use crate::blinded_path::{BlindedPath, NodeIdLookUp};
 use crate::blinded_path::message::ForwardNode;
 use crate::blinded_path::payment::{Bolt12OfferContext, Bolt12RefundContext, PaymentConstraints, PaymentContext, ReceiveTlvs};
@@ -10253,10 +10254,17 @@ where
        R::Target: Router,
        L::Target: Logger,
 {
-       fn handle_message(&self, message: OffersMessage, responder: Option<Responder>) -> ResponseInstruction<OffersMessage> {
+       fn handle_message(&self, message: OffersMessage, context: OffersContext, responder: Option<Responder>) -> ResponseInstruction<OffersMessage> {
                let secp_ctx = &self.secp_ctx;
                let expanded_key = &self.inbound_payment_key;
 
+               let abandon_if_payment = |context| {
+                       match context {
+                               OffersContext::OutboundPayment { payment_id } => self.abandon_payment(payment_id),
+                               _ => {},
+                       }
+               };
+
                match message {
                        OffersMessage::InvoiceRequest(invoice_request) => {
                                let responder = match responder {
@@ -10369,12 +10377,21 @@ where
                                };
 
                                match result {
-                                       Ok(()) => ResponseInstruction::NoResponse,
-                                       Err(e) => match responder {
-                                               Some(responder) => responder.respond(OffersMessage::InvoiceError(e)),
+                                       Ok(_) => ResponseInstruction::NoResponse,
+                                       Err(err) => match responder {
+                                               Some(responder) => {
+                                                       abandon_if_payment(context);
+                                                       responder.respond(OffersMessage::InvoiceError(err))
+                                               },
                                                None => {
-                                                       log_trace!(self.logger, "No reply path for sending invoice error: {:?}", e);
-                                                       ResponseInstruction::NoResponse
+                                                       abandon_if_payment(context);
+                                                       log_trace!(
+                                                               self.logger,
+                                                               "An error response was generated, but there is no reply_path specified \
+                                                               for sending the response. Error: {}",
+                                                               err
+                                                       );
+                                                       return ResponseInstruction::NoResponse;
                                                },
                                        },
                                }
@@ -10391,6 +10408,7 @@ where
                                }
                        },
                        OffersMessage::InvoiceError(invoice_error) => {
+                               abandon_if_payment(context);
                                log_trace!(self.logger, "Received invoice_error: {}", invoice_error);
                                ResponseInstruction::NoResponse
                        },
index 1b75755fac2b897079d89902a4682dbe8b21c604..7a46bee9d738f4b9823e146a3a5a1726f10b8b5f 100644 (file)
@@ -18,6 +18,7 @@
 use bitcoin::blockdata::constants::ChainHash;
 use bitcoin::secp256k1::{self, Secp256k1, SecretKey, PublicKey};
 
+use crate::blinded_path::message::OffersContext;
 use crate::sign::{NodeSigner, Recipient};
 use crate::events::{MessageSendEvent, MessageSendEventsProvider};
 use crate::ln::types::ChannelId;
@@ -145,7 +146,7 @@ impl OnionMessageHandler for IgnoringMessageHandler {
 }
 
 impl OffersMessageHandler for IgnoringMessageHandler {
-       fn handle_message(&self, _message: OffersMessage, _responder: Option<Responder>) -> ResponseInstruction<OffersMessage> {
+       fn handle_message(&self, _message: OffersMessage, _context: OffersContext, _responder: Option<Responder>) -> ResponseInstruction<OffersMessage> {
                ResponseInstruction::NoResponse
        }
 }
@@ -159,7 +160,7 @@ impl AsyncPaymentsMessageHandler for IgnoringMessageHandler {
 }
 impl CustomOnionMessageHandler for IgnoringMessageHandler {
        type CustomMessage = Infallible;
-       fn handle_custom_message(&self, _message: Self::CustomMessage, _responder: Option<Responder>) -> ResponseInstruction<Self::CustomMessage> {
+       fn handle_custom_message(&self, _message: Self::CustomMessage, _context: Option<Vec<u8>>, _responder: Option<Responder>) -> ResponseInstruction<Self::CustomMessage> {
                // Since we always return `None` in the read the handle method should never be called.
                unreachable!();
        }
index b169f21f52ede1042bbbd3f7bd0aaaf273bb6750..2851cfed1a4c1e9ff1fd37e2faabb9c568f79912 100644 (file)
@@ -10,7 +10,7 @@
 //! Onion message testing and test utilities live here.
 
 use crate::blinded_path::{BlindedPath, EmptyNodeIdLookUp};
-use crate::blinded_path::message::ForwardNode;
+use crate::blinded_path::message::{ForwardNode, OffersContext};
 use crate::events::{Event, EventsProvider};
 use crate::ln::features::{ChannelFeatures, InitFeatures};
 use crate::ln::msgs::{self, DecodeError, OnionMessageHandler};
@@ -76,7 +76,7 @@ impl Drop for MessengerNode {
 struct TestOffersMessageHandler {}
 
 impl OffersMessageHandler for TestOffersMessageHandler {
-       fn handle_message(&self, _message: OffersMessage, _responder: Option<Responder>) -> ResponseInstruction<OffersMessage> {
+       fn handle_message(&self, _message: OffersMessage, _context: OffersContext, _responder: Option<Responder>) -> ResponseInstruction<OffersMessage> {
                ResponseInstruction::NoResponse
        }
 }
@@ -174,7 +174,7 @@ impl Drop for TestCustomMessageHandler {
 
 impl CustomOnionMessageHandler for TestCustomMessageHandler {
        type CustomMessage = TestCustomMessage;
-       fn handle_custom_message(&self, msg: Self::CustomMessage, responder: Option<Responder>) -> ResponseInstruction<Self::CustomMessage> {
+       fn handle_custom_message(&self, msg: Self::CustomMessage, _context: Option<Vec<u8>>, responder: Option<Responder>) -> ResponseInstruction<Self::CustomMessage> {
                let expectation = self.get_next_expectation();
                assert_eq!(msg, expectation.expect);
 
@@ -437,7 +437,7 @@ fn async_response_over_one_blinded_hop() {
 
        // 5. Expect Alice to receive the message and create a response instruction for it.
        alice.custom_message_handler.expect_message(message.clone());
-       let response_instruction = nodes[0].custom_message_handler.handle_custom_message(message, responder);
+       let response_instruction = nodes[0].custom_message_handler.handle_custom_message(message, None, responder);
 
        // 6. Simulate Alice asynchronously responding back to Bob with a response.
        assert_eq!(
@@ -470,7 +470,7 @@ fn async_response_with_reply_path_succeeds() {
        // Alice asynchronously responds to Bob, expecting a response back from him.
        let responder = Responder::new(reply_path);
        alice.custom_message_handler.expect_message_and_response(message.clone());
-       let response_instruction = alice.custom_message_handler.handle_custom_message(message, Some(responder));
+       let response_instruction = alice.custom_message_handler.handle_custom_message(message, None, Some(responder));
 
        assert_eq!(
                alice.messenger.handle_onion_message_response(response_instruction),
@@ -508,7 +508,7 @@ fn async_response_with_reply_path_fails() {
        disconnect_peers(alice, bob);
        let responder = Responder::new(reply_path);
        alice.custom_message_handler.expect_message_and_response(message.clone());
-       let response_instruction = alice.custom_message_handler.handle_custom_message(message, Some(responder));
+       let response_instruction = alice.custom_message_handler.handle_custom_message(message, None, Some(responder));
 
        assert_eq!(
                alice.messenger.handle_onion_message_response(response_instruction),
index 03d35bbba5570c50d43e531b2cf392e25f806eaf..f96937fd909db56ee802033984a3a8adeeb8e63b 100644 (file)
@@ -16,7 +16,7 @@ use bitcoin::hashes::sha256::Hash as Sha256;
 use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey};
 
 use crate::blinded_path::{BlindedPath, IntroductionNode, NextMessageHop, NodeIdLookUp};
-use crate::blinded_path::message::{advance_path_by_one, ForwardNode, ForwardTlvs, ReceiveTlvs, MessageContext};
+use crate::blinded_path::message::{advance_path_by_one, ForwardNode, ForwardTlvs, MessageContext, OffersContext, ReceiveTlvs};
 use crate::blinded_path::utils;
 use crate::events::{Event, EventHandler, EventsProvider};
 use crate::sign::{EntropySource, NodeSigner, Recipient};
@@ -768,7 +768,7 @@ pub trait CustomOnionMessageHandler {
        /// 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, message: Self::CustomMessage, responder: Option<Responder>) -> ResponseInstruction<Self::CustomMessage>;
+       fn handle_custom_message(&self, message: Self::CustomMessage, context: Option<Vec<u8>>, responder: Option<Responder>) -> ResponseInstruction<Self::CustomMessage>;
 
        /// Read a custom message of type `message_type` from `buffer`, returning `Ok(None)` if the
        /// message type is unknown.
@@ -1446,7 +1446,7 @@ where
        fn handle_onion_message(&self, peer_node_id: &PublicKey, msg: &OnionMessage) {
                let logger = WithContext::from(&self.logger, Some(*peer_node_id), None, None);
                match self.peel_onion_message(msg) {
-                       Ok(PeeledOnion::Receive(message, _context, reply_path)) => {
+                       Ok(PeeledOnion::Receive(message, context, reply_path)) => {
                                log_trace!(
                                        logger,
                                        "Received an onion message with {} reply_path: {:?}",
@@ -1455,7 +1455,15 @@ where
                                let responder = reply_path.map(Responder::new);
                                match message {
                                        ParsedOnionMessageContents::Offers(msg) => {
-                                               let response_instructions = self.offers_handler.handle_message(msg, responder);
+                                               let context = match context {
+                                                       None => OffersContext::Unknown {},
+                                                       Some(MessageContext::Offers(context)) => context,
+                                                       Some(MessageContext::Custom(_)) => {
+                                                               debug_assert!(false, "Shouldn't have triggered this case.");
+                                                               return
+                                                       }
+                                               };
+                                               let response_instructions = self.offers_handler.handle_message(msg, context, responder);
                                                let _ = self.handle_onion_message_response(response_instructions);
                                        },
                                        #[cfg(async_payments)]
@@ -1470,7 +1478,15 @@ where
                                                self.async_payments_handler.release_held_htlc(msg);
                                        },
                                        ParsedOnionMessageContents::Custom(msg) => {
-                                               let response_instructions = self.custom_handler.handle_custom_message(msg, responder);
+                                               let context = match context {
+                                                       None => None,
+                                                       Some(MessageContext::Custom(data)) => Some(data),
+                                                       Some(MessageContext::Offers(_)) => {
+                                                               debug_assert!(false, "Shouldn't have triggered this case.");
+                                                               return
+                                                       }
+                                               };
+                                               let response_instructions = self.custom_handler.handle_custom_message(msg, context, responder);
                                                let _ = self.handle_onion_message_response(response_instructions);
                                        },
                                }
index 397f4b8a72b7a827b8bb0543f78a076cd9eb2210..a8f43c2d213141cf09e453c3855f05f7085edd4b 100644 (file)
@@ -10,6 +10,7 @@
 //! Message handling for BOLT 12 Offers.
 
 use core::fmt;
+use crate::blinded_path::message::OffersContext;
 use crate::io::{self, Read};
 use crate::ln::msgs::DecodeError;
 use crate::offers::invoice_error::InvoiceError;
@@ -44,7 +45,7 @@ pub trait OffersMessageHandler {
        /// The returned [`OffersMessage`], if any, is enqueued to be sent by [`OnionMessenger`].
        ///
        /// [`OnionMessenger`]: crate::onion_message::messenger::OnionMessenger
-       fn handle_message(&self, message: OffersMessage, responder: Option<Responder>) -> ResponseInstruction<OffersMessage>;
+       fn handle_message(&self, message: OffersMessage, context: OffersContext, responder: Option<Responder>) -> ResponseInstruction<OffersMessage>;
 
        /// Releases any [`OffersMessage`]s that need to be sent.
        ///