channeldb: expand PaymentStatus to explicitly represent payment status

This commit introduces more granular statuses to better determine a
payment's current state. Based on whether there are inflight HTLCs, the
state of each of the HTLCs, and whether the payment is failed, a total
of 5 states are derived, which can give a finer control over what action
to take based on a given state.

Also, `fetchPayment` now uses `decidePaymentStatus`. After applying the
new function, the returned payment status would be different,

```
| inflight | settled | failed | reason |       previous  ->   now          |
|:--------:|:-------:|:------:|:------:|:---------------------------------:|
|   true   |   true  |  true  |   yes  |    StatusInFlight(unchanged)      |
|   true   |   true  |  true  |   no   |    StatusInFlight(unchanged)      |
|   true   |   true  |  false |   yes  |    StatusInFlight(unchanged)      |
|   true   |   true  |  false |   no   |    StatusInFlight(unchanged)      |
|   true   |   false |  true  |   yes  |    StatusInFlight(unchanged)      |
|   true   |   false |  true  |   no   |    StatusInFlight(unchanged)      |
|   true   |   false |  false |   yes  |    StatusInFlight(unchanged)      |
|   true   |   false |  false |   no   |    StatusInFlight(unchanged)      |
|   false  |   true  |  true  |   yes  |    StatusSucceeded(unchanged)     |
|   false  |   true  |  true  |   no   |    StatusSucceeded(unchanged)     |
|   false  |   true  |  false |   yes  |    StatusSucceeded(unchanged)     |
|   false  |   true  |  false |   no   |    StatusSucceeded(unchanged)     |
|   false  |   false |  true  |   yes  |     StatusFailed(unchanged)       |
|   false  |   false |  true  |   no   |     StatusInFlight(unchanged)     |
|   false  |   false |  false |   yes  |     StatusFailed(unchanged)       |
|   false  |   false |  false |   no   |  StatusInFlight -> StatusInitiated|
```
This commit is contained in:
yyforyongyu
2022-11-24 17:40:49 +08:00
committed by Olaoluwa Osuntokun
parent 09b67af48d
commit 390f3c8253
3 changed files with 160 additions and 59 deletions

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"crypto/rand"
"crypto/sha256"
"errors"
"fmt"
"io"
"reflect"
@@ -67,7 +68,9 @@ func TestPaymentControlSwitchFail(t *testing.T) {
require.NoError(t, err, "unable to send htlc message")
assertPaymentIndex(t, pControl, info.PaymentIdentifier)
assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
assertPaymentStatus(
t, pControl, info.PaymentIdentifier, StatusInitiated,
)
assertPaymentInfo(
t, pControl, info.PaymentIdentifier, info, nil, nil,
)
@@ -98,7 +101,9 @@ func TestPaymentControlSwitchFail(t *testing.T) {
assertPaymentIndex(t, pControl, info.PaymentIdentifier)
assertNoIndex(t, pControl, payment.SequenceNum)
assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
assertPaymentStatus(
t, pControl, info.PaymentIdentifier, StatusInitiated,
)
assertPaymentInfo(
t, pControl, info.PaymentIdentifier, info, nil, nil,
)
@@ -119,7 +124,9 @@ func TestPaymentControlSwitchFail(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
assertPaymentStatus(
t, pControl, info.PaymentIdentifier, StatusInFlight,
)
htlc := &htlcStatus{
HTLCAttemptInfo: attempt,
@@ -198,7 +205,9 @@ func TestPaymentControlSwitchDoubleSend(t *testing.T) {
require.NoError(t, err, "unable to send htlc message")
assertPaymentIndex(t, pControl, info.PaymentIdentifier)
assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
assertPaymentStatus(
t, pControl, info.PaymentIdentifier, StatusInitiated,
)
assertPaymentInfo(
t, pControl, info.PaymentIdentifier, info, nil, nil,
)
@@ -207,10 +216,9 @@ func TestPaymentControlSwitchDoubleSend(t *testing.T) {
// payment hash, should result in error indicating that payment has
// already been sent.
err = pControl.InitPayment(info.PaymentIdentifier, info)
if err != ErrPaymentInFlight {
t.Fatalf("payment control wrong behaviour: " +
"double sending must trigger ErrPaymentInFlight error")
}
require.Equal(t, ErrPaymentExists, err, "payment control wrong "+
"behaviour: init payment again must trigger ErrPaymentExists "+
"error")
// Record an attempt.
_, err = pControl.RegisterAttempt(info.PaymentIdentifier, attempt)
@@ -682,7 +690,9 @@ func TestPaymentControlMultiShard(t *testing.T) {
}
assertPaymentIndex(t, pControl, info.PaymentIdentifier)
assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
assertPaymentStatus(
t, pControl, info.PaymentIdentifier, StatusInitiated,
)
assertPaymentInfo(
t, pControl, info.PaymentIdentifier, info, nil, nil,
)
@@ -708,7 +718,8 @@ func TestPaymentControlMultiShard(t *testing.T) {
t.Fatalf("unable to send htlc message: %v", err)
}
assertPaymentStatus(
t, pControl, info.PaymentIdentifier, StatusInFlight,
t, pControl, info.PaymentIdentifier,
StatusInFlight,
)
htlc := &htlcStatus{
@@ -807,11 +818,14 @@ func TestPaymentControlMultiShard(t *testing.T) {
// Record the reason we failed the payment, such that
// we can assert this later in the test.
firstFailReason = &failReason
}
// The payment should still be considered in-flight, since there
// is still an active HTLC.
assertPaymentStatus(t, pControl, info.PaymentIdentifier, StatusInFlight)
// The payment is now considered pending fail, since
// there is still an active HTLC.
assertPaymentStatus(
t, pControl, info.PaymentIdentifier,
StatusInFlight,
)
}
// Try to register yet another attempt. This should fail now
// that the payment has reached a terminal condition.
@@ -839,15 +853,12 @@ func TestPaymentControlMultiShard(t *testing.T) {
Preimage: preimg,
},
)
if err != nil {
t.Fatalf("error shouldn't have been "+
"received, got: %v", err)
}
require.NoError(t, err, "unable to settle")
htlc.settle = &preimg
assertPaymentInfo(
t, pControl, info.PaymentIdentifier, info,
firstFailReason, htlc,
t, pControl, info.PaymentIdentifier,
info, firstFailReason, htlc,
)
} else {
// Fail the attempt.
@@ -875,9 +886,7 @@ func TestPaymentControlMultiShard(t *testing.T) {
// syncing.
failReason := FailureReasonPaymentDetails
_, err = pControl.Fail(info.PaymentIdentifier, failReason)
if err != nil {
t.Fatalf("unable to fail payment hash: %v", err)
}
require.NoError(t, err, "unable to fail")
}
var (
@@ -1105,7 +1114,7 @@ func assertPaymentStatus(t *testing.T, p *PaymentControl,
t.Helper()
payment, err := p.FetchPayment(hash)
if err == ErrPaymentNotInitiated {
if errors.Is(err, ErrPaymentNotInitiated) {
return
}
if err != nil {