@@ -21,6 +21,7 @@ use crate::ln::channelmanager::{PaymentId, RecentPaymentDetails, Retry, self};
21
21
use crate :: ln:: functional_test_utils:: * ;
22
22
use crate :: ln:: msgs:: { ChannelMessageHandler , Init , OnionMessage , OnionMessageHandler } ;
23
23
use crate :: offers:: invoice:: Bolt12Invoice ;
24
+ use crate :: offers:: invoice_error:: InvoiceError ;
24
25
use crate :: offers:: invoice_request:: InvoiceRequest ;
25
26
use crate :: offers:: parse:: Bolt12SemanticError ;
26
27
use crate :: onion_message:: { OffersMessage , ParsedOnionMessageContents , PeeledOnion } ;
@@ -132,6 +133,23 @@ fn extract_invoice<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessage)
132
133
}
133
134
}
134
135
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
+
135
153
/// Checks that an offer can be paid through blinded paths and that ephemeral pubkeys are used
136
154
/// rather than exposing a node's pubkey.
137
155
#[ test]
@@ -638,3 +656,117 @@ fn fails_creating_refund_with_duplicate_payment_id() {
638
656
639
657
expect_recent_payment ! ( nodes[ 0 ] , RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
640
658
}
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