Skip to content

Commit 13aa66f

Browse files
committed
Functional tests for failing without payment paths
1 parent de52f41 commit 13aa66f

File tree

1 file changed

+132
-0
lines changed

1 file changed

+132
-0
lines changed

lightning/src/ln/offers_tests.rs

+132
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::ln::channelmanager::{PaymentId, RecentPaymentDetails, Retry, self};
2121
use crate::ln::functional_test_utils::*;
2222
use crate::ln::msgs::{ChannelMessageHandler, Init, OnionMessage, OnionMessageHandler};
2323
use crate::offers::invoice::Bolt12Invoice;
24+
use crate::offers::invoice_error::InvoiceError;
2425
use crate::offers::invoice_request::InvoiceRequest;
2526
use crate::offers::parse::Bolt12SemanticError;
2627
use crate::onion_message::{OffersMessage, ParsedOnionMessageContents, PeeledOnion};
@@ -132,6 +133,23 @@ fn extract_invoice<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessage)
132133
}
133134
}
134135

136+
fn extract_invoice_error<'a, 'b, 'c>(
137+
node: &Node<'a, 'b, 'c>, message: &OnionMessage
138+
) -> InvoiceError {
139+
match node.onion_messenger.peel_onion_message(message) {
140+
Ok(PeeledOnion::Receive(message, _, _)) => match message {
141+
ParsedOnionMessageContents::Offers(offers_message) => match offers_message {
142+
OffersMessage::InvoiceRequest(invoice_request) => panic!("Unexpected invoice_request: {:?}", invoice_request),
143+
OffersMessage::Invoice(invoice) => panic!("Unexpected invoice: {:?}", invoice),
144+
OffersMessage::InvoiceError(error) => error,
145+
},
146+
ParsedOnionMessageContents::Custom(message) => panic!("Unexpected custom message: {:?}", message),
147+
},
148+
Ok(PeeledOnion::Forward(_, _)) => panic!("Unexpected onion message forward"),
149+
Err(e) => panic!("Failed to process onion message {:?}", e),
150+
}
151+
}
152+
135153
/// Checks that an offer can be paid through blinded paths and that ephemeral pubkeys are used
136154
/// rather than exposing a node's pubkey.
137155
#[test]
@@ -638,3 +656,117 @@ fn fails_creating_refund_with_duplicate_payment_id() {
638656

639657
expect_recent_payment!(nodes[0], RecentPaymentDetails::AwaitingInvoice, payment_id);
640658
}
659+
660+
#[test]
661+
fn fails_sending_invoice_without_blinded_payment_paths_for_offer() {
662+
let mut accept_forward_cfg = test_default_channel_config();
663+
accept_forward_cfg.accept_forwards_to_priv_channels = true;
664+
665+
// Clearing route_blinding prevents forming any payment paths since the node is unannounced.
666+
let mut features = channelmanager::provided_init_features(&accept_forward_cfg);
667+
features.set_onion_messages_optional();
668+
features.clear_route_blinding();
669+
670+
let chanmon_cfgs = create_chanmon_cfgs(6);
671+
let node_cfgs = create_node_cfgs(6, &chanmon_cfgs);
672+
673+
*node_cfgs[1].override_init_features.borrow_mut() = Some(features);
674+
675+
let node_chanmgrs = create_node_chanmgrs(
676+
6, &node_cfgs, &[None, Some(accept_forward_cfg), None, None, None, None]
677+
);
678+
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
679+
680+
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
681+
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
682+
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
683+
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
684+
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
685+
create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 10_000_000, 1_000_000_000);
686+
create_announced_chan_between_nodes_with_value(&nodes, 2, 5, 10_000_000, 1_000_000_000);
687+
688+
let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
689+
let alice_id = alice.node.get_our_node_id();
690+
let bob_id = bob.node.get_our_node_id();
691+
let charlie_id = charlie.node.get_our_node_id();
692+
let david_id = david.node.get_our_node_id();
693+
694+
disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5]]);
695+
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);
696+
697+
let offer = alice.node
698+
.create_offer_builder("coffee".to_string()).unwrap()
699+
.amount_msats(10_000_000)
700+
.build().unwrap();
701+
702+
let payment_id = PaymentId([1; 32]);
703+
david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None)
704+
.unwrap();
705+
706+
connect_peers(david, bob);
707+
708+
let onion_message = david.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
709+
bob.onion_messenger.handle_onion_message(&david_id, &onion_message);
710+
711+
connect_peers(alice, charlie);
712+
713+
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
714+
alice.onion_messenger.handle_onion_message(&bob_id, &onion_message);
715+
716+
let onion_message = alice.onion_messenger.next_onion_message_for_peer(charlie_id).unwrap();
717+
charlie.onion_messenger.handle_onion_message(&alice_id, &onion_message);
718+
719+
let onion_message = charlie.onion_messenger.next_onion_message_for_peer(david_id).unwrap();
720+
david.onion_messenger.handle_onion_message(&charlie_id, &onion_message);
721+
722+
let invoice_error = extract_invoice_error(david, &onion_message);
723+
assert_eq!(invoice_error, InvoiceError::from(Bolt12SemanticError::MissingPaths));
724+
}
725+
726+
#[test]
727+
fn fails_sending_invoice_without_blinded_payment_paths_for_refund() {
728+
let mut accept_forward_cfg = test_default_channel_config();
729+
accept_forward_cfg.accept_forwards_to_priv_channels = true;
730+
731+
// Clearing route_blinding prevents forming any payment paths since the node is unannounced.
732+
let mut features = channelmanager::provided_init_features(&accept_forward_cfg);
733+
features.set_onion_messages_optional();
734+
features.clear_route_blinding();
735+
736+
let chanmon_cfgs = create_chanmon_cfgs(6);
737+
let node_cfgs = create_node_cfgs(6, &chanmon_cfgs);
738+
739+
*node_cfgs[1].override_init_features.borrow_mut() = Some(features);
740+
741+
let node_chanmgrs = create_node_chanmgrs(
742+
6, &node_cfgs, &[None, Some(accept_forward_cfg), None, None, None, None]
743+
);
744+
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
745+
746+
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
747+
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
748+
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
749+
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
750+
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
751+
create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 10_000_000, 1_000_000_000);
752+
create_announced_chan_between_nodes_with_value(&nodes, 2, 5, 10_000_000, 1_000_000_000);
753+
754+
let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
755+
756+
disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5]]);
757+
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);
758+
759+
let absolute_expiry = Duration::from_secs(u64::MAX);
760+
let payment_id = PaymentId([1; 32]);
761+
let refund = david.node
762+
.create_refund_builder(
763+
"refund".to_string(), 10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None
764+
)
765+
.unwrap()
766+
.build().unwrap();
767+
768+
match alice.node.request_refund_payment(&refund) {
769+
Ok(_) => panic!("Expected error"),
770+
Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
771+
}
772+
}

0 commit comments

Comments
 (0)