Update routing hints upon insufficient fees failure.#2151
Update routing hints upon insufficient fees failure.#2151Bluetegu wants to merge 5 commits intolightningnetwork:masterfrom
Conversation
routing/missioncontrol.go
Outdated
There was a problem hiding this comment.
It seems the return value is used nowhere and can just as well be removed.
routing/router.go
Outdated
There was a problem hiding this comment.
This is not the only case where we can get back a channel update. For example, FailIncorrectCltvExpiry. I think we should try to update additionalEdges also in those cases.
There was a problem hiding this comment.
Can the update maybe be done inside applyChannelUpdate ?
routing/router_test.go
Outdated
There was a problem hiding this comment.
There are currently two ways of writing these kind of path finding tests. One is the way you did it, using the json file. The other option is used in for example TestChannelUpdateValidation. It allows programmatically building the test graph and generates some values like the keys by itself (as the actual value isn't important for the tests, it just needs a value). You could consider using that instead. I think it is clearer than keep adding new channels to the json file.
There was a problem hiding this comment.
I think that you will still have the problem of needing a private key even if you use TestChannelUpdateValidation approach, as the validation of the error message is part of the tested code. Anyhow, I like the approach of using the basic graph in many tests all based on a non trivial topology. It requires the writer of the test to rethink whether the logic indeed covers all scenarios, beyond the simplest topology needed for testing the particular feature or fix she was aiming to do.
There was a problem hiding this comment.
That's okay, just wanted to mention the option.
|
Needs to be rebased |
|
Also, have a look at the commit message format described in https://dev.lightning.community/contribute/. We add the subsystem prefix to the message. |
57fbf15 to
cc5444f
Compare
|
Thanks for the review! |
1ba5022 to
4b1f171
Compare
|
I rebased again, but for some reason the third CI test (coverage) fails in auto pilot and I don't think this has anything to do with the code modification in this PR. I forced push twice already and got the same error there. |
4b1f171 to
2ef99a0
Compare
routing/router.go
Outdated
There was a problem hiding this comment.
This line and others too exceed the max line width of 80 chars (project coding standard).
There was a problem hiding this comment.
The log line is of 77 width. I believe I kept the <80 width everywhere.
There was a problem hiding this comment.
I have it at 96 chars. Do you have tab size 8?
There was a problem hiding this comment.
tab size 4. Using vscode.
There was a problem hiding this comment.
The standard is 80 chars max @ tab size 8.
There was a problem hiding this comment.
Sorry about that. Fixed.
routing/router.go
Outdated
There was a problem hiding this comment.
Why is this added here? Validation is also done inside r.applyChannelUpdate.
There was a problem hiding this comment.
I agree this is ugly. My excuse it that I'm trying to minimize the changes I do in code to those mandatory for this PR. Therefore, if validation fails, processChannelUpdateAndRetry should immediately return, and should not update paySession at all (neither update hints or report edge policy failure), so the check must be there. However we can not rely on the error returned by applyChannelUpdate, as it may well error in other scenarios (i.e. not validation errors) which are perfectly ok, and do require retries. Initially I thought of doing the validation much earlier, i.e. before the switch on the error types, but this looks like a change that is too major for this PR; hence my feeling was that adding validation here is the right way to go, with only bad consequence being that its checked twice.
There was a problem hiding this comment.
I think it is ok to not update the payment session if the graph update fails. ReportEdgeFailure is important to call in case of a validation error. If we get an incorrect update we don't want to try that channel anymore.
There was a problem hiding this comment.
Ok. I removed the extra validation and returned if applyChannelUpdate fails after the edge is pruned.
I'm uncomfortable with the handling of error messages that fail in signature validation, as they do prune edges. Doesn't that allow an attacker to send error messages and cause the routing to fail?
routing/router.go
Outdated
There was a problem hiding this comment.
You've added it in here, but for other cases where r.applyChannelUpdate is called directly, the payment session isn't updated.
There was a problem hiding this comment.
My idea is that the hints are updated only when a retry is aimed at. It now handles all those cases (not only insufficient fees). Otherwise the vertex or channel is removed completely, and there is no need for the update. I thought that is the whole purpose of defining processChannelUpdateAndRetry (which includes the paySession in its closure).
Said in another way, it doesn't seem right to me to plug it into applyChannelUpdate, exactly because this function is called for changing database edges/vertexes (and don't have paySession in closure).
There was a problem hiding this comment.
Yes, I think you're right. All other calls to applyChannelUpdate prune immediately, so those edges will never show up in subsequent payment attempts anymore.
routing/router_test.go
Outdated
There was a problem hiding this comment.
That's okay, just wanted to mention the option.
routing/missioncontrol.go
Outdated
There was a problem hiding this comment.
Are you updating the channel in both directions? I think you may also need to match the pubkey in additional edges to update only a single direction.
There was a problem hiding this comment.
The channel is updated only in one direction. That is, the node generates an error on the outgoing channel policy, and you update the hints accordingly. Am I missing something here?
There was a problem hiding this comment.
I mean, suppose you have two additional edges relating to the same channel id but in opposite direction. They will both be updated?
There was a problem hiding this comment.
Yes. I changed it such that it takes direction into account too, such that policy will be updated only if channel ID and direction both match.
I think this also fixes a general hidden bug in routing through hint hops, not related to this PR, as additionalEdges policies didn't take into account direction. That is, the Flags were not initialized in NewPaymentSession, and routing assumes the direction is initialized in all edge policies.
cf3f300 to
a0ccce4
Compare
|
Ready for inspection :-) |
routing/missioncontrol.go
Outdated
There was a problem hiding this comment.
New line after wrapped line
routing/router.go
Outdated
There was a problem hiding this comment.
failedEdge.direction can be used directly.
There was a problem hiding this comment.
Not sure. failedEdge direction is unit8 while Flags are unit16.
There was a problem hiding this comment.
Ok, you may need to do a type cast, but the if statement is not necessary.
routing/missioncontrol.go
Outdated
routing/missioncontrol.go
Outdated
There was a problem hiding this comment.
Capital at beginning of sentence. Period at end.
routing/router.go
Outdated
There was a problem hiding this comment.
Is this a fix in itself? Ideally this could be yet another separate commit, but if you find it too small for that, it's fine with me.
There was a problem hiding this comment.
I had to add it as otherwise you would get errors on applyChannelUpdate when trying to update private channels hops.
There was a problem hiding this comment.
I think maybe the proper fix here is something like this: ad92e5c (feel free to cherry-pick it into this PR if needed).
I believe then you wouldn't have to flip the AssumeChannelValid in the config during tests?
routing/router.go
Outdated
There was a problem hiding this comment.
This vars are introduced because of line length I assume. But maybe that indicates that now is the time to extract this closure to a separate function.
There was a problem hiding this comment.
Yes. But I don't get much if I move it to a separate function defined within the closure, as the names are so long here that it doesn't make it much better. I rather leave it as is. Defining a separate function altogether for an internal code that is called once is not something I personally prefer.
There was a problem hiding this comment.
There are plenty of internal functions that are called only once, it does help to make the code more understandable. Inline functions can be useful especially if a lot of local vars are bound.
How about just creating a function taking failedEdge and update and returning the ChannelEdgePolicy? Or better, updating the signature of UpdateEdgePolicy to take failedEdge and update. Also consistent with other pay session funcs that take an edgeLocator too.
There was a problem hiding this comment.
Yes, this is the way to go. Thanks!
routing/router_test.go
Outdated
routing/missioncontrol.go
Outdated
There was a problem hiding this comment.
This was indeed not set, but I think it didn't have impact before, because that flag was never read right?
There was a problem hiding this comment.
I think it did have impact, i.e. it was an open bug, but the situations where it matters were rare enough such that it wasn't noticed. I haven't fully thought this out. What happened was that when I tried to fix UpdateEdgePolicy to consider direction as well, following your comment, the (new) test failed, and adding direction here fixed it.
There was a problem hiding this comment.
Yes, it was an omission that surfaced when you fixed UpdateEdgePolicy. But I think that before that, the situations where it mattered where non-existent. Just interested to know whether that was true. In any case, it is fixed now.
a0ccce4 to
d469a0e
Compare
|
Changes made. |
|
@halseth Hi Johan, Is the block tag necessary? Let's try to push this to completion. Thanks! |
This would be great if possible, as we at Fastbitcoins are encountering the issue this PR addresses. |
|
Ok, great. Let me know if anything is needed on my side. |
373efcd to
5868c85
Compare
|
@halseth Thanks! |
routing/router_test.go
Outdated
routing/router_test.go
Outdated
There was a problem hiding this comment.
Excellent test description! 👍
routing/router_test.go
Outdated
There was a problem hiding this comment.
move defer cleanUp() after error check
routing/router_test.go
Outdated
There was a problem hiding this comment.
not needed anymore I think
routing/router_test.go
Outdated
routing/payment_session.go
Outdated
There was a problem hiding this comment.
just return non-pointer value.
routing/payment_session.go
Outdated
There was a problem hiding this comment.
also better to take non-pointer for the edgeLocator here.
routing/router.go
Outdated
routing/router_test.go
Outdated
routing/router_test.go
Outdated
and its parser. Required to correctly sign and later verify error messages in some test scenarios.
The simulated error returned was rejected due to signature failure, and didn't simulate correctly the insufficient fees error as intended. Fix error by including correct signature.
Hints are updated if the error message is either: - FailFeeInsufficient - FailAmountBelowMinimum - FailIncorrectCltvExpiry
5868c85 to
0f1d233
Compare
0f1d233 to
3d2cea0
Compare
|
I did the rebase, but I cannot figure out why the new direction unitest TestSendPaymentPrivateEdgeDirection fails. It didn't fail in the version before the rebase. |
|
@Bluetegu No worries! Thanks for your excellent contributions 👍 |
|
Somebody should pick this up and rebase the still relevant parts. |
|
Replaced by #5332 |
This pull request address issue #2066
Reconstruct the problem:
Setup composed of 3 nodes, A -> B -> C, where B -> C is private.
Create an invoice on C (C:addinvoice with private flag)
Increase fee on B->C (B:updatechanpolicy to a higher fee)
Attempt to pay invoice from A (A:sendpayment --pay_req=xxx)
Receive payment error ("unable to route payment to destination: FeeInsufficient ... ")
After the fix the payment goes through.
A unit test on the 'basic graph' was added. The test adds a private channel between son goku and elst, with lower fees compared with the alternative routes from roasbeef to elst. A fee error is returned on first attempt to route through the private channel, with a higher fee, but still better compared with the alternative routes. The test checks that the after the update the payment is still routed through the private channel but with the updated higher fees.
A bug in the existing test TestSendPaymentErrorRepeatedFeeInsufficient was fixed too. I did a minimal fix. I believe this test can be further improved. The major issue was that the simulated error returned was rejected due to signature failure, and hence didn't simulate correctly the insufficient fees error as intended. In order to correctly sign the errors, an optional private key attribute was added to the basic graph and its parser.