From 07d766a5e9d227f05e86319ff1019aeab1e1126b Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 29 Feb 2024 15:03:31 -0600 Subject: [PATCH 1/3] Test failing pay_for_offer on an unsupported chain --- lightning/src/ln/offers_tests.rs | 27 +++++++++++++++++++++++++++ lightning/src/offers/offer.rs | 6 ++++++ 2 files changed, 33 insertions(+) diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index e16c0ed515f..050df53f375 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -40,6 +40,7 @@ //! Nodes without channels are disconnected and connected as needed to ensure that deterministic //! blinded paths are used. +use bitcoin::network::constants::Network; use core::time::Duration; use crate::blinded_path::BlindedPath; use crate::events::{Event, MessageSendEventsProvider, PaymentPurpose}; @@ -732,6 +733,32 @@ fn fails_creating_refund_without_blinded_paths() { assert!(nodes[0].node.list_recent_payments().is_empty()); } +/// Fails creating an invoice request when the offer contains an unsupported chain. +#[test] +fn fails_creating_invoice_request_for_unsupported_chain() { + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + + create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000); + + let alice = &nodes[0]; + let bob = &nodes[1]; + + let offer = alice.node + .create_offer_builder("coffee".to_string()).unwrap() + .clear_chains() + .chain(Network::Signet) + .build().unwrap(); + + let payment_id = PaymentId([1; 32]); + match bob.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) { + Ok(_) => panic!("Expected error"), + Err(e) => assert_eq!(e, Bolt12SemanticError::UnsupportedChain), + } +} + /// Fails creating an invoice request when a blinded reply path cannot be created without exposing /// the node's id. #[test] diff --git a/lightning/src/offers/offer.rs b/lightning/src/offers/offer.rs index e9e35836a96..bf5e50deb77 100644 --- a/lightning/src/offers/offer.rs +++ b/lightning/src/offers/offer.rs @@ -390,6 +390,12 @@ macro_rules! offer_builder_test_methods { ( $return_value } + #[cfg_attr(c_bindings, allow(dead_code))] + pub(crate) fn clear_chains($($self_mut)* $self: $self_type) -> $return_type { + $self.offer.chains = None; + $return_value + } + #[cfg_attr(c_bindings, allow(dead_code))] pub(crate) fn clear_paths($($self_mut)* $self: $self_type) -> $return_type { $self.offer.paths = None; From ad91fcd510d7620df438a4cf59f7ed7b080adb19 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 29 Feb 2024 15:44:57 -0600 Subject: [PATCH 2/3] Update pay_for_offer docs about unsupported chains --- lightning/src/ln/channelmanager.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 8dfd0c8fcaa..02aa5efcd81 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -7830,6 +7830,7 @@ where /// Errors if: /// - a duplicate `payment_id` is provided given the caveats in the aforementioned link, /// - the provided parameters are invalid for the offer, + /// - the offer is for an unsupported chain, or /// - the parameterized [`Router`] is unable to create a blinded reply path for the invoice /// request. /// From 228e72ca34428ec9d70da677c592fe128e470b3c Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 29 Feb 2024 15:21:03 -0600 Subject: [PATCH 3/3] Fail request_refund_payment for unsupported chain If a Refund has an unsupported chain, ChannelManager should not send an invoice as it can't be paid on that chain. Instead, return an error when calling ChannelManager::request_refund_payment for such refunds. --- lightning/src/ln/channelmanager.rs | 10 ++++++++-- lightning/src/ln/offers_tests.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 02aa5efcd81..7bd395f999a 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -7919,8 +7919,10 @@ where /// /// # Errors /// - /// Errors if the parameterized [`Router`] is unable to create a blinded payment path or reply - /// path for the invoice. + /// Errors if: + /// - the refund is for an unsupported chain, or + /// - the parameterized [`Router`] is unable to create a blinded payment path or reply path for + /// the invoice. /// /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice pub fn request_refund_payment(&self, refund: &Refund) -> Result<(), Bolt12SemanticError> { @@ -7931,6 +7933,10 @@ where let amount_msats = refund.amount_msats(); let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32; + if refund.chain() != self.chain_hash { + return Err(Bolt12SemanticError::UnsupportedChain); + } + match self.create_inbound_payment(Some(amount_msats), relative_expiry, None) { Ok((payment_hash, payment_secret)) => { let payment_paths = self.create_blinded_payment_paths(amount_msats, payment_secret) diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index 050df53f375..63e73975b94 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -759,6 +759,35 @@ fn fails_creating_invoice_request_for_unsupported_chain() { } } +/// Fails requesting a payment when the refund contains an unsupported chain. +#[test] +fn fails_sending_invoice_with_unsupported_chain_for_refund() { + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + + create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000); + + let alice = &nodes[0]; + let bob = &nodes[1]; + + let absolute_expiry = Duration::from_secs(u64::MAX); + let payment_id = PaymentId([1; 32]); + let refund = bob.node + .create_refund_builder( + "refund".to_string(), 10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None + ) + .unwrap() + .chain(Network::Signet) + .build().unwrap(); + + match alice.node.request_refund_payment(&refund) { + Ok(_) => panic!("Expected error"), + Err(e) => assert_eq!(e, Bolt12SemanticError::UnsupportedChain), + } +} + /// Fails creating an invoice request when a blinded reply path cannot be created without exposing /// the node's id. #[test]