From 66df3292365182fb7e34aca730a678c67a68e6a9 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Wed, 5 Jun 2024 13:06:11 -0400 Subject: [PATCH 1/7] ser_macros: support messages with no fields --- lightning/src/util/ser_macros.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lightning/src/util/ser_macros.rs b/lightning/src/util/ser_macros.rs index 740b7c12561..255fd3ebc32 100644 --- a/lightning/src/util/ser_macros.rs +++ b/lightning/src/util/ser_macros.rs @@ -633,7 +633,7 @@ macro_rules! impl_writeable_msg { $($crate::_init_tlv_field_var!($tlvfield, $fieldty);)* $crate::decode_tlv_stream!(r, {$(($type, $tlvfield, $fieldty)),*}); Ok(Self { - $($field),*, + $($field,)* $($tlvfield),* }) } @@ -1531,4 +1531,18 @@ mod tests { fn simple_test_tlv_write() { do_simple_test_tlv_write().unwrap(); } + + #[derive(Debug, Eq, PartialEq)] + struct EmptyMsg {} + impl_writeable_msg!(EmptyMsg, {}, {}); + + #[test] + fn impl_writeable_msg_empty() { + let msg = EmptyMsg {}; + let mut encoded_msg = msg.encode(); + assert!(encoded_msg.is_empty()); + let mut encoded_msg_stream = Cursor::new(&mut encoded_msg); + let decoded_msg: EmptyMsg = Readable::read(&mut encoded_msg_stream).unwrap(); + assert_eq!(msg, decoded_msg); + } } From 445ec8d50840c9a3377bba80351c09df46527060 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Wed, 5 Jun 2024 13:41:07 -0400 Subject: [PATCH 2/7] Onion message payload for async payments Async payments uses onion messages to indicate when HTLCs are held and released. Add these types along with the necessary parsing and encoding. --- lightning/src/ln/offers_tests.rs | 3 + lightning/src/onion_message/async_payments.rs | 110 ++++++++++++++++++ lightning/src/onion_message/messenger.rs | 1 + lightning/src/onion_message/mod.rs | 1 + lightning/src/onion_message/packet.rs | 11 ++ 5 files changed, 126 insertions(+) create mode 100644 lightning/src/onion_message/async_payments.rs diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index eca43afee8a..c965ba50e8d 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -194,6 +194,7 @@ fn extract_invoice_request<'a, 'b, 'c>( OffersMessage::Invoice(invoice) => panic!("Unexpected invoice: {:?}", invoice), OffersMessage::InvoiceError(error) => panic!("Unexpected invoice_error: {:?}", error), }, + ParsedOnionMessageContents::AsyncPayments(message) => panic!("Unexpected async payments message: {:?}", message), ParsedOnionMessageContents::Custom(message) => panic!("Unexpected custom message: {:?}", message), }, Ok(PeeledOnion::Forward(_, _)) => panic!("Unexpected onion message forward"), @@ -209,6 +210,7 @@ fn extract_invoice<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessage) OffersMessage::Invoice(invoice) => invoice, OffersMessage::InvoiceError(error) => panic!("Unexpected invoice_error: {:?}", error), }, + ParsedOnionMessageContents::AsyncPayments(message) => panic!("Unexpected async payments message: {:?}", message), ParsedOnionMessageContents::Custom(message) => panic!("Unexpected custom message: {:?}", message), }, Ok(PeeledOnion::Forward(_, _)) => panic!("Unexpected onion message forward"), @@ -226,6 +228,7 @@ fn extract_invoice_error<'a, 'b, 'c>( OffersMessage::Invoice(invoice) => panic!("Unexpected invoice: {:?}", invoice), OffersMessage::InvoiceError(error) => error, }, + ParsedOnionMessageContents::AsyncPayments(message) => panic!("Unexpected async payments message: {:?}", message), ParsedOnionMessageContents::Custom(message) => panic!("Unexpected custom message: {:?}", message), }, Ok(PeeledOnion::Forward(_, _)) => panic!("Unexpected onion message forward"), diff --git a/lightning/src/onion_message/async_payments.rs b/lightning/src/onion_message/async_payments.rs new file mode 100644 index 00000000000..aa6779fb33d --- /dev/null +++ b/lightning/src/onion_message/async_payments.rs @@ -0,0 +1,110 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +//! Message handling for async payments. + +use crate::io; +use crate::ln::msgs::DecodeError; +use crate::onion_message::packet::OnionMessageContents; +use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer}; + +// TLV record types for the `onionmsg_tlv` TLV stream as defined in BOLT 4. +const HELD_HTLC_AVAILABLE_TLV_TYPE: u64 = 72; +const RELEASE_HELD_HTLC_TLV_TYPE: u64 = 74; + +/// Possible async payment messages sent and received via an [`OnionMessage`]. +/// +/// [`OnionMessage`]: crate::ln::msgs::OnionMessage +#[derive(Clone, Debug)] +pub enum AsyncPaymentsMessage { + /// An HTLC is being held upstream for the often-offline recipient, to be released via + /// [`ReleaseHeldHtlc`]. + HeldHtlcAvailable(HeldHtlcAvailable), + + /// Releases the HTLC corresponding to an inbound [`HeldHtlcAvailable`] message. + ReleaseHeldHtlc(ReleaseHeldHtlc), +} + +/// An HTLC destined for the recipient of this message is being held upstream. The reply path +/// accompanying this onion message should be used to send a [`ReleaseHeldHtlc`] response, which +/// will cause the upstream HTLC to be released. +#[derive(Clone, Debug)] +pub struct HeldHtlcAvailable { + /// The secret that will be used by the recipient of this message to release the held HTLC. + pub payment_release_secret: [u8; 32], +} + +/// Releases the HTLC corresponding to an inbound [`HeldHtlcAvailable`] message. +#[derive(Clone, Debug)] +pub struct ReleaseHeldHtlc { + /// Used to release the HTLC held upstream if it matches the corresponding + /// [`HeldHtlcAvailable::payment_release_secret`]. + pub payment_release_secret: [u8; 32], +} + +impl OnionMessageContents for ReleaseHeldHtlc { + fn tlv_type(&self) -> u64 { + RELEASE_HELD_HTLC_TLV_TYPE + } + fn msg_type(&self) -> &'static str { + "Release Held HTLC" + } +} + +impl_writeable_tlv_based!(HeldHtlcAvailable, { + (0, payment_release_secret, required), +}); + +impl_writeable_tlv_based!(ReleaseHeldHtlc, { + (0, payment_release_secret, required), +}); + +impl AsyncPaymentsMessage { + /// Returns whether `tlv_type` corresponds to a TLV record for async payment messages. + pub fn is_known_type(tlv_type: u64) -> bool { + match tlv_type { + HELD_HTLC_AVAILABLE_TLV_TYPE | RELEASE_HELD_HTLC_TLV_TYPE => true, + _ => false, + } + } +} + +impl OnionMessageContents for AsyncPaymentsMessage { + fn tlv_type(&self) -> u64 { + match self { + Self::HeldHtlcAvailable(_) => HELD_HTLC_AVAILABLE_TLV_TYPE, + Self::ReleaseHeldHtlc(msg) => msg.tlv_type(), + } + } + fn msg_type(&self) -> &'static str { + match &self { + Self::HeldHtlcAvailable(_) => "Held HTLC Available", + Self::ReleaseHeldHtlc(msg) => msg.msg_type(), + } + } +} + +impl Writeable for AsyncPaymentsMessage { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + match self { + Self::HeldHtlcAvailable(message) => message.write(w), + Self::ReleaseHeldHtlc(message) => message.write(w), + } + } +} + +impl ReadableArgs for AsyncPaymentsMessage { + fn read(r: &mut R, tlv_type: u64) -> Result { + match tlv_type { + HELD_HTLC_AVAILABLE_TLV_TYPE => Ok(Self::HeldHtlcAvailable(Readable::read(r)?)), + RELEASE_HELD_HTLC_TLV_TYPE => Ok(Self::ReleaseHeldHtlc(Readable::read(r)?)), + _ => Err(DecodeError::InvalidValue), + } + } +} diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 0fb72c52d27..c991c5bccc5 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -1428,6 +1428,7 @@ where let response_instructions = self.offers_handler.handle_message(msg, responder); let _ = self.handle_onion_message_response(response_instructions); }, + ParsedOnionMessageContents::AsyncPayments(_msg) => todo!(), ParsedOnionMessageContents::Custom(msg) => { let responder = reply_path.map( |reply_path| Responder::new(reply_path, path_id) diff --git a/lightning/src/onion_message/mod.rs b/lightning/src/onion_message/mod.rs index 05a8b7d6fbd..1693c5a9911 100644 --- a/lightning/src/onion_message/mod.rs +++ b/lightning/src/onion_message/mod.rs @@ -21,6 +21,7 @@ //! [blinded paths]: crate::blinded_path::BlindedPath //! [`OnionMessenger`]: self::messenger::OnionMessenger +pub mod async_payments; pub mod messenger; pub mod offers; pub mod packet; diff --git a/lightning/src/onion_message/packet.rs b/lightning/src/onion_message/packet.rs index 75ec3cd90ab..47b1a0313d7 100644 --- a/lightning/src/onion_message/packet.rs +++ b/lightning/src/onion_message/packet.rs @@ -17,6 +17,7 @@ use crate::blinded_path::message::{ForwardTlvs, ReceiveTlvs}; use crate::blinded_path::utils::Padding; use crate::ln::msgs::DecodeError; use crate::ln::onion_utils; +use super::async_payments::AsyncPaymentsMessage; use super::messenger::CustomOnionMessageHandler; use super::offers::OffersMessage; use crate::crypto::streams::{ChaChaPolyReadAdapter, ChaChaPolyWriteAdapter}; @@ -128,6 +129,8 @@ pub(super) enum Payload { pub enum ParsedOnionMessageContents { /// A message related to BOLT 12 Offers. Offers(OffersMessage), + /// A message related to async payments. + AsyncPayments(AsyncPaymentsMessage), /// A custom onion message specified by the user. Custom(T), } @@ -139,12 +142,14 @@ impl OnionMessageContents for ParsedOnionMessageContent fn tlv_type(&self) -> u64 { match self { &ParsedOnionMessageContents::Offers(ref msg) => msg.tlv_type(), + &ParsedOnionMessageContents::AsyncPayments(ref msg) => msg.tlv_type(), &ParsedOnionMessageContents::Custom(ref msg) => msg.tlv_type(), } } fn msg_type(&self) -> &'static str { match self { ParsedOnionMessageContents::Offers(ref msg) => msg.msg_type(), + ParsedOnionMessageContents::AsyncPayments(ref msg) => msg.msg_type(), ParsedOnionMessageContents::Custom(ref msg) => msg.msg_type(), } } @@ -154,6 +159,7 @@ impl Writeable for ParsedOnionMessageContents { fn write(&self, w: &mut W) -> Result<(), io::Error> { match self { ParsedOnionMessageContents::Offers(msg) => Ok(msg.write(w)?), + ParsedOnionMessageContents::AsyncPayments(msg) => Ok(msg.write(w)?), ParsedOnionMessageContents::Custom(msg) => Ok(msg.write(w)?), } } @@ -255,6 +261,11 @@ for Payload::CustomM message = Some(ParsedOnionMessageContents::Offers(msg)); Ok(true) }, + tlv_type if AsyncPaymentsMessage::is_known_type(tlv_type) => { + let msg = AsyncPaymentsMessage::read(msg_reader, tlv_type)?; + message = Some(ParsedOnionMessageContents::AsyncPayments(msg)); + Ok(true) + }, _ => match handler.read_custom_message(msg_type, msg_reader)? { Some(msg) => { message = Some(ParsedOnionMessageContents::Custom(msg)); From e8f154dd3c299c7988762909df48b0c9d919d6f8 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Wed, 5 Jun 2024 16:00:18 -0400 Subject: [PATCH 3/7] AsyncPaymentsMessageHandler trait for OnionMessenger Add a trait for handling async payments messages to OnionMessenger. This allows users to either provide their own custom handling for async payments messages or rely on a version provided by LDK. --- fuzz/src/onion_message.rs | 16 +++++ lightning-background-processor/src/lib.rs | 6 +- lightning/src/ln/functional_test_utils.rs | 3 +- lightning/src/ln/peer_handler.rs | 9 +++ lightning/src/onion_message/async_payments.rs | 42 ++++++++++++ .../src/onion_message/functional_tests.rs | 18 ++++- lightning/src/onion_message/messenger.rs | 67 +++++++++++++------ 7 files changed, 136 insertions(+), 25 deletions(-) diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index a8a290fefb3..ba76815af59 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -12,6 +12,9 @@ use lightning::ln::msgs::{self, DecodeError, OnionMessageHandler}; use lightning::ln::script::ShutdownScript; use lightning::offers::invoice::UnsignedBolt12Invoice; use lightning::offers::invoice_request::UnsignedInvoiceRequest; +use lightning::onion_message::async_payments::{ + AsyncPaymentsMessage, AsyncPaymentsMessageHandler, HeldHtlcAvailable, ReleaseHeldHtlc, +}; use lightning::onion_message::messenger::{ CustomOnionMessageHandler, Destination, MessageRouter, OnionMessagePath, OnionMessenger, PendingOnionMessage, Responder, ResponseInstruction, @@ -39,6 +42,7 @@ pub fn do_test(data: &[u8], logger: &L) { let node_id_lookup = EmptyNodeIdLookUp {}; let message_router = TestMessageRouter {}; let offers_msg_handler = TestOffersMessageHandler {}; + let async_payments_msg_handler = TestAsyncPaymentsMessageHandler {}; let custom_msg_handler = TestCustomMessageHandler {}; let onion_messenger = OnionMessenger::new( &keys_manager, @@ -47,6 +51,7 @@ pub fn do_test(data: &[u8], logger: &L) { &node_id_lookup, &message_router, &offers_msg_handler, + &async_payments_msg_handler, &custom_msg_handler, ); @@ -105,6 +110,17 @@ impl OffersMessageHandler for TestOffersMessageHandler { } } +struct TestAsyncPaymentsMessageHandler {} + +impl AsyncPaymentsMessageHandler for TestAsyncPaymentsMessageHandler { + fn held_htlc_available( + &self, _message: HeldHtlcAvailable, _responder: Option, + ) -> ResponseInstruction { + ResponseInstruction::NoResponse + } + fn release_held_htlc(&self, _message: ReleaseHeldHtlc) {} +} + #[derive(Debug)] struct TestCustomMessage {} diff --git a/lightning-background-processor/src/lib.rs b/lightning-background-processor/src/lib.rs index 4719d7e5c1a..aae64e981bb 100644 --- a/lightning-background-processor/src/lib.rs +++ b/lightning-background-processor/src/lib.rs @@ -568,7 +568,7 @@ use core::task; /// # type NetworkGraph = lightning::routing::gossip::NetworkGraph>; /// # type P2PGossipSync
    = lightning::routing::gossip::P2PGossipSync, Arc
      , Arc>; /// # type ChannelManager = lightning::ln::channelmanager::SimpleArcChannelManager, B, FE, Logger>; -/// # type OnionMessenger = lightning::onion_message::messenger::OnionMessenger, Arc, Arc, Arc>, Arc, Arc, Arc>>, Arc>, lightning::ln::peer_handler::IgnoringMessageHandler>; +/// # type OnionMessenger = lightning::onion_message::messenger::OnionMessenger, Arc, Arc, Arc>, Arc, Arc, Arc>>, Arc>, lightning::ln::peer_handler::IgnoringMessageHandler, lightning::ln::peer_handler::IgnoringMessageHandler>; /// # type Scorer = RwLock, Arc>>; /// # type PeerManager = lightning::ln::peer_handler::SimpleArcPeerManager, B, FE, Arc
        , Logger>; /// # @@ -996,7 +996,7 @@ mod tests { type PGS = Arc>>, Arc, Arc>>; type RGS = Arc>>, Arc>>; - type OM = OnionMessenger, Arc, Arc, Arc, Arc>>, Arc, Arc>>, IgnoringMessageHandler, IgnoringMessageHandler>; + type OM = OnionMessenger, Arc, Arc, Arc, Arc>>, Arc, Arc>>, IgnoringMessageHandler, IgnoringMessageHandler, IgnoringMessageHandler>; struct Node { node: Arc, @@ -1291,7 +1291,7 @@ mod tests { let best_block = BestBlock::from_network(network); let params = ChainParameters { network, best_block }; let manager = Arc::new(ChannelManager::new(fee_estimator.clone(), chain_monitor.clone(), tx_broadcaster.clone(), router.clone(), logger.clone(), keys_manager.clone(), keys_manager.clone(), keys_manager.clone(), UserConfig::default(), params, genesis_block.header.time)); - let messenger = Arc::new(OnionMessenger::new(keys_manager.clone(), keys_manager.clone(), logger.clone(), manager.clone(), msg_router.clone(), IgnoringMessageHandler {}, IgnoringMessageHandler {})); + let messenger = Arc::new(OnionMessenger::new(keys_manager.clone(), keys_manager.clone(), logger.clone(), manager.clone(), msg_router.clone(), IgnoringMessageHandler {}, IgnoringMessageHandler {}, IgnoringMessageHandler {})); let wallet = Arc::new(TestWallet {}); let sweeper = Arc::new(OutputSweeper::new(best_block, Arc::clone(&tx_broadcaster), Arc::clone(&fee_estimator), None::>, Arc::clone(&keys_manager), wallet, Arc::clone(&kv_store), Arc::clone(&logger))); diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 7e57f20595a..079f6345fc9 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -421,6 +421,7 @@ type TestOnionMessenger<'chan_man, 'node_cfg, 'chan_mon_cfg> = OnionMessenger< &'node_cfg test_utils::TestMessageRouter<'chan_mon_cfg>, &'chan_man TestChannelManager<'node_cfg, 'chan_mon_cfg>, IgnoringMessageHandler, + IgnoringMessageHandler, >; /// For use with [`OnionMessenger`] otherwise `test_restored_packages_retry` will fail. This is @@ -3228,7 +3229,7 @@ pub fn create_network<'a, 'b: 'a, 'c: 'b>(node_count: usize, cfgs: &'b Vec, + ) -> ResponseInstruction { + ResponseInstruction::NoResponse + } + fn release_held_htlc(&self, _message: ReleaseHeldHtlc) {} +} impl CustomOnionMessageHandler for IgnoringMessageHandler { type CustomMessage = Infallible; fn handle_custom_message(&self, _message: Self::CustomMessage, _responder: Option) -> ResponseInstruction { diff --git a/lightning/src/onion_message/async_payments.rs b/lightning/src/onion_message/async_payments.rs index aa6779fb33d..f5953c6361a 100644 --- a/lightning/src/onion_message/async_payments.rs +++ b/lightning/src/onion_message/async_payments.rs @@ -11,13 +11,55 @@ use crate::io; use crate::ln::msgs::DecodeError; +use crate::onion_message::messenger::PendingOnionMessage; +use crate::onion_message::messenger::{Responder, ResponseInstruction}; use crate::onion_message::packet::OnionMessageContents; +use crate::prelude::*; use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer}; // TLV record types for the `onionmsg_tlv` TLV stream as defined in BOLT 4. const HELD_HTLC_AVAILABLE_TLV_TYPE: u64 = 72; const RELEASE_HELD_HTLC_TLV_TYPE: u64 = 74; +/// A handler for an [`OnionMessage`] containing an async payments message as its payload. +/// +/// [`OnionMessage`]: crate::ln::msgs::OnionMessage +pub trait AsyncPaymentsMessageHandler { + /// Handle a [`HeldHtlcAvailable`] message. A [`ReleaseHeldHtlc`] should be returned to release + /// the held funds. + fn held_htlc_available( + &self, message: HeldHtlcAvailable, responder: Option, + ) -> ResponseInstruction; + + /// Handle a [`ReleaseHeldHtlc`] message. If authentication of the message succeeds, an HTLC + /// should be released to the corresponding payee. + fn release_held_htlc(&self, message: ReleaseHeldHtlc); + + /// Release any [`AsyncPaymentsMessage`]s that need to be sent. + /// + /// Typically, this is used for messages initiating an async payment flow rather than in response + /// to another message. + #[cfg(not(c_bindings))] + fn release_pending_messages(&self) -> Vec> { + vec![] + } + + /// Release any [`AsyncPaymentsMessage`]s that need to be sent. + /// + /// Typically, this is used for messages initiating a payment flow rather than in response to + /// another message. + #[cfg(c_bindings)] + fn release_pending_messages( + &self, + ) -> Vec<( + AsyncPaymentsMessage, + crate::onion_message::messenger::Destination, + Option, + )> { + vec![] + } +} + /// Possible async payment messages sent and received via an [`OnionMessage`]. /// /// [`OnionMessage`]: crate::ln::msgs::OnionMessage diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index 08be1b2c502..9a2dc36f873 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -19,6 +19,7 @@ use crate::routing::test_utils::{add_channel, add_or_update_node}; use crate::sign::{NodeSigner, Recipient}; use crate::util::ser::{FixedLengthReader, LengthReadable, Writeable, Writer}; use crate::util::test_utils; +use super::async_payments::{AsyncPaymentsMessageHandler, HeldHtlcAvailable, ReleaseHeldHtlc}; use super::messenger::{CustomOnionMessageHandler, DefaultMessageRouter, Destination, OnionMessagePath, OnionMessenger, PendingOnionMessage, Responder, ResponseInstruction, SendError, SendSuccess}; use super::offers::{OffersMessage, OffersMessageHandler}; use super::packet::{OnionMessageContents, Packet}; @@ -50,6 +51,7 @@ struct MessengerNode { Arc >>, Arc, + Arc, Arc >, custom_message_handler: Arc, @@ -79,6 +81,17 @@ impl OffersMessageHandler for TestOffersMessageHandler { } } +struct TestAsyncPaymentsMessageHandler {} + +impl AsyncPaymentsMessageHandler for TestAsyncPaymentsMessageHandler { + fn held_htlc_available( + &self, _message: HeldHtlcAvailable, _responder: Option, + ) -> ResponseInstruction { + ResponseInstruction::NoResponse + } + fn release_held_htlc(&self, _message: ReleaseHeldHtlc) {} +} + #[derive(Clone, Debug, PartialEq)] enum TestCustomMessage { Ping, @@ -249,18 +262,19 @@ fn create_nodes_using_cfgs(cfgs: Vec) -> Vec { DefaultMessageRouter::new(network_graph.clone(), entropy_source.clone()) ); let offers_message_handler = Arc::new(TestOffersMessageHandler {}); + let async_payments_message_handler = Arc::new(TestAsyncPaymentsMessageHandler {}); let custom_message_handler = Arc::new(TestCustomMessageHandler::new()); let messenger = if cfg.intercept_offline_peer_oms { OnionMessenger::new_with_offline_peer_interception( entropy_source.clone(), node_signer.clone(), logger.clone(), node_id_lookup, message_router, offers_message_handler, - custom_message_handler.clone() + async_payments_message_handler, custom_message_handler.clone() ) } else { OnionMessenger::new( entropy_source.clone(), node_signer.clone(), logger.clone(), node_id_lookup, message_router, offers_message_handler, - custom_message_handler.clone() + async_payments_message_handler, custom_message_handler.clone() ) }; nodes.push(MessengerNode { diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index c991c5bccc5..2e47e7c84a6 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -24,6 +24,7 @@ use crate::ln::features::{InitFeatures, NodeFeatures}; use crate::ln::msgs::{self, OnionMessage, OnionMessageHandler, SocketAddress}; use crate::ln::onion_utils; use crate::routing::gossip::{NetworkGraph, NodeId, ReadOnlyNetworkGraph}; +use super::async_payments::{AsyncPaymentsMessage, AsyncPaymentsMessageHandler}; use super::packet::OnionMessageContents; use super::packet::ParsedOnionMessageContents; use super::offers::OffersMessageHandler; @@ -76,22 +77,27 @@ pub trait AOnionMessenger { type OffersMessageHandler: OffersMessageHandler + ?Sized; /// A type that may be dereferenced to [`Self::OffersMessageHandler`] type OMH: Deref; + /// A type implementing [`AsyncPaymentsMessageHandler`] + type AsyncPaymentsMessageHandler: AsyncPaymentsMessageHandler + ?Sized; + /// A type that may be dereferenced to [`Self::AsyncPaymentsMessageHandler`] + type APH: Deref; /// A type implementing [`CustomOnionMessageHandler`] type CustomOnionMessageHandler: CustomOnionMessageHandler + ?Sized; /// A type that may be dereferenced to [`Self::CustomOnionMessageHandler`] type CMH: Deref; /// Returns a reference to the actual [`OnionMessenger`] object. - fn get_om(&self) -> &OnionMessenger; + fn get_om(&self) -> &OnionMessenger; } -impl AOnionMessenger -for OnionMessenger where +impl AOnionMessenger +for OnionMessenger where ES::Target: EntropySource, NS::Target: NodeSigner, L::Target: Logger, NL::Target: NodeIdLookUp, MR::Target: MessageRouter, OMH::Target: OffersMessageHandler, + APH:: Target: AsyncPaymentsMessageHandler, CMH::Target: CustomOnionMessageHandler, { type EntropySource = ES::Target; @@ -106,9 +112,11 @@ for OnionMessenger where type MR = MR; type OffersMessageHandler = OMH::Target; type OMH = OMH; + type AsyncPaymentsMessageHandler = APH::Target; + type APH = APH; type CustomOnionMessageHandler = CMH::Target; type CMH = CMH; - fn get_om(&self) -> &OnionMessenger { self } + fn get_om(&self) -> &OnionMessenger { self } } /// A sender, receiver and forwarder of [`OnionMessage`]s. @@ -180,11 +188,12 @@ for OnionMessenger where /// # let message_router = Arc::new(FakeMessageRouter {}); /// # let custom_message_handler = IgnoringMessageHandler {}; /// # let offers_message_handler = IgnoringMessageHandler {}; +/// # let async_payments_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, &node_id_lookup, message_router, -/// &offers_message_handler, &custom_message_handler +/// &offers_message_handler, &async_payments_message_handler, &custom_message_handler /// ); /// # #[derive(Debug)] @@ -225,14 +234,16 @@ for OnionMessenger where /// /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice -pub struct OnionMessenger -where +pub struct OnionMessenger< + ES: Deref, NS: Deref, L: Deref, NL: Deref, MR: Deref, OMH: Deref, APH: Deref, CMH: Deref +> where ES::Target: EntropySource, NS::Target: NodeSigner, L::Target: Logger, NL::Target: NodeIdLookUp, MR::Target: MessageRouter, OMH::Target: OffersMessageHandler, + APH::Target: AsyncPaymentsMessageHandler, CMH::Target: CustomOnionMessageHandler, { entropy_source: ES, @@ -243,6 +254,7 @@ where node_id_lookup: NL, message_router: MR, offers_handler: OMH, + async_payments_handler: APH, custom_handler: CMH, intercept_messages_for_offline_peers: bool, pending_events: Mutex, @@ -986,8 +998,8 @@ where } } -impl -OnionMessenger +impl +OnionMessenger where ES::Target: EntropySource, NS::Target: NodeSigner, @@ -995,17 +1007,18 @@ where NL::Target: NodeIdLookUp, MR::Target: MessageRouter, OMH::Target: OffersMessageHandler, + APH::Target: AsyncPaymentsMessageHandler, 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, node_id_lookup: NL, message_router: MR, - offers_handler: OMH, custom_handler: CMH + offers_handler: OMH, async_payments_handler: APH, custom_handler: CMH ) -> Self { Self::new_inner( entropy_source, node_signer, logger, node_id_lookup, message_router, - offers_handler, custom_handler, false + offers_handler, async_payments_handler, custom_handler, false ) } @@ -1032,17 +1045,17 @@ where /// peers. pub fn new_with_offline_peer_interception( entropy_source: ES, node_signer: NS, logger: L, node_id_lookup: NL, - message_router: MR, offers_handler: OMH, custom_handler: CMH + message_router: MR, offers_handler: OMH, async_payments_handler: APH, custom_handler: CMH ) -> Self { Self::new_inner( entropy_source, node_signer, logger, node_id_lookup, message_router, - offers_handler, custom_handler, true + offers_handler, async_payments_handler, custom_handler, true ) } fn new_inner( entropy_source: ES, node_signer: NS, logger: L, node_id_lookup: NL, - message_router: MR, offers_handler: OMH, custom_handler: CMH, + message_router: MR, offers_handler: OMH, async_payments_handler: APH, custom_handler: CMH, intercept_messages_for_offline_peers: bool ) -> Self { let mut secp_ctx = Secp256k1::new(); @@ -1056,6 +1069,7 @@ where node_id_lookup, message_router, offers_handler, + async_payments_handler, custom_handler, intercept_messages_for_offline_peers, pending_events: Mutex::new(PendingEvents { @@ -1360,8 +1374,8 @@ fn outbound_buffer_full(peer_node_id: &PublicKey, buffer: &HashMap EventsProvider -for OnionMessenger +impl EventsProvider +for OnionMessenger where ES::Target: EntropySource, NS::Target: NodeSigner, @@ -1369,6 +1383,7 @@ where NL::Target: NodeIdLookUp, MR::Target: MessageRouter, OMH::Target: OffersMessageHandler, + APH::Target: AsyncPaymentsMessageHandler, CMH::Target: CustomOnionMessageHandler, { fn process_pending_events(&self, handler: H) where H::Target: EventHandler { @@ -1400,8 +1415,8 @@ where } } -impl OnionMessageHandler -for OnionMessenger +impl OnionMessageHandler +for OnionMessenger where ES::Target: EntropySource, NS::Target: NodeSigner, @@ -1409,6 +1424,7 @@ where NL::Target: NodeIdLookUp, MR::Target: MessageRouter, OMH::Target: OffersMessageHandler, + APH::Target: AsyncPaymentsMessageHandler, CMH::Target: CustomOnionMessageHandler, { fn handle_onion_message(&self, peer_node_id: &PublicKey, msg: &OnionMessage) { @@ -1428,7 +1444,18 @@ where let response_instructions = self.offers_handler.handle_message(msg, responder); let _ = self.handle_onion_message_response(response_instructions); }, - ParsedOnionMessageContents::AsyncPayments(_msg) => todo!(), + ParsedOnionMessageContents::AsyncPayments(AsyncPaymentsMessage::HeldHtlcAvailable(msg)) => { + let responder = reply_path.map( + |reply_path| Responder::new(reply_path, path_id) + ); + let response_instructions = self.async_payments_handler.held_htlc_available( + msg, responder + ); + let _ = self.handle_onion_message_response(response_instructions); + }, + ParsedOnionMessageContents::AsyncPayments(AsyncPaymentsMessage::ReleaseHeldHtlc(msg)) => { + self.async_payments_handler.release_held_htlc(msg); + }, ParsedOnionMessageContents::Custom(msg) => { let responder = reply_path.map( |reply_path| Responder::new(reply_path, path_id) @@ -1600,6 +1627,7 @@ pub type SimpleArcOnionMessenger = OnionMessenger< Arc>, Arc>>, Arc, Arc>>, Arc>, + IgnoringMessageHandler, IgnoringMessageHandler >; @@ -1620,6 +1648,7 @@ pub type SimpleRefOnionMessenger< &'i SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, M, T, F, L>, &'j DefaultMessageRouter<&'g NetworkGraph<&'b L>, &'b L, &'a KeysManager>, &'i SimpleRefChannelManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, M, T, F, L>, + IgnoringMessageHandler, IgnoringMessageHandler >; From 691e10f01eb904804a6a33d8cec8fc6568b0a884 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Thu, 6 Jun 2024 11:56:37 -0400 Subject: [PATCH 4/7] DRY responder instantiation for onion messages. --- lightning/src/onion_message/messenger.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 2e47e7c84a6..4182fdf0307 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -1436,18 +1436,15 @@ where "Received an onion message with path_id {:02x?} and {} reply_path: {:?}", path_id, if reply_path.is_some() { "a" } else { "no" }, message); + let responder = reply_path.map( + |reply_path| Responder::new(reply_path, path_id) + ); match message { ParsedOnionMessageContents::Offers(msg) => { - let responder = reply_path.map( - |reply_path| Responder::new(reply_path, path_id) - ); let response_instructions = self.offers_handler.handle_message(msg, responder); let _ = self.handle_onion_message_response(response_instructions); }, ParsedOnionMessageContents::AsyncPayments(AsyncPaymentsMessage::HeldHtlcAvailable(msg)) => { - let responder = reply_path.map( - |reply_path| Responder::new(reply_path, path_id) - ); let response_instructions = self.async_payments_handler.held_htlc_available( msg, responder ); @@ -1457,9 +1454,6 @@ where self.async_payments_handler.release_held_htlc(msg); }, ParsedOnionMessageContents::Custom(msg) => { - let responder = reply_path.map( - |reply_path| Responder::new(reply_path, path_id) - ); let response_instructions = self.custom_handler.handle_custom_message(msg, responder); let _ = self.handle_onion_message_response(response_instructions); }, From 6553d15aad48d70676f8b86905349c19dfd441d1 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Wed, 29 May 2024 14:48:05 -0400 Subject: [PATCH 5/7] Add OffersMessage variant for static invoices. --- lightning/src/ln/channelmanager.rs | 10 ++++++++++ lightning/src/ln/offers_tests.rs | 3 +++ lightning/src/onion_message/offers.rs | 17 ++++++++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 274edf6d7b4..f189aee04cf 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -10337,6 +10337,16 @@ where }, } }, + OffersMessage::StaticInvoice(_invoice) => { + match responder { + Some(responder) => { + responder.respond(OffersMessage::InvoiceError( + InvoiceError::from_string("Static invoices not yet supported".to_string()) + )) + }, + None => return ResponseInstruction::NoResponse, + } + }, OffersMessage::InvoiceError(invoice_error) => { log_trace!(self.logger, "Received invoice_error: {}", invoice_error); ResponseInstruction::NoResponse diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index c965ba50e8d..10ebd599bde 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -192,6 +192,7 @@ fn extract_invoice_request<'a, 'b, 'c>( ParsedOnionMessageContents::Offers(offers_message) => match offers_message { OffersMessage::InvoiceRequest(invoice_request) => (invoice_request, reply_path.unwrap()), OffersMessage::Invoice(invoice) => panic!("Unexpected invoice: {:?}", invoice), + OffersMessage::StaticInvoice(invoice) => panic!("Unexpected static invoice: {:?}", invoice), OffersMessage::InvoiceError(error) => panic!("Unexpected invoice_error: {:?}", error), }, ParsedOnionMessageContents::AsyncPayments(message) => panic!("Unexpected async payments message: {:?}", message), @@ -208,6 +209,7 @@ fn extract_invoice<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessage) ParsedOnionMessageContents::Offers(offers_message) => match offers_message { OffersMessage::InvoiceRequest(invoice_request) => panic!("Unexpected invoice_request: {:?}", invoice_request), OffersMessage::Invoice(invoice) => invoice, + OffersMessage::StaticInvoice(invoice) => panic!("Unexpected static invoice: {:?}", invoice), OffersMessage::InvoiceError(error) => panic!("Unexpected invoice_error: {:?}", error), }, ParsedOnionMessageContents::AsyncPayments(message) => panic!("Unexpected async payments message: {:?}", message), @@ -226,6 +228,7 @@ fn extract_invoice_error<'a, 'b, 'c>( ParsedOnionMessageContents::Offers(offers_message) => match offers_message { OffersMessage::InvoiceRequest(invoice_request) => panic!("Unexpected invoice_request: {:?}", invoice_request), OffersMessage::Invoice(invoice) => panic!("Unexpected invoice: {:?}", invoice), + OffersMessage::StaticInvoice(invoice) => panic!("Unexpected invoice: {:?}", invoice), OffersMessage::InvoiceError(error) => error, }, ParsedOnionMessageContents::AsyncPayments(message) => panic!("Unexpected async payments message: {:?}", message), diff --git a/lightning/src/onion_message/offers.rs b/lightning/src/onion_message/offers.rs index 42c6914157e..52dacd84e3d 100644 --- a/lightning/src/onion_message/offers.rs +++ b/lightning/src/onion_message/offers.rs @@ -16,6 +16,7 @@ use crate::offers::invoice_error::InvoiceError; use crate::offers::invoice_request::InvoiceRequest; use crate::offers::invoice::Bolt12Invoice; use crate::offers::parse::Bolt12ParseError; +use crate::offers::static_invoice::StaticInvoice; use crate::onion_message::packet::OnionMessageContents; use crate::util::logger::Logger; use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer}; @@ -29,6 +30,7 @@ use crate::prelude::*; const INVOICE_REQUEST_TLV_TYPE: u64 = 64; const INVOICE_TLV_TYPE: u64 = 66; const INVOICE_ERROR_TLV_TYPE: u64 = 68; +const STATIC_INVOICE_TLV_TYPE: u64 = 70; /// A handler for an [`OnionMessage`] containing a BOLT 12 Offers message as its payload. /// @@ -72,6 +74,9 @@ pub enum OffersMessage { /// [`Refund`]: crate::offers::refund::Refund Invoice(Bolt12Invoice), + /// A `StaticInvoice` sent in response to an [`InvoiceRequest`]. + StaticInvoice(StaticInvoice), + /// An error from handling an [`OffersMessage`]. InvoiceError(InvoiceError), } @@ -80,7 +85,10 @@ impl OffersMessage { /// Returns whether `tlv_type` corresponds to a TLV record for Offers. pub fn is_known_type(tlv_type: u64) -> bool { match tlv_type { - INVOICE_REQUEST_TLV_TYPE | INVOICE_TLV_TYPE | INVOICE_ERROR_TLV_TYPE => true, + INVOICE_REQUEST_TLV_TYPE + | INVOICE_TLV_TYPE + | STATIC_INVOICE_TLV_TYPE + | INVOICE_ERROR_TLV_TYPE => true, _ => false, } } @@ -89,6 +97,7 @@ impl OffersMessage { match tlv_type { INVOICE_REQUEST_TLV_TYPE => Ok(Self::InvoiceRequest(InvoiceRequest::try_from(bytes)?)), INVOICE_TLV_TYPE => Ok(Self::Invoice(Bolt12Invoice::try_from(bytes)?)), + STATIC_INVOICE_TLV_TYPE => Ok(Self::StaticInvoice(StaticInvoice::try_from(bytes)?)), _ => Err(Bolt12ParseError::Decode(DecodeError::InvalidValue)), } } @@ -103,6 +112,9 @@ impl fmt::Debug for OffersMessage { OffersMessage::Invoice(message) => { write!(f, "{:?}", message.as_tlv_stream()) } + OffersMessage::StaticInvoice(message) => { + write!(f, "{:?}", message) + } OffersMessage::InvoiceError(message) => { write!(f, "{:?}", message) } @@ -115,6 +127,7 @@ impl OnionMessageContents for OffersMessage { match self { OffersMessage::InvoiceRequest(_) => INVOICE_REQUEST_TLV_TYPE, OffersMessage::Invoice(_) => INVOICE_TLV_TYPE, + OffersMessage::StaticInvoice(_) => STATIC_INVOICE_TLV_TYPE, OffersMessage::InvoiceError(_) => INVOICE_ERROR_TLV_TYPE, } } @@ -122,6 +135,7 @@ impl OnionMessageContents for OffersMessage { match &self { OffersMessage::InvoiceRequest(_) => "Invoice Request", OffersMessage::Invoice(_) => "Invoice", + OffersMessage::StaticInvoice(_) => "Static Invoice", OffersMessage::InvoiceError(_) => "Invoice Error", } } @@ -132,6 +146,7 @@ impl Writeable for OffersMessage { match self { OffersMessage::InvoiceRequest(message) => message.write(w), OffersMessage::Invoice(message) => message.write(w), + OffersMessage::StaticInvoice(message) => message.write(w), OffersMessage::InvoiceError(message) => message.write(w), } } From f20bd3de9ff97235d74d1db8075597b041ae6c61 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Thu, 13 Jun 2024 14:08:03 -0400 Subject: [PATCH 6/7] Remove unused imports in static_invoice.rs --- lightning/src/offers/static_invoice.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lightning/src/offers/static_invoice.rs b/lightning/src/offers/static_invoice.rs index d0846b29af6..69f4073e678 100644 --- a/lightning/src/offers/static_invoice.rs +++ b/lightning/src/offers/static_invoice.rs @@ -15,8 +15,8 @@ use crate::ln::features::{Bolt12InvoiceFeatures, OfferFeatures}; use crate::ln::inbound_payment::ExpandedKey; use crate::ln::msgs::DecodeError; use crate::offers::invoice::{ - check_invoice_signing_pubkey, construct_payment_paths, filter_fallbacks, BlindedPathIter, - BlindedPayInfo, BlindedPayInfoIter, FallbackAddress, InvoiceTlvStream, InvoiceTlvStreamRef, + check_invoice_signing_pubkey, construct_payment_paths, filter_fallbacks, BlindedPayInfo, + FallbackAddress, InvoiceTlvStream, InvoiceTlvStreamRef, }; use crate::offers::invoice_macros::{invoice_accessors_common, invoice_builder_methods_common}; use crate::offers::merkle::{ @@ -26,9 +26,7 @@ use crate::offers::offer::{ Amount, Offer, OfferContents, OfferTlvStream, OfferTlvStreamRef, Quantity, }; use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError, ParsedMessage}; -use crate::util::ser::{ - HighZeroBytesDroppedBigSize, Iterable, SeekReadable, WithoutLength, Writeable, Writer, -}; +use crate::util::ser::{Iterable, SeekReadable, WithoutLength, Writeable, Writer}; use crate::util::string::PrintableString; use bitcoin::address::Address; use bitcoin::blockdata::constants::ChainHash; From 5c7af8c6d32dd4bb2b307ba29c68667a15cb8509 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Thu, 13 Jun 2024 14:09:12 -0400 Subject: [PATCH 7/7] Cfg-gate async payments module and public enum variants. --- ci/check-cfg-flags.py | 2 ++ ci/ci-tests.sh | 2 ++ lightning/src/ln/channelmanager.rs | 1 + lightning/src/ln/offers_tests.rs | 6 ++++++ lightning/src/offers/mod.rs | 4 ++-- lightning/src/offers/offer.rs | 1 + lightning/src/onion_message/messenger.rs | 7 ++++++- lightning/src/onion_message/offers.rs | 13 +++++++++++-- lightning/src/onion_message/packet.rs | 6 ++++++ 9 files changed, 37 insertions(+), 5 deletions(-) diff --git a/ci/check-cfg-flags.py b/ci/check-cfg-flags.py index c33e8aa3a15..d73bf50a1f6 100755 --- a/ci/check-cfg-flags.py +++ b/ci/check-cfg-flags.py @@ -104,6 +104,8 @@ def check_cfg_tag(cfg): pass elif cfg == "splicing": pass + elif cfg == "async_payments": + pass else: print("Bad cfg tag: " + cfg) assert False diff --git a/ci/ci-tests.sh b/ci/ci-tests.sh index 0dc654d8bed..d0ba7c7fe9e 100755 --- a/ci/ci-tests.sh +++ b/ci/ci-tests.sh @@ -179,3 +179,5 @@ RUSTFLAGS="--cfg=async_signing" cargo test --verbose --color always -p lightning RUSTFLAGS="--cfg=dual_funding" cargo test --verbose --color always -p lightning [ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean RUSTFLAGS="--cfg=splicing" cargo test --verbose --color always -p lightning +[ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean +RUSTFLAGS="--cfg=async_payments" cargo test --verbose --color always -p lightning diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index f189aee04cf..fe3320a1360 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -10337,6 +10337,7 @@ where }, } }, + #[cfg(async_payments)] OffersMessage::StaticInvoice(_invoice) => { match responder { Some(responder) => { diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index 10ebd599bde..e174dfc1cb4 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -192,9 +192,11 @@ fn extract_invoice_request<'a, 'b, 'c>( ParsedOnionMessageContents::Offers(offers_message) => match offers_message { OffersMessage::InvoiceRequest(invoice_request) => (invoice_request, reply_path.unwrap()), OffersMessage::Invoice(invoice) => panic!("Unexpected invoice: {:?}", invoice), + #[cfg(async_payments)] OffersMessage::StaticInvoice(invoice) => panic!("Unexpected static invoice: {:?}", invoice), OffersMessage::InvoiceError(error) => panic!("Unexpected invoice_error: {:?}", error), }, + #[cfg(async_payments)] ParsedOnionMessageContents::AsyncPayments(message) => panic!("Unexpected async payments message: {:?}", message), ParsedOnionMessageContents::Custom(message) => panic!("Unexpected custom message: {:?}", message), }, @@ -209,9 +211,11 @@ fn extract_invoice<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessage) ParsedOnionMessageContents::Offers(offers_message) => match offers_message { OffersMessage::InvoiceRequest(invoice_request) => panic!("Unexpected invoice_request: {:?}", invoice_request), OffersMessage::Invoice(invoice) => invoice, + #[cfg(async_payments)] OffersMessage::StaticInvoice(invoice) => panic!("Unexpected static invoice: {:?}", invoice), OffersMessage::InvoiceError(error) => panic!("Unexpected invoice_error: {:?}", error), }, + #[cfg(async_payments)] ParsedOnionMessageContents::AsyncPayments(message) => panic!("Unexpected async payments message: {:?}", message), ParsedOnionMessageContents::Custom(message) => panic!("Unexpected custom message: {:?}", message), }, @@ -228,9 +232,11 @@ fn extract_invoice_error<'a, 'b, 'c>( ParsedOnionMessageContents::Offers(offers_message) => match offers_message { OffersMessage::InvoiceRequest(invoice_request) => panic!("Unexpected invoice_request: {:?}", invoice_request), OffersMessage::Invoice(invoice) => panic!("Unexpected invoice: {:?}", invoice), + #[cfg(async_payments)] OffersMessage::StaticInvoice(invoice) => panic!("Unexpected invoice: {:?}", invoice), OffersMessage::InvoiceError(error) => error, }, + #[cfg(async_payments)] ParsedOnionMessageContents::AsyncPayments(message) => panic!("Unexpected async payments message: {:?}", message), ParsedOnionMessageContents::Custom(message) => panic!("Unexpected custom message: {:?}", message), }, diff --git a/lightning/src/offers/mod.rs b/lightning/src/offers/mod.rs index b77eec16119..e5e894e2a12 100644 --- a/lightning/src/offers/mod.rs +++ b/lightning/src/offers/mod.rs @@ -24,7 +24,7 @@ pub mod parse; mod payer; pub mod refund; pub(crate) mod signer; -#[allow(unused)] -pub(crate) mod static_invoice; +#[cfg(async_payments)] +pub mod static_invoice; #[cfg(test)] pub(crate) mod test_utils; diff --git a/lightning/src/offers/offer.rs b/lightning/src/offers/offer.rs index dd58c75cec2..253de8652bb 100644 --- a/lightning/src/offers/offer.rs +++ b/lightning/src/offers/offer.rs @@ -665,6 +665,7 @@ impl Offer { self.contents.expects_quantity() } + #[cfg(async_payments)] pub(super) fn verify( &self, key: &ExpandedKey, secp_ctx: &Secp256k1 ) -> Result<(OfferId, Option), ()> { diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 4182fdf0307..c7da29307bc 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -24,7 +24,9 @@ use crate::ln::features::{InitFeatures, NodeFeatures}; use crate::ln::msgs::{self, OnionMessage, OnionMessageHandler, SocketAddress}; use crate::ln::onion_utils; use crate::routing::gossip::{NetworkGraph, NodeId, ReadOnlyNetworkGraph}; -use super::async_payments::{AsyncPaymentsMessage, AsyncPaymentsMessageHandler}; +use super::async_payments::AsyncPaymentsMessageHandler; +#[cfg(async_payments)] +use super::async_payments::AsyncPaymentsMessage; use super::packet::OnionMessageContents; use super::packet::ParsedOnionMessageContents; use super::offers::OffersMessageHandler; @@ -254,6 +256,7 @@ pub struct OnionMessenger< node_id_lookup: NL, message_router: MR, offers_handler: OMH, + #[allow(unused)] async_payments_handler: APH, custom_handler: CMH, intercept_messages_for_offline_peers: bool, @@ -1444,12 +1447,14 @@ where let response_instructions = self.offers_handler.handle_message(msg, responder); let _ = self.handle_onion_message_response(response_instructions); }, + #[cfg(async_payments)] ParsedOnionMessageContents::AsyncPayments(AsyncPaymentsMessage::HeldHtlcAvailable(msg)) => { let response_instructions = self.async_payments_handler.held_htlc_available( msg, responder ); let _ = self.handle_onion_message_response(response_instructions); }, + #[cfg(async_payments)] ParsedOnionMessageContents::AsyncPayments(AsyncPaymentsMessage::ReleaseHeldHtlc(msg)) => { self.async_payments_handler.release_held_htlc(msg); }, diff --git a/lightning/src/onion_message/offers.rs b/lightning/src/onion_message/offers.rs index 52dacd84e3d..397f4b8a72b 100644 --- a/lightning/src/onion_message/offers.rs +++ b/lightning/src/onion_message/offers.rs @@ -16,6 +16,7 @@ use crate::offers::invoice_error::InvoiceError; use crate::offers::invoice_request::InvoiceRequest; use crate::offers::invoice::Bolt12Invoice; use crate::offers::parse::Bolt12ParseError; +#[cfg(async_payments)] use crate::offers::static_invoice::StaticInvoice; use crate::onion_message::packet::OnionMessageContents; use crate::util::logger::Logger; @@ -30,6 +31,7 @@ use crate::prelude::*; const INVOICE_REQUEST_TLV_TYPE: u64 = 64; const INVOICE_TLV_TYPE: u64 = 66; const INVOICE_ERROR_TLV_TYPE: u64 = 68; +#[cfg(async_payments)] const STATIC_INVOICE_TLV_TYPE: u64 = 70; /// A handler for an [`OnionMessage`] containing a BOLT 12 Offers message as its payload. @@ -74,7 +76,8 @@ pub enum OffersMessage { /// [`Refund`]: crate::offers::refund::Refund Invoice(Bolt12Invoice), - /// A `StaticInvoice` sent in response to an [`InvoiceRequest`]. + #[cfg(async_payments)] + /// A [`StaticInvoice`] sent in response to an [`InvoiceRequest`]. StaticInvoice(StaticInvoice), /// An error from handling an [`OffersMessage`]. @@ -87,8 +90,9 @@ impl OffersMessage { match tlv_type { INVOICE_REQUEST_TLV_TYPE | INVOICE_TLV_TYPE - | STATIC_INVOICE_TLV_TYPE | INVOICE_ERROR_TLV_TYPE => true, + #[cfg(async_payments)] + STATIC_INVOICE_TLV_TYPE => true, _ => false, } } @@ -97,6 +101,7 @@ impl OffersMessage { match tlv_type { INVOICE_REQUEST_TLV_TYPE => Ok(Self::InvoiceRequest(InvoiceRequest::try_from(bytes)?)), INVOICE_TLV_TYPE => Ok(Self::Invoice(Bolt12Invoice::try_from(bytes)?)), + #[cfg(async_payments)] STATIC_INVOICE_TLV_TYPE => Ok(Self::StaticInvoice(StaticInvoice::try_from(bytes)?)), _ => Err(Bolt12ParseError::Decode(DecodeError::InvalidValue)), } @@ -112,6 +117,7 @@ impl fmt::Debug for OffersMessage { OffersMessage::Invoice(message) => { write!(f, "{:?}", message.as_tlv_stream()) } + #[cfg(async_payments)] OffersMessage::StaticInvoice(message) => { write!(f, "{:?}", message) } @@ -127,6 +133,7 @@ impl OnionMessageContents for OffersMessage { match self { OffersMessage::InvoiceRequest(_) => INVOICE_REQUEST_TLV_TYPE, OffersMessage::Invoice(_) => INVOICE_TLV_TYPE, + #[cfg(async_payments)] OffersMessage::StaticInvoice(_) => STATIC_INVOICE_TLV_TYPE, OffersMessage::InvoiceError(_) => INVOICE_ERROR_TLV_TYPE, } @@ -135,6 +142,7 @@ impl OnionMessageContents for OffersMessage { match &self { OffersMessage::InvoiceRequest(_) => "Invoice Request", OffersMessage::Invoice(_) => "Invoice", + #[cfg(async_payments)] OffersMessage::StaticInvoice(_) => "Static Invoice", OffersMessage::InvoiceError(_) => "Invoice Error", } @@ -146,6 +154,7 @@ impl Writeable for OffersMessage { match self { OffersMessage::InvoiceRequest(message) => message.write(w), OffersMessage::Invoice(message) => message.write(w), + #[cfg(async_payments)] OffersMessage::StaticInvoice(message) => message.write(w), OffersMessage::InvoiceError(message) => message.write(w), } diff --git a/lightning/src/onion_message/packet.rs b/lightning/src/onion_message/packet.rs index 47b1a0313d7..fca7dd6a91a 100644 --- a/lightning/src/onion_message/packet.rs +++ b/lightning/src/onion_message/packet.rs @@ -17,6 +17,7 @@ use crate::blinded_path::message::{ForwardTlvs, ReceiveTlvs}; use crate::blinded_path::utils::Padding; use crate::ln::msgs::DecodeError; use crate::ln::onion_utils; +#[cfg(async_payments)] use super::async_payments::AsyncPaymentsMessage; use super::messenger::CustomOnionMessageHandler; use super::offers::OffersMessage; @@ -130,6 +131,7 @@ pub enum ParsedOnionMessageContents { /// A message related to BOLT 12 Offers. Offers(OffersMessage), /// A message related to async payments. + #[cfg(async_payments)] AsyncPayments(AsyncPaymentsMessage), /// A custom onion message specified by the user. Custom(T), @@ -142,6 +144,7 @@ impl OnionMessageContents for ParsedOnionMessageContent fn tlv_type(&self) -> u64 { match self { &ParsedOnionMessageContents::Offers(ref msg) => msg.tlv_type(), + #[cfg(async_payments)] &ParsedOnionMessageContents::AsyncPayments(ref msg) => msg.tlv_type(), &ParsedOnionMessageContents::Custom(ref msg) => msg.tlv_type(), } @@ -149,6 +152,7 @@ impl OnionMessageContents for ParsedOnionMessageContent fn msg_type(&self) -> &'static str { match self { ParsedOnionMessageContents::Offers(ref msg) => msg.msg_type(), + #[cfg(async_payments)] ParsedOnionMessageContents::AsyncPayments(ref msg) => msg.msg_type(), ParsedOnionMessageContents::Custom(ref msg) => msg.msg_type(), } @@ -159,6 +163,7 @@ impl Writeable for ParsedOnionMessageContents { fn write(&self, w: &mut W) -> Result<(), io::Error> { match self { ParsedOnionMessageContents::Offers(msg) => Ok(msg.write(w)?), + #[cfg(async_payments)] ParsedOnionMessageContents::AsyncPayments(msg) => Ok(msg.write(w)?), ParsedOnionMessageContents::Custom(msg) => Ok(msg.write(w)?), } @@ -261,6 +266,7 @@ for Payload::CustomM message = Some(ParsedOnionMessageContents::Offers(msg)); Ok(true) }, + #[cfg(async_payments)] tlv_type if AsyncPaymentsMessage::is_known_type(tlv_type) => { let msg = AsyncPaymentsMessage::read(msg_reader, tlv_type)?; message = Some(ParsedOnionMessageContents::AsyncPayments(msg));