Skip to content

Commit ded3373

Browse files
Respect route hint max_htlc in pathfinding
1 parent 88821cb commit ded3373

File tree

3 files changed

+66
-3
lines changed

3 files changed

+66
-3
lines changed

lightning/src/routing/gossip.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,11 @@ pub enum EffectiveCapacity {
10331033
/// A capacity sufficient to route any payment, typically used for private channels provided by
10341034
/// an invoice.
10351035
Infinite,
1036+
/// The maximum HTLC amount as provided by an invoice route hint.
1037+
HintMaxHTLC {
1038+
/// The maximum HTLC amount denominated in millisatoshi.
1039+
amount_msat: u64,
1040+
},
10361041
/// A capacity that is unknown possibly because either the chain state is unavailable to know
10371042
/// the total capacity or the `htlc_maximum_msat` was not advertised on the gossip network.
10381043
Unknown,
@@ -1049,6 +1054,7 @@ impl EffectiveCapacity {
10491054
EffectiveCapacity::ExactLiquidity { liquidity_msat } => *liquidity_msat,
10501055
EffectiveCapacity::AdvertisedMaxHTLC { amount_msat } => *amount_msat,
10511056
EffectiveCapacity::Total { capacity_msat, .. } => *capacity_msat,
1057+
EffectiveCapacity::HintMaxHTLC { amount_msat } => *amount_msat,
10521058
EffectiveCapacity::Infinite => u64::max_value(),
10531059
EffectiveCapacity::Unknown => UNKNOWN_CHANNEL_CAPACITY_MSAT,
10541060
}

lightning/src/routing/router.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -951,7 +951,10 @@ impl<'a> CandidateRouteHop<'a> {
951951
liquidity_msat: details.next_outbound_htlc_limit_msat,
952952
},
953953
CandidateRouteHop::PublicHop { info, .. } => info.effective_capacity(),
954-
CandidateRouteHop::PrivateHop { .. } => EffectiveCapacity::Infinite,
954+
CandidateRouteHop::PrivateHop { hint } => {
955+
hint.htlc_maximum_msat.map_or(EffectiveCapacity::Infinite,
956+
|max| EffectiveCapacity::HintMaxHTLC { amount_msat: max })
957+
},
955958
}
956959
}
957960
}
@@ -965,6 +968,7 @@ fn max_htlc_from_capacity(capacity: EffectiveCapacity, max_channel_saturation_po
965968
EffectiveCapacity::Unknown => EffectiveCapacity::Unknown.as_msat(),
966969
EffectiveCapacity::AdvertisedMaxHTLC { amount_msat } =>
967970
amount_msat.checked_shr(saturation_shift).unwrap_or(0),
971+
EffectiveCapacity::HintMaxHTLC { amount_msat } => amount_msat,
968972
EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat } =>
969973
cmp::min(capacity_msat.checked_shr(saturation_shift).unwrap_or(0), htlc_maximum_msat),
970974
}
@@ -6050,6 +6054,57 @@ mod tests {
60506054
assert_eq!(route.paths[0].blinded_tail.as_ref().unwrap().excess_final_cltv_expiry_delta, 40);
60516055
assert_eq!(route.paths[0].hops.last().unwrap().cltv_expiry_delta, 40);
60526056
}
6057+
6058+
#[test]
6059+
fn respect_route_hint_max_htlc() {
6060+
// Make sure that any max_htlc provided in the route hints of the payment params is respected in
6061+
// the final route.
6062+
let (secp_ctx, network_graph, _, _, logger) = build_graph();
6063+
let netgraph = network_graph.read_only();
6064+
let (_, our_id, _, nodes) = get_nodes(&secp_ctx);
6065+
let scorer = ln_test_utils::TestScorer::new();
6066+
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
6067+
let random_seed_bytes = keys_manager.get_secure_random_bytes();
6068+
let config = UserConfig::default();
6069+
6070+
let max_htlc_msat = 50_000;
6071+
let route_hint_1 = RouteHint(vec![RouteHintHop {
6072+
src_node_id: nodes[2],
6073+
short_channel_id: 42,
6074+
fees: RoutingFees {
6075+
base_msat: 100,
6076+
proportional_millionths: 0,
6077+
},
6078+
cltv_expiry_delta: 10,
6079+
htlc_minimum_msat: None,
6080+
htlc_maximum_msat: Some(max_htlc_msat),
6081+
}]);
6082+
let dest_node_id = ln_test_utils::pubkey(42);
6083+
let payment_params = PaymentParameters::from_node_id(dest_node_id, 42)
6084+
.with_route_hints(vec![route_hint_1.clone()]).unwrap()
6085+
.with_bolt11_features(channelmanager::provided_invoice_features(&config)).unwrap();
6086+
6087+
// Make sure we'll error if our route hints don't have enough liquidity according to their
6088+
// max_htlc.
6089+
if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id,
6090+
&payment_params, &netgraph, None, max_htlc_msat + 1, Arc::clone(&logger), &scorer, &(),
6091+
&random_seed_bytes)
6092+
{
6093+
assert_eq!(err, "Failed to find a sufficient route to the given destination");
6094+
} else { panic!(); }
6095+
6096+
// Make sure we'll split an MPP payment across route hints if their max_htlcs warrant it.
6097+
let mut route_hint_2 = route_hint_1.clone();
6098+
route_hint_2.0[0].short_channel_id = 43;
6099+
let payment_params = PaymentParameters::from_node_id(dest_node_id, 42)
6100+
.with_route_hints(vec![route_hint_1, route_hint_2]).unwrap()
6101+
.with_bolt11_features(channelmanager::provided_invoice_features(&config)).unwrap();
6102+
let route = get_route(&our_id, &payment_params, &netgraph, None, max_htlc_msat + 1,
6103+
Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
6104+
assert_eq!(route.paths.len(), 2);
6105+
assert!(route.paths[0].hops.last().unwrap().fee_msat <= max_htlc_msat);
6106+
assert!(route.paths[1].hops.last().unwrap().fee_msat <= max_htlc_msat);
6107+
}
60536108
}
60546109

60556110
#[cfg(all(test, not(feature = "no-std")))]

lightning/src/routing/scoring.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,8 +1243,10 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
12431243

12441244
let mut anti_probing_penalty_msat = 0;
12451245
match usage.effective_capacity {
1246-
EffectiveCapacity::ExactLiquidity { liquidity_msat } => {
1247-
if usage.amount_msat > liquidity_msat {
1246+
EffectiveCapacity::ExactLiquidity { liquidity_msat: amount_msat } |
1247+
EffectiveCapacity::HintMaxHTLC { amount_msat } =>
1248+
{
1249+
if usage.amount_msat > amount_msat {
12481250
return u64::max_value();
12491251
} else {
12501252
return base_penalty_msat;

0 commit comments

Comments
 (0)