Skip to content

Commit aa334d5

Browse files
authored
Merge pull request #2917 from jkczyz/2024-02-refund-unsupported-chain
Fail `request_refund_payment` for unsupported chain
2 parents 6d5c952 + 228e72c commit aa334d5

File tree

3 files changed

+71
-2
lines changed

3 files changed

+71
-2
lines changed

lightning/src/ln/channelmanager.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -7830,6 +7830,7 @@ where
78307830
/// Errors if:
78317831
/// - a duplicate `payment_id` is provided given the caveats in the aforementioned link,
78327832
/// - the provided parameters are invalid for the offer,
7833+
/// - the offer is for an unsupported chain, or
78337834
/// - the parameterized [`Router`] is unable to create a blinded reply path for the invoice
78347835
/// request.
78357836
///
@@ -7918,8 +7919,10 @@ where
79187919
///
79197920
/// # Errors
79207921
///
7921-
/// Errors if the parameterized [`Router`] is unable to create a blinded payment path or reply
7922-
/// path for the invoice.
7922+
/// Errors if:
7923+
/// - the refund is for an unsupported chain, or
7924+
/// - the parameterized [`Router`] is unable to create a blinded payment path or reply path for
7925+
/// the invoice.
79237926
///
79247927
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
79257928
pub fn request_refund_payment(&self, refund: &Refund) -> Result<(), Bolt12SemanticError> {
@@ -7930,6 +7933,10 @@ where
79307933
let amount_msats = refund.amount_msats();
79317934
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
79327935

7936+
if refund.chain() != self.chain_hash {
7937+
return Err(Bolt12SemanticError::UnsupportedChain);
7938+
}
7939+
79337940
match self.create_inbound_payment(Some(amount_msats), relative_expiry, None) {
79347941
Ok((payment_hash, payment_secret)) => {
79357942
let payment_paths = self.create_blinded_payment_paths(amount_msats, payment_secret)

lightning/src/ln/offers_tests.rs

+56
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
//! Nodes without channels are disconnected and connected as needed to ensure that deterministic
4141
//! blinded paths are used.
4242
43+
use bitcoin::network::constants::Network;
4344
use core::time::Duration;
4445
use crate::blinded_path::BlindedPath;
4546
use crate::events::{Event, MessageSendEventsProvider, PaymentPurpose};
@@ -732,6 +733,61 @@ fn fails_creating_refund_without_blinded_paths() {
732733
assert!(nodes[0].node.list_recent_payments().is_empty());
733734
}
734735

736+
/// Fails creating an invoice request when the offer contains an unsupported chain.
737+
#[test]
738+
fn fails_creating_invoice_request_for_unsupported_chain() {
739+
let chanmon_cfgs = create_chanmon_cfgs(2);
740+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
741+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
742+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
743+
744+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
745+
746+
let alice = &nodes[0];
747+
let bob = &nodes[1];
748+
749+
let offer = alice.node
750+
.create_offer_builder("coffee".to_string()).unwrap()
751+
.clear_chains()
752+
.chain(Network::Signet)
753+
.build().unwrap();
754+
755+
let payment_id = PaymentId([1; 32]);
756+
match bob.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) {
757+
Ok(_) => panic!("Expected error"),
758+
Err(e) => assert_eq!(e, Bolt12SemanticError::UnsupportedChain),
759+
}
760+
}
761+
762+
/// Fails requesting a payment when the refund contains an unsupported chain.
763+
#[test]
764+
fn fails_sending_invoice_with_unsupported_chain_for_refund() {
765+
let chanmon_cfgs = create_chanmon_cfgs(2);
766+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
767+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
768+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
769+
770+
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
771+
772+
let alice = &nodes[0];
773+
let bob = &nodes[1];
774+
775+
let absolute_expiry = Duration::from_secs(u64::MAX);
776+
let payment_id = PaymentId([1; 32]);
777+
let refund = bob.node
778+
.create_refund_builder(
779+
"refund".to_string(), 10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None
780+
)
781+
.unwrap()
782+
.chain(Network::Signet)
783+
.build().unwrap();
784+
785+
match alice.node.request_refund_payment(&refund) {
786+
Ok(_) => panic!("Expected error"),
787+
Err(e) => assert_eq!(e, Bolt12SemanticError::UnsupportedChain),
788+
}
789+
}
790+
735791
/// Fails creating an invoice request when a blinded reply path cannot be created without exposing
736792
/// the node's id.
737793
#[test]

lightning/src/offers/offer.rs

+6
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,12 @@ macro_rules! offer_builder_test_methods { (
390390
$return_value
391391
}
392392

393+
#[cfg_attr(c_bindings, allow(dead_code))]
394+
pub(crate) fn clear_chains($($self_mut)* $self: $self_type) -> $return_type {
395+
$self.offer.chains = None;
396+
$return_value
397+
}
398+
393399
#[cfg_attr(c_bindings, allow(dead_code))]
394400
pub(crate) fn clear_paths($($self_mut)* $self: $self_type) -> $return_type {
395401
$self.offer.paths = None;

0 commit comments

Comments
 (0)