@@ -1143,31 +1143,32 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
11431143 . get ( & hop. short_channel_id )
11441144 . and_then ( |channel| channel. as_directed_to ( & target) ) ;
11451145
1146- if hop. short_channel_id == short_channel_id && hop_idx == 0 {
1146+ let at_failed_channel = hop. short_channel_id == short_channel_id;
1147+ if at_failed_channel && hop_idx == 0 {
11471148 log_warn ! ( self . logger, "Payment failed at the first hop - we do not attempt to learn channel info in such cases as we can directly observe local state.\n \t Because we know the local state, we should generally not see failures here - this may be an indication that your channel peer on channel {} is broken and you may wish to close the channel." , hop. short_channel_id) ;
11481149 }
11491150
11501151 // Only score announced channels.
11511152 if let Some ( ( channel, source) ) = channel_directed_from_source {
11521153 let capacity_msat = channel. effective_capacity ( ) . as_msat ( ) ;
1153- if hop . short_channel_id == short_channel_id {
1154+ if at_failed_channel {
11541155 self . channel_liquidities
11551156 . entry ( hop. short_channel_id )
11561157 . or_insert_with ( ChannelLiquidity :: new)
11571158 . as_directed_mut ( source, & target, capacity_msat, & self . params )
11581159 . failed_at_channel ( amount_msat, format_args ! ( "SCID {}, towards {:?}" , hop. short_channel_id, target) , & self . logger ) ;
1159- break ;
1160+ } else {
1161+ self . channel_liquidities
1162+ . entry ( hop. short_channel_id )
1163+ . or_insert_with ( ChannelLiquidity :: new)
1164+ . as_directed_mut ( source, & target, capacity_msat, & self . params )
1165+ . failed_downstream ( amount_msat, format_args ! ( "SCID {}, towards {:?}" , hop. short_channel_id, target) , & self . logger ) ;
11601166 }
1161-
1162- self . channel_liquidities
1163- . entry ( hop. short_channel_id )
1164- . or_insert_with ( ChannelLiquidity :: new)
1165- . as_directed_mut ( source, & target, capacity_msat, & self . params )
1166- . failed_downstream ( amount_msat, format_args ! ( "SCID {}, towards {:?}" , hop. short_channel_id, target) , & self . logger ) ;
11671167 } else {
11681168 log_debug ! ( self . logger, "Not able to penalize channel with SCID {} as we do not have graph info for it (likely a route-hint last-hop)." ,
11691169 hop. short_channel_id) ;
11701170 }
1171+ if at_failed_channel { break ; }
11711172 }
11721173 }
11731174
@@ -1745,32 +1746,22 @@ mod tests {
17451746 network_graph. update_channel ( & signed_update) . unwrap ( ) ;
17461747 }
17471748
1749+ fn path_hop ( pubkey : PublicKey , short_channel_id : u64 , fee_msat : u64 ) -> RouteHop {
1750+ RouteHop {
1751+ pubkey,
1752+ node_features : channelmanager:: provided_node_features ( ) ,
1753+ short_channel_id,
1754+ channel_features : channelmanager:: provided_channel_features ( ) ,
1755+ fee_msat,
1756+ cltv_expiry_delta : 18 ,
1757+ }
1758+ }
1759+
17481760 fn payment_path_for_amount ( amount_msat : u64 ) -> Vec < RouteHop > {
17491761 vec ! [
1750- RouteHop {
1751- pubkey: source_pubkey( ) ,
1752- node_features: channelmanager:: provided_node_features( ) ,
1753- short_channel_id: 41 ,
1754- channel_features: channelmanager:: provided_channel_features( ) ,
1755- fee_msat: 1 ,
1756- cltv_expiry_delta: 18 ,
1757- } ,
1758- RouteHop {
1759- pubkey: target_pubkey( ) ,
1760- node_features: channelmanager:: provided_node_features( ) ,
1761- short_channel_id: 42 ,
1762- channel_features: channelmanager:: provided_channel_features( ) ,
1763- fee_msat: 2 ,
1764- cltv_expiry_delta: 18 ,
1765- } ,
1766- RouteHop {
1767- pubkey: recipient_pubkey( ) ,
1768- node_features: channelmanager:: provided_node_features( ) ,
1769- short_channel_id: 43 ,
1770- channel_features: channelmanager:: provided_channel_features( ) ,
1771- fee_msat: amount_msat,
1772- cltv_expiry_delta: 18 ,
1773- } ,
1762+ path_hop( source_pubkey( ) , 41 , 1 ) ,
1763+ path_hop( target_pubkey( ) , 42 , 2 ) ,
1764+ path_hop( recipient_pubkey( ) , 43 , amount_msat) ,
17741765 ]
17751766 }
17761767
@@ -2145,6 +2136,65 @@ mod tests {
21452136 assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , u64 :: max_value( ) ) ;
21462137 }
21472138
2139+ #[ test]
2140+ fn ignores_channels_after_removed_failed_channel ( ) {
2141+ // Previously, if we'd tried to send over a channel which was removed from the network
2142+ // graph before we call `payment_path_failed` (which is the default if the we get a "no
2143+ // such channel" error in the `InvoicePayer`), we would call `failed_downstream` on all
2144+ // channels in the route, even ones which they payment never reached. This tests to ensure
2145+ // we do not score such channels.
2146+ let secp_ctx = Secp256k1 :: new ( ) ;
2147+ let logger = TestLogger :: new ( ) ;
2148+ let genesis_hash = genesis_block ( Network :: Testnet ) . header . block_hash ( ) ;
2149+ let mut network_graph = NetworkGraph :: new ( genesis_hash, & logger) ;
2150+ let secret_a = SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) ;
2151+ let secret_b = SecretKey :: from_slice ( & [ 43 ; 32 ] ) . unwrap ( ) ;
2152+ let secret_c = SecretKey :: from_slice ( & [ 44 ; 32 ] ) . unwrap ( ) ;
2153+ let secret_d = SecretKey :: from_slice ( & [ 45 ; 32 ] ) . unwrap ( ) ;
2154+ add_channel ( & mut network_graph, 42 , secret_a, secret_b) ;
2155+ // Don't add the channel from B -> C.
2156+ add_channel ( & mut network_graph, 44 , secret_c, secret_d) ;
2157+
2158+ let pub_a = PublicKey :: from_secret_key ( & secp_ctx, & secret_a) ;
2159+ let pub_b = PublicKey :: from_secret_key ( & secp_ctx, & secret_b) ;
2160+ let pub_c = PublicKey :: from_secret_key ( & secp_ctx, & secret_c) ;
2161+ let pub_d = PublicKey :: from_secret_key ( & secp_ctx, & secret_d) ;
2162+
2163+ let path = vec ! [
2164+ path_hop( pub_b, 42 , 1 ) ,
2165+ path_hop( pub_c, 43 , 2 ) ,
2166+ path_hop( pub_d, 44 , 100 ) ,
2167+ ] ;
2168+
2169+ let node_a = NodeId :: from_pubkey ( & pub_a) ;
2170+ let node_b = NodeId :: from_pubkey ( & pub_b) ;
2171+ let node_c = NodeId :: from_pubkey ( & pub_c) ;
2172+ let node_d = NodeId :: from_pubkey ( & pub_d) ;
2173+
2174+ let params = ProbabilisticScoringParameters {
2175+ liquidity_penalty_multiplier_msat : 1_000 ,
2176+ ..ProbabilisticScoringParameters :: zero_penalty ( )
2177+ } ;
2178+ let mut scorer = ProbabilisticScorer :: new ( params, & network_graph, & logger) ;
2179+
2180+ let usage = ChannelUsage {
2181+ amount_msat : 250 ,
2182+ inflight_htlc_msat : 0 ,
2183+ effective_capacity : EffectiveCapacity :: Total { capacity_msat : 1_000 , htlc_maximum_msat : 1_000 } ,
2184+ } ;
2185+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & node_a, & node_b, usage) , 128 ) ;
2186+ // Note that a default liquidity bound is used for B -> C as no channel exists
2187+ assert_eq ! ( scorer. channel_penalty_msat( 43 , & node_b, & node_c, usage) , 128 ) ;
2188+ assert_eq ! ( scorer. channel_penalty_msat( 44 , & node_c, & node_d, usage) , 128 ) ;
2189+
2190+ scorer. payment_path_failed ( & path. iter ( ) . collect :: < Vec < _ > > ( ) , 43 ) ;
2191+
2192+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & node_a, & node_b, usage) , 80 ) ;
2193+ // Note that a default liquidity bound is used for B -> C as no channel exists
2194+ assert_eq ! ( scorer. channel_penalty_msat( 43 , & node_b, & node_c, usage) , 128 ) ;
2195+ assert_eq ! ( scorer. channel_penalty_msat( 44 , & node_c, & node_d, usage) , 128 ) ;
2196+ }
2197+
21482198 #[ test]
21492199 fn reduces_liquidity_upper_bound_along_path_on_success ( ) {
21502200 let logger = TestLogger :: new ( ) ;
0 commit comments