@@ -16,9 +16,9 @@ use chain::keysinterface::{KeysInterface, Recipient};
16
16
use ln:: { PaymentHash , PaymentSecret } ;
17
17
use ln:: channelmanager:: { HTLCForwardInfo , CLTV_FAR_FAR_AWAY , MIN_CLTV_EXPIRY_DELTA , PendingHTLCInfo , PendingHTLCRouting } ;
18
18
use ln:: onion_utils;
19
- use routing:: network_graph:: { NetworkUpdate , RoutingFees } ;
19
+ use routing:: network_graph:: { NetworkUpdate , RoutingFees , NodeId } ;
20
20
use routing:: router:: { get_route, PaymentParameters , Route , RouteHint , RouteHintHop } ;
21
- use ln:: features:: { InitFeatures , InvoiceFeatures } ;
21
+ use ln:: features:: { InitFeatures , InvoiceFeatures , NodeFeatures } ;
22
22
use ln:: msgs;
23
23
use ln:: msgs:: { ChannelMessageHandler , ChannelUpdate , OptionalField } ;
24
24
use util:: events:: { Event , MessageSendEvent , MessageSendEventsProvider } ;
@@ -577,6 +577,168 @@ fn test_onion_failure() {
577
577
} , true , Some ( 23 ) , None , None ) ;
578
578
}
579
579
580
+ #[ test]
581
+ fn test_default_to_onion_payload_tlv_format ( ) {
582
+ // Tests that we default to creating tlv format onion payloads when no `NodeAnnouncementInfo`
583
+ // `features` for a node in the `network_graph` exists, or when the node isn't in the
584
+ // `network_graph`, and no other known `features` for the node exists.
585
+ let mut priv_channels_conf = UserConfig :: default ( ) ;
586
+ priv_channels_conf. channel_options . announced_channel = false ;
587
+ let chanmon_cfgs = create_chanmon_cfgs ( 5 ) ;
588
+ let node_cfgs = create_node_cfgs ( 5 , & chanmon_cfgs) ;
589
+ let node_chanmgrs = create_node_chanmgrs ( 5 , & node_cfgs, & [ None , None , None , None , Some ( priv_channels_conf) ] ) ;
590
+ let mut nodes = create_network ( 5 , & node_cfgs, & node_chanmgrs) ;
591
+
592
+ create_announced_chan_between_nodes ( & nodes, 0 , 1 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
593
+ create_announced_chan_between_nodes ( & nodes, 1 , 2 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
594
+ create_announced_chan_between_nodes ( & nodes, 2 , 3 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
595
+ create_unannounced_chan_between_nodes_with_value ( & nodes, 3 , 4 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
596
+
597
+ let payment_params = PaymentParameters :: from_node_id ( nodes[ 3 ] . node . get_our_node_id ( ) ) ;
598
+ let origin_node = & nodes[ 0 ] ;
599
+ let network_graph = origin_node. network_graph ;
600
+
601
+ // Clears all the `NodeAnnouncementInfo` for all nodes of `nodes[0]`'s `network_graph`, so that
602
+ // their `features` aren't used when creating the `route`.
603
+ network_graph. clear_nodes_announcement_info ( ) ;
604
+
605
+ let ( announced_route, _, _, _) = get_route_and_payment_hash ! (
606
+ origin_node, nodes[ 3 ] , payment_params, 10_000 , TEST_FINAL_CLTV ) ;
607
+
608
+ let hops = & announced_route. paths [ 0 ] ;
609
+ // Assert that the hop between `nodes[1]` and `nodes[2]` defaults to supporting variable length
610
+ // onions, as `nodes[0]` has no `NodeAnnouncementInfo` `features` for `node[2]`
611
+ assert ! ( hops[ 1 ] . node_features. supports_variable_length_onion( ) ) ;
612
+ // Assert that the hop between `nodes[2]` and `nodes[3]` defaults to supporting variable length
613
+ // onions, as `nodes[0]` has no `NodeAnnouncementInfo` `features` for `node[3]`, and no `InvoiceFeatures`
614
+ // for the `payment_params`, which would otherwise have been used.
615
+ assert ! ( hops[ 2 ] . node_features. supports_variable_length_onion( ) ) ;
616
+ // Note that we do not assert that `hops[0]` (the channel between `nodes[0]` and `nodes[1]`)
617
+ // supports variable length onions, as the `InitFeatures` exchanged in the init message
618
+ // between the nodes will be used when creating the route. We therefore do not default to
619
+ // supporting variable length onions for that hop, as the `InitFeatures` in this case are
620
+ // `InitFeatures::known()`.
621
+
622
+ let unannounced_chan = & nodes[ 4 ] . node . list_usable_channels ( ) [ 0 ] ;
623
+
624
+ let last_hop = RouteHint ( vec ! [ RouteHintHop {
625
+ src_node_id: nodes[ 3 ] . node. get_our_node_id( ) ,
626
+ short_channel_id: unannounced_chan. short_channel_id. unwrap( ) ,
627
+ fees: RoutingFees {
628
+ base_msat: 0 ,
629
+ proportional_millionths: 0 ,
630
+ } ,
631
+ cltv_expiry_delta: 42 ,
632
+ htlc_minimum_msat: None ,
633
+ htlc_maximum_msat: None ,
634
+ } ] ) ;
635
+
636
+ let unannounced_chan_params = PaymentParameters :: from_node_id ( nodes[ 4 ] . node . get_our_node_id ( ) ) . with_route_hints ( vec ! [ last_hop] ) ;
637
+ let ( unannounced_route, _, _, _) = get_route_and_payment_hash ! (
638
+ origin_node, nodes[ 4 ] , unannounced_chan_params, 10_000 , TEST_FINAL_CLTV ) ;
639
+
640
+ let unannounced_chan_hop = & unannounced_route. paths [ 0 ] [ 3 ] ;
641
+ // Ensure that `nodes[4]` doesn't exist in `nodes[0]`'s `network_graph`, as it's not public.
642
+ assert ! ( & network_graph. read_only( ) . nodes( ) . get( & NodeId :: from_pubkey( & nodes[ 4 ] . node. get_our_node_id( ) ) ) . is_none( ) ) ;
643
+ // Assert that the hop between `nodes[3]` and `nodes[4]` defaults to supporting variable length
644
+ // onions, even though `nodes[4]` as `nodes[0]` doesn't exists in `nodes[0]`'s `network_graph`,
645
+ // and no `InvoiceFeatures` for the `payment_params` exists, which would otherwise have been
646
+ // used.
647
+ assert ! ( unannounced_chan_hop. node_features. supports_variable_length_onion( ) ) ;
648
+
649
+ let cur_height = nodes[ 0 ] . best_block_info ( ) . 1 + 1 ;
650
+ let ( announced_route_payloads, _htlc_msat, _htlc_cltv) = onion_utils:: build_onion_payloads ( & announced_route. paths [ 0 ] , 40000 , & None , cur_height, & None ) . unwrap ( ) ;
651
+ let ( unannounced_route_paylods, _htlc_msat, _htlc_cltv) = onion_utils:: build_onion_payloads ( & unannounced_route. paths [ 0 ] , 40000 , & None , cur_height, & None ) . unwrap ( ) ;
652
+
653
+ for onion_payloads in vec ! [ announced_route_payloads, unannounced_route_paylods] {
654
+ for onion_payload in onion_payloads. iter ( ) {
655
+ match onion_payload. format {
656
+ msgs:: OnionHopDataFormat :: Legacy { ..} => {
657
+ panic ! ( "Generated a `msgs::OnionHopDataFormat::Legacy` payload, even though that shouldn't have happend." ) ;
658
+ }
659
+ _ => { }
660
+ }
661
+ }
662
+ }
663
+ }
664
+
665
+ #[ test]
666
+ fn test_do_not_default_to_onion_payload_tlv_format_when_unsupported ( ) {
667
+ // Tests that we do not default to creating tlv onions if either of these types features
668
+ // exists, which specifies no support for variable length onions for a specific hop, when
669
+ // creating a route:
670
+ // 1. `InitFeatures` to the counterparty node exchanged with the init message to the node.
671
+ // 2. `NodeFeatures` in the `NodeAnnouncementInfo` of a node in sender node's `network_graph`.
672
+ // 3. `InvoiceFeatures` specified by the receiving node, when no `NodeAnnouncementInfo`
673
+ // `features` exists for the receiver in the sender's `network_graph`.
674
+ let chanmon_cfgs = create_chanmon_cfgs ( 4 ) ;
675
+ let mut node_cfgs = create_node_cfgs ( 4 , & chanmon_cfgs) ;
676
+
677
+ // Set `node[1]` config to `InitFeatures::empty()` which return `false` for
678
+ // `supports_variable_length_onion()`
679
+ let mut node_1_cfg = & mut node_cfgs[ 1 ] ;
680
+ node_1_cfg. features = InitFeatures :: empty ( ) ;
681
+
682
+ let node_chanmgrs = create_node_chanmgrs ( 4 , & node_cfgs, & [ None , None , None , None ] ) ;
683
+ let mut nodes = create_network ( 4 , & node_cfgs, & node_chanmgrs) ;
684
+
685
+ create_announced_chan_between_nodes ( & nodes, 0 , 1 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
686
+ create_announced_chan_between_nodes ( & nodes, 1 , 2 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
687
+ create_announced_chan_between_nodes ( & nodes, 2 , 3 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
688
+
689
+ let payment_params = PaymentParameters :: from_node_id ( nodes[ 3 ] . node . get_our_node_id ( ) )
690
+ . with_features ( InvoiceFeatures :: empty ( ) ) ;
691
+ let origin_node = & nodes[ 0 ] ;
692
+ let network_graph = origin_node. network_graph ;
693
+ network_graph. clear_nodes_announcement_info ( ) ;
694
+
695
+ // Set `NodeAnnouncementInfo` `features` which do not support variable length onions for
696
+ // `nodes[2]` in `nodes[0]`'s `network_graph`.
697
+ let nodes_2_unsigned_node_announcement = msgs:: UnsignedNodeAnnouncement {
698
+ features : NodeFeatures :: empty ( ) ,
699
+ timestamp : 0 ,
700
+ node_id : nodes[ 2 ] . node . get_our_node_id ( ) ,
701
+ rgb : [ 32 ; 3 ] ,
702
+ alias : [ 16 ; 32 ] ,
703
+ addresses : Vec :: new ( ) ,
704
+ excess_address_data : Vec :: new ( ) ,
705
+ excess_data : Vec :: new ( ) ,
706
+ } ;
707
+ let _res = network_graph. update_node_from_unsigned_announcement ( & nodes_2_unsigned_node_announcement) ;
708
+
709
+ let ( route, _, _, _) = get_route_and_payment_hash ! (
710
+ origin_node, nodes[ 3 ] , payment_params, 10_000 , TEST_FINAL_CLTV ) ;
711
+
712
+ let hops = & route. paths [ 0 ] ;
713
+
714
+ // Assert that the hop between `nodes[0]` and `nodes[1]` doesn't support variable length
715
+ // onions, as as the `InitFeatures` exchanged (`InitFeatures::empty()`) in the init message
716
+ // between the nodes when setting up the channel is used when creating the `route` and that we
717
+ // therefore do not default to supporting variable length onions. Despite `nodes[0]` having no
718
+ // `NodeAnnouncementInfo` `features` for `node[1]`.
719
+ assert ! ( !hops[ 0 ] . node_features. supports_variable_length_onion( ) ) ;
720
+ // Assert that the hop between `nodes[1]` and `nodes[2]` uses the `features` from
721
+ // `nodes_2_unsigned_node_announcement` that doesn't support variable length onions.
722
+ assert ! ( !hops[ 1 ] . node_features. supports_variable_length_onion( ) ) ;
723
+ // Assert that the hop between `nodes[2]` and `nodes[3]` uses the `InvoiceFeatures` set to the
724
+ // `payment_params`, that doesn't support variable length onions. We therefore do not end up
725
+ // defaulting to supporting variable length onions, despite `nodes[0]` having no
726
+ // `NodeAnnouncementInfo` `features` for `node[3]`.
727
+ assert ! ( !hops[ 2 ] . node_features. supports_variable_length_onion( ) ) ;
728
+
729
+ let cur_height = nodes[ 0 ] . best_block_info ( ) . 1 + 1 ;
730
+ let ( onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils:: build_onion_payloads ( & route. paths [ 0 ] , 40000 , & None , cur_height, & None ) . unwrap ( ) ;
731
+
732
+ for onion_payload in onion_payloads. iter ( ) {
733
+ match onion_payload. format {
734
+ msgs:: OnionHopDataFormat :: Legacy { ..} => { }
735
+ _ => {
736
+ panic ! ( "Should have only have generated `msgs::OnionHopDataFormat::Legacy` payloads" ) ;
737
+ }
738
+ }
739
+ }
740
+ }
741
+
580
742
macro_rules! get_phantom_route {
581
743
( $nodes: expr, $amt: expr, $channel: expr) => { {
582
744
let secp_ctx = Secp256k1 :: new( ) ;
0 commit comments