Skip to content

Commit ffe2a3d

Browse files
author
Elias Rohrer
committed
Limit total CLTV delta.
1 parent e4365a9 commit ffe2a3d

File tree

1 file changed

+27
-13
lines changed

1 file changed

+27
-13
lines changed

lightning/src/routing/router.rs

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ struct RouteGraphNode {
296296
node_id: NodeId,
297297
lowest_fee_to_peer_through_node: u64,
298298
lowest_fee_to_node: u64,
299+
total_cltv_delta: u32,
299300
// The maximum value a yet-to-be-constructed payment path might flow through this node.
300301
// This value is upper-bounded by us by:
301302
// - how much is needed for a path being constructed
@@ -722,7 +723,7 @@ where L::Target: Logger {
722723
// since that value has to be transferred over this channel.
723724
// Returns whether this channel caused an update to `targets`.
724725
( $chan_id: expr, $src_node_id: expr, $dest_node_id: expr, $directional_info: expr, $capacity_sats: expr, $chan_features: expr, $next_hops_fee_msat: expr,
725-
$next_hops_value_contribution: expr, $next_hops_path_htlc_minimum_msat: expr, $next_hops_path_penalty_msat: expr ) => { {
726+
$next_hops_value_contribution: expr, $next_hops_path_htlc_minimum_msat: expr, $next_hops_path_penalty_msat: expr, $next_hops_cltv_delta: expr ) => { {
726727
// We "return" whether we updated the path at the end, via this:
727728
let mut did_add_update_path_to_src_node = false;
728729
// Channels to self should not be used. This is more of belt-and-suspenders, because in
@@ -784,6 +785,13 @@ where L::Target: Logger {
784785
// Verify the liquidity offered by this channel complies to the minimal contribution.
785786
let contributes_sufficient_value = available_value_contribution_msat >= minimal_value_contribution_msat;
786787

788+
789+
// Do not consider candidates that exceed the MAX_TOTAL_CLTV_DELTA limit.
790+
const MAX_TOTAL_CLTV_DELTA: u32 = 1000;
791+
let hop_total_cltv_delta = $next_hops_cltv_delta + $directional_info.cltv_expiry_delta as u32;
792+
let doesnt_exceed_cltv_delta_limit = hop_total_cltv_delta <= MAX_TOTAL_CLTV_DELTA;
793+
log_trace!(logger, "Checking total CLTV delta: {} / {}. doesnt_exceed_cltv_delta_limit: {}", hop_total_cltv_delta, MAX_TOTAL_CLTV_DELTA, doesnt_exceed_cltv_delta_limit);
794+
787795
let value_contribution_msat = cmp::min(available_value_contribution_msat, $next_hops_value_contribution);
788796
// Includes paying fees for the use of the following channels.
789797
let amount_to_transfer_over_msat: u64 = match value_contribution_msat.checked_add($next_hops_fee_msat) {
@@ -802,7 +810,7 @@ where L::Target: Logger {
802810
// as not sufficient.
803811
if !over_path_minimum_msat {
804812
hit_minimum_limit = true;
805-
} else if contributes_sufficient_value {
813+
} else if contributes_sufficient_value && doesnt_exceed_cltv_delta_limit {
806814
// Note that low contribution here (limited by available_liquidity_msat)
807815
// might violate htlc_minimum_msat on the hops which are next along the
808816
// payment path (upstream to the payee). To avoid that, we recompute
@@ -899,6 +907,7 @@ where L::Target: Logger {
899907
node_id: $src_node_id,
900908
lowest_fee_to_peer_through_node: total_fee_msat,
901909
lowest_fee_to_node: $next_hops_fee_msat as u64 + hop_use_fee_msat,
910+
total_cltv_delta: hop_total_cltv_delta,
902911
value_contribution_msat: value_contribution_msat,
903912
path_htlc_minimum_msat,
904913
path_penalty_msat,
@@ -990,7 +999,7 @@ where L::Target: Logger {
990999
// meaning how much will be paid in fees after this node (to the best of our knowledge).
9911000
// This data can later be helpful to optimize routing (pay lower fees).
9921001
macro_rules! add_entries_to_cheapest_to_target_node {
993-
( $node: expr, $node_id: expr, $fee_to_target_msat: expr, $next_hops_value_contribution: expr, $next_hops_path_htlc_minimum_msat: expr, $next_hops_path_penalty_msat: expr ) => {
1002+
( $node: expr, $node_id: expr, $fee_to_target_msat: expr, $next_hops_value_contribution: expr, $next_hops_path_htlc_minimum_msat: expr, $next_hops_path_penalty_msat: expr, $next_hops_cltv_delta: expr ) => {
9941003
let skip_node = if let Some(elem) = dist.get_mut(&$node_id) {
9951004
let was_processed = elem.was_processed;
9961005
elem.was_processed = true;
@@ -1006,7 +1015,7 @@ where L::Target: Logger {
10061015
if !skip_node {
10071016
if let Some(first_channels) = first_hop_targets.get(&$node_id) {
10081017
for (ref first_hop, ref features, ref outbound_capacity_msat, _) in first_channels {
1009-
add_entry!(first_hop, our_node_id, $node_id, dummy_directional_info, Some(outbound_capacity_msat / 1000), features, $fee_to_target_msat, $next_hops_value_contribution, $next_hops_path_htlc_minimum_msat, $next_hops_path_penalty_msat);
1018+
add_entry!(first_hop, our_node_id, $node_id, dummy_directional_info, Some(outbound_capacity_msat / 1000), features, $fee_to_target_msat, $next_hops_value_contribution, $next_hops_path_htlc_minimum_msat, $next_hops_path_penalty_msat, $next_hops_cltv_delta);
10101019
}
10111020
}
10121021

@@ -1025,15 +1034,15 @@ where L::Target: Logger {
10251034
if first_hops.is_none() || chan.node_two != our_node_id {
10261035
if let Some(two_to_one) = chan.two_to_one.as_ref() {
10271036
if two_to_one.enabled {
1028-
add_entry!(chan_id, chan.node_two, chan.node_one, two_to_one, chan.capacity_sats, &chan.features, $fee_to_target_msat, $next_hops_value_contribution, $next_hops_path_htlc_minimum_msat, $next_hops_path_penalty_msat);
1037+
add_entry!(chan_id, chan.node_two, chan.node_one, two_to_one, chan.capacity_sats, &chan.features, $fee_to_target_msat, $next_hops_value_contribution, $next_hops_path_htlc_minimum_msat, $next_hops_path_penalty_msat, $next_hops_cltv_delta);
10291038
}
10301039
}
10311040
}
10321041
} else {
10331042
if first_hops.is_none() || chan.node_one != our_node_id{
10341043
if let Some(one_to_two) = chan.one_to_two.as_ref() {
10351044
if one_to_two.enabled {
1036-
add_entry!(chan_id, chan.node_one, chan.node_two, one_to_two, chan.capacity_sats, &chan.features, $fee_to_target_msat, $next_hops_value_contribution, $next_hops_path_htlc_minimum_msat, $next_hops_path_penalty_msat);
1045+
add_entry!(chan_id, chan.node_one, chan.node_two, one_to_two, chan.capacity_sats, &chan.features, $fee_to_target_msat, $next_hops_value_contribution, $next_hops_path_htlc_minimum_msat, $next_hops_path_penalty_msat, $next_hops_cltv_delta);
10371046
}
10381047
}
10391048
}
@@ -1060,7 +1069,7 @@ where L::Target: Logger {
10601069
// place where it could be added.
10611070
if let Some(first_channels) = first_hop_targets.get(&payee_node_id) {
10621071
for (ref first_hop, ref features, ref outbound_capacity_msat, _) in first_channels {
1063-
let added = add_entry!(first_hop, our_node_id, payee_node_id, dummy_directional_info, Some(outbound_capacity_msat / 1000), features, 0, path_value_msat, 0, 0u64);
1072+
let added = add_entry!(first_hop, our_node_id, payee_node_id, dummy_directional_info, Some(outbound_capacity_msat / 1000), features, 0, path_value_msat, 0, 0u64, 0);
10641073
log_trace!(logger, "{} direct route to payee via SCID {}", if added { "Added" } else { "Skipped" }, first_hop);
10651074
}
10661075
}
@@ -1074,7 +1083,7 @@ where L::Target: Logger {
10741083
// If not, targets.pop() will not even let us enter the loop in step 2.
10751084
None => {},
10761085
Some(node) => {
1077-
add_entries_to_cheapest_to_target_node!(node, payee_node_id, 0, path_value_msat, 0, 0u64);
1086+
add_entries_to_cheapest_to_target_node!(node, payee_node_id, 0, path_value_msat, 0, 0u64, 0);
10781087
},
10791088
}
10801089

@@ -1100,6 +1109,7 @@ where L::Target: Logger {
11001109
let mut aggregate_next_hops_fee_msat: u64 = 0;
11011110
let mut aggregate_next_hops_path_htlc_minimum_msat: u64 = 0;
11021111
let mut aggregate_next_hops_path_penalty_msat: u64 = 0;
1112+
let mut aggregate_next_hops_cltv_delta: u32 = 0;
11031113

11041114
for (idx, (hop, prev_hop_id)) in hop_iter.zip(prev_hop_iter).enumerate() {
11051115
// BOLT 11 doesn't allow inclusion of features for the last hop hints, which
@@ -1130,11 +1140,15 @@ where L::Target: Logger {
11301140
.checked_add(scorer.channel_penalty_msat(hop.short_channel_id, final_value_msat, None, &src_node_id, &dest_node_id))
11311141
.unwrap_or_else(|| u64::max_value());
11321142

1143+
aggregate_next_hops_cltv_delta = aggregate_next_hops_cltv_delta
1144+
.checked_add(hop.cltv_expiry_delta as u32)
1145+
.unwrap_or_else(|| u32::max_value());
1146+
11331147
// We assume that the recipient only included route hints for routes which had
11341148
// sufficient value to route `final_value_msat`. Note that in the case of "0-value"
11351149
// invoices where the invoice does not specify value this may not be the case, but
11361150
// better to include the hints than not.
1137-
if !add_entry!(hop.short_channel_id, src_node_id, dest_node_id, directional_info, channel_cap_sat, &empty_channel_features, aggregate_next_hops_fee_msat, path_value_msat, aggregate_next_hops_path_htlc_minimum_msat, aggregate_next_hops_path_penalty_msat) {
1151+
if !add_entry!(hop.short_channel_id, src_node_id, dest_node_id, directional_info, channel_cap_sat, &empty_channel_features, aggregate_next_hops_fee_msat, path_value_msat, aggregate_next_hops_path_htlc_minimum_msat, aggregate_next_hops_path_penalty_msat, aggregate_next_hops_cltv_delta) {
11381152
// If this hop was not used then there is no use checking the preceding hops
11391153
// in the RouteHint. We can break by just searching for a direct channel between
11401154
// last checked hop and first_hop_targets
@@ -1144,7 +1158,7 @@ where L::Target: Logger {
11441158
// Searching for a direct channel between last checked hop and first_hop_targets
11451159
if let Some(first_channels) = first_hop_targets.get(&NodeId::from_pubkey(&prev_hop_id)) {
11461160
for (ref first_hop, ref features, ref outbound_capacity_msat, _) in first_channels {
1147-
add_entry!(first_hop, our_node_id , NodeId::from_pubkey(&prev_hop_id), dummy_directional_info, Some(outbound_capacity_msat / 1000), features, aggregate_next_hops_fee_msat, path_value_msat, aggregate_next_hops_path_htlc_minimum_msat, aggregate_next_hops_path_penalty_msat);
1161+
add_entry!(first_hop, our_node_id , NodeId::from_pubkey(&prev_hop_id), dummy_directional_info, Some(outbound_capacity_msat / 1000), features, aggregate_next_hops_fee_msat, path_value_msat, aggregate_next_hops_path_htlc_minimum_msat, aggregate_next_hops_path_penalty_msat, aggregate_next_hops_cltv_delta);
11481162
}
11491163
}
11501164

@@ -1178,7 +1192,7 @@ where L::Target: Logger {
11781192
// path.
11791193
if let Some(first_channels) = first_hop_targets.get(&NodeId::from_pubkey(&hop.src_node_id)) {
11801194
for (ref first_hop, ref features, ref outbound_capacity_msat, _) in first_channels {
1181-
add_entry!(first_hop, our_node_id , NodeId::from_pubkey(&hop.src_node_id), dummy_directional_info, Some(outbound_capacity_msat / 1000), features, aggregate_next_hops_fee_msat, path_value_msat, aggregate_next_hops_path_htlc_minimum_msat, aggregate_next_hops_path_penalty_msat);
1195+
add_entry!(first_hop, our_node_id , NodeId::from_pubkey(&hop.src_node_id), dummy_directional_info, Some(outbound_capacity_msat / 1000), features, aggregate_next_hops_fee_msat, path_value_msat, aggregate_next_hops_path_htlc_minimum_msat, aggregate_next_hops_path_penalty_msat, aggregate_next_hops_cltv_delta);
11821196
}
11831197
}
11841198
}
@@ -1201,7 +1215,7 @@ where L::Target: Logger {
12011215
// Both these cases (and other cases except reaching recommended_value_msat) mean that
12021216
// paths_collection will be stopped because found_new_path==false.
12031217
// This is not necessarily a routing failure.
1204-
'path_construction: while let Some(RouteGraphNode { node_id, lowest_fee_to_node, value_contribution_msat, path_htlc_minimum_msat, path_penalty_msat, .. }) = targets.pop() {
1218+
'path_construction: while let Some(RouteGraphNode { node_id, lowest_fee_to_node, total_cltv_delta, value_contribution_msat, path_htlc_minimum_msat, path_penalty_msat, .. }) = targets.pop() {
12051219

12061220
// Since we're going payee-to-payer, hitting our node as a target means we should stop
12071221
// traversing the graph and arrange the path out of what we found.
@@ -1327,7 +1341,7 @@ where L::Target: Logger {
13271341
match network_nodes.get(&node_id) {
13281342
None => {},
13291343
Some(node) => {
1330-
add_entries_to_cheapest_to_target_node!(node, node_id, lowest_fee_to_node, value_contribution_msat, path_htlc_minimum_msat, path_penalty_msat);
1344+
add_entries_to_cheapest_to_target_node!(node, node_id, lowest_fee_to_node, value_contribution_msat, path_htlc_minimum_msat, path_penalty_msat, total_cltv_delta);
13311345
},
13321346
}
13331347
}

0 commit comments

Comments
 (0)