multi: move payment state handling into MPPayment

This commit moves the struct `paymentState` used in `routing` into
`channeldb` and replaces it with `MPPaymentState`. In the following
commit we'd see the benefit, that we don't need to pass variables back
and forth between the two packages. More importantly, this state is put
closer to its origin, and is strictly updated whenever a payment is read
from disk. This approach is less error-prone comparing to the previous
one, which both the `payment` and `paymentState` need to be updated at
the same time to make sure the data stay consistant in a parallel
environment.
This commit is contained in:
yyforyongyu
2023-02-08 03:10:20 +08:00
committed by Olaoluwa Osuntokun
parent bf99e42f8e
commit 52c00e8cc4
7 changed files with 281 additions and 407 deletions

View File

@@ -5,6 +5,9 @@ import (
"fmt"
"testing"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/stretchr/testify/require"
)
@@ -119,3 +122,153 @@ func TestRegistrable(t *testing.T) {
})
}
}
// TestPaymentSetState checks that the method setState creates the
// MPPaymentState as expected.
func TestPaymentSetState(t *testing.T) {
t.Parallel()
// Create a test preimage and failure reason.
preimage := lntypes.Preimage{1}
failureReasonError := FailureReasonError
testCases := []struct {
name string
payment *MPPayment
totalAmt int
expectedState *MPPaymentState
errExpected error
}{
{
// Test that when the sentAmt exceeds totalAmount, the
// error is returned.
name: "amount exceeded error",
// SentAmt returns 90, 10
// TerminalInfo returns non-nil, nil
// InFlightHTLCs returns 0
payment: &MPPayment{
HTLCs: []HTLCAttempt{
makeSettledAttempt(100, 10, preimage),
},
},
totalAmt: 1,
errExpected: ErrSentExceedsTotal,
},
{
// Test that when the htlc is failed, the fee is not
// used.
name: "fee excluded for failed htlc",
payment: &MPPayment{
// SentAmt returns 90, 10
// TerminalInfo returns nil, nil
// InFlightHTLCs returns 1
HTLCs: []HTLCAttempt{
makeActiveAttempt(100, 10),
makeFailedAttempt(100, 10),
},
},
totalAmt: 1000,
expectedState: &MPPaymentState{
NumAttemptsInFlight: 1,
RemainingAmt: 1000 - 90,
FeesPaid: 10,
Terminate: false,
},
},
{
// Test when the payment is settled, the state should
// be marked as terminated.
name: "payment settled",
// SentAmt returns 90, 10
// TerminalInfo returns non-nil, nil
// InFlightHTLCs returns 0
payment: &MPPayment{
HTLCs: []HTLCAttempt{
makeSettledAttempt(100, 10, preimage),
},
},
totalAmt: 1000,
expectedState: &MPPaymentState{
NumAttemptsInFlight: 0,
RemainingAmt: 1000 - 90,
FeesPaid: 10,
Terminate: true,
},
},
{
// Test when the payment is failed, the state should be
// marked as terminated.
name: "payment failed",
// SentAmt returns 0, 0
// TerminalInfo returns nil, non-nil
// InFlightHTLCs returns 0
payment: &MPPayment{
FailureReason: &failureReasonError,
},
totalAmt: 1000,
expectedState: &MPPaymentState{
NumAttemptsInFlight: 0,
RemainingAmt: 1000,
FeesPaid: 0,
Terminate: true,
},
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
// Attach the payment info.
info := &PaymentCreationInfo{
Value: lnwire.MilliSatoshi(tc.totalAmt),
}
tc.payment.Info = info
// Call the method that updates the payment state.
err := tc.payment.setState()
require.ErrorIs(t, err, tc.errExpected)
require.Equal(
t, tc.expectedState, tc.payment.State,
"state not updated as expected",
)
})
}
}
func makeActiveAttempt(total, fee int) HTLCAttempt {
return HTLCAttempt{
HTLCAttemptInfo: makeAttemptInfo(total, total-fee),
}
}
func makeSettledAttempt(total, fee int,
preimage lntypes.Preimage) HTLCAttempt {
return HTLCAttempt{
HTLCAttemptInfo: makeAttemptInfo(total, total-fee),
Settle: &HTLCSettleInfo{Preimage: preimage},
}
}
func makeFailedAttempt(total, fee int) HTLCAttempt {
return HTLCAttempt{
HTLCAttemptInfo: makeAttemptInfo(total, total-fee),
Failure: &HTLCFailInfo{
Reason: HTLCFailInternal,
},
}
}
func makeAttemptInfo(total, amtForwarded int) HTLCAttemptInfo {
hop := &route.Hop{AmtToForward: lnwire.MilliSatoshi(amtForwarded)}
return HTLCAttemptInfo{
Route: route.Route{
TotalAmount: lnwire.MilliSatoshi(total),
Hops: []*route.Hop{hop},
},
}
}