@@ -737,4 +737,194 @@ mod test {
737737 _ => panic ! ( "Unexpected event" )
738738 }
739739 }
740+
741+ #[ test]
742+ fn test_multi_node_hints_includes_single_public_channels_to_participating_nodes ( ) {
743+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
744+ let seed_1 = [ 42 as u8 ; 32 ] ;
745+ let seed_2 = [ 43 as u8 ; 32 ] ;
746+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
747+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
748+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
749+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
750+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
751+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
752+ let chan_0_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
753+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1. 1 ) ;
754+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1. 0 ) ;
755+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
756+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
757+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
758+
759+ let payment_amt = 10_000 ;
760+ let ( _, payment_hash, payment_secret) = {
761+ let ( payment_hash, payment_secret) = nodes[ 1 ] . node . create_inbound_payment ( Some ( payment_amt) , 3600 ) . unwrap ( ) ;
762+ let payment_preimage = nodes[ 1 ] . node . get_payment_preimage ( payment_hash, payment_secret) . unwrap ( ) ;
763+ ( payment_preimage, payment_hash, payment_secret)
764+ } ;
765+ let route_hints = vec ! [
766+ nodes[ 1 ] . node. get_phantom_route_hints( ) ,
767+ nodes[ 2 ] . node. get_phantom_route_hints( ) ,
768+ ] ;
769+ let invoice = :: utils:: create_phantom_invoice :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( Some ( payment_amt) , "test" . to_string ( ) , payment_hash, payment_secret, route_hints, & nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
770+
771+ let hints = invoice. private_routes ( ) ;
772+ assert_eq ! ( hints. len( ) , 2 ) ;
773+
774+ let mut short_chan_ids = HashSet :: new ( ) ;
775+ short_chan_ids. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
776+ short_chan_ids. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
777+ for hint in hints {
778+ let hint_short_chan_id = hint. 0 . 0 [ 0 ] . short_channel_id ;
779+ assert ! ( short_chan_ids. contains( & hint_short_chan_id) ) ;
780+ short_chan_ids. remove ( & hint_short_chan_id) ;
781+ }
782+ }
783+
784+ #[ test]
785+ fn test_multi_node_hints_has_only_highest_inbound_capacity_channel ( ) {
786+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
787+ let seed_1 = [ 42 as u8 ; 32 ] ;
788+ let seed_2 = [ 43 as u8 ; 32 ] ;
789+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
790+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
791+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
792+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
793+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
794+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
795+ let chan_0_1_low_inbound_capacity = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
796+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_low_inbound_capacity. 1 ) ;
797+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_low_inbound_capacity. 0 ) ;
798+ let chan_0_1_high_inbound_capacity = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
799+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_high_inbound_capacity. 1 ) ;
800+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_high_inbound_capacity. 0 ) ;
801+ let chan_0_1_medium_inbound_capacity = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
802+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1_medium_inbound_capacity. 1 ) ;
803+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1_medium_inbound_capacity. 0 ) ;
804+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
805+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
806+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
807+
808+ let payment_amt = 10_000 ;
809+ let ( _, payment_hash, payment_secret) = {
810+ let ( payment_hash, payment_secret) = nodes[ 1 ] . node . create_inbound_payment ( Some ( payment_amt) , 3600 ) . unwrap ( ) ;
811+ let payment_preimage = nodes[ 1 ] . node . get_payment_preimage ( payment_hash, payment_secret) . unwrap ( ) ;
812+ ( payment_preimage, payment_hash, payment_secret)
813+ } ;
814+ let route_hints = vec ! [
815+ nodes[ 1 ] . node. get_phantom_route_hints( ) ,
816+ nodes[ 2 ] . node. get_phantom_route_hints( ) ,
817+ ] ;
818+ let invoice = :: utils:: create_phantom_invoice :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( Some ( payment_amt) , "test" . to_string ( ) , payment_hash, payment_secret, route_hints, & nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
819+
820+ let hints = invoice. private_routes ( ) ;
821+ assert_eq ! ( hints. len( ) , 2 ) ;
822+
823+ let mut short_chan_ids = HashSet :: new ( ) ;
824+ short_chan_ids. insert ( chan_0_1_high_inbound_capacity. 0 . contents . short_channel_id . clone ( ) ) ;
825+ short_chan_ids. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
826+ for hint in hints {
827+ let hint_short_chan_id = hint. 0 . 0 [ 0 ] . short_channel_id ;
828+ assert ! ( short_chan_ids. contains( & hint_short_chan_id) ) ;
829+ short_chan_ids. remove ( & hint_short_chan_id) ;
830+ }
831+ }
832+
833+ #[ test]
834+ fn test_multi_node_hints_has_no_channels_with_lower_inbound_capacity_than_invoice_amt ( ) {
835+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
836+ let seed_1 = [ 42 as u8 ; 32 ] ;
837+ let seed_2 = [ 43 as u8 ; 32 ] ;
838+ let cross_node_seed = [ 44 as u8 ; 32 ] ;
839+ chanmon_cfgs[ 1 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_1, 43 , 44 , & cross_node_seed) ;
840+ chanmon_cfgs[ 2 ] . keys_manager . backing = PhantomKeysManager :: new ( & seed_2, 43 , 44 , & cross_node_seed) ;
841+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
842+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
843+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
844+ let chan_0_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
845+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1. 1 ) ;
846+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1. 0 ) ;
847+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 1_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
848+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
849+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
850+
851+ // 1 msat above chan_0_1's inbound capacity
852+ let payment_amt_99_000_001_msat = 99_000_001 ;
853+ let ( _, payment_hash_99_000_001_msat, payment_secret_99_000_001_msat) = {
854+ let ( payment_hash, payment_secret) = nodes[ 1 ] . node . create_inbound_payment ( Some ( payment_amt_99_000_001_msat) , 3600 ) . unwrap ( ) ;
855+ let payment_preimage = nodes[ 1 ] . node . get_payment_preimage ( payment_hash, payment_secret) . unwrap ( ) ;
856+ ( payment_preimage, payment_hash, payment_secret)
857+ } ;
858+
859+ let route_hints_99_000_001_msat = vec ! [
860+ nodes[ 1 ] . node. get_phantom_route_hints( ) ,
861+ nodes[ 2 ] . node. get_phantom_route_hints( ) ,
862+ ] ;
863+
864+ let invoice_99_000_001_msat = :: utils:: create_phantom_invoice :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( Some ( payment_amt_99_000_001_msat) , "test" . to_string ( ) , payment_hash_99_000_001_msat, payment_secret_99_000_001_msat, route_hints_99_000_001_msat, & nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
865+
866+ let hints_99_000_001_msat = invoice_99_000_001_msat. private_routes ( ) ;
867+ assert_eq ! ( hints_99_000_001_msat. len( ) , 1 ) ;
868+
869+ let mut short_chan_ids_99_000_001_msat = HashSet :: new ( ) ;
870+ short_chan_ids_99_000_001_msat. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
871+ for hint in hints_99_000_001_msat {
872+ let hint_short_chan_id = hint. 0 . 0 [ 0 ] . short_channel_id ;
873+ assert ! ( short_chan_ids_99_000_001_msat. contains( & hint_short_chan_id) ) ;
874+ short_chan_ids_99_000_001_msat. remove ( & hint_short_chan_id) ;
875+ }
876+
877+ // Exactly at chan_0_1's inbound capacity
878+ let payment_amt_99_000_000_msat = 99_000_000 ;
879+ let ( _, payment_hash_99_000_000_msat, payment_secret_99_000_000_msat) = {
880+ let ( payment_hash, payment_secret) = nodes[ 1 ] . node . create_inbound_payment ( Some ( payment_amt_99_000_000_msat) , 3600 ) . unwrap ( ) ;
881+ let payment_preimage = nodes[ 1 ] . node . get_payment_preimage ( payment_hash, payment_secret) . unwrap ( ) ;
882+ ( payment_preimage, payment_hash, payment_secret)
883+ } ;
884+
885+ let route_hints_99_000_000_msat = vec ! [
886+ nodes[ 1 ] . node. get_phantom_route_hints( ) ,
887+ nodes[ 2 ] . node. get_phantom_route_hints( ) ,
888+ ] ;
889+
890+ let invoice_99_000_000_msat = :: utils:: create_phantom_invoice :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( Some ( payment_amt_99_000_000_msat) , "test" . to_string ( ) , payment_hash_99_000_000_msat, payment_secret_99_000_000_msat, route_hints_99_000_000_msat, & nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
891+
892+ let hints_99_000_000_msat = invoice_99_000_000_msat. private_routes ( ) ;
893+ assert_eq ! ( hints_99_000_000_msat. len( ) , 2 ) ;
894+
895+ let mut short_chan_ids_99_000_000_msat = HashSet :: new ( ) ;
896+ short_chan_ids_99_000_000_msat. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
897+ short_chan_ids_99_000_000_msat. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
898+ for hint in hints_99_000_000_msat {
899+ let hint_short_chan_id = hint. 0 . 0 [ 0 ] . short_channel_id ;
900+ assert ! ( short_chan_ids_99_000_000_msat. contains( & hint_short_chan_id) ) ;
901+ short_chan_ids_99_000_000_msat. remove ( & hint_short_chan_id) ;
902+ }
903+
904+ // An invoice with no specified amount should include all participating nodes in the hints.
905+ let ( _, payment_hash_no_specified_amount, payment_secret_no_specified_amount) = {
906+ let ( payment_hash, payment_secret) = nodes[ 1 ] . node . create_inbound_payment ( None , 3600 ) . unwrap ( ) ;
907+ let payment_preimage = nodes[ 1 ] . node . get_payment_preimage ( payment_hash, payment_secret) . unwrap ( ) ;
908+ ( payment_preimage, payment_hash, payment_secret)
909+ } ;
910+
911+ let route_hints_no_specified_amount = vec ! [
912+ nodes[ 1 ] . node. get_phantom_route_hints( ) ,
913+ nodes[ 2 ] . node. get_phantom_route_hints( ) ,
914+ ] ;
915+
916+ let invoice_no_specified_amount = :: utils:: create_phantom_invoice :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( None , "test" . to_string ( ) , payment_hash_no_specified_amount, payment_secret_no_specified_amount, route_hints_no_specified_amount, & nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
917+
918+ let hints_no_specified_amount = invoice_no_specified_amount. private_routes ( ) ;
919+ assert_eq ! ( hints_no_specified_amount. len( ) , 2 ) ;
920+
921+ let mut short_chan_ids_no_specified_amount = HashSet :: new ( ) ;
922+ short_chan_ids_no_specified_amount. insert ( chan_0_1. 0 . contents . short_channel_id . clone ( ) ) ;
923+ short_chan_ids_no_specified_amount. insert ( chan_0_2. 0 . contents . short_channel_id . clone ( ) ) ;
924+ for hint in hints_no_specified_amount {
925+ let hint_short_chan_id = hint. 0 . 0 [ 0 ] . short_channel_id ;
926+ assert ! ( short_chan_ids_no_specified_amount. contains( & hint_short_chan_id) ) ;
927+ short_chan_ids_no_specified_amount. remove ( & hint_short_chan_id) ;
928+ }
929+ }
740930}
0 commit comments