Skip to content

Commit d15b7cb

Browse files
authored
Merge pull request #1817 from TheBlueMatt/2022-10-removed-no-score-after
2 parents 3ba91ce + 00607a5 commit d15b7cb

File tree

1 file changed

+83
-33
lines changed

1 file changed

+83
-33
lines changed

lightning/src/routing/scoring.rs

+83-33
Original file line numberDiff line numberDiff line change
@@ -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\tBecause 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

Comments
 (0)