@@ -296,6 +296,7 @@ struct RouteGraphNode {
296
296
node_id : NodeId ,
297
297
lowest_fee_to_peer_through_node : u64 ,
298
298
lowest_fee_to_node : u64 ,
299
+ total_cltv_delta : u32 ,
299
300
// The maximum value a yet-to-be-constructed payment path might flow through this node.
300
301
// This value is upper-bounded by us by:
301
302
// - how much is needed for a path being constructed
@@ -722,7 +723,7 @@ where L::Target: Logger {
722
723
// since that value has to be transferred over this channel.
723
724
// Returns whether this channel caused an update to `targets`.
724
725
( $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 ) => { {
726
727
// We "return" whether we updated the path at the end, via this:
727
728
let mut did_add_update_path_to_src_node = false ;
728
729
// Channels to self should not be used. This is more of belt-and-suspenders, because in
@@ -784,6 +785,13 @@ where L::Target: Logger {
784
785
// Verify the liquidity offered by this channel complies to the minimal contribution.
785
786
let contributes_sufficient_value = available_value_contribution_msat >= minimal_value_contribution_msat;
786
787
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
+
787
795
let value_contribution_msat = cmp:: min( available_value_contribution_msat, $next_hops_value_contribution) ;
788
796
// Includes paying fees for the use of the following channels.
789
797
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 {
802
810
// as not sufficient.
803
811
if !over_path_minimum_msat {
804
812
hit_minimum_limit = true ;
805
- } else if contributes_sufficient_value {
813
+ } else if contributes_sufficient_value && doesnt_exceed_cltv_delta_limit {
806
814
// Note that low contribution here (limited by available_liquidity_msat)
807
815
// might violate htlc_minimum_msat on the hops which are next along the
808
816
// payment path (upstream to the payee). To avoid that, we recompute
@@ -899,6 +907,7 @@ where L::Target: Logger {
899
907
node_id: $src_node_id,
900
908
lowest_fee_to_peer_through_node: total_fee_msat,
901
909
lowest_fee_to_node: $next_hops_fee_msat as u64 + hop_use_fee_msat,
910
+ total_cltv_delta: hop_total_cltv_delta,
902
911
value_contribution_msat: value_contribution_msat,
903
912
path_htlc_minimum_msat,
904
913
path_penalty_msat,
@@ -990,7 +999,7 @@ where L::Target: Logger {
990
999
// meaning how much will be paid in fees after this node (to the best of our knowledge).
991
1000
// This data can later be helpful to optimize routing (pay lower fees).
992
1001
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 ) => {
994
1003
let skip_node = if let Some ( elem) = dist. get_mut( & $node_id) {
995
1004
let was_processed = elem. was_processed;
996
1005
elem. was_processed = true ;
@@ -1006,7 +1015,7 @@ where L::Target: Logger {
1006
1015
if !skip_node {
1007
1016
if let Some ( first_channels) = first_hop_targets. get( & $node_id) {
1008
1017
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 ) ;
1010
1019
}
1011
1020
}
1012
1021
@@ -1025,15 +1034,15 @@ where L::Target: Logger {
1025
1034
if first_hops. is_none( ) || chan. node_two != our_node_id {
1026
1035
if let Some ( two_to_one) = chan. two_to_one. as_ref( ) {
1027
1036
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 ) ;
1029
1038
}
1030
1039
}
1031
1040
}
1032
1041
} else {
1033
1042
if first_hops. is_none( ) || chan. node_one != our_node_id{
1034
1043
if let Some ( one_to_two) = chan. one_to_two. as_ref( ) {
1035
1044
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 ) ;
1037
1046
}
1038
1047
}
1039
1048
}
@@ -1060,7 +1069,7 @@ where L::Target: Logger {
1060
1069
// place where it could be added.
1061
1070
if let Some ( first_channels) = first_hop_targets. get ( & payee_node_id) {
1062
1071
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 ) ;
1064
1073
log_trace ! ( logger, "{} direct route to payee via SCID {}" , if added { "Added" } else { "Skipped" } , first_hop) ;
1065
1074
}
1066
1075
}
@@ -1074,7 +1083,7 @@ where L::Target: Logger {
1074
1083
// If not, targets.pop() will not even let us enter the loop in step 2.
1075
1084
None => { } ,
1076
1085
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 ) ;
1078
1087
} ,
1079
1088
}
1080
1089
@@ -1100,6 +1109,7 @@ where L::Target: Logger {
1100
1109
let mut aggregate_next_hops_fee_msat: u64 = 0 ;
1101
1110
let mut aggregate_next_hops_path_htlc_minimum_msat: u64 = 0 ;
1102
1111
let mut aggregate_next_hops_path_penalty_msat: u64 = 0 ;
1112
+ let mut aggregate_next_hops_cltv_delta: u32 = 0 ;
1103
1113
1104
1114
for ( idx, ( hop, prev_hop_id) ) in hop_iter. zip ( prev_hop_iter) . enumerate ( ) {
1105
1115
// BOLT 11 doesn't allow inclusion of features for the last hop hints, which
@@ -1130,11 +1140,15 @@ where L::Target: Logger {
1130
1140
. checked_add ( scorer. channel_penalty_msat ( hop. short_channel_id , final_value_msat, None , & src_node_id, & dest_node_id) )
1131
1141
. unwrap_or_else ( || u64:: max_value ( ) ) ;
1132
1142
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
+
1133
1147
// We assume that the recipient only included route hints for routes which had
1134
1148
// sufficient value to route `final_value_msat`. Note that in the case of "0-value"
1135
1149
// invoices where the invoice does not specify value this may not be the case, but
1136
1150
// 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 ) {
1138
1152
// If this hop was not used then there is no use checking the preceding hops
1139
1153
// in the RouteHint. We can break by just searching for a direct channel between
1140
1154
// last checked hop and first_hop_targets
@@ -1144,7 +1158,7 @@ where L::Target: Logger {
1144
1158
// Searching for a direct channel between last checked hop and first_hop_targets
1145
1159
if let Some ( first_channels) = first_hop_targets. get ( & NodeId :: from_pubkey ( & prev_hop_id) ) {
1146
1160
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 ) ;
1148
1162
}
1149
1163
}
1150
1164
@@ -1178,7 +1192,7 @@ where L::Target: Logger {
1178
1192
// path.
1179
1193
if let Some ( first_channels) = first_hop_targets. get ( & NodeId :: from_pubkey ( & hop. src_node_id ) ) {
1180
1194
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 ) ;
1182
1196
}
1183
1197
}
1184
1198
}
@@ -1201,7 +1215,7 @@ where L::Target: Logger {
1201
1215
// Both these cases (and other cases except reaching recommended_value_msat) mean that
1202
1216
// paths_collection will be stopped because found_new_path==false.
1203
1217
// 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 ( ) {
1205
1219
1206
1220
// Since we're going payee-to-payer, hitting our node as a target means we should stop
1207
1221
// traversing the graph and arrange the path out of what we found.
@@ -1327,7 +1341,7 @@ where L::Target: Logger {
1327
1341
match network_nodes. get ( & node_id) {
1328
1342
None => { } ,
1329
1343
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 ) ;
1331
1345
} ,
1332
1346
}
1333
1347
}
0 commit comments