@@ -1143,31 +1143,32 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
1143
1143
. get ( & hop. short_channel_id )
1144
1144
. and_then ( |channel| channel. as_directed_to ( & target) ) ;
1145
1145
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 {
1147
1148
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) ;
1148
1149
}
1149
1150
1150
1151
// Only score announced channels.
1151
1152
if let Some ( ( channel, source) ) = channel_directed_from_source {
1152
1153
let capacity_msat = channel. effective_capacity ( ) . as_msat ( ) ;
1153
- if hop . short_channel_id == short_channel_id {
1154
+ if at_failed_channel {
1154
1155
self . channel_liquidities
1155
1156
. entry ( hop. short_channel_id )
1156
1157
. or_insert_with ( ChannelLiquidity :: new)
1157
1158
. as_directed_mut ( source, & target, capacity_msat, & self . params )
1158
1159
. 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 ) ;
1160
1166
}
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 ) ;
1167
1167
} else {
1168
1168
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)." ,
1169
1169
hop. short_channel_id) ;
1170
1170
}
1171
+ if at_failed_channel { break ; }
1171
1172
}
1172
1173
}
1173
1174
@@ -1745,32 +1746,22 @@ mod tests {
1745
1746
network_graph. update_channel ( & signed_update) . unwrap ( ) ;
1746
1747
}
1747
1748
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
+
1748
1760
fn payment_path_for_amount ( amount_msat : u64 ) -> Vec < RouteHop > {
1749
1761
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) ,
1774
1765
]
1775
1766
}
1776
1767
@@ -2145,6 +2136,65 @@ mod tests {
2145
2136
assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target, usage) , u64 :: max_value( ) ) ;
2146
2137
}
2147
2138
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
+
2148
2198
#[ test]
2149
2199
fn reduces_liquidity_upper_bound_along_path_on_success ( ) {
2150
2200
let logger = TestLogger :: new ( ) ;
0 commit comments