@@ -513,6 +513,7 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
513513 // $directional_info.
514514 // $next_hops_fee_msat represents the fees paid for using all the channel *after* this one,
515515 // since that value has to be transferred over this channel.
516+ // Returns whether this channel caused an update to `targets`.
516517 ( $chan_id: expr, $src_node_id: expr, $dest_node_id: expr, $directional_info: expr, $capacity_sats: expr, $chan_features: expr, $next_hops_fee_msat: expr,
517518 $next_hops_value_contribution: expr, $next_hops_path_htlc_minimum_msat: expr ) => {
518519 // Channels to self should not be used. This is more of belt-and-suspenders, because in
@@ -592,6 +593,7 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
592593 // as not sufficient.
593594 if !over_path_minimum_msat {
594595 hit_minimum_limit = true ;
596+ false
595597 } else if contributes_sufficient_value {
596598 // Note that low contribution here (limited by available_liquidity_msat)
597599 // might violate htlc_minimum_msat on the hops which are next along the
@@ -726,6 +728,7 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
726728 {
727729 old_entry. value_contribution_msat = value_contribution_msat;
728730 }
731+ true
729732 } else if old_entry. was_processed && new_cost < old_cost {
730733 #[ cfg( any( test, feature = "fuzztarget" ) ) ]
731734 {
@@ -751,11 +754,12 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
751754 debug_assert!( path_htlc_minimum_msat < old_entry. path_htlc_minimum_msat) ;
752755 debug_assert!( value_contribution_msat < old_entry. value_contribution_msat) ;
753756 }
754- }
755- }
756- }
757- }
758- }
757+ false
758+ } else { false }
759+ } else { false }
760+ } else { false }
761+ } else { false }
762+ } else { false }
759763 } ;
760764 }
761765
@@ -859,22 +863,10 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
859863 // it matters only if the fees are exactly the same.
860864 for hop in last_hops. iter ( ) {
861865 let have_hop_src_in_graph =
862- if let Some ( & ( ref first_hop, ref features, ref outbound_capacity_msat, _) ) = first_hop_targets. get ( & hop. src_node_id ) {
863- // If this hop connects to a node with which we have a direct channel, ignore
864- // the network graph and add both the hop and our direct channel to
865- // the candidate set.
866- //
867- // Currently there are no channel-context features defined, so we are a
868- // bit lazy here. In the future, we should pull them out via our
869- // ChannelManager, but there's no reason to waste the space until we
870- // need them.
871- add_entry ! ( first_hop, * our_node_id , hop. src_node_id, dummy_directional_info, Some ( outbound_capacity_msat / 1000 ) , features, 0 , path_value_msat, 0 ) ;
872- true
873- } else {
874- // In any other case, only add the hop if the source is in the regular network
875- // graph:
876- network. get_nodes ( ) . get ( & hop. src_node_id ) . is_some ( )
877- } ;
866+ // Only add the last hop to our candidate set if either we have a direct channel or
867+ // they are in the regular network graph.
868+ first_hop_targets. get ( & hop. src_node_id ) . is_some ( ) ||
869+ network. get_nodes ( ) . get ( & hop. src_node_id ) . is_some ( ) ;
878870 if have_hop_src_in_graph {
879871 // BOLT 11 doesn't allow inclusion of features for the last hop hints, which
880872 // really sucks, cause we're gonna need that eventually.
@@ -888,7 +880,23 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
888880 htlc_maximum_msat : hop. htlc_maximum_msat ,
889881 fees : hop. fees ,
890882 } ;
891- add_entry ! ( hop. short_channel_id, hop. src_node_id, payee, directional_info, None :: <u64 >, & empty_channel_features, 0 , path_value_msat, 0 ) ;
883+ if add_entry ! ( hop. short_channel_id, hop. src_node_id, payee, directional_info, None :: <u64 >, & empty_channel_features, 0 , path_value_msat, 0 ) {
884+ if let Some ( & ( ref first_hop, ref features, ref outbound_capacity_msat, _) ) = first_hop_targets. get ( & hop. src_node_id ) {
885+ // If this hop connects to a node with which we have a direct channel,
886+ // ignore the network graph and, if the last hop was added, add our
887+ // direct channel to the candidate set.
888+ //
889+ // Note that we *must* check if the last hop was added as `add_entry`
890+ // always assumes that the third argument is a node to which we have a
891+ // path.
892+ //
893+ // Currently there are no channel-context features defined, so we are a
894+ // bit lazy here. In the future, we should pull them out via our
895+ // ChannelManager, but there's no reason to waste the space until we
896+ // need them.
897+ add_entry ! ( first_hop, * our_node_id , hop. src_node_id, dummy_directional_info, Some ( outbound_capacity_msat / 1000 ) , features, 0 , path_value_msat, 0 ) ;
898+ }
899+ }
892900 }
893901 }
894902
@@ -1159,7 +1167,7 @@ pub fn get_route<L: Deref>(our_node_id: &PublicKey, network: &NetworkGraph, paye
11591167
11601168#[ cfg( test) ]
11611169mod tests {
1162- use routing:: router:: { get_route, RouteHint , RouteHintHop , RoutingFees } ;
1170+ use routing:: router:: { get_route, Route , RouteHint , RouteHintHop , RoutingFees } ;
11631171 use routing:: network_graph:: { NetworkGraph , NetGraphMsgHandler } ;
11641172 use chain:: transaction:: OutPoint ;
11651173 use ln:: features:: { ChannelFeatures , InitFeatures , InvoiceFeatures , NodeFeatures } ;
@@ -2307,11 +2315,7 @@ mod tests {
23072315 assert_eq ! ( route. paths[ 0 ] [ 4 ] . channel_features. le_flags( ) , & Vec :: <u8 >:: new( ) ) ; // We can't learn any flags from invoices, sadly
23082316 }
23092317
2310- #[ test]
2311- fn unannounced_path_test ( ) {
2312- // We should be able to send a payment to a destination without any help of a routing graph
2313- // if we have a channel with a common counterparty that appears in the first and last hop
2314- // hints.
2318+ fn do_unannounced_path_test ( last_hop_htlc_max : Option < u64 > , last_hop_fee_prop : u32 , outbound_capacity_msat : u64 , route_val : u64 ) -> Result < Route , LightningError > {
23152319 let source_node_id = PublicKey :: from_secret_key ( & Secp256k1 :: new ( ) , & SecretKey :: from_slice ( & hex:: decode ( format ! ( "{:02}" , 41 ) . repeat ( 32 ) ) . unwrap ( ) [ ..] ) . unwrap ( ) ) ;
23162320 let middle_node_id = PublicKey :: from_secret_key ( & Secp256k1 :: new ( ) , & SecretKey :: from_slice ( & hex:: decode ( format ! ( "{:02}" , 42 ) . repeat ( 32 ) ) . unwrap ( ) [ ..] ) . unwrap ( ) ) ;
23172321 let target_node_id = PublicKey :: from_secret_key ( & Secp256k1 :: new ( ) , & SecretKey :: from_slice ( & hex:: decode ( format ! ( "{:02}" , 43 ) . repeat ( 32 ) ) . unwrap ( ) [ ..] ) . unwrap ( ) ) ;
@@ -2322,11 +2326,11 @@ mod tests {
23222326 short_channel_id: 8 ,
23232327 fees: RoutingFees {
23242328 base_msat: 1000 ,
2325- proportional_millionths: 0 ,
2329+ proportional_millionths: last_hop_fee_prop ,
23262330 } ,
23272331 cltv_expiry_delta: ( 8 << 8 ) | 1 ,
23282332 htlc_minimum_msat: None ,
2329- htlc_maximum_msat: None ,
2333+ htlc_maximum_msat: last_hop_htlc_max ,
23302334 } ] ) ;
23312335 let our_chans = vec ! [ channelmanager:: ChannelDetails {
23322336 channel_id: [ 0 ; 32 ] ,
@@ -2336,31 +2340,57 @@ mod tests {
23362340 counterparty_features: InitFeatures :: from_le_bytes( vec![ 0b11 ] ) ,
23372341 channel_value_satoshis: 100000 ,
23382342 user_id: 0 ,
2339- outbound_capacity_msat: 100000 ,
2343+ outbound_capacity_msat: outbound_capacity_msat ,
23402344 inbound_capacity_msat: 100000 ,
23412345 is_outbound: true , is_funding_locked: true ,
23422346 is_usable: true , is_public: true ,
23432347 counterparty_forwarding_info: None ,
23442348 } ] ;
2345- let route = get_route ( & source_node_id, & NetworkGraph :: new ( genesis_block ( Network :: Testnet ) . header . block_hash ( ) ) , & target_node_id, None , Some ( & our_chans. iter ( ) . collect :: < Vec < _ > > ( ) ) , & vec ! [ & last_hops] , 100 , 42 , Arc :: new ( test_utils:: TestLogger :: new ( ) ) ) . unwrap ( ) ;
2349+ get_route ( & source_node_id, & NetworkGraph :: new ( genesis_block ( Network :: Testnet ) . header . block_hash ( ) ) , & target_node_id, None , Some ( & our_chans. iter ( ) . collect :: < Vec < _ > > ( ) ) , & vec ! [ & last_hops] , route_val, 42 , Arc :: new ( test_utils:: TestLogger :: new ( ) ) )
2350+ }
2351+ #[ test]
2352+ fn unannounced_path_test ( ) {
2353+ // We should be able to send a payment to a destination without any help of a routing graph
2354+ // if we have a channel with a common counterparty that appears in the first and last hop
2355+ // hints.
2356+ let route = do_unannounced_path_test ( None , 1 , 2000000 , 1000000 ) . unwrap ( ) ;
23462357
2358+ let middle_node_id = PublicKey :: from_secret_key ( & Secp256k1 :: new ( ) , & SecretKey :: from_slice ( & hex:: decode ( format ! ( "{:02}" , 42 ) . repeat ( 32 ) ) . unwrap ( ) [ ..] ) . unwrap ( ) ) ;
2359+ let target_node_id = PublicKey :: from_secret_key ( & Secp256k1 :: new ( ) , & SecretKey :: from_slice ( & hex:: decode ( format ! ( "{:02}" , 43 ) . repeat ( 32 ) ) . unwrap ( ) [ ..] ) . unwrap ( ) ) ;
23472360 assert_eq ! ( route. paths[ 0 ] . len( ) , 2 ) ;
23482361
23492362 assert_eq ! ( route. paths[ 0 ] [ 0 ] . pubkey, middle_node_id) ;
23502363 assert_eq ! ( route. paths[ 0 ] [ 0 ] . short_channel_id, 42 ) ;
2351- assert_eq ! ( route. paths[ 0 ] [ 0 ] . fee_msat, 1000 ) ;
2364+ assert_eq ! ( route. paths[ 0 ] [ 0 ] . fee_msat, 1001 ) ;
23522365 assert_eq ! ( route. paths[ 0 ] [ 0 ] . cltv_expiry_delta, ( 8 << 8 ) | 1 ) ;
23532366 assert_eq ! ( route. paths[ 0 ] [ 0 ] . node_features. le_flags( ) , & [ 0b11 ] ) ;
23542367 assert_eq ! ( route. paths[ 0 ] [ 0 ] . channel_features. le_flags( ) , & [ 0 ; 0 ] ) ; // We can't learn any flags from invoices, sadly
23552368
23562369 assert_eq ! ( route. paths[ 0 ] [ 1 ] . pubkey, target_node_id) ;
23572370 assert_eq ! ( route. paths[ 0 ] [ 1 ] . short_channel_id, 8 ) ;
2358- assert_eq ! ( route. paths[ 0 ] [ 1 ] . fee_msat, 100 ) ;
2371+ assert_eq ! ( route. paths[ 0 ] [ 1 ] . fee_msat, 1000000 ) ;
23592372 assert_eq ! ( route. paths[ 0 ] [ 1 ] . cltv_expiry_delta, 42 ) ;
23602373 assert_eq ! ( route. paths[ 0 ] [ 1 ] . node_features. le_flags( ) , & [ 0 ; 0 ] ) ; // We dont pass flags in from invoices yet
23612374 assert_eq ! ( route. paths[ 0 ] [ 1 ] . channel_features. le_flags( ) , & [ 0 ; 0 ] ) ; // We can't learn any flags from invoices, sadly
2375+
2376+ }
2377+
2378+ #[ test]
2379+ fn overflow_unannounced_path_test_a ( ) {
2380+ // Previously, when we had a last-hop hint connected directly to a first-hop channel, where
2381+ // the last-hop had a value-overflowing fee, we'd panic.
2382+ // This was due to us adding the first-hop from us unconditionally, causing us to think
2383+ // we'd built a path (as our node is in the "best candidate" set), when we had not.
2384+ assert ! ( do_unannounced_path_test( Some ( 21_000_000_0000_0000_000 ) , 0 , 21_000_000_0000_0000_000 , 21_000_000_0000_0000_000 ) . is_err( ) ) ;
23622385 }
23632386
2387+ #[ test]
2388+ fn overflow_unannounced_path_test_b ( ) {
2389+ // This tests for the same case as above, but with a slightly different codepath.
2390+ assert ! ( do_unannounced_path_test( Some ( 21_000_000_0000_0000_000 ) , 50000 , 21_000_000_0000_0000_000 , 21_000_000_0000_0000_000 ) . is_err( ) ) ;
2391+ }
2392+
2393+
23642394 #[ test]
23652395 fn available_amount_while_routing_test ( ) {
23662396 // Tests whether we choose the correct available channel amount while routing.
0 commit comments