From da37fe20fc480552484feaddd2171368c0d992c8 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 10 Jun 2025 13:05:49 +0200 Subject: [PATCH] routing: add comments and clean-up to `findBlindedPaths` Here we add some more comments and a bit of code clean up to the `findBlindedPaths` function. No logic is changed here. --- routing/pathfind.go | 77 +++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 27 deletions(-) diff --git a/routing/pathfind.go b/routing/pathfind.go index ace174fef..d2082f4e5 100644 --- a/routing/pathfind.go +++ b/routing/pathfind.go @@ -1227,24 +1227,46 @@ func findBlindedPaths(g Graph, target route.Vertex, } var ( - // The target node is always the last hop in the path. - incomingPath = []blindedHop{{vertex: target}} - whiteListedNodes = map[route.Vertex]bool{target: true} + // The target node is always the last hop in the path, and so + // we add it to the incoming path from the get-go. Any additions + // to the slice should be prepended. + incomingPath = []blindedHop{{ + vertex: target, + }} + + // supportsRouteBlinding is a list of nodes that we can assume + // support route blinding without needing to rely on the feature + // bits announced in their node announcement. Since we are + // finding a path to the target node, we can assume it supports + // route blinding. + supportsRouteBlinding = map[route.Vertex]bool{ + target: true, + } + visited = make(map[route.Vertex]bool) - errChanFound = errors.New("found incoming channel") nextTarget = target + haveIncomingPath = len(restrictions.incomingChainedChannels) > 0 + + // errChanFound is an error variable we return from the DB + // iteration call below when we have found the channel we are + // looking for. This lets us exit the iteration early. + errChanFound = errors.New("found incoming channel") ) for _, chanID := range restrictions.incomingChainedChannels { + // Mark that we have visited this node so that we don't revisit + // it later on when we call "processNodeForBlindedPath". visited[nextTarget] = true err := g.ForEachNodeDirectedChannel(nextTarget, func(channel *graphdb.DirectedChannel) error { - // Not the right channel, continue to the node's - // other channels. + // This is not the right channel, continue to + // the node's other channels. if channel.ChannelID != chanID { return nil } + // We found the channel in question. Prepend it + // to the incoming path. incomingPath = append([]blindedHop{ { vertex: channel.OtherNode, @@ -1259,39 +1281,37 @@ func findBlindedPaths(g Graph, target route.Vertex, return errChanFound }, ) - if err == nil { + // We expect errChanFound to be returned if the channel in + // question was found. + if !errors.Is(err, errChanFound) && err != nil { + return nil, err + } else if err == nil { return nil, fmt.Errorf("incoming channel %d is not "+ "seen as owned by node %v", chanID, nextTarget) } - if !errors.Is(err, errChanFound) { - return nil, err - } // Check that the user didn't accidentally add a channel that - // is owned by a node in the node omission set + // is owned by a node in the node omission set. if restrictions.nodeOmissionSet.Contains(nextTarget) { return nil, fmt.Errorf("node %v cannot simultaneously "+ "be included in the omission set and in the "+ "partially specified path", nextTarget) } - if whiteListedNodes[nextTarget] { + // Check that we have not already visited the next target node + // since this would mean a circular incoming path. + if visited[nextTarget] { return nil, fmt.Errorf("a circular route cannot be " + "specified for the incoming blinded path") } - whiteListedNodes[nextTarget] = true + + supportsRouteBlinding[nextTarget] = true } - // If the node is not the destination node, then it is required that the - // node advertise the route blinding feature-bit in order for it to be - // chosen as a node on the blinded path. - // We skip checking the target node, as accepting blinded payments - // (via invoice) doesn't imply support for routing them (via node - // announcement). - // We skip checking incomingChainedChannels nodes, as we might not yet - // have an updated node announcement for them. - supportsRouteBlinding := func(node route.Vertex) (bool, error) { - if whiteListedNodes[node] { + // A helper closure which checks if the node in question has advertised + // that it supports route blinding. + nodeSupportsRouteBlinding := func(node route.Vertex) (bool, error) { + if supportsRouteBlinding[node] { return true, nil } @@ -1308,8 +1328,12 @@ func findBlindedPaths(g Graph, target route.Vertex, // conditions such as: The maxHops number being reached or reaching // a node that doesn't have any other edges - in that final case, the // whole path should be ignored. + // + // NOTE: any paths returned will end at the "nextTarget" node meaning + // that if we have a fixed list of incoming chained channels, then this + // fixed list must be appended to any of the returned paths. paths, _, err := processNodeForBlindedPath( - g, nextTarget, supportsRouteBlinding, visited, restrictions, + g, nextTarget, nodeSupportsRouteBlinding, visited, restrictions, ) if err != nil { return nil, err @@ -1319,8 +1343,7 @@ func findBlindedPaths(g Graph, target route.Vertex, // When there is no path to add, but incomingChainedChannels can be // used. - lenChainedChannels := int8(len(restrictions.incomingChainedChannels)) - if len(paths) == 0 && lenChainedChannels > 0 { + if len(paths) == 0 && haveIncomingPath { orderedPaths = [][]blindedHop{incomingPath} } else { // Reverse each path so that the order is correct (from @@ -1337,7 +1360,7 @@ func findBlindedPaths(g Graph, target route.Vertex, // Handle the special case that allows a blinded path with the // introduction node as the destination node. - if restrictions.minNumHops == 0 && lenChainedChannels == 0 { + if restrictions.minNumHops == 0 && !haveIncomingPath { singleHopPath := [][]blindedHop{{{vertex: target}}} //nolint:makezero