From: shaavan Date: Sat, 15 Jun 2024 13:52:28 +0000 (+0530) Subject: Update handle_message to Accept offers_data as an Input Field X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=8acd90c852fba5c49436d3fae0e4091b6dbd3323;p=rust-lightning Update handle_message to Accept offers_data as an Input Field 1. Handling Offers Data: - Updated `handle_message` to accept `offers_data` as an input field. - If `offers_data` 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. --- diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index 07d271bce..b1c6312a9 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, _responder: Option, _context: OffersContext, ) -> ResponseInstruction { ResponseInstruction::NoResponse } @@ -147,7 +148,7 @@ struct TestCustomMessageHandler {} impl CustomOnionMessageHandler for TestCustomMessageHandler { type CustomMessage = TestCustomMessage; fn handle_custom_message( - &self, message: Self::CustomMessage, responder: Option, + &self, message: Self::CustomMessage, responder: Option, _context: Vec, ) -> ResponseInstruction { match responder { Some(responder) => responder.respond(message), @@ -337,9 +338,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 6ba7396eb..2fb741dee 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}; @@ -10251,10 +10252,17 @@ where R::Target: Router, L::Target: Logger, { - fn handle_message(&self, message: OffersMessage, responder: Option) -> ResponseInstruction { + fn handle_message(&self, message: OffersMessage, responder: Option, context: OffersContext) -> 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 { @@ -10367,14 +10375,25 @@ where }; match result { - Ok(()) => ResponseInstruction::NoResponse, - Err(e) => match responder { - Some(responder) => responder.respond(OffersMessage::InvoiceError(e)), - None => { - log_trace!(self.logger, "No reply path for sending invoice error: {:?}", e); - ResponseInstruction::NoResponse - }, - }, + Err(err) => { + match responder { + Some(responder) => { + abandon_if_payment(context); + responder.respond(OffersMessage::InvoiceError(err)) + } + None => { + abandon_if_payment(context); + log_trace!( + self.logger, + "A error response was generated, but there is no reply_path specified \ + for sending the response. Error: {}", + err + ); + return ResponseInstruction::NoResponse; + } + } + } + Ok(_) => return ResponseInstruction::NoResponse, } }, #[cfg(async_payments)] @@ -10389,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 9a026d709..ac3392911 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, _responder: Option, _context: OffersContext) -> 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, _responder: Option, _context: Vec) -> 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..390a22e91 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, _responder: Option, _context: OffersContext) -> 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, responder: Option, _context: Vec) -> 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, responder, Vec::new()); // 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, Some(responder), Vec::new()); 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, Some(responder), Vec::new()); 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 3bd5c08c9..2158ef3ff 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, responder: Option, context: Vec) -> 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, _recipient_data, 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, responder, context); 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 => vec![], + Some(MessageContext::Custom(data)) => data, + Some(MessageContext::Offers(_)) => { + debug_assert!(false, "Shouldn't have triggered this case."); + return + } + }; + let response_instructions = self.custom_handler.handle_custom_message(msg, responder, context); 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..0666c5687 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, responder: Option, context: OffersContext) -> ResponseInstruction; /// Releases any [`OffersMessage`]s that need to be sent. ///