-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[feature]: Proposal for a different cutoff between InboundFee and OutboundFee in pathfinding #8945
Comments
Yes, unfortunately I think that doesn't solve it, during implementation/review of #6934 this approach was tried but not documented. Here's an example graph that would lead to non-optimal outcomes with the suggested approach. Take the following graph with outbound and inbound fees as indicated on the edges: flowchart LR
S -->|out: 0, in: -4| A
A -->|out: 9, in: -11| B
A -->|out: 0, in: -6| C
B -->|out: 8, in: 0| T
C -->|out: 10, in: 0| T
The top route ( I'll show the current approach, the suggested approach and the line-graph approach as examples. Capped total channel feesThis is the currently implemented approach: taking the weight as the edge's inbound fee plus its outbound fee, capped from below by zero. Dijkstra's algorithm would work like this:
Inbound fee and previous outbound fee
The accumulated weights are 0 for both, so the order by which nodes are explored
Both nodes in the queue have the same accumulated weight. 1.1. explore A first
1.2. explore C first
So in some cases optimal routes are found, sometimes not. Perhaps one could apply the next outbound fee as a tie-breaker and maybe there are other edge cases, but I think the next approach is the exact one. Inbound fee and previous outbound fee with line graphTransforming the problem to a line graph (https://en.wikipedia.org/wiki/Line_graph) solves the problem for this example graph. The new pivots of exploration are the middle points between two nodes, which helps to keep track of weights without overriding information (a solution found by Joost Jager).
Again, we have same weights, any tuple could get picked.
Both nodes in the queue both have again the same weight. 1.1. explore (A,B) first
1.2. explore (C,T) first
Next stepsSo the suggestion to use the inbound fee plus the previous outbound fee makes the algo correct (at least for this toy graph) if the heap/queue is used with a node pair tuple, which is the case with 54c4988. I'm going to explore this change and check it's execution time behavior. The exit condition can be changed by adding a fake hop |
First of all, thank you very much for the detailed answer and the very interesting example. I already thought that the dependencies between inbound and outbound go much deeper, but haven't seen it yet. To summarize it for me: 1.1. vs. 1.2. is about the decision of I suppose you can also construct cases where it is better to choose a higher distance with a higher outbound fee, which is later improved by discounts. So the classic reason why Dijsktra does not find the optimal solution with negative weights |
Not sure if I have really understood the current approach. I had expected Edit: You could set |
Ah yes, thank you for the correction, updated (it doesn't change the outcome)!
Changing to that approach could make sense, as it is closer to the optimal solution 👍, but I think it's worth to explore the behavior of the line-graph approach first. |
I did a bit more research on this, the line graph approach fixes all known non-optimal test cases, see https://github.com/bitromortac/lnd/commits/2410-line-graph. Unfortunately, when benchmarking the line-graph approach (see https://github.com/bitromortac/lnd/commits/2410-line-graph/), I saw quite long pathfinding run times when computing paths to random nodes (typically they took several seconds): The number of explored nodes isn't surprising as the line graph has the original graph's number of edges. I was wondering about the large number of edges explored, but it makes sense since when converting an LN graph to the line graph representation (via networkx) this leads to: LN graph: 15932 nodes and 52414 edges The run time complexity of the current implementation looks to be linear in the number of edges explored (with 8 µs per explored edge, which is rather slow), which is why I think we'd need significant improvements in the current edge traversal first in order to be able to make up for a factor of ~250 in computational time when using the line graph. Maybe it's possible to skip some edge evaluations if no inbound discounts were involved. I also tried the suggested approach (using the inbound fee + previous outbound fee), but it fails to compute an optimal path in the following case: |
Hey, thanks for the analysis. It's crazy to see these numbers. Additional thought: In my opinion, the line graph is also only helpful with floored inbound fees as we currently use them. For inbound fees without a floor (i.e. negative fordward fees), we can probably also work with a node graph, as we would then have no dependency of the inbound fees on the previous outbound fees. I like the idea of negative fees more and more ;). |
Is your feature request related to a problem? Please describe.
I am picking up a topic that I already mentioned in #8940. In the course of #6934, a split for the total channel fees was implemented. The current cutoff results in not always finding the optimal route as mentioned here.
#6934 (review)
Here is another example from the perspective of a sender A, who can send a payment to D either through B or C.
A-[out fee 0 msat | in fee -100 msat]-B-[out 150 msat | in fee 0]-D
and
A-[out fee 0 msat | in fee 0 msat]-C-[out 100 msat | in fee 0]-D
Since the
out_fee
in the outgoing channels of a source is always counted as 0, the incoming fee on this channel is completely absorbed by the current cutoff, and both source channels are considered with a weight of 0 in the pathfinding (ignoring the timelock penalty). The optimal solution is determined based on the second channel, and the result is the more expensive second route (about 50ppm). This is even though the success probability of the second route could be lower.However, if a
fee_limit
of 75ppm is set, the first route will be found at least after the fix of #8940.Describe the solution you'd like
In my opinion, this behavior can be addressed if we do not base the calculation on the total channel fee, but measure the distance from the
fromVertex
to thetarget
without considering the outbound fee of thefromVertex
. Instead calculating thefee
withlnd/routing/pathfind.go
Lines 805 to 809 in b7c59b3
it should be calculated with
fee := toNodeDist.outboundFee + inboundFee
, which cannot become negative due to the construction of theinboundFee
. The outbound fee of the source would be disregarded, which is unproblematic since it is currently counted as 0. Moreover, the individualfee
components would add up to thetotalFee
again after merging #8941.In the end, the proposal is nothing more than shifting the measurement point of the distance from the point between the involved edges to the middle of the outgoing edge of the
fromVertex
. Intuitively, I would even argue that we find the optimal solution in this way without transforming the graph into a line graph.I am looking forward to your assessment or if I am missing something. The shift seems to be too simple to be true. ;)
The text was updated successfully, but these errors were encountered: