From fbe9dfa938a3bbbc7ba2a196e7d8972c1085a8b9 Mon Sep 17 00:00:00 2001 From: shaavan Date: Sat, 15 Jun 2024 19:22:28 +0530 Subject: [PATCH] Update handle_message to accept OffersContext data as an input field 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 | 17 +++++++---- lightning/src/ln/channelmanager.rs | 30 +++++++++++++++---- lightning/src/ln/peer_handler.rs | 5 ++-- .../src/onion_message/functional_tests.rs | 12 ++++---- lightning/src/onion_message/messenger.rs | 26 ++++++++++++---- lightning/src/onion_message/offers.rs | 3 +- 6 files changed, 68 insertions(+), 25 deletions(-) diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index 8e71a41f9..e7f2c8daa 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -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, + &self, _message: OffersMessage, _context: OffersContext, _responder: Option, ) -> ResponseInstruction { 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, + &self, message: Self::CustomMessage, _context: Option>, + responder: Option, ) -> ResponseInstruction { match responder { Some(responder) => responder.respond(message), @@ -342,9 +344,14 @@ mod tests { super::do_test(&>::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(), diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 807dce7cd..a5c32897d 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -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) -> ResponseInstruction { + fn handle_message(&self, message: OffersMessage, context: OffersContext, responder: Option) -> ResponseInstruction { 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 }, diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 1b75755fa..7a46bee9d 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -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) -> ResponseInstruction { + fn handle_message(&self, _message: OffersMessage, _context: OffersContext, _responder: Option) -> ResponseInstruction { 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) -> ResponseInstruction { + fn handle_custom_message(&self, _message: Self::CustomMessage, _context: Option>, _responder: Option) -> ResponseInstruction { // Since we always return `None` in the read the handle method should never be called. unreachable!(); } diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index b169f21f5..2851cfed1 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -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) -> ResponseInstruction { + fn handle_message(&self, _message: OffersMessage, _context: OffersContext, _responder: Option) -> ResponseInstruction { 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) -> ResponseInstruction { + fn handle_custom_message(&self, msg: Self::CustomMessage, _context: Option>, responder: Option) -> ResponseInstruction { 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), diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 03d35bbba..f96937fd9 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -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) -> ResponseInstruction; + fn handle_custom_message(&self, message: Self::CustomMessage, context: Option>, responder: Option) -> ResponseInstruction; /// 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); }, } diff --git a/lightning/src/onion_message/offers.rs b/lightning/src/onion_message/offers.rs index 397f4b8a7..a8f43c2d2 100644 --- a/lightning/src/onion_message/offers.rs +++ b/lightning/src/onion_message/offers.rs @@ -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) -> ResponseInstruction; + fn handle_message(&self, message: OffersMessage, context: OffersContext, responder: Option) -> ResponseInstruction; /// Releases any [`OffersMessage`]s that need to be sent. /// -- 2.39.5