Skip to content

Commit f6fa8e9

Browse files
authored
Merge pull request #1370 from TheBlueMatt/2022-03-pref-first-hop-chans
Avoid needless MPP on multiple channels to the same first-hop
2 parents fcfd683 + b1bc078 commit f6fa8e9

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed

lightning/src/routing/router.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,29 @@ where L::Target: Logger {
811811
// - when we want to stop looking for new paths.
812812
let mut already_collected_value_msat = 0;
813813

814+
for (_, channels) in first_hop_targets.iter_mut() {
815+
// Sort the first_hops channels to the same node(s) in priority order of which channel we'd
816+
// most like to use.
817+
//
818+
// First, if channels are below `recommended_value_msat`, sort them in descending order,
819+
// preferring larger channels to avoid splitting the payment into more MPP parts than is
820+
// required.
821+
//
822+
// Second, because simply always sorting in descending order would always use our largest
823+
// available outbound capacity, needlessly fragmenting our available channel capacities,
824+
// sort channels above `recommended_value_msat` in ascending order, preferring channels
825+
// which have enough, but not too much, capacity for the payment.
826+
channels.sort_unstable_by(|chan_a, chan_b| {
827+
if chan_b.outbound_capacity_msat < recommended_value_msat || chan_a.outbound_capacity_msat < recommended_value_msat {
828+
// Sort in descending order
829+
chan_b.outbound_capacity_msat.cmp(&chan_a.outbound_capacity_msat)
830+
} else {
831+
// Sort in ascending order
832+
chan_a.outbound_capacity_msat.cmp(&chan_b.outbound_capacity_msat)
833+
}
834+
});
835+
}
836+
814837
log_trace!(logger, "Building path from {} (payee) to {} (us/payer) for value {} msat.", payment_params.payee_pubkey, our_node_pubkey, final_value_msat);
815838

816839
macro_rules! add_entry {
@@ -4907,6 +4930,32 @@ mod tests {
49074930
assert_eq!(route.paths[1][0].short_channel_id, 2);
49084931
assert_eq!(route.paths[1][0].fee_msat, 50_000);
49094932
}
4933+
4934+
{
4935+
// If we have a bunch of outbound channels to the same node, where most are not
4936+
// sufficient to pay the full payment, but one is, we should default to just using the
4937+
// one single channel that has sufficient balance, avoiding MPP.
4938+
//
4939+
// If we have several options above the 3xpayment value threshold, we should pick the
4940+
// smallest of them, avoiding further fragmenting our available outbound balance to
4941+
// this node.
4942+
let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&[
4943+
&get_channel_details(Some(2), nodes[0], InitFeatures::known(), 50_000),
4944+
&get_channel_details(Some(3), nodes[0], InitFeatures::known(), 50_000),
4945+
&get_channel_details(Some(5), nodes[0], InitFeatures::known(), 50_000),
4946+
&get_channel_details(Some(6), nodes[0], InitFeatures::known(), 300_000),
4947+
&get_channel_details(Some(7), nodes[0], InitFeatures::known(), 50_000),
4948+
&get_channel_details(Some(8), nodes[0], InitFeatures::known(), 50_000),
4949+
&get_channel_details(Some(9), nodes[0], InitFeatures::known(), 50_000),
4950+
&get_channel_details(Some(4), nodes[0], InitFeatures::known(), 1_000_000),
4951+
]), 100_000, 42, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
4952+
assert_eq!(route.paths.len(), 1);
4953+
assert_eq!(route.paths[0].len(), 1);
4954+
4955+
assert_eq!(route.paths[0][0].pubkey, nodes[0]);
4956+
assert_eq!(route.paths[0][0].short_channel_id, 6);
4957+
assert_eq!(route.paths[0][0].fee_msat, 100_000);
4958+
}
49104959
}
49114960

49124961
#[test]

0 commit comments

Comments
 (0)