mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-08-29 15:11:09 +02:00
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:
committed by
Olaoluwa Osuntokun
parent
bf99e42f8e
commit
52c00e8cc4
@@ -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},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user