-
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
routing: add build route functionality #3440
Conversation
1158ce8
to
038d33b
Compare
7da0d23
to
c175ba8
Compare
769d394
to
e24a703
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty good to me :)
e24a703
to
24742c7
Compare
24742c7
to
00e13a6
Compare
00e13a6
to
f06a175
Compare
ba36796
to
94bbee4
Compare
routing/router_test.go
Outdated
_, err = ctx.router.BuildRoute( | ||
nil, hops, nil, 40, | ||
) | ||
if _, ok := err.(ErrNoChannel); !ok { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Asserts fields of error as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added
35ad463
to
396c5b6
Compare
8e8fa7c
to
8712e88
Compare
Also extended the test so that it also exercises selecting the best channel when there are multiple channels between a pair of nodes. |
routing/router.go
Outdated
|
||
// Determine max htlc value. | ||
maxHtlc := lnwire.NewMSatFromSatoshis(capacity) | ||
if policy.MaxHTLC != 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should use HasMaxHtlc
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed. This is the confusion that I think we shouldn't need to have.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, looking in the link, it also checks for MaxHTLC == 0
. I left the check identical to what happens in the link.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's because the link uses ForwardingPolicy
, which doesn't contain information about whether the bit is set or not. I'm in favor of adding the check for the bit being set here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, it is indeed a good idea, because this function is also used for non-local channels. Changed
routing/router.go
Outdated
// incompatible channel policies. | ||
// | ||
// There is possibility with pubkey addressing that we should | ||
// have selected a different channel downstream, but we don't |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't we fix that? Should this be a TODO, or is there another reason?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would complicate path finding while we expect this situation to be rare. The spec recommends to keep all policies towards a peer identical. If that is the case, there isn't a better channel that we should have selected.
Added this as a comment
8712e88
to
e05425d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only a few nits and suggestions from me, LGTM 🏆
// If we have a specific amount for which we are building the route, | ||
// validate it against the channel constraints and return the new | ||
// running amount. | ||
if !canIncreaseAmt { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe this had would been less confusing if the param was called findMinAmt
or similar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I purposely renamed it to canIncreaseAmt
because I realized that it is a more generic function here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it work to not pass this bool to the method, and instead let the caller check the returned amount? So if the amount has increased, but we cannot increase it, it will take action.
It should be equivalent, I just find the current branching within the prependChannel
a bit confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand your suggestion, but I think it may be confusing in another way. The current code has already seen a few earlier iterations. If there isn't a way that very clearly improves the readability, I'd rather leave it as is.
) | ||
if err != nil { | ||
log.Tracef("Skipping chan %v: %v", | ||
inEdge.ChannelID, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this an expected error? If not maybe log as Warn
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it can happen if channels have distinct policies. If all of them do not match, we return a proper error. Warn
is definitely too heavy in this situation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's just that if this is expected to happen, and it leads us to not be able to build a route, the reason will likely never surface, as it's on trace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The trace log is intended for use during development. The problem with reporting the exact reason to the caller is similar to the situation that we have in path finding. There may be multiple reasons. I am afraid that just exposing a random one of them will lead to the same incorrect assumptions that we currently have for path finding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be clear, even if the call succeeds in building a route, some channels may have been skipped. We can't log it on Warn, because it may really not be a warning.
e05425d
to
21f3a06
Compare
21f3a06
to
03d33cb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 💫
if hasAmt { | ||
amtMsat = ctx.Int64("amt") * 1000 | ||
if amtMsat == 0 { | ||
return fmt.Errorf("non-zero amount required") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One last nit: do we still need all of this? Seems like AmtMsat
can just be ctx.Uint64("amt") * 1000
.
This PR adds a new rpc for advanced users that allows them to build a fully specified route from a list of pubkeys. The call looks up the relevant channel policies from the graph and calculates the required fees and time lock values.
Route building is exposed via
lncli
. Example command to build a two hop route:lncli buildroute --hops <pubkey1>,<pubkey2> --amt 500
It is also possible to leave out the
--amt
parameter. In that case, a route is built for the minimum amount that it can carry. This option is useful to execute probe payments for which the primary objective is to pick up black holes (stuck htlc). If the payment gets stuck, the time-locked amount is minimal.