Skip to content

Commit b2c635b

Browse files
committed
Add direct hops to intros after all blinded paths in pathfinding
When we do pathfinding with blinded paths, we start each pathfinding iteration by inserting all the blinded paths into our nodes map as last-hops to the destination. As we do that, we check if any of the introduction points happen to be nodes we have direct chanels with, as we want to use the local info for such channels and support finding a path even if that channel is not publicly announced. However, as we iterate the blinded paths, we may find a second blinded path from the same introduction point which we prefer over the first. If this happens, we would already have added info from us over the local channel to that intro point and end up with calculations for the first hop to a blinded path that we no longer prefer. This is ultimately fixed here in two ways: (a) we process the first-hop channels to blinded path introduction points in a separate loop after we've processed all blinded paths, ensuring we only ever consider a channel to the blinded path we will ultimately prefer. (b) In the next commit, we add we add a new tracking bool in `PathBuildingHop` called `best_path_from_hop_selected` which we set when we process a channel backwards from a node, indicating that we've committed to the best path to the node and check when we add a new path to a node. This would have resulted in a much earlier debug-assertion in fuzzing or several tests.
1 parent 0351a24 commit b2c635b

File tree

1 file changed

+13
-3
lines changed

1 file changed

+13
-3
lines changed

lightning/src/routing/router.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2937,6 +2937,7 @@ where L::Target: Logger {
29372937
introduction_node_id_cache.len(),
29382938
"introduction_node_id_cache was built by iterating the blinded_route_hints, so they should be the same len"
29392939
);
2940+
let mut blind_intros_added = hash_map_with_capacity(payment_params.payee.blinded_route_hints().len());
29402941
for (hint_idx, hint) in payment_params.payee.blinded_route_hints().iter().enumerate() {
29412942
// Only add the hops in this route to our candidate set if either
29422943
// we have a direct channel to the first hop or the first hop is
@@ -2951,12 +2952,21 @@ where L::Target: Logger {
29512952
} else {
29522953
CandidateRouteHop::Blinded(BlindedPathCandidate { source_node_counter, source_node_id, hint, hint_idx })
29532954
};
2954-
let mut path_contribution_msat = path_value_msat;
29552955
if let Some(hop_used_msat) = add_entry!(&candidate,
2956-
0, path_contribution_msat, 0, 0_u64, 0, 0)
2956+
0, path_value_msat, 0, 0_u64, 0, 0)
29572957
{
2958-
path_contribution_msat = hop_used_msat;
2958+
blind_intros_added.insert(source_node_id, (hop_used_msat, candidate));
29592959
} else { continue }
2960+
}
2961+
// If we added a blinded path from an introduction node to the destination, where the
2962+
// introduction node is one of our direct peers, we need to scan our `first_channels`
2963+
// to detect this. However, doing so immediately after calling `add_entry`, above, could
2964+
// result in incorrect behavior if we, in a later loop iteration, update the fee from the
2965+
// same introduction point to the destination (due to a different blinded path with the
2966+
// same introduction point having a lower score).
2967+
// Thus, we track the nodes that we added paths from in `blind_intros_added` and scan for
2968+
// introduction points we have a channel with after processing all blinded paths.
2969+
for (source_node_id, (path_contribution_msat, candidate)) in blind_intros_added {
29602970
if let Some((first_channels, peer_node_counter)) = first_hop_targets.get_mut(source_node_id) {
29612971
sort_first_hop_channels(
29622972
first_channels, &used_liquidities, recommended_value_msat, our_node_pubkey

0 commit comments

Comments
 (0)