-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
multi: fix payment failure overwrite #9543
multi: fix payment failure overwrite #9543
Conversation
Important Review skippedAuto reviews are limited to specific labels. 🏷️ Labels to auto review (1)
Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
ab5cd5f
to
4eca3b9
Compare
If the approach is ok, will add a unit-test. lnd/channeldb/payment_control_test.go Lines 891 to 894 in 5fe900d
|
Why did we fail the payment twice? Can we make it fail it once instead? |
We fail it almost certainly twice in Lines 1189 to 1206 in 5fe900d
|
routing/router.go
Outdated
@@ -1200,7 +1200,12 @@ func (r *ChannelRouter) sendToRoute(htlcHash lntypes.Hash, rt *route.Route, | |||
// as failed if we don't skip temp error. | |||
if !skipTempErr { | |||
err := r.cfg.Control.FailPayment(paymentIdentifier, reason) | |||
if err != nil { | |||
|
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 think a better approach is to perform a check on this payment, if it's already failed, we skip calling the above FailPayment
. We don't wanna this single case to change the underlying logic/assumptions for our CRUD.
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, I think that’s a better approach too.
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 added a check into the fail method so that we just return nil
if it is already failed.
@ziggie1984, remember to re-request review from reviewers when ready |
4eca3b9
to
38bbcaf
Compare
f74c370
to
bee1eba
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.
I think we should just do another payment check in sendToRoute
and exit if it's already failed,
diff --git a/routing/router.go b/routing/router.go
index 323fe7616..6e95a5ffd 100644
--- a/routing/router.go
+++ b/routing/router.go
@@ -1199,7 +1199,21 @@ func (r *ChannelRouter) sendToRoute(htlcHash lntypes.Hash, rt *route.Route,
// An error returned from collecting the result, we'll mark the payment
// as failed if we don't skip temp error.
if !skipTempErr {
- err := r.cfg.Control.FailPayment(paymentIdentifier, reason)
+ // We now look up the payment to see if it's already failed.
+ payment, err := p.router.cfg.Control.FetchPayment(p.identifier)
+ if err != nil {
+ return result.attempt, err
+ }
+
+ // Exit if the above error has caused the payment to be failed, we also
+ // return the error from sending attempt to mimic the old behavior of
+ // this method.
+ _, failedReason := payment.TerminalInfo()
+ if failedReason != nil {
+ return result.attempt, result.err
+ }
+
+ err = r.cfg.Control.FailPayment(paymentIdentifier, reason)
if err != nil {
return nil, err
}
91a37c4
to
fc69b22
Compare
fc69b22
to
e01814a
Compare
e01814a
to
398f4ab
Compare
398f4ab
to
a4bcddd
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.
Pending linter fix otherwise good to go🚢
ca93ab8
to
e19902f
Compare
// already failed. | ||
_, failedReason := payment.TerminalInfo() | ||
if failedReason != nil { | ||
return nil |
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.
previously we'd return return result.attempt, result.err
when there's a failed reason, but it's no longer returned?
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 I kept it the same, failPayment returns nil, and then we return:
return result.attempt, result.err
?
e19902f
to
ca839ba
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!
The code and the concept looks good to me!
I propose to add an itest to help prevent this bug in the future.
@@ -1048,6 +1048,29 @@ func (r *ChannelRouter) sendToRoute(htlcHash lntypes.Hash, rt *route.Route, | |||
firstHopCustomRecords lnwire.CustomRecords) (*channeldb.HTLCAttempt, | |||
error) { | |||
|
|||
// Helper function to fail a payment. It makes sure the payment is only | |||
// failed once so that the failure reason is not overwritten. | |||
failPayment := func(paymentIdentifier lntypes.Hash, |
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.
In the bug report it is said that the bug is reproducible with bos probe
. I propose to add an itest reproducing the original bug to make sure it won't re-occur in the future if the code is changed. The itest would fail if run without this patch and pass if the patch is applied.
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 an itest.
0e37e4e
to
76a6296
Compare
76a6296
to
b010e95
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🚢
We are not consistent when handling payment failures so we need to make sure we do not fail a payment twice overwriting its previous failure reason.
Thanks @feelancer21 for reporting. Fixes #9542
Observed in the
sendtoroute
cmd. When tracking the payment it can be observed that we overwrite the payment failure.