-
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 payment failure reason FailureReasonCancel
#8836
routing: add payment failure reason FailureReasonCancel
#8836
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 Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 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 as PR comments)
Additionally, you can add CodeRabbit Configuration File (
|
ffe9cf8
to
a8a49f2
Compare
a8a49f2
to
1b2ec34
Compare
d67ffc1
to
3cb50a8
Compare
3cb50a8
to
bd6c7f4
Compare
// TODO(halseth): cancel state. | ||
// FailureReasonCanceled indicates that the payment was canceled by the | ||
// user. | ||
FailureReasonCanceled FailureReason = 5 |
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.
need to update the String
method below, also wondering if it's easy to modify one of the itest cases to check this behavior (probably not as we don't have an easy way to cancel context there). Mentioning the test because I think there are other places that also need to be updated, such as lnrpc.PaymentFailureReason
.
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.
Thank you for noticing this, I've adjusted the String
method and complemented the lnrpc
part.
For an itest
we'd probably have to create harness rpc method like SendPaymentWithContext
or so, then pre-cancel it and try sending the payment, which should result in lnrpc.FAILURE_REASON_CANCELED
.
Should we do that?
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.
yeah sounds feasible to me! So sth like,
stream := alice.RPC.SendPaymentWithContext(ctx, req)
ht.AssertPaymentStatusFromStream(stream, lnrpc.Payment_IN_FLIGHT)
ctx.Cancel()
ht.AssertPaymentStatusFromStream(stream, lnrpc.Payment_CANCELED)
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 am unsure if we should introduce lnrpc.Payment_CANCELED
because adding this state would be a deviation from how we handle other payment FailureReason
s.
In the reference below we define state lnrpc.Payment_FAILED
as an umbrella state for any FailureReason
. So adding a further distinction here would complicate the flow.
lnd/channeldb/payment_status.go
Line 180 in 8c0d786
paymentFailed = true |
I think the proper way to check for a cancel is first to check the payment for lnrpc.Payment_FAILED
, then check the payment failure reason for PaymentFailureReason_FAILURE_REASON_INCORRECT_PAYMENT_DETAILS
lnrpc. PaymentFailureReason_FAILURE_REASON_CANCELED
.
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.
yea my bad that code ref is incorrect as we def don't want to add a new status, what I meant is,
stream := alice.RPC.SendPaymentWithContext(ctx, req)
ht.AssertPaymentStatusFromStream(stream, lnrpc.Payment_IN_FLIGHT)
ctx.Cancel()
payment := ht.AssertPaymentStatusFromStream(stream, lnrpc.Payment_FAILED)
require.Equal(ht, lnrpc.PaymentFailureReason_FAILURE_REASON_CANCELED, payment.FailureReason)
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.
If there is nothing preventing the payment from settling then the payment status after the ctx.Cancel()
should be lnrpc.Payment_SUCCEEDED
since the cancellation can't abort the current payment attempt. But the failure reason should be canceled.
If attached an itest.
Edit: I've extended the test to resemble a real world example more closely.
In the itest A tries to pay C's invoice in A - B - C. B intercepts and holds the htlc until A cancels the payment context, then B fails the htlc. The expected result is that no further payment attempts are taken, that the payment is in payment state FAILED and the failure reason is FAILURE_REASON_CANCELED.
3c1d246
to
4ac08ce
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 an itest, otherwise LGTM!
// TODO(halseth): cancel state. | ||
// FailureReasonCanceled indicates that the payment was canceled by the | ||
// user. | ||
FailureReasonCanceled FailureReason = 5 |
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.
yeah sounds feasible to me! So sth like,
stream := alice.RPC.SendPaymentWithContext(ctx, req)
ht.AssertPaymentStatusFromStream(stream, lnrpc.Payment_IN_FLIGHT)
ctx.Cancel()
ht.AssertPaymentStatusFromStream(stream, lnrpc.Payment_CANCELED)
@bitromortac: review reminder |
4ac08ce
to
e95fe0d
Compare
aa68ded
to
0dc2414
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.
Looking good, only a few comments in the itest.
// FAILURE_REASON_CANCELED. This failure reason indicates that the context was | ||
// cancelled manually by the user. It does not interrupt the current payment | ||
// attempt, but will prevent any further payment attempts. The test steps are: | ||
// 1.) Alice pays Carol's invoice through Bob. |
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.
nice👍
itest/lnd_payment_test.go
Outdated
cancelInterceptor() | ||
|
||
// Make sure all goroutines are finished. | ||
select { |
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.
this is unnecessary as we know paymentStream
was returned in the above goroutine.
func (h *HarnessRPC) SendPaymentWithContext(context context.Context, | ||
req *routerrpc.SendPaymentRequest) PaymentClient { | ||
|
||
require.NotNil(h.T, context, "context must not be 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.
👍
itest/lnd_payment_test.go
Outdated
|
||
var preimage lntypes.Preimage | ||
copy(preimage[:], invoice.RPreimage) | ||
ht.AssertPaymentStatus(alice, preimage, lnrpc.Payment_IN_FLIGHT) |
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 this method already returns a payment
and we can assert the failure reason directly via payment.FailureReason
.
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.
This works here, but below we need to call AssertPaymentFailureReason
since the failure reason update on the payment doesn't seem to happen immediately.
@@ -1639,6 +1639,19 @@ func (h *HarnessTest) AssertPaymentStatus(hn *node.HarnessNode, | |||
return target | |||
} | |||
|
|||
// AssertPaymentFailureReason asserts that the given node lists a payment with | |||
// the given preimage which has the expected failure reason. | |||
func (h *HarnessTest) AssertPaymentFailureReason(hn *node.HarnessNode, |
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.
think this assertion is unnecessary since we always have the payment and can assert the fields on it directly.
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.
not addressed
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've removed the Predicate
but for mentioned reason I couldn't remove the assertion.
lntest/harness_assertion.go
Outdated
preimage lntypes.Preimage, reason lnrpc.PaymentFailureReason) { | ||
|
||
payHash := preimage.Hash() | ||
err := wait.Predicate(func() bool { |
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.
future tips: we almost never use Predicate
and favor NoError
as it gives us more descriptive error - maybe we should remove it someday.
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.
Nice, almost ready 👍. Have a suggestion concerning the itest
@@ -772,17 +772,17 @@ func TestResumePaymentFailContextCancel(t *testing.T) { | |||
cancel() | |||
|
|||
m.control.On( | |||
"FailPayment", p.identifier, channeldb.FailureReasonTimeout, | |||
"FailPayment", p.identifier, channeldb.FailureReasonCanceled, |
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.
nit: could you squash this with the previous commit, to make the unit test pass there? I think it's important to let every unit test pass in each commit, to make bisecting of commits easier
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.
💡
0dc2414
to
9c97a61
Compare
81589c4
to
b55ff63
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.
One final comment, otherwise good to go!
require.NoError(ht, err, "failed to send request") | ||
|
||
// Assert that the payment status is as expected. | ||
ht.AssertPaymentStatus(alice, preimage, expectedPaymentStatus) |
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.
think we can grab the payment
here and check its FailureReason
below.
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 status on the payment here is not set yet, hence waiting for it in the extra assertion, see comment #8836 (comment)
@@ -1639,6 +1639,19 @@ func (h *HarnessTest) AssertPaymentStatus(hn *node.HarnessNode, | |||
return target | |||
} | |||
|
|||
// AssertPaymentFailureReason asserts that the given node lists a payment with | |||
// the given preimage which has the expected failure reason. | |||
func (h *HarnessTest) AssertPaymentFailureReason(hn *node.HarnessNode, |
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.
not addressed
b55ff63
to
808d958
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.
Thanks for the fix! LGTM🛳️
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 PR looks good 🎉, but technically this is a breaking change, should somebody rely on the timeout
failure code which now becomes canceled
(in some cases). So therefore v0.18.3 may not be the best release for that.
|
This PR depends on #8734 which introduced a user-cancelable payment loop.
It adds a new failure reason code
channeldb.FailureReasonCanceled
to distinguish payment-timeout cancels in the db from manual user cancellations.