multi: move payment related code into own package
This commit moves most of the code into its own package. It is the smallest code move possible without moving import cycles and keeping the changes to the code base as small as possible during refactor.
This commit is contained in:
26 files changed
+1075
-948
No files matched your search
@@ -183,11 +183,6 @@ func WriteElement(w io.Writer, element interface{}) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
case paymentIndexType:
|
|
||||||
if err := binary.Write(w, byteOrder, e); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
case lnwire.FundingFlag:
|
case lnwire.FundingFlag:
|
||||||
if err := binary.Write(w, byteOrder, e); err != nil {
|
if err := binary.Write(w, byteOrder, e); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -416,11 +411,6 @@ func ReadElement(r io.Reader, element interface{}) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
case *paymentIndexType:
|
|
||||||
if err := binary.Read(r, byteOrder, e); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
case *lnwire.FundingFlag:
|
case *lnwire.FundingFlag:
|
||||||
if err := binary.Read(r, byteOrder, e); err != nil {
|
if err := binary.Read(r, byteOrder, e); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
+7
-6
@@ -203,11 +203,13 @@ var (
|
|||||||
migration: mig.CreateTLB(payAddrIndexBucket),
|
migration: mig.CreateTLB(payAddrIndexBucket),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Initialize payment index bucket which will be used
|
// This used to be create payment related top-level
|
||||||
// to index payments by sequence number. This index will
|
// buckets, however this is now done by the payment
|
||||||
// be used to allow more efficient ListPayments queries.
|
// package.
|
||||||
number: 15,
|
number: 15,
|
||||||
migration: mig.CreateTLB(paymentsIndexBucket),
|
migration: func(tx kvdb.RwTx) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Add our existing payments to the index bucket created
|
// Add our existing payments to the index bucket created
|
||||||
@@ -450,7 +452,6 @@ var dbTopLevelBuckets = [][]byte{
|
|||||||
invoiceBucket,
|
invoiceBucket,
|
||||||
payAddrIndexBucket,
|
payAddrIndexBucket,
|
||||||
setIDIndexBucket,
|
setIDIndexBucket,
|
||||||
paymentsIndexBucket,
|
|
||||||
peersBucket,
|
peersBucket,
|
||||||
nodeInfoBucket,
|
nodeInfoBucket,
|
||||||
metaBucket,
|
metaBucket,
|
||||||
|
|||||||
@@ -92,71 +92,3 @@ func (p *PaymentCreationInfo) String() string {
|
|||||||
return fmt.Sprintf("payment_id=%v, amount=%v, created_at=%v",
|
return fmt.Sprintf("payment_id=%v, amount=%v, created_at=%v",
|
||||||
p.PaymentIdentifier, p.Value, p.CreationTime)
|
p.PaymentIdentifier, p.Value, p.CreationTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PaymentsQuery represents a query to the payments database starting or ending
|
|
||||||
// at a certain offset index. The number of retrieved records can be limited.
|
|
||||||
type PaymentsQuery struct {
|
|
||||||
// IndexOffset determines the starting point of the payments query and
|
|
||||||
// is always exclusive. In normal order, the query starts at the next
|
|
||||||
// higher (available) index compared to IndexOffset. In reversed order,
|
|
||||||
// the query ends at the next lower (available) index compared to the
|
|
||||||
// IndexOffset. In the case of a zero index_offset, the query will start
|
|
||||||
// with the oldest payment when paginating forwards, or will end with
|
|
||||||
// the most recent payment when paginating backwards.
|
|
||||||
IndexOffset uint64
|
|
||||||
|
|
||||||
// MaxPayments is the maximal number of payments returned in the
|
|
||||||
// payments query.
|
|
||||||
MaxPayments uint64
|
|
||||||
|
|
||||||
// Reversed gives a meaning to the IndexOffset. If reversed is set to
|
|
||||||
// true, the query will fetch payments with indices lower than the
|
|
||||||
// IndexOffset, otherwise, it will return payments with indices greater
|
|
||||||
// than the IndexOffset.
|
|
||||||
Reversed bool
|
|
||||||
|
|
||||||
// If IncludeIncomplete is true, then return payments that have not yet
|
|
||||||
// fully completed. This means that pending payments, as well as failed
|
|
||||||
// payments will show up if this field is set to true.
|
|
||||||
IncludeIncomplete bool
|
|
||||||
|
|
||||||
// CountTotal indicates that all payments currently present in the
|
|
||||||
// payment index (complete and incomplete) should be counted.
|
|
||||||
CountTotal bool
|
|
||||||
|
|
||||||
// CreationDateStart, expressed in Unix seconds, if set, filters out
|
|
||||||
// all payments with a creation date greater than or equal to it.
|
|
||||||
CreationDateStart int64
|
|
||||||
|
|
||||||
// CreationDateEnd, expressed in Unix seconds, if set, filters out all
|
|
||||||
// payments with a creation date less than or equal to it.
|
|
||||||
CreationDateEnd int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// PaymentsResponse contains the result of a query to the payments database.
|
|
||||||
// It includes the set of payments that match the query and integers which
|
|
||||||
// represent the index of the first and last item returned in the series of
|
|
||||||
// payments. These integers allow callers to resume their query in the event
|
|
||||||
// that the query's response exceeds the max number of returnable events.
|
|
||||||
type PaymentsResponse struct {
|
|
||||||
// Payments is the set of payments returned from the database for the
|
|
||||||
// PaymentsQuery.
|
|
||||||
Payments []*MPPayment
|
|
||||||
|
|
||||||
// FirstIndexOffset is the index of the first element in the set of
|
|
||||||
// returned MPPayments. Callers can use this to resume their query
|
|
||||||
// in the event that the slice has too many events to fit into a single
|
|
||||||
// response. The offset can be used to continue reverse pagination.
|
|
||||||
FirstIndexOffset uint64
|
|
||||||
|
|
||||||
// LastIndexOffset is the index of the last element in the set of
|
|
||||||
// returned MPPayments. Callers can use this to resume their query
|
|
||||||
// in the event that the slice has too many events to fit into a single
|
|
||||||
// response. The offset can be used to continue forward pagination.
|
|
||||||
LastIndexOffset uint64
|
|
||||||
|
|
||||||
// TotalCount represents the total number of payments that are currently
|
|
||||||
// stored in the payment database. This will only be set if the
|
|
||||||
// CountTotal field in the query was set to true.
|
|
||||||
TotalCount uint64
|
|
||||||
}
|
|
||||||
@@ -1,474 +0,0 @@
|
|||||||
package channeldb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
|
||||||
"github.com/lightningnetwork/lnd/record"
|
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
priv, _ = btcec.NewPrivateKey()
|
|
||||||
pub = priv.PubKey()
|
|
||||||
vertex = route.NewVertex(pub)
|
|
||||||
|
|
||||||
testHop1 = &route.Hop{
|
|
||||||
PubKeyBytes: vertex,
|
|
||||||
ChannelID: 12345,
|
|
||||||
OutgoingTimeLock: 111,
|
|
||||||
AmtToForward: 555,
|
|
||||||
CustomRecords: record.CustomSet{
|
|
||||||
65536: []byte{},
|
|
||||||
80001: []byte{},
|
|
||||||
},
|
|
||||||
MPP: record.NewMPP(32, [32]byte{0x42}),
|
|
||||||
Metadata: []byte{1, 2, 3},
|
|
||||||
}
|
|
||||||
|
|
||||||
testHop2 = &route.Hop{
|
|
||||||
PubKeyBytes: vertex,
|
|
||||||
ChannelID: 12345,
|
|
||||||
OutgoingTimeLock: 111,
|
|
||||||
AmtToForward: 555,
|
|
||||||
LegacyPayload: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
testHop3 = &route.Hop{
|
|
||||||
PubKeyBytes: route.NewVertex(pub),
|
|
||||||
ChannelID: 12345,
|
|
||||||
OutgoingTimeLock: 111,
|
|
||||||
AmtToForward: 555,
|
|
||||||
CustomRecords: record.CustomSet{
|
|
||||||
65536: []byte{},
|
|
||||||
80001: []byte{},
|
|
||||||
},
|
|
||||||
AMP: record.NewAMP([32]byte{0x69}, [32]byte{0x42}, 1),
|
|
||||||
Metadata: []byte{1, 2, 3},
|
|
||||||
}
|
|
||||||
|
|
||||||
testRoute = route.Route{
|
|
||||||
TotalTimeLock: 123,
|
|
||||||
TotalAmount: 1234567,
|
|
||||||
SourcePubKey: vertex,
|
|
||||||
Hops: []*route.Hop{
|
|
||||||
testHop2,
|
|
||||||
testHop1,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
testBlindedRoute = route.Route{
|
|
||||||
TotalTimeLock: 150,
|
|
||||||
TotalAmount: 1000,
|
|
||||||
SourcePubKey: vertex,
|
|
||||||
Hops: []*route.Hop{
|
|
||||||
{
|
|
||||||
PubKeyBytes: vertex,
|
|
||||||
ChannelID: 9876,
|
|
||||||
OutgoingTimeLock: 120,
|
|
||||||
AmtToForward: 900,
|
|
||||||
EncryptedData: []byte{1, 3, 3},
|
|
||||||
BlindingPoint: pub,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
PubKeyBytes: vertex,
|
|
||||||
EncryptedData: []byte{3, 2, 1},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
PubKeyBytes: vertex,
|
|
||||||
Metadata: []byte{4, 5, 6},
|
|
||||||
AmtToForward: 500,
|
|
||||||
OutgoingTimeLock: 100,
|
|
||||||
TotalAmtMsat: 500,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// assertRouteEquals compares to routes for equality and returns an error if
|
|
||||||
// they are not equal.
|
|
||||||
func assertRouteEqual(a, b *route.Route) error {
|
|
||||||
if !reflect.DeepEqual(a, b) {
|
|
||||||
return fmt.Errorf("HTLCAttemptInfos don't match: %v vs %v",
|
|
||||||
spew.Sdump(a), spew.Sdump(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestQueryPayments tests retrieval of payments with forwards and reversed
|
|
||||||
// queries.
|
|
||||||
func TestQueryPayments(t *testing.T) {
|
|
||||||
// Define table driven test for QueryPayments.
|
|
||||||
// Test payments have sequence indices [1, 3, 4, 5, 6, 7].
|
|
||||||
// Note that the payment with index 7 has the same payment hash as 6,
|
|
||||||
// and is stored in a nested bucket within payment 6 rather than being
|
|
||||||
// its own entry in the payments bucket. We do this to test retrieval
|
|
||||||
// of legacy payments.
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
query PaymentsQuery
|
|
||||||
firstIndex uint64
|
|
||||||
lastIndex uint64
|
|
||||||
|
|
||||||
// expectedSeqNrs contains the set of sequence numbers we expect
|
|
||||||
// our query to return.
|
|
||||||
expectedSeqNrs []uint64
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "IndexOffset at the end of the payments range",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 7,
|
|
||||||
MaxPayments: 7,
|
|
||||||
Reversed: false,
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
},
|
|
||||||
firstIndex: 0,
|
|
||||||
lastIndex: 0,
|
|
||||||
expectedSeqNrs: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "query in forwards order, start at beginning",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 0,
|
|
||||||
MaxPayments: 2,
|
|
||||||
Reversed: false,
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
},
|
|
||||||
firstIndex: 1,
|
|
||||||
lastIndex: 3,
|
|
||||||
expectedSeqNrs: []uint64{1, 3},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "query in forwards order, start at end, overflow",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 6,
|
|
||||||
MaxPayments: 2,
|
|
||||||
Reversed: false,
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
},
|
|
||||||
firstIndex: 7,
|
|
||||||
lastIndex: 7,
|
|
||||||
expectedSeqNrs: []uint64{7},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "start at offset index outside of payments",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 20,
|
|
||||||
MaxPayments: 2,
|
|
||||||
Reversed: false,
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
},
|
|
||||||
firstIndex: 0,
|
|
||||||
lastIndex: 0,
|
|
||||||
expectedSeqNrs: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "overflow in forwards order",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 4,
|
|
||||||
MaxPayments: math.MaxUint64,
|
|
||||||
Reversed: false,
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
},
|
|
||||||
firstIndex: 5,
|
|
||||||
lastIndex: 7,
|
|
||||||
expectedSeqNrs: []uint64{5, 6, 7},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "start at offset index outside of payments, " +
|
|
||||||
"reversed order",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 9,
|
|
||||||
MaxPayments: 2,
|
|
||||||
Reversed: true,
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
},
|
|
||||||
firstIndex: 6,
|
|
||||||
lastIndex: 7,
|
|
||||||
expectedSeqNrs: []uint64{6, 7},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "query in reverse order, start at end",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 0,
|
|
||||||
MaxPayments: 2,
|
|
||||||
Reversed: true,
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
},
|
|
||||||
firstIndex: 6,
|
|
||||||
lastIndex: 7,
|
|
||||||
expectedSeqNrs: []uint64{6, 7},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "query in reverse order, starting in middle",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 4,
|
|
||||||
MaxPayments: 2,
|
|
||||||
Reversed: true,
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
},
|
|
||||||
firstIndex: 1,
|
|
||||||
lastIndex: 3,
|
|
||||||
expectedSeqNrs: []uint64{1, 3},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "query in reverse order, starting in middle, " +
|
|
||||||
"with underflow",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 4,
|
|
||||||
MaxPayments: 5,
|
|
||||||
Reversed: true,
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
},
|
|
||||||
firstIndex: 1,
|
|
||||||
lastIndex: 3,
|
|
||||||
expectedSeqNrs: []uint64{1, 3},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "all payments in reverse, order maintained",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 0,
|
|
||||||
MaxPayments: 7,
|
|
||||||
Reversed: true,
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
},
|
|
||||||
firstIndex: 1,
|
|
||||||
lastIndex: 7,
|
|
||||||
expectedSeqNrs: []uint64{1, 3, 4, 5, 6, 7},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "exclude incomplete payments",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 0,
|
|
||||||
MaxPayments: 7,
|
|
||||||
Reversed: false,
|
|
||||||
IncludeIncomplete: false,
|
|
||||||
},
|
|
||||||
firstIndex: 7,
|
|
||||||
lastIndex: 7,
|
|
||||||
expectedSeqNrs: []uint64{7},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "query payments at index gap",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 1,
|
|
||||||
MaxPayments: 7,
|
|
||||||
Reversed: false,
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
},
|
|
||||||
firstIndex: 3,
|
|
||||||
lastIndex: 7,
|
|
||||||
expectedSeqNrs: []uint64{3, 4, 5, 6, 7},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "query payments reverse before index gap",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 3,
|
|
||||||
MaxPayments: 7,
|
|
||||||
Reversed: true,
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
},
|
|
||||||
firstIndex: 1,
|
|
||||||
lastIndex: 1,
|
|
||||||
expectedSeqNrs: []uint64{1},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "query payments reverse on index gap",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 2,
|
|
||||||
MaxPayments: 7,
|
|
||||||
Reversed: true,
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
},
|
|
||||||
firstIndex: 1,
|
|
||||||
lastIndex: 1,
|
|
||||||
expectedSeqNrs: []uint64{1},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "query payments forward on index gap",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 2,
|
|
||||||
MaxPayments: 2,
|
|
||||||
Reversed: false,
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
},
|
|
||||||
firstIndex: 3,
|
|
||||||
lastIndex: 4,
|
|
||||||
expectedSeqNrs: []uint64{3, 4},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "query in forwards order, with start creation " +
|
|
||||||
"time",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 0,
|
|
||||||
MaxPayments: 2,
|
|
||||||
Reversed: false,
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
CreationDateStart: 5,
|
|
||||||
},
|
|
||||||
firstIndex: 5,
|
|
||||||
lastIndex: 6,
|
|
||||||
expectedSeqNrs: []uint64{5, 6},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "query in forwards order, with start creation " +
|
|
||||||
"time at end, overflow",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 0,
|
|
||||||
MaxPayments: 2,
|
|
||||||
Reversed: false,
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
CreationDateStart: 7,
|
|
||||||
},
|
|
||||||
firstIndex: 7,
|
|
||||||
lastIndex: 7,
|
|
||||||
expectedSeqNrs: []uint64{7},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "query with start and end creation time",
|
|
||||||
query: PaymentsQuery{
|
|
||||||
IndexOffset: 9,
|
|
||||||
MaxPayments: math.MaxUint64,
|
|
||||||
Reversed: true,
|
|
||||||
IncludeIncomplete: true,
|
|
||||||
CreationDateStart: 3,
|
|
||||||
CreationDateEnd: 5,
|
|
||||||
},
|
|
||||||
firstIndex: 3,
|
|
||||||
lastIndex: 5,
|
|
||||||
expectedSeqNrs: []uint64{3, 4, 5},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
db, err := MakeTestDB(t)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Initialize the payment database.
|
|
||||||
paymentDB, err := NewKVPaymentsDB(db)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Make a preliminary query to make sure it's ok to
|
|
||||||
// query when we have no payments.
|
|
||||||
resp, err := paymentDB.QueryPayments(ctx, tt.query)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Len(t, resp.Payments, 0)
|
|
||||||
|
|
||||||
// Populate the database with a set of test payments.
|
|
||||||
// We create 6 original payments, deleting the payment
|
|
||||||
// at index 2 so that we cover the case where sequence
|
|
||||||
// numbers are missing. We also add a duplicate payment
|
|
||||||
// to the last payment added to test the legacy case
|
|
||||||
// where we have duplicates in the nested duplicates
|
|
||||||
// bucket.
|
|
||||||
nonDuplicatePayments := 6
|
|
||||||
|
|
||||||
for i := 0; i < nonDuplicatePayments; i++ {
|
|
||||||
// Generate a test payment.
|
|
||||||
info, _, preimg, err := genInfo(t)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to create test "+
|
|
||||||
"payment: %v", err)
|
|
||||||
}
|
|
||||||
// Override creation time to allow for testing
|
|
||||||
// of CreationDateStart and CreationDateEnd.
|
|
||||||
info.CreationTime = time.Unix(int64(i+1), 0)
|
|
||||||
|
|
||||||
// Create a new payment entry in the database.
|
|
||||||
err = paymentDB.InitPayment(
|
|
||||||
info.PaymentIdentifier, info,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Immediately delete the payment with index 2.
|
|
||||||
if i == 1 {
|
|
||||||
pmt, err := paymentDB.FetchPayment(
|
|
||||||
info.PaymentIdentifier,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
deletePayment(
|
|
||||||
t, db, info.PaymentIdentifier,
|
|
||||||
pmt.SequenceNum,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are on the last payment entry, add a
|
|
||||||
// duplicate payment with sequence number equal
|
|
||||||
// to the parent payment + 1. Note that
|
|
||||||
// duplicate payments will always be succeeded.
|
|
||||||
if i == (nonDuplicatePayments - 1) {
|
|
||||||
pmt, err := paymentDB.FetchPayment(
|
|
||||||
info.PaymentIdentifier,
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
appendDuplicatePayment(
|
|
||||||
t, paymentDB.db,
|
|
||||||
info.PaymentIdentifier,
|
|
||||||
pmt.SequenceNum+1,
|
|
||||||
preimg,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch all payments in the database.
|
|
||||||
allPayments, err := paymentDB.FetchPayments()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("payments could not be fetched from "+
|
|
||||||
"database: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(allPayments) != 6 {
|
|
||||||
t.Fatalf("Number of payments received does "+
|
|
||||||
"not match expected one. Got %v, "+
|
|
||||||
"want %v.", len(allPayments), 6)
|
|
||||||
}
|
|
||||||
|
|
||||||
querySlice, err := paymentDB.QueryPayments(
|
|
||||||
ctx, tt.query,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if tt.firstIndex != querySlice.FirstIndexOffset ||
|
|
||||||
tt.lastIndex != querySlice.LastIndexOffset {
|
|
||||||
|
|
||||||
t.Errorf("First or last index does not match "+
|
|
||||||
"expected index. Want (%d, %d), "+
|
|
||||||
"got (%d, %d).",
|
|
||||||
tt.firstIndex, tt.lastIndex,
|
|
||||||
querySlice.FirstIndexOffset,
|
|
||||||
querySlice.LastIndexOffset)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(querySlice.Payments) != len(tt.expectedSeqNrs) {
|
|
||||||
t.Errorf("expected: %v payments, got: %v",
|
|
||||||
len(tt.expectedSeqNrs),
|
|
||||||
len(querySlice.Payments))
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, seqNr := range tt.expectedSeqNrs {
|
|
||||||
q := querySlice.Payments[i]
|
|
||||||
if seqNr != q.SequenceNum {
|
|
||||||
t.Errorf("sequence numbers do not "+
|
|
||||||
"match, got %v, want %v",
|
|
||||||
q.SequenceNum, seqNr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
-2
@@ -927,7 +927,7 @@ type DatabaseInstances struct {
|
|||||||
|
|
||||||
// KVPaymentsDB is the database that stores all payment related
|
// KVPaymentsDB is the database that stores all payment related
|
||||||
// information.
|
// information.
|
||||||
KVPaymentsDB *channeldb.KVPaymentsDB
|
KVPaymentsDB *paymentsdb.KVPaymentsDB
|
||||||
|
|
||||||
// MacaroonDB is the database that stores macaroon root keys.
|
// MacaroonDB is the database that stores macaroon root keys.
|
||||||
MacaroonDB kvdb.Backend
|
MacaroonDB kvdb.Backend
|
||||||
@@ -1225,7 +1225,7 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
|
|||||||
cfg.KeepFailedPaymentAttempts,
|
cfg.KeepFailedPaymentAttempts,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
kvPaymentsDB, err := channeldb.NewKVPaymentsDB(
|
kvPaymentsDB, err := paymentsdb.NewKVPaymentsDB(
|
||||||
dbs.ChanStateDB,
|
dbs.ChanStateDB,
|
||||||
paymentsDBOptions...,
|
paymentsDBOptions...,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
|
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||||
"github.com/lightningnetwork/lnd/record"
|
"github.com/lightningnetwork/lnd/record"
|
||||||
"github.com/lightningnetwork/lnd/routing"
|
"github.com/lightningnetwork/lnd/routing"
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
"github.com/lightningnetwork/lnd/routing/route"
|
||||||
@@ -1488,7 +1489,7 @@ func UnmarshalAMP(reqAMP *lnrpc.AMPRecord) (*record.AMP, error) {
|
|||||||
|
|
||||||
// MarshalHTLCAttempt constructs an RPC HTLCAttempt from the db representation.
|
// MarshalHTLCAttempt constructs an RPC HTLCAttempt from the db representation.
|
||||||
func (r *RouterBackend) MarshalHTLCAttempt(
|
func (r *RouterBackend) MarshalHTLCAttempt(
|
||||||
htlc channeldb.HTLCAttempt) (*lnrpc.HTLCAttempt, error) {
|
htlc paymentsdb.HTLCAttempt) (*lnrpc.HTLCAttempt, error) {
|
||||||
|
|
||||||
route, err := r.MarshallRoute(&htlc.Route)
|
route, err := r.MarshallRoute(&htlc.Route)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1529,7 +1530,7 @@ func (r *RouterBackend) MarshalHTLCAttempt(
|
|||||||
|
|
||||||
// marshallHtlcFailure marshalls htlc fail info from the database to its rpc
|
// marshallHtlcFailure marshalls htlc fail info from the database to its rpc
|
||||||
// representation.
|
// representation.
|
||||||
func marshallHtlcFailure(failure *channeldb.HTLCFailInfo) (*lnrpc.Failure,
|
func marshallHtlcFailure(failure *paymentsdb.HTLCFailInfo) (*lnrpc.Failure,
|
||||||
error) {
|
error) {
|
||||||
|
|
||||||
rpcFailure := &lnrpc.Failure{
|
rpcFailure := &lnrpc.Failure{
|
||||||
@@ -1537,16 +1538,16 @@ func marshallHtlcFailure(failure *channeldb.HTLCFailInfo) (*lnrpc.Failure,
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch failure.Reason {
|
switch failure.Reason {
|
||||||
case channeldb.HTLCFailUnknown:
|
case paymentsdb.HTLCFailUnknown:
|
||||||
rpcFailure.Code = lnrpc.Failure_UNKNOWN_FAILURE
|
rpcFailure.Code = lnrpc.Failure_UNKNOWN_FAILURE
|
||||||
|
|
||||||
case channeldb.HTLCFailUnreadable:
|
case paymentsdb.HTLCFailUnreadable:
|
||||||
rpcFailure.Code = lnrpc.Failure_UNREADABLE_FAILURE
|
rpcFailure.Code = lnrpc.Failure_UNREADABLE_FAILURE
|
||||||
|
|
||||||
case channeldb.HTLCFailInternal:
|
case paymentsdb.HTLCFailInternal:
|
||||||
rpcFailure.Code = lnrpc.Failure_INTERNAL_FAILURE
|
rpcFailure.Code = lnrpc.Failure_INTERNAL_FAILURE
|
||||||
|
|
||||||
case channeldb.HTLCFailMessage:
|
case paymentsdb.HTLCFailMessage:
|
||||||
err := marshallWireError(failure.Message, rpcFailure)
|
err := marshallWireError(failure.Message, rpcFailure)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -1743,7 +1744,7 @@ func marshallChannelUpdate(update *lnwire.ChannelUpdate1) *lnrpc.ChannelUpdate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MarshallPayment marshall a payment to its rpc representation.
|
// MarshallPayment marshall a payment to its rpc representation.
|
||||||
func (r *RouterBackend) MarshallPayment(payment *channeldb.MPPayment) (
|
func (r *RouterBackend) MarshallPayment(payment *paymentsdb.MPPayment) (
|
||||||
*lnrpc.Payment, error) {
|
*lnrpc.Payment, error) {
|
||||||
|
|
||||||
// Fetch the payment's preimage and the total paid in fees.
|
// Fetch the payment's preimage and the total paid in fees.
|
||||||
@@ -1813,11 +1814,11 @@ func (r *RouterBackend) MarshallPayment(payment *channeldb.MPPayment) (
|
|||||||
|
|
||||||
// convertPaymentStatus converts a channeldb.PaymentStatus to the type expected
|
// convertPaymentStatus converts a channeldb.PaymentStatus to the type expected
|
||||||
// by the RPC.
|
// by the RPC.
|
||||||
func convertPaymentStatus(dbStatus channeldb.PaymentStatus, useInit bool) (
|
func convertPaymentStatus(dbStatus paymentsdb.PaymentStatus, useInit bool) (
|
||||||
lnrpc.Payment_PaymentStatus, error) {
|
lnrpc.Payment_PaymentStatus, error) {
|
||||||
|
|
||||||
switch dbStatus {
|
switch dbStatus {
|
||||||
case channeldb.StatusInitiated:
|
case paymentsdb.StatusInitiated:
|
||||||
// If the client understands the new status, return it.
|
// If the client understands the new status, return it.
|
||||||
if useInit {
|
if useInit {
|
||||||
return lnrpc.Payment_INITIATED, nil
|
return lnrpc.Payment_INITIATED, nil
|
||||||
@@ -1826,13 +1827,13 @@ func convertPaymentStatus(dbStatus channeldb.PaymentStatus, useInit bool) (
|
|||||||
// Otherwise remain the old behavior.
|
// Otherwise remain the old behavior.
|
||||||
return lnrpc.Payment_IN_FLIGHT, nil
|
return lnrpc.Payment_IN_FLIGHT, nil
|
||||||
|
|
||||||
case channeldb.StatusInFlight:
|
case paymentsdb.StatusInFlight:
|
||||||
return lnrpc.Payment_IN_FLIGHT, nil
|
return lnrpc.Payment_IN_FLIGHT, nil
|
||||||
|
|
||||||
case channeldb.StatusSucceeded:
|
case paymentsdb.StatusSucceeded:
|
||||||
return lnrpc.Payment_SUCCEEDED, nil
|
return lnrpc.Payment_SUCCEEDED, nil
|
||||||
|
|
||||||
case channeldb.StatusFailed:
|
case paymentsdb.StatusFailed:
|
||||||
return lnrpc.Payment_FAILED, nil
|
return lnrpc.Payment_FAILED, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import (
|
|||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||||
"github.com/lightningnetwork/lnd/aliasmgr"
|
"github.com/lightningnetwork/lnd/aliasmgr"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
|
||||||
"github.com/lightningnetwork/lnd/fn/v2"
|
"github.com/lightningnetwork/lnd/fn/v2"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
|
||||||
@@ -927,7 +926,7 @@ func (s *Server) SendToRouteV2(ctx context.Context,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var attempt *channeldb.HTLCAttempt
|
var attempt *paymentsdb.HTLCAttempt
|
||||||
|
|
||||||
// Pass route to the router. This call returns the full htlc attempt
|
// Pass route to the router. This call returns the full htlc attempt
|
||||||
// information as it is stored in the database. It is possible that both
|
// information as it is stored in the database. It is possible that both
|
||||||
@@ -1449,17 +1448,17 @@ func (s *Server) trackPaymentStream(context context.Context,
|
|||||||
// No more payment updates.
|
// No more payment updates.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
result := item.(*channeldb.MPPayment)
|
result := item.(*paymentsdb.MPPayment)
|
||||||
|
|
||||||
log.Tracef("Payment %v updated to state %v",
|
log.Tracef("Payment %v updated to state %v",
|
||||||
result.Info.PaymentIdentifier, result.Status)
|
result.Info.PaymentIdentifier, result.Status)
|
||||||
|
|
||||||
// Skip in-flight updates unless requested.
|
// Skip in-flight updates unless requested.
|
||||||
if noInflightUpdates {
|
if noInflightUpdates {
|
||||||
if result.Status == channeldb.StatusInitiated {
|
if result.Status == paymentsdb.StatusInitiated {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if result.Status == channeldb.StatusInFlight {
|
if result.Status == paymentsdb.StatusInFlight {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
graphdb "github.com/lightningnetwork/lnd/graph/db"
|
graphdb "github.com/lightningnetwork/lnd/graph/db"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
|
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||||
"github.com/lightningnetwork/lnd/queue"
|
"github.com/lightningnetwork/lnd/queue"
|
||||||
"github.com/lightningnetwork/lnd/routing"
|
"github.com/lightningnetwork/lnd/routing"
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
"github.com/lightningnetwork/lnd/routing/route"
|
||||||
@@ -129,13 +130,13 @@ func TestTrackPaymentsInflightUpdates(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// Enqueue some payment updates on the mock.
|
// Enqueue some payment updates on the mock.
|
||||||
towerMock.queue.ChanIn() <- &channeldb.MPPayment{
|
towerMock.queue.ChanIn() <- &paymentsdb.MPPayment{
|
||||||
Info: &channeldb.PaymentCreationInfo{},
|
Info: &channeldb.PaymentCreationInfo{},
|
||||||
Status: channeldb.StatusInFlight,
|
Status: paymentsdb.StatusInFlight,
|
||||||
}
|
}
|
||||||
towerMock.queue.ChanIn() <- &channeldb.MPPayment{
|
towerMock.queue.ChanIn() <- &paymentsdb.MPPayment{
|
||||||
Info: &channeldb.PaymentCreationInfo{},
|
Info: &channeldb.PaymentCreationInfo{},
|
||||||
Status: channeldb.StatusSucceeded,
|
Status: paymentsdb.StatusSucceeded,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait until there's 2 updates or the deadline is exceeded.
|
// Wait until there's 2 updates or the deadline is exceeded.
|
||||||
@@ -191,13 +192,13 @@ func TestTrackPaymentsNoInflightUpdates(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// Enqueue some payment updates on the mock.
|
// Enqueue some payment updates on the mock.
|
||||||
towerMock.queue.ChanIn() <- &channeldb.MPPayment{
|
towerMock.queue.ChanIn() <- &paymentsdb.MPPayment{
|
||||||
Info: &channeldb.PaymentCreationInfo{},
|
Info: &channeldb.PaymentCreationInfo{},
|
||||||
Status: channeldb.StatusInFlight,
|
Status: paymentsdb.StatusInFlight,
|
||||||
}
|
}
|
||||||
towerMock.queue.ChanIn() <- &channeldb.MPPayment{
|
towerMock.queue.ChanIn() <- &paymentsdb.MPPayment{
|
||||||
Info: &channeldb.PaymentCreationInfo{},
|
Info: &channeldb.PaymentCreationInfo{},
|
||||||
Status: channeldb.StatusSucceeded,
|
Status: paymentsdb.StatusSucceeded,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait until there's 1 update or the deadline is exceeded.
|
// Wait until there's 1 update or the deadline is exceeded.
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
package paymentsdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Big endian is the preferred byte order, due to cursor scans over
|
||||||
|
// integer keys iterating in order.
|
||||||
|
var byteOrder = binary.BigEndian
|
||||||
|
|
||||||
|
// UnknownElementType is an alias for channeldb.UnknownElementType.
|
||||||
|
type UnknownElementType = channeldb.UnknownElementType
|
||||||
|
|
||||||
|
// ReadElement deserializes a single element from the provided io.Reader.
|
||||||
|
func ReadElement(r io.Reader, element interface{}) error {
|
||||||
|
err := channeldb.ReadElement(r, element)
|
||||||
|
switch {
|
||||||
|
|
||||||
|
// Known to channeldb codec.
|
||||||
|
case err == nil:
|
||||||
|
return nil
|
||||||
|
|
||||||
|
// Fail if error is not UnknownElementType.
|
||||||
|
default:
|
||||||
|
if _, ok := err.(UnknownElementType); !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process any paymentsdb-specific extensions to the codec.
|
||||||
|
switch e := element.(type) {
|
||||||
|
|
||||||
|
case *paymentIndexType:
|
||||||
|
if err := binary.Read(r, byteOrder, e); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type is still unknown to paymentsdb extensions, fail.
|
||||||
|
default:
|
||||||
|
return channeldb.NewUnknownElementType(
|
||||||
|
"ReadElement", element,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteElement serializes a single element into the provided io.Writer.
|
||||||
|
func WriteElement(w io.Writer, element interface{}) error {
|
||||||
|
err := channeldb.WriteElement(w, element)
|
||||||
|
switch {
|
||||||
|
|
||||||
|
// Known to channeldb codec.
|
||||||
|
case err == nil:
|
||||||
|
return nil
|
||||||
|
|
||||||
|
// Fail if error is not UnknownElementType.
|
||||||
|
default:
|
||||||
|
if _, ok := err.(UnknownElementType); !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process any paymentsdb-specific extensions to the codec.
|
||||||
|
switch e := element.(type) {
|
||||||
|
|
||||||
|
case paymentIndexType:
|
||||||
|
if err := binary.Write(w, byteOrder, e); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type is still unknown to paymentsdb extensions, fail.
|
||||||
|
default:
|
||||||
|
return channeldb.NewUnknownElementType(
|
||||||
|
"WriteElement", element,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteElements serializes a variadic list of elements into the given
|
||||||
|
// io.Writer.
|
||||||
|
func WriteElements(w io.Writer, elements ...interface{}) error {
|
||||||
|
for _, element := range elements {
|
||||||
|
if err := WriteElement(w, element); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadElements deserializes the provided io.Reader into a variadic list of
|
||||||
|
// target elements.
|
||||||
|
func ReadElements(r io.Reader, elements ...interface{}) error {
|
||||||
|
for _, element := range elements {
|
||||||
|
if err := ReadElement(r, element); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// deserializeTime deserializes time as unix nanoseconds.
|
||||||
|
func deserializeTime(r io.Reader) (time.Time, error) {
|
||||||
|
var scratch [8]byte
|
||||||
|
if _, err := io.ReadFull(r, scratch[:]); err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to time.Time. Interpret unix nano time zero as a zero
|
||||||
|
// time.Time value.
|
||||||
|
unixNano := byteOrder.Uint64(scratch[:])
|
||||||
|
if unixNano == 0 {
|
||||||
|
return time.Time{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return time.Unix(0, int64(unixNano)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// serializeTime serializes time as unix nanoseconds.
|
||||||
|
func serializeTime(w io.Writer, t time.Time) error {
|
||||||
|
var scratch [8]byte
|
||||||
|
|
||||||
|
// Convert to unix nano seconds, but only if time is non-zero. Calling
|
||||||
|
// UnixNano() on a zero time yields an undefined result.
|
||||||
|
var unixNano int64
|
||||||
|
if !t.IsZero() {
|
||||||
|
unixNano = t.UnixNano()
|
||||||
|
}
|
||||||
|
|
||||||
|
byteOrder.PutUint64(scratch[:], uint64(unixNano))
|
||||||
|
_, err := w.Write(scratch[:])
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package channeldb
|
package paymentsdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/kvdb"
|
"github.com/lightningnetwork/lnd/kvdb"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
"github.com/lightningnetwork/lnd/routing/route"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ func fetchDuplicatePaymentStatus(bucket kvdb.RBucket) (PaymentStatus, error) {
|
|||||||
return StatusInFlight, nil
|
return StatusInFlight, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0, paymentsdb.ErrPaymentNotInitiated
|
return 0, ErrPaymentNotInitiated
|
||||||
}
|
}
|
||||||
|
|
||||||
func deserializeDuplicateHTLCAttemptInfo(r io.Reader) (
|
func deserializeDuplicateHTLCAttemptInfo(r io.Reader) (
|
||||||
@@ -94,11 +94,11 @@ func deserializeDuplicateHTLCAttemptInfo(r io.Reader) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deserializeDuplicatePaymentCreationInfo(r io.Reader) (
|
func deserializeDuplicatePaymentCreationInfo(r io.Reader) (
|
||||||
*PaymentCreationInfo, error) {
|
*channeldb.PaymentCreationInfo, error) {
|
||||||
|
|
||||||
var scratch [8]byte
|
var scratch [8]byte
|
||||||
|
|
||||||
c := &PaymentCreationInfo{}
|
c := &channeldb.PaymentCreationInfo{}
|
||||||
|
|
||||||
if _, err := io.ReadFull(r, c.PaymentIdentifier[:]); err != nil {
|
if _, err := io.ReadFull(r, c.PaymentIdentifier[:]); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -157,10 +157,10 @@ func fetchDuplicatePayment(bucket kvdb.RBucket) (*MPPayment, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get failure reason if available.
|
// Get failure reason if available.
|
||||||
var failureReason *FailureReason
|
var failureReason *channeldb.FailureReason
|
||||||
b = bucket.Get(duplicatePaymentFailInfoKey)
|
b = bucket.Get(duplicatePaymentFailInfoKey)
|
||||||
if b != nil {
|
if b != nil {
|
||||||
reason := FailureReason(b[0])
|
reason := channeldb.FailureReason(b[0])
|
||||||
failureReason = &reason
|
failureReason = &reason
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package channeldb
|
package paymentsdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -13,10 +13,10 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/kvdb"
|
"github.com/lightningnetwork/lnd/kvdb"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
|
||||||
"github.com/lightningnetwork/lnd/record"
|
"github.com/lightningnetwork/lnd/record"
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
"github.com/lightningnetwork/lnd/routing/route"
|
||||||
"github.com/lightningnetwork/lnd/tlv"
|
"github.com/lightningnetwork/lnd/tlv"
|
||||||
@@ -131,15 +131,15 @@ type KVPaymentsDB struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// defaultKVStoreOptions returns the default options for the KV store.
|
// defaultKVStoreOptions returns the default options for the KV store.
|
||||||
func defaultKVStoreOptions() *paymentsdb.StoreOptions {
|
func defaultKVStoreOptions() *StoreOptions {
|
||||||
return &paymentsdb.StoreOptions{
|
return &StoreOptions{
|
||||||
KeepFailedPaymentAttempts: false,
|
KeepFailedPaymentAttempts: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewKVPaymentsDB creates a new KVStore for payments.
|
// NewKVPaymentsDB creates a new KVStore for payments.
|
||||||
func NewKVPaymentsDB(db kvdb.Backend,
|
func NewKVPaymentsDB(db kvdb.Backend,
|
||||||
options ...paymentsdb.OptionModifier) (*KVPaymentsDB, error) {
|
options ...OptionModifier) (*KVPaymentsDB, error) {
|
||||||
|
|
||||||
opts := defaultKVStoreOptions()
|
opts := defaultKVStoreOptions()
|
||||||
for _, applyOption := range options {
|
for _, applyOption := range options {
|
||||||
@@ -186,7 +186,7 @@ func initKVStore(db kvdb.Backend) error {
|
|||||||
// method returns successfully, the payment is guaranteed to be in the InFlight
|
// method returns successfully, the payment is guaranteed to be in the InFlight
|
||||||
// state.
|
// state.
|
||||||
func (p *KVPaymentsDB) InitPayment(paymentHash lntypes.Hash,
|
func (p *KVPaymentsDB) InitPayment(paymentHash lntypes.Hash,
|
||||||
info *PaymentCreationInfo) error {
|
info *channeldb.PaymentCreationInfo) error {
|
||||||
|
|
||||||
// Obtain a new sequence number for this payment. This is used
|
// Obtain a new sequence number for this payment. This is used
|
||||||
// to sort the payments in order of creation, and also acts as
|
// to sort the payments in order of creation, and also acts as
|
||||||
@@ -229,7 +229,7 @@ func (p *KVPaymentsDB) InitPayment(paymentHash lntypes.Hash,
|
|||||||
|
|
||||||
// Otherwise, if the error is not `ErrPaymentNotInitiated`,
|
// Otherwise, if the error is not `ErrPaymentNotInitiated`,
|
||||||
// we'll return the error.
|
// we'll return the error.
|
||||||
case !errors.Is(err, paymentsdb.ErrPaymentNotInitiated):
|
case !errors.Is(err, ErrPaymentNotInitiated):
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,7 +403,7 @@ func (p *KVPaymentsDB) RegisterAttempt(paymentHash lntypes.Hash,
|
|||||||
|
|
||||||
// MPP records should not be set for attempts to blinded paths.
|
// MPP records should not be set for attempts to blinded paths.
|
||||||
if isBlinded && mpp != nil {
|
if isBlinded && mpp != nil {
|
||||||
return paymentsdb.ErrMPPRecordInBlindedPayment
|
return ErrMPPRecordInBlindedPayment
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, h := range payment.InFlightHTLCs() {
|
for _, h := range payment.InFlightHTLCs() {
|
||||||
@@ -412,7 +412,7 @@ func (p *KVPaymentsDB) RegisterAttempt(paymentHash lntypes.Hash,
|
|||||||
// If this is a blinded payment, then no existing HTLCs
|
// If this is a blinded payment, then no existing HTLCs
|
||||||
// should have MPP records.
|
// should have MPP records.
|
||||||
if isBlinded && hMpp != nil {
|
if isBlinded && hMpp != nil {
|
||||||
return paymentsdb.ErrMPPRecordInBlindedPayment
|
return ErrMPPRecordInBlindedPayment
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a blinded payment, then we just need to
|
// If this is a blinded payment, then we just need to
|
||||||
@@ -424,7 +424,7 @@ func (p *KVPaymentsDB) RegisterAttempt(paymentHash lntypes.Hash,
|
|||||||
h.Route.FinalHop().TotalAmtMsat {
|
h.Route.FinalHop().TotalAmtMsat {
|
||||||
|
|
||||||
//nolint:ll
|
//nolint:ll
|
||||||
return paymentsdb.ErrBlindedPaymentTotalAmountMismatch
|
return ErrBlindedPaymentTotalAmountMismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
continue
|
continue
|
||||||
@@ -434,12 +434,12 @@ func (p *KVPaymentsDB) RegisterAttempt(paymentHash lntypes.Hash,
|
|||||||
// We tried to register a non-MPP attempt for a MPP
|
// We tried to register a non-MPP attempt for a MPP
|
||||||
// payment.
|
// payment.
|
||||||
case mpp == nil && hMpp != nil:
|
case mpp == nil && hMpp != nil:
|
||||||
return paymentsdb.ErrMPPayment
|
return ErrMPPayment
|
||||||
|
|
||||||
// We tried to register a MPP shard for a non-MPP
|
// We tried to register a MPP shard for a non-MPP
|
||||||
// payment.
|
// payment.
|
||||||
case mpp != nil && hMpp == nil:
|
case mpp != nil && hMpp == nil:
|
||||||
return paymentsdb.ErrNonMPPayment
|
return ErrNonMPPayment
|
||||||
|
|
||||||
// Non-MPP payment, nothing more to validate.
|
// Non-MPP payment, nothing more to validate.
|
||||||
case mpp == nil:
|
case mpp == nil:
|
||||||
@@ -448,11 +448,11 @@ func (p *KVPaymentsDB) RegisterAttempt(paymentHash lntypes.Hash,
|
|||||||
|
|
||||||
// Check that MPP options match.
|
// Check that MPP options match.
|
||||||
if mpp.PaymentAddr() != hMpp.PaymentAddr() {
|
if mpp.PaymentAddr() != hMpp.PaymentAddr() {
|
||||||
return paymentsdb.ErrMPPPaymentAddrMismatch
|
return ErrMPPPaymentAddrMismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
if mpp.TotalMsat() != hMpp.TotalMsat() {
|
if mpp.TotalMsat() != hMpp.TotalMsat() {
|
||||||
return paymentsdb.ErrMPPTotalAmountMismatch
|
return ErrMPPTotalAmountMismatch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,14 +461,14 @@ func (p *KVPaymentsDB) RegisterAttempt(paymentHash lntypes.Hash,
|
|||||||
// attempt.
|
// attempt.
|
||||||
amt := attempt.Route.ReceiverAmt()
|
amt := attempt.Route.ReceiverAmt()
|
||||||
if !isBlinded && mpp == nil && amt != payment.Info.Value {
|
if !isBlinded && mpp == nil && amt != payment.Info.Value {
|
||||||
return paymentsdb.ErrValueMismatch
|
return ErrValueMismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we aren't sending more than the total payment amount.
|
// Ensure we aren't sending more than the total payment amount.
|
||||||
sentAmt, _ := payment.SentAmt()
|
sentAmt, _ := payment.SentAmt()
|
||||||
if sentAmt+amt > payment.Info.Value {
|
if sentAmt+amt > payment.Info.Value {
|
||||||
return fmt.Errorf("%w: attempted=%v, payment amount="+
|
return fmt.Errorf("%w: attempted=%v, payment amount="+
|
||||||
"%v", paymentsdb.ErrValueExceedsAmt,
|
"%v", ErrValueExceedsAmt,
|
||||||
sentAmt+amt, payment.Info.Value)
|
sentAmt+amt, payment.Info.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,12 +574,12 @@ func (p *KVPaymentsDB) updateHtlcKey(paymentHash lntypes.Hash,
|
|||||||
// Make sure the shard is not already failed or settled.
|
// Make sure the shard is not already failed or settled.
|
||||||
failKey := htlcBucketKey(htlcFailInfoKey, aid)
|
failKey := htlcBucketKey(htlcFailInfoKey, aid)
|
||||||
if htlcsBucket.Get(failKey) != nil {
|
if htlcsBucket.Get(failKey) != nil {
|
||||||
return paymentsdb.ErrAttemptAlreadyFailed
|
return ErrAttemptAlreadyFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
settleKey := htlcBucketKey(htlcSettleInfoKey, aid)
|
settleKey := htlcBucketKey(htlcSettleInfoKey, aid)
|
||||||
if htlcsBucket.Get(settleKey) != nil {
|
if htlcsBucket.Get(settleKey) != nil {
|
||||||
return paymentsdb.ErrAttemptAlreadySettled
|
return ErrAttemptAlreadySettled
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add or update the key for this htlc.
|
// Add or update the key for this htlc.
|
||||||
@@ -605,7 +605,7 @@ func (p *KVPaymentsDB) updateHtlcKey(paymentHash lntypes.Hash,
|
|||||||
// its next call for this payment hash, allowing the switch to make a
|
// its next call for this payment hash, allowing the switch to make a
|
||||||
// subsequent payment.
|
// subsequent payment.
|
||||||
func (p *KVPaymentsDB) Fail(paymentHash lntypes.Hash,
|
func (p *KVPaymentsDB) Fail(paymentHash lntypes.Hash,
|
||||||
reason FailureReason) (*MPPayment, error) {
|
reason channeldb.FailureReason) (*MPPayment, error) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
updateErr error
|
updateErr error
|
||||||
@@ -619,8 +619,8 @@ func (p *KVPaymentsDB) Fail(paymentHash lntypes.Hash,
|
|||||||
|
|
||||||
prefetchPayment(tx, paymentHash)
|
prefetchPayment(tx, paymentHash)
|
||||||
bucket, err := fetchPaymentBucketUpdate(tx, paymentHash)
|
bucket, err := fetchPaymentBucketUpdate(tx, paymentHash)
|
||||||
if errors.Is(err, paymentsdb.ErrPaymentNotInitiated) {
|
if errors.Is(err, ErrPaymentNotInitiated) {
|
||||||
updateErr = paymentsdb.ErrPaymentNotInitiated
|
updateErr = ErrPaymentNotInitiated
|
||||||
return nil
|
return nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -631,8 +631,8 @@ func (p *KVPaymentsDB) Fail(paymentHash lntypes.Hash,
|
|||||||
// failure to the KVPaymentsDB without synchronizing with
|
// failure to the KVPaymentsDB without synchronizing with
|
||||||
// other attempts.
|
// other attempts.
|
||||||
_, err = fetchPaymentStatus(bucket)
|
_, err = fetchPaymentStatus(bucket)
|
||||||
if errors.Is(err, paymentsdb.ErrPaymentNotInitiated) {
|
if errors.Is(err, ErrPaymentNotInitiated) {
|
||||||
updateErr = paymentsdb.ErrPaymentNotInitiated
|
updateErr = ErrPaymentNotInitiated
|
||||||
return nil
|
return nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -725,12 +725,12 @@ func fetchPaymentBucket(tx kvdb.RTx, paymentHash lntypes.Hash) (
|
|||||||
|
|
||||||
payments := tx.ReadBucket(paymentsRootBucket)
|
payments := tx.ReadBucket(paymentsRootBucket)
|
||||||
if payments == nil {
|
if payments == nil {
|
||||||
return nil, paymentsdb.ErrPaymentNotInitiated
|
return nil, ErrPaymentNotInitiated
|
||||||
}
|
}
|
||||||
|
|
||||||
bucket := payments.NestedReadBucket(paymentHash[:])
|
bucket := payments.NestedReadBucket(paymentHash[:])
|
||||||
if bucket == nil {
|
if bucket == nil {
|
||||||
return nil, paymentsdb.ErrPaymentNotInitiated
|
return nil, ErrPaymentNotInitiated
|
||||||
}
|
}
|
||||||
|
|
||||||
return bucket, nil
|
return bucket, nil
|
||||||
@@ -743,12 +743,12 @@ func fetchPaymentBucketUpdate(tx kvdb.RwTx, paymentHash lntypes.Hash) (
|
|||||||
|
|
||||||
payments := tx.ReadWriteBucket(paymentsRootBucket)
|
payments := tx.ReadWriteBucket(paymentsRootBucket)
|
||||||
if payments == nil {
|
if payments == nil {
|
||||||
return nil, paymentsdb.ErrPaymentNotInitiated
|
return nil, ErrPaymentNotInitiated
|
||||||
}
|
}
|
||||||
|
|
||||||
bucket := payments.NestedReadWriteBucket(paymentHash[:])
|
bucket := payments.NestedReadWriteBucket(paymentHash[:])
|
||||||
if bucket == nil {
|
if bucket == nil {
|
||||||
return nil, paymentsdb.ErrPaymentNotInitiated
|
return nil, ErrPaymentNotInitiated
|
||||||
}
|
}
|
||||||
|
|
||||||
return bucket, nil
|
return bucket, nil
|
||||||
@@ -805,7 +805,7 @@ func fetchPaymentStatus(bucket kvdb.RBucket) (PaymentStatus, error) {
|
|||||||
// Creation info should be set for all payments, regardless of state.
|
// Creation info should be set for all payments, regardless of state.
|
||||||
// If not, it is unknown.
|
// If not, it is unknown.
|
||||||
if bucket.Get(paymentCreationInfoKey) == nil {
|
if bucket.Get(paymentCreationInfoKey) == nil {
|
||||||
return 0, paymentsdb.ErrPaymentNotInitiated
|
return 0, ErrPaymentNotInitiated
|
||||||
}
|
}
|
||||||
|
|
||||||
payment, err := fetchPayment(bucket)
|
payment, err := fetchPayment(bucket)
|
||||||
@@ -943,7 +943,7 @@ func (p *KVPaymentsDB) FetchPayments() ([]*MPPayment, error) {
|
|||||||
return payments, nil
|
return payments, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchCreationInfo(bucket kvdb.RBucket) (*PaymentCreationInfo, error) {
|
func fetchCreationInfo(bucket kvdb.RBucket) (*channeldb.PaymentCreationInfo, error) {
|
||||||
b := bucket.Get(paymentCreationInfoKey)
|
b := bucket.Get(paymentCreationInfoKey)
|
||||||
if b == nil {
|
if b == nil {
|
||||||
return nil, fmt.Errorf("creation info not found")
|
return nil, fmt.Errorf("creation info not found")
|
||||||
@@ -979,10 +979,10 @@ func fetchPayment(bucket kvdb.RBucket) (*MPPayment, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get failure reason if available.
|
// Get failure reason if available.
|
||||||
var failureReason *FailureReason
|
var failureReason *channeldb.FailureReason
|
||||||
b := bucket.Get(paymentFailInfoKey)
|
b := bucket.Get(paymentFailInfoKey)
|
||||||
if b != nil {
|
if b != nil {
|
||||||
reason := FailureReason(b[0])
|
reason := channeldb.FailureReason(b[0])
|
||||||
failureReason = &reason
|
failureReason = &reason
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1051,7 +1051,7 @@ func fetchHtlcAttempts(bucket kvdb.RBucket) ([]HTLCAttempt, error) {
|
|||||||
|
|
||||||
// Sanity check that all htlcs have an attempt info.
|
// Sanity check that all htlcs have an attempt info.
|
||||||
if attemptInfoCount != len(htlcsMap) {
|
if attemptInfoCount != len(htlcsMap) {
|
||||||
return nil, paymentsdb.ErrNoAttemptInfo
|
return nil, ErrNoAttemptInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
keys := make([]uint64, len(htlcsMap))
|
keys := make([]uint64, len(htlcsMap))
|
||||||
@@ -1205,7 +1205,7 @@ func (p *KVPaymentsDB) QueryPayments(_ context.Context,
|
|||||||
|
|
||||||
// Create a paginator which reads from our sequence index bucket
|
// Create a paginator which reads from our sequence index bucket
|
||||||
// with the parameters provided by the payments query.
|
// with the parameters provided by the payments query.
|
||||||
paginator := NewPaginator(
|
paginator := channeldb.NewPaginator(
|
||||||
indexes.ReadCursor(), query.Reversed, query.IndexOffset,
|
indexes.ReadCursor(), query.Reversed, query.IndexOffset,
|
||||||
query.MaxPayments,
|
query.MaxPayments,
|
||||||
)
|
)
|
||||||
@@ -1290,7 +1290,7 @@ func fetchPaymentWithSequenceNumber(tx kvdb.RTx, paymentHash lntypes.Hash,
|
|||||||
// the payment we are actually looking for.
|
// the payment we are actually looking for.
|
||||||
seqBytes := bucket.Get(paymentSequenceKey)
|
seqBytes := bucket.Get(paymentSequenceKey)
|
||||||
if seqBytes == nil {
|
if seqBytes == nil {
|
||||||
return nil, paymentsdb.ErrNoSequenceNumber
|
return nil, ErrNoSequenceNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this top level payment has the sequence number we are looking for,
|
// If this top level payment has the sequence number we are looking for,
|
||||||
@@ -1305,7 +1305,7 @@ func fetchPaymentWithSequenceNumber(tx kvdb.RTx, paymentHash lntypes.Hash,
|
|||||||
// find a duplicate payments bucket here, something is wrong.
|
// find a duplicate payments bucket here, something is wrong.
|
||||||
dup := bucket.NestedReadBucket(duplicatePaymentsBucket)
|
dup := bucket.NestedReadBucket(duplicatePaymentsBucket)
|
||||||
if dup == nil {
|
if dup == nil {
|
||||||
return nil, paymentsdb.ErrNoDuplicateBucket
|
return nil, ErrNoDuplicateBucket
|
||||||
}
|
}
|
||||||
|
|
||||||
var duplicatePayment *MPPayment
|
var duplicatePayment *MPPayment
|
||||||
@@ -1313,7 +1313,7 @@ func fetchPaymentWithSequenceNumber(tx kvdb.RTx, paymentHash lntypes.Hash,
|
|||||||
subBucket := dup.NestedReadBucket(k)
|
subBucket := dup.NestedReadBucket(k)
|
||||||
if subBucket == nil {
|
if subBucket == nil {
|
||||||
// We one bucket for each duplicate to be found.
|
// We one bucket for each duplicate to be found.
|
||||||
return paymentsdb.ErrNoDuplicateNestedBucket
|
return ErrNoDuplicateNestedBucket
|
||||||
}
|
}
|
||||||
|
|
||||||
seqBytes := subBucket.Get(duplicatePaymentSequenceKey)
|
seqBytes := subBucket.Get(duplicatePaymentSequenceKey)
|
||||||
@@ -1342,7 +1342,7 @@ func fetchPaymentWithSequenceNumber(tx kvdb.RTx, paymentHash lntypes.Hash,
|
|||||||
// failed to find the payment with this sequence number; something is
|
// failed to find the payment with this sequence number; something is
|
||||||
// wrong.
|
// wrong.
|
||||||
if duplicatePayment == nil {
|
if duplicatePayment == nil {
|
||||||
return nil, paymentsdb.ErrDuplicateNotFound
|
return nil, ErrDuplicateNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return duplicatePayment, nil
|
return duplicatePayment, nil
|
||||||
@@ -1621,7 +1621,7 @@ func fetchSequenceNumbers(paymentBucket kvdb.RBucket) ([][]byte, error) {
|
|||||||
return sequenceNumbers, nil
|
return sequenceNumbers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func serializePaymentCreationInfo(w io.Writer, c *PaymentCreationInfo) error {
|
func serializePaymentCreationInfo(w io.Writer, c *channeldb.PaymentCreationInfo) error {
|
||||||
var scratch [8]byte
|
var scratch [8]byte
|
||||||
|
|
||||||
if _, err := w.Write(c.PaymentIdentifier[:]); err != nil {
|
if _, err := w.Write(c.PaymentIdentifier[:]); err != nil {
|
||||||
@@ -1658,12 +1658,12 @@ func serializePaymentCreationInfo(w io.Writer, c *PaymentCreationInfo) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deserializePaymentCreationInfo(r io.Reader) (*PaymentCreationInfo,
|
func deserializePaymentCreationInfo(r io.Reader) (*channeldb.PaymentCreationInfo,
|
||||||
error) {
|
error) {
|
||||||
|
|
||||||
var scratch [8]byte
|
var scratch [8]byte
|
||||||
|
|
||||||
c := &PaymentCreationInfo{}
|
c := &channeldb.PaymentCreationInfo{}
|
||||||
|
|
||||||
if _, err := io.ReadFull(r, c.PaymentIdentifier[:]); err != nil {
|
if _, err := io.ReadFull(r, c.PaymentIdentifier[:]); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package channeldb
|
package paymentsdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -13,10 +13,10 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcwallet/walletdb"
|
"github.com/btcsuite/btcwallet/walletdb"
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/kvdb"
|
"github.com/lightningnetwork/lnd/kvdb"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
|
||||||
"github.com/lightningnetwork/lnd/record"
|
"github.com/lightningnetwork/lnd/record"
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
"github.com/lightningnetwork/lnd/routing/route"
|
||||||
"github.com/lightningnetwork/lnd/tlv"
|
"github.com/lightningnetwork/lnd/tlv"
|
||||||
@@ -32,7 +32,7 @@ func genPreimage() ([32]byte, error) {
|
|||||||
return preimage, nil
|
return preimage, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func genInfo(t *testing.T) (*PaymentCreationInfo, *HTLCAttemptInfo,
|
func genInfo(t *testing.T) (*channeldb.PaymentCreationInfo, *HTLCAttemptInfo,
|
||||||
lntypes.Preimage, error) {
|
lntypes.Preimage, error) {
|
||||||
|
|
||||||
preimage, err := genPreimage()
|
preimage, err := genPreimage()
|
||||||
@@ -50,7 +50,7 @@ func genInfo(t *testing.T) (*PaymentCreationInfo, *HTLCAttemptInfo,
|
|||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
return &PaymentCreationInfo{
|
return &channeldb.PaymentCreationInfo{
|
||||||
PaymentIdentifier: rhash,
|
PaymentIdentifier: rhash,
|
||||||
Value: testRoute.ReceiverAmt(),
|
Value: testRoute.ReceiverAmt(),
|
||||||
CreationTime: time.Unix(time.Now().Unix(), 0),
|
CreationTime: time.Unix(time.Now().Unix(), 0),
|
||||||
@@ -64,11 +64,7 @@ func genInfo(t *testing.T) (*PaymentCreationInfo, *HTLCAttemptInfo,
|
|||||||
func TestKVPaymentsDBSwitchFail(t *testing.T) {
|
func TestKVPaymentsDBSwitchFail(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
db, err := MakeTestDB(t)
|
paymentDB := NewTestDB(t)
|
||||||
require.NoError(t, err, "unable to init db")
|
|
||||||
|
|
||||||
paymentDB, err := NewKVPaymentsDB(db)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
info, attempt, preimg, err := genInfo(t)
|
info, attempt, preimg, err := genInfo(t)
|
||||||
require.NoError(t, err, "unable to generate htlc message")
|
require.NoError(t, err, "unable to generate htlc message")
|
||||||
@@ -86,7 +82,7 @@ func TestKVPaymentsDBSwitchFail(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Fail the payment, which should moved it to Failed.
|
// Fail the payment, which should moved it to Failed.
|
||||||
failReason := FailureReasonNoRoute
|
failReason := channeldb.FailureReasonNoRoute
|
||||||
_, err = paymentDB.Fail(info.PaymentIdentifier, failReason)
|
_, err = paymentDB.Fail(info.PaymentIdentifier, failReason)
|
||||||
require.NoError(t, err, "unable to fail payment hash")
|
require.NoError(t, err, "unable to fail payment hash")
|
||||||
|
|
||||||
@@ -195,7 +191,7 @@ func TestKVPaymentsDBSwitchFail(t *testing.T) {
|
|||||||
// Attempt a final payment, which should now fail since the prior
|
// Attempt a final payment, which should now fail since the prior
|
||||||
// payment succeed.
|
// payment succeed.
|
||||||
err = paymentDB.InitPayment(info.PaymentIdentifier, info)
|
err = paymentDB.InitPayment(info.PaymentIdentifier, info)
|
||||||
if !errors.Is(err, paymentsdb.ErrAlreadyPaid) {
|
if !errors.Is(err, ErrAlreadyPaid) {
|
||||||
t.Fatalf("unable to send htlc message: %v", err)
|
t.Fatalf("unable to send htlc message: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,11 +201,7 @@ func TestKVPaymentsDBSwitchFail(t *testing.T) {
|
|||||||
func TestKVPaymentsDBSwitchDoubleSend(t *testing.T) {
|
func TestKVPaymentsDBSwitchDoubleSend(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
db, err := MakeTestDB(t)
|
paymentDB := NewTestDB(t)
|
||||||
require.NoError(t, err, "unable to init db")
|
|
||||||
|
|
||||||
paymentDB, err := NewKVPaymentsDB(db)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
info, attempt, preimg, err := genInfo(t)
|
info, attempt, preimg, err := genInfo(t)
|
||||||
require.NoError(t, err, "unable to generate htlc message")
|
require.NoError(t, err, "unable to generate htlc message")
|
||||||
@@ -231,7 +223,7 @@ func TestKVPaymentsDBSwitchDoubleSend(t *testing.T) {
|
|||||||
// payment hash, should result in error indicating that payment has
|
// payment hash, should result in error indicating that payment has
|
||||||
// already been sent.
|
// already been sent.
|
||||||
err = paymentDB.InitPayment(info.PaymentIdentifier, info)
|
err = paymentDB.InitPayment(info.PaymentIdentifier, info)
|
||||||
require.ErrorIs(t, err, paymentsdb.ErrPaymentExists)
|
require.ErrorIs(t, err, ErrPaymentExists)
|
||||||
|
|
||||||
// Record an attempt.
|
// Record an attempt.
|
||||||
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, attempt)
|
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, attempt)
|
||||||
@@ -249,7 +241,7 @@ func TestKVPaymentsDBSwitchDoubleSend(t *testing.T) {
|
|||||||
|
|
||||||
// Sends base htlc message which initiate StatusInFlight.
|
// Sends base htlc message which initiate StatusInFlight.
|
||||||
err = paymentDB.InitPayment(info.PaymentIdentifier, info)
|
err = paymentDB.InitPayment(info.PaymentIdentifier, info)
|
||||||
if !errors.Is(err, paymentsdb.ErrPaymentInFlight) {
|
if !errors.Is(err, ErrPaymentInFlight) {
|
||||||
t.Fatalf("payment control wrong behaviour: " +
|
t.Fatalf("payment control wrong behaviour: " +
|
||||||
"double sending must trigger ErrPaymentInFlight error")
|
"double sending must trigger ErrPaymentInFlight error")
|
||||||
}
|
}
|
||||||
@@ -272,7 +264,7 @@ func TestKVPaymentsDBSwitchDoubleSend(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
err = paymentDB.InitPayment(info.PaymentIdentifier, info)
|
err = paymentDB.InitPayment(info.PaymentIdentifier, info)
|
||||||
if !errors.Is(err, paymentsdb.ErrAlreadyPaid) {
|
if !errors.Is(err, ErrAlreadyPaid) {
|
||||||
t.Fatalf("unable to send htlc message: %v", err)
|
t.Fatalf("unable to send htlc message: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,11 +274,7 @@ func TestKVPaymentsDBSwitchDoubleSend(t *testing.T) {
|
|||||||
func TestKVPaymentsDBSuccessesWithoutInFlight(t *testing.T) {
|
func TestKVPaymentsDBSuccessesWithoutInFlight(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
db, err := MakeTestDB(t)
|
paymentDB := NewTestDB(t)
|
||||||
require.NoError(t, err, "unable to init db")
|
|
||||||
|
|
||||||
paymentDB, err := NewKVPaymentsDB(db)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
info, _, preimg, err := genInfo(t)
|
info, _, preimg, err := genInfo(t)
|
||||||
require.NoError(t, err, "unable to generate htlc message")
|
require.NoError(t, err, "unable to generate htlc message")
|
||||||
@@ -298,7 +286,7 @@ func TestKVPaymentsDBSuccessesWithoutInFlight(t *testing.T) {
|
|||||||
Preimage: preimg,
|
Preimage: preimg,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
require.ErrorIs(t, err, paymentsdb.ErrPaymentNotInitiated)
|
require.ErrorIs(t, err, ErrPaymentNotInitiated)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestKVPaymentsDBFailsWithoutInFlight checks that a strict payment
|
// TestKVPaymentsDBFailsWithoutInFlight checks that a strict payment
|
||||||
@@ -306,18 +294,16 @@ func TestKVPaymentsDBSuccessesWithoutInFlight(t *testing.T) {
|
|||||||
func TestKVPaymentsDBFailsWithoutInFlight(t *testing.T) {
|
func TestKVPaymentsDBFailsWithoutInFlight(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
db, err := MakeTestDB(t)
|
paymentDB := NewTestDB(t)
|
||||||
require.NoError(t, err, "unable to init db")
|
|
||||||
|
|
||||||
paymentDB, err := NewKVPaymentsDB(db)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
info, _, _, err := genInfo(t)
|
info, _, _, err := genInfo(t)
|
||||||
require.NoError(t, err, "unable to generate htlc message")
|
require.NoError(t, err, "unable to generate htlc message")
|
||||||
|
|
||||||
// Calling Fail should return an error.
|
// Calling Fail should return an error.
|
||||||
_, err = paymentDB.Fail(info.PaymentIdentifier, FailureReasonNoRoute)
|
_, err = paymentDB.Fail(
|
||||||
require.ErrorIs(t, err, paymentsdb.ErrPaymentNotInitiated)
|
info.PaymentIdentifier, channeldb.FailureReasonNoRoute,
|
||||||
|
)
|
||||||
|
require.ErrorIs(t, err, ErrPaymentNotInitiated)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestKVPaymentsDBDeleteNonInFlight checks that calling DeletePayments only
|
// TestKVPaymentsDBDeleteNonInFlight checks that calling DeletePayments only
|
||||||
@@ -325,17 +311,13 @@ func TestKVPaymentsDBFailsWithoutInFlight(t *testing.T) {
|
|||||||
func TestKVPaymentsDBDeleteNonInFlight(t *testing.T) {
|
func TestKVPaymentsDBDeleteNonInFlight(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
db, err := MakeTestDB(t)
|
paymentDB := NewTestDB(t)
|
||||||
require.NoError(t, err, "unable to init db")
|
|
||||||
|
|
||||||
// Create a sequence number for duplicate payments that will not collide
|
// Create a sequence number for duplicate payments that will not collide
|
||||||
// with the sequence numbers for the payments we create. These values
|
// with the sequence numbers for the payments we create. These values
|
||||||
// start at 1, so 9999 is a safe bet for this test.
|
// start at 1, so 9999 is a safe bet for this test.
|
||||||
var duplicateSeqNr = 9999
|
var duplicateSeqNr = 9999
|
||||||
|
|
||||||
paymentDB, err := NewKVPaymentsDB(db)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
payments := []struct {
|
payments := []struct {
|
||||||
failed bool
|
failed bool
|
||||||
success bool
|
success bool
|
||||||
@@ -401,7 +383,7 @@ func TestKVPaymentsDBDeleteNonInFlight(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fail the payment, which should moved it to Failed.
|
// Fail the payment, which should moved it to Failed.
|
||||||
failReason := FailureReasonNoRoute
|
failReason := channeldb.FailureReasonNoRoute
|
||||||
_, err = paymentDB.Fail(
|
_, err = paymentDB.Fail(
|
||||||
info.PaymentIdentifier, failReason,
|
info.PaymentIdentifier, failReason,
|
||||||
)
|
)
|
||||||
@@ -531,7 +513,7 @@ func TestKVPaymentsDBDeleteNonInFlight(t *testing.T) {
|
|||||||
// Finally, check that we only have a single index left in the payment
|
// Finally, check that we only have a single index left in the payment
|
||||||
// index bucket.
|
// index bucket.
|
||||||
var indexCount int
|
var indexCount int
|
||||||
err = kvdb.View(db, func(tx walletdb.ReadTx) error {
|
err = kvdb.View(paymentDB.db, func(tx walletdb.ReadTx) error {
|
||||||
index := tx.ReadBucket(paymentsIndexBucket)
|
index := tx.ReadBucket(paymentsIndexBucket)
|
||||||
|
|
||||||
return index.ForEach(func(k, v []byte) error {
|
return index.ForEach(func(k, v []byte) error {
|
||||||
@@ -549,11 +531,7 @@ func TestKVPaymentsDBDeleteNonInFlight(t *testing.T) {
|
|||||||
func TestKVPaymentsDBDeletePayments(t *testing.T) {
|
func TestKVPaymentsDBDeletePayments(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
db, err := MakeTestDB(t)
|
paymentDB := NewTestDB(t)
|
||||||
require.NoError(t, err, "unable to init db")
|
|
||||||
|
|
||||||
paymentDB, err := NewKVPaymentsDB(db)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Register three payments:
|
// Register three payments:
|
||||||
// 1. A payment with two failed attempts.
|
// 1. A payment with two failed attempts.
|
||||||
@@ -611,11 +589,7 @@ func TestKVPaymentsDBDeletePayments(t *testing.T) {
|
|||||||
func TestKVPaymentsDBDeleteSinglePayment(t *testing.T) {
|
func TestKVPaymentsDBDeleteSinglePayment(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
db, err := MakeTestDB(t)
|
paymentDB := NewTestDB(t)
|
||||||
require.NoError(t, err, "unable to init db")
|
|
||||||
|
|
||||||
paymentDB, err := NewKVPaymentsDB(db)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Register four payments:
|
// Register four payments:
|
||||||
// All payments will have one failed HTLC attempt and one HTLC attempt
|
// All payments will have one failed HTLC attempt and one HTLC attempt
|
||||||
@@ -716,13 +690,7 @@ func TestKVPaymentsDBMultiShard(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
runSubTest := func(t *testing.T, test testCase) {
|
runSubTest := func(t *testing.T, test testCase) {
|
||||||
db, err := MakeTestDB(t)
|
paymentDB := NewTestDB(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to init db: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
paymentDB, err := NewKVPaymentsDB(db)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
info, attempt, preimg, err := genInfo(t)
|
info, attempt, preimg, err := genInfo(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -785,7 +753,7 @@ func TestKVPaymentsDBMultiShard(t *testing.T) {
|
|||||||
b := *attempt
|
b := *attempt
|
||||||
b.AttemptID = 3
|
b.AttemptID = 3
|
||||||
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, &b)
|
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, &b)
|
||||||
require.ErrorIs(t, err, paymentsdb.ErrValueExceedsAmt)
|
require.ErrorIs(t, err, ErrValueExceedsAmt)
|
||||||
|
|
||||||
// Fail the second attempt.
|
// Fail the second attempt.
|
||||||
a := attempts[1]
|
a := attempts[1]
|
||||||
@@ -819,7 +787,7 @@ func TestKVPaymentsDBMultiShard(t *testing.T) {
|
|||||||
HTLCAttemptInfo: a,
|
HTLCAttemptInfo: a,
|
||||||
}
|
}
|
||||||
|
|
||||||
var firstFailReason *FailureReason
|
var firstFailReason *channeldb.FailureReason
|
||||||
if test.settleFirst {
|
if test.settleFirst {
|
||||||
_, err := paymentDB.SettleAttempt(
|
_, err := paymentDB.SettleAttempt(
|
||||||
info.PaymentIdentifier, a.AttemptID,
|
info.PaymentIdentifier, a.AttemptID,
|
||||||
@@ -859,7 +827,7 @@ func TestKVPaymentsDBMultiShard(t *testing.T) {
|
|||||||
|
|
||||||
// We also record a payment level fail, to move it into
|
// We also record a payment level fail, to move it into
|
||||||
// a terminal state.
|
// a terminal state.
|
||||||
failReason := FailureReasonNoRoute
|
failReason := channeldb.FailureReasonNoRoute
|
||||||
_, err = paymentDB.Fail(
|
_, err = paymentDB.Fail(
|
||||||
info.PaymentIdentifier, failReason,
|
info.PaymentIdentifier, failReason,
|
||||||
)
|
)
|
||||||
@@ -886,11 +854,11 @@ func TestKVPaymentsDBMultiShard(t *testing.T) {
|
|||||||
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, &b)
|
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, &b)
|
||||||
if test.settleFirst {
|
if test.settleFirst {
|
||||||
require.ErrorIs(
|
require.ErrorIs(
|
||||||
t, err, paymentsdb.ErrPaymentPendingSettled,
|
t, err, ErrPaymentPendingSettled,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
require.ErrorIs(
|
require.ErrorIs(
|
||||||
t, err, paymentsdb.ErrPaymentPendingFailed,
|
t, err, ErrPaymentPendingFailed,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -942,7 +910,7 @@ func TestKVPaymentsDBMultiShard(t *testing.T) {
|
|||||||
// failure. This is to allow multiple concurrent shard
|
// failure. This is to allow multiple concurrent shard
|
||||||
// write a terminal failure to the database without
|
// write a terminal failure to the database without
|
||||||
// syncing.
|
// syncing.
|
||||||
failReason := FailureReasonPaymentDetails
|
failReason := channeldb.FailureReasonPaymentDetails
|
||||||
_, err = paymentDB.Fail(
|
_, err = paymentDB.Fail(
|
||||||
info.PaymentIdentifier, failReason,
|
info.PaymentIdentifier, failReason,
|
||||||
)
|
)
|
||||||
@@ -960,21 +928,21 @@ func TestKVPaymentsDBMultiShard(t *testing.T) {
|
|||||||
// settled.
|
// settled.
|
||||||
case test.settleFirst && !test.settleLast:
|
case test.settleFirst && !test.settleLast:
|
||||||
finalStatus = StatusSucceeded
|
finalStatus = StatusSucceeded
|
||||||
registerErr = paymentsdb.ErrPaymentAlreadySucceeded
|
registerErr = ErrPaymentAlreadySucceeded
|
||||||
|
|
||||||
case !test.settleFirst && test.settleLast:
|
case !test.settleFirst && test.settleLast:
|
||||||
finalStatus = StatusSucceeded
|
finalStatus = StatusSucceeded
|
||||||
registerErr = paymentsdb.ErrPaymentAlreadySucceeded
|
registerErr = ErrPaymentAlreadySucceeded
|
||||||
|
|
||||||
// If both failed, we end up in a failed status.
|
// If both failed, we end up in a failed status.
|
||||||
case !test.settleFirst && !test.settleLast:
|
case !test.settleFirst && !test.settleLast:
|
||||||
finalStatus = StatusFailed
|
finalStatus = StatusFailed
|
||||||
registerErr = paymentsdb.ErrPaymentAlreadyFailed
|
registerErr = ErrPaymentAlreadyFailed
|
||||||
|
|
||||||
// Otherwise, the payment has a succeed status.
|
// Otherwise, the payment has a succeed status.
|
||||||
case test.settleFirst && test.settleLast:
|
case test.settleFirst && test.settleLast:
|
||||||
finalStatus = StatusSucceeded
|
finalStatus = StatusSucceeded
|
||||||
registerErr = paymentsdb.ErrPaymentAlreadySucceeded
|
registerErr = ErrPaymentAlreadySucceeded
|
||||||
}
|
}
|
||||||
|
|
||||||
assertPaymentStatus(
|
assertPaymentStatus(
|
||||||
@@ -1000,11 +968,7 @@ func TestKVPaymentsDBMultiShard(t *testing.T) {
|
|||||||
func TestKVPaymentsDBMPPRecordValidation(t *testing.T) {
|
func TestKVPaymentsDBMPPRecordValidation(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
db, err := MakeTestDB(t)
|
paymentDB := NewTestDB(t)
|
||||||
require.NoError(t, err, "unable to init db")
|
|
||||||
|
|
||||||
paymentDB, err := NewKVPaymentsDB(db)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
info, attempt, _, err := genInfo(t)
|
info, attempt, _, err := genInfo(t)
|
||||||
require.NoError(t, err, "unable to generate htlc message")
|
require.NoError(t, err, "unable to generate htlc message")
|
||||||
@@ -1031,21 +995,21 @@ func TestKVPaymentsDBMPPRecordValidation(t *testing.T) {
|
|||||||
b.AttemptID = 1
|
b.AttemptID = 1
|
||||||
b.Route.FinalHop().MPP = nil
|
b.Route.FinalHop().MPP = nil
|
||||||
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, &b)
|
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, &b)
|
||||||
require.ErrorIs(t, err, paymentsdb.ErrMPPayment)
|
require.ErrorIs(t, err, ErrMPPayment)
|
||||||
|
|
||||||
// Try to register attempt one with a different payment address.
|
// Try to register attempt one with a different payment address.
|
||||||
b.Route.FinalHop().MPP = record.NewMPP(
|
b.Route.FinalHop().MPP = record.NewMPP(
|
||||||
info.Value, [32]byte{2},
|
info.Value, [32]byte{2},
|
||||||
)
|
)
|
||||||
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, &b)
|
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, &b)
|
||||||
require.ErrorIs(t, err, paymentsdb.ErrMPPPaymentAddrMismatch)
|
require.ErrorIs(t, err, ErrMPPPaymentAddrMismatch)
|
||||||
|
|
||||||
// Try registering one with a different total amount.
|
// Try registering one with a different total amount.
|
||||||
b.Route.FinalHop().MPP = record.NewMPP(
|
b.Route.FinalHop().MPP = record.NewMPP(
|
||||||
info.Value/2, [32]byte{1},
|
info.Value/2, [32]byte{1},
|
||||||
)
|
)
|
||||||
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, &b)
|
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, &b)
|
||||||
require.ErrorIs(t, err, paymentsdb.ErrMPPTotalAmountMismatch)
|
require.ErrorIs(t, err, ErrMPPTotalAmountMismatch)
|
||||||
|
|
||||||
// Create and init a new payment. This time we'll check that we cannot
|
// Create and init a new payment. This time we'll check that we cannot
|
||||||
// register an MPP attempt if we already registered a non-MPP one.
|
// register an MPP attempt if we already registered a non-MPP one.
|
||||||
@@ -1067,7 +1031,7 @@ func TestKVPaymentsDBMPPRecordValidation(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, &b)
|
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, &b)
|
||||||
require.ErrorIs(t, err, paymentsdb.ErrNonMPPayment)
|
require.ErrorIs(t, err, ErrNonMPPayment)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestDeleteFailedAttempts checks that DeleteFailedAttempts properly removes
|
// TestDeleteFailedAttempts checks that DeleteFailedAttempts properly removes
|
||||||
@@ -1084,16 +1048,9 @@ func TestDeleteFailedAttempts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testDeleteFailedAttempts(t *testing.T, keepFailedPaymentAttempts bool) {
|
func testDeleteFailedAttempts(t *testing.T, keepFailedPaymentAttempts bool) {
|
||||||
db, err := MakeTestDB(t)
|
paymentDB := NewTestDB(
|
||||||
require.NoError(t, err, "unable to init db")
|
t, WithKeepFailedPaymentAttempts(keepFailedPaymentAttempts),
|
||||||
|
|
||||||
paymentDB, err := NewKVPaymentsDB(
|
|
||||||
db,
|
|
||||||
paymentsdb.WithKeepFailedPaymentAttempts(
|
|
||||||
keepFailedPaymentAttempts,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Register three payments:
|
// Register three payments:
|
||||||
// All payments will have one failed HTLC attempt and one HTLC attempt
|
// All payments will have one failed HTLC attempt and one HTLC attempt
|
||||||
@@ -1177,7 +1134,7 @@ func assertPaymentStatus(t *testing.T, p *KVPaymentsDB,
|
|||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
payment, err := p.FetchPayment(hash)
|
payment, err := p.FetchPayment(hash)
|
||||||
if errors.Is(err, paymentsdb.ErrPaymentNotInitiated) {
|
if errors.Is(err, ErrPaymentNotInitiated) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1199,7 +1156,8 @@ type htlcStatus struct {
|
|||||||
// assertPaymentInfo retrieves the payment referred to by hash and verifies the
|
// assertPaymentInfo retrieves the payment referred to by hash and verifies the
|
||||||
// expected values.
|
// expected values.
|
||||||
func assertPaymentInfo(t *testing.T, p *KVPaymentsDB, hash lntypes.Hash,
|
func assertPaymentInfo(t *testing.T, p *KVPaymentsDB, hash lntypes.Hash,
|
||||||
c *PaymentCreationInfo, f *FailureReason, a *htlcStatus) {
|
c *channeldb.PaymentCreationInfo, f *channeldb.FailureReason,
|
||||||
|
a *htlcStatus) {
|
||||||
|
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
@@ -1277,7 +1235,7 @@ func fetchPaymentIndexEntry(_ *testing.T, p *KVPaymentsDB,
|
|||||||
|
|
||||||
indexValue := indexBucket.Get(key)
|
indexValue := indexBucket.Get(key)
|
||||||
if indexValue == nil {
|
if indexValue == nil {
|
||||||
return paymentsdb.ErrNoSequenceNrIndex
|
return ErrNoSequenceNrIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
r := bytes.NewReader(indexValue)
|
r := bytes.NewReader(indexValue)
|
||||||
@@ -1313,7 +1271,7 @@ func assertPaymentIndex(t *testing.T, p *KVPaymentsDB,
|
|||||||
// exist.
|
// exist.
|
||||||
func assertNoIndex(t *testing.T, p *KVPaymentsDB, seqNr uint64) {
|
func assertNoIndex(t *testing.T, p *KVPaymentsDB, seqNr uint64) {
|
||||||
_, err := fetchPaymentIndexEntry(t, p, seqNr)
|
_, err := fetchPaymentIndexEntry(t, p, seqNr)
|
||||||
require.Equal(t, paymentsdb.ErrNoSequenceNrIndex, err)
|
require.Equal(t, ErrNoSequenceNrIndex, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// payment is a helper structure that holds basic information on a test payment,
|
// payment is a helper structure that holds basic information on a test payment,
|
||||||
@@ -1381,7 +1339,7 @@ func createTestPayments(t *testing.T, p *KVPaymentsDB, payments []*payment) {
|
|||||||
)
|
)
|
||||||
require.NoError(t, err, "unable to fail htlc")
|
require.NoError(t, err, "unable to fail htlc")
|
||||||
|
|
||||||
failReason := FailureReasonNoRoute
|
failReason := channeldb.FailureReasonNoRoute
|
||||||
_, err = p.Fail(info.PaymentIdentifier,
|
_, err = p.Fail(info.PaymentIdentifier,
|
||||||
failReason)
|
failReason)
|
||||||
require.NoError(t, err, "unable to fail payment hash")
|
require.NoError(t, err, "unable to fail payment hash")
|
||||||
@@ -1439,13 +1397,15 @@ func assertPayments(t *testing.T, paymentDB *KVPaymentsDB,
|
|||||||
require.Equal(t, payments, p)
|
require.Equal(t, payments, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeFakeInfo(t *testing.T) (*PaymentCreationInfo, *HTLCAttemptInfo) {
|
func makeFakeInfo(t *testing.T) (*channeldb.PaymentCreationInfo,
|
||||||
|
*HTLCAttemptInfo) {
|
||||||
|
|
||||||
var preimg lntypes.Preimage
|
var preimg lntypes.Preimage
|
||||||
copy(preimg[:], rev[:])
|
copy(preimg[:], rev[:])
|
||||||
|
|
||||||
hash := preimg.Hash()
|
hash := preimg.Hash()
|
||||||
|
|
||||||
c := &PaymentCreationInfo{
|
c := &channeldb.PaymentCreationInfo{
|
||||||
PaymentIdentifier: hash,
|
PaymentIdentifier: hash,
|
||||||
Value: 1000,
|
Value: 1000,
|
||||||
// Use single second precision to avoid false positive test
|
// Use single second precision to avoid false positive test
|
||||||
@@ -1552,7 +1512,7 @@ func testSerializeRoute(t *testing.T, route route.Route) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// deletePayment removes a payment with paymentHash from the payments database.
|
// deletePayment removes a payment with paymentHash from the payments database.
|
||||||
func deletePayment(t *testing.T, db *DB, paymentHash lntypes.Hash,
|
func deletePayment(t *testing.T, db kvdb.Backend, paymentHash lntypes.Hash,
|
||||||
seqNr uint64) {
|
seqNr uint64) {
|
||||||
|
|
||||||
t.Helper()
|
t.Helper()
|
||||||
@@ -1587,11 +1547,7 @@ func deletePayment(t *testing.T, db *DB, paymentHash lntypes.Hash,
|
|||||||
// case where a specific duplicate is not found and the duplicates bucket is not
|
// case where a specific duplicate is not found and the duplicates bucket is not
|
||||||
// present when we expect it to be.
|
// present when we expect it to be.
|
||||||
func TestFetchPaymentWithSequenceNumber(t *testing.T) {
|
func TestFetchPaymentWithSequenceNumber(t *testing.T) {
|
||||||
db, err := MakeTestDB(t)
|
paymentDB := NewTestDB(t)
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
paymentDB, err := NewKVPaymentsDB(db)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Generate a test payment which does not have duplicates.
|
// Generate a test payment which does not have duplicates.
|
||||||
noDuplicates, _, _, err := genInfo(t)
|
noDuplicates, _, _, err := genInfo(t)
|
||||||
@@ -1634,12 +1590,12 @@ func TestFetchPaymentWithSequenceNumber(t *testing.T) {
|
|||||||
|
|
||||||
// Add two duplicates to our second payment.
|
// Add two duplicates to our second payment.
|
||||||
appendDuplicatePayment(
|
appendDuplicatePayment(
|
||||||
t, db, hasDuplicates.PaymentIdentifier, duplicateOneSeqNr,
|
t, paymentDB.db, hasDuplicates.PaymentIdentifier,
|
||||||
preimg,
|
duplicateOneSeqNr, preimg,
|
||||||
)
|
)
|
||||||
appendDuplicatePayment(
|
appendDuplicatePayment(
|
||||||
t, db, hasDuplicates.PaymentIdentifier, duplicateTwoSeqNr,
|
t, paymentDB.db, hasDuplicates.PaymentIdentifier,
|
||||||
preimg,
|
duplicateTwoSeqNr, preimg,
|
||||||
)
|
)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@@ -1676,14 +1632,14 @@ func TestFetchPaymentWithSequenceNumber(t *testing.T) {
|
|||||||
name: "lookup non-existent duplicate",
|
name: "lookup non-existent duplicate",
|
||||||
paymentHash: hasDuplicates.PaymentIdentifier,
|
paymentHash: hasDuplicates.PaymentIdentifier,
|
||||||
sequenceNumber: 999999,
|
sequenceNumber: 999999,
|
||||||
expectedErr: paymentsdb.ErrDuplicateNotFound,
|
expectedErr: ErrDuplicateNotFound,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "lookup duplicate, no duplicates " +
|
name: "lookup duplicate, no duplicates " +
|
||||||
"bucket",
|
"bucket",
|
||||||
paymentHash: noDuplicates.PaymentIdentifier,
|
paymentHash: noDuplicates.PaymentIdentifier,
|
||||||
sequenceNumber: duplicateTwoSeqNr,
|
sequenceNumber: duplicateTwoSeqNr,
|
||||||
expectedErr: paymentsdb.ErrNoDuplicateBucket,
|
expectedErr: ErrNoDuplicateBucket,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1692,7 +1648,7 @@ func TestFetchPaymentWithSequenceNumber(t *testing.T) {
|
|||||||
|
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
err := kvdb.Update(
|
err := kvdb.Update(
|
||||||
db, func(tx walletdb.ReadWriteTx) error {
|
paymentDB.db, func(tx walletdb.ReadWriteTx) error {
|
||||||
var seqNrBytes [8]byte
|
var seqNrBytes [8]byte
|
||||||
byteOrder.PutUint64(
|
byteOrder.PutUint64(
|
||||||
seqNrBytes[:],
|
seqNrBytes[:],
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package channeldb
|
package paymentsdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -12,13 +12,81 @@ import (
|
|||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
sphinx "github.com/lightningnetwork/lightning-onion"
|
sphinx "github.com/lightningnetwork/lightning-onion"
|
||||||
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnutils"
|
"github.com/lightningnetwork/lnd/lnutils"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
"github.com/lightningnetwork/lnd/routing/route"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// PaymentsQuery represents a query to the payments database starting or ending
|
||||||
|
// at a certain offset index. The number of retrieved records can be limited.
|
||||||
|
type PaymentsQuery struct {
|
||||||
|
// IndexOffset determines the starting point of the payments query and
|
||||||
|
// is always exclusive. In normal order, the query starts at the next
|
||||||
|
// higher (available) index compared to IndexOffset. In reversed order,
|
||||||
|
// the query ends at the next lower (available) index compared to the
|
||||||
|
// IndexOffset. In the case of a zero index_offset, the query will start
|
||||||
|
// with the oldest payment when paginating forwards, or will end with
|
||||||
|
// the most recent payment when paginating backwards.
|
||||||
|
IndexOffset uint64
|
||||||
|
|
||||||
|
// MaxPayments is the maximal number of payments returned in the
|
||||||
|
// payments query.
|
||||||
|
MaxPayments uint64
|
||||||
|
|
||||||
|
// Reversed gives a meaning to the IndexOffset. If reversed is set to
|
||||||
|
// true, the query will fetch payments with indices lower than the
|
||||||
|
// IndexOffset, otherwise, it will return payments with indices greater
|
||||||
|
// than the IndexOffset.
|
||||||
|
Reversed bool
|
||||||
|
|
||||||
|
// If IncludeIncomplete is true, then return payments that have not yet
|
||||||
|
// fully completed. This means that pending payments, as well as failed
|
||||||
|
// payments will show up if this field is set to true.
|
||||||
|
IncludeIncomplete bool
|
||||||
|
|
||||||
|
// CountTotal indicates that all payments currently present in the
|
||||||
|
// payment index (complete and incomplete) should be counted.
|
||||||
|
CountTotal bool
|
||||||
|
|
||||||
|
// CreationDateStart, expressed in Unix seconds, if set, filters out
|
||||||
|
// all payments with a creation date greater than or equal to it.
|
||||||
|
CreationDateStart int64
|
||||||
|
|
||||||
|
// CreationDateEnd, expressed in Unix seconds, if set, filters out all
|
||||||
|
// payments with a creation date less than or equal to it.
|
||||||
|
CreationDateEnd int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// PaymentsResponse contains the result of a query to the payments database.
|
||||||
|
// It includes the set of payments that match the query and integers which
|
||||||
|
// represent the index of the first and last item returned in the series of
|
||||||
|
// payments. These integers allow callers to resume their query in the event
|
||||||
|
// that the query's response exceeds the max number of returnable events.
|
||||||
|
type PaymentsResponse struct {
|
||||||
|
// Payments is the set of payments returned from the database for the
|
||||||
|
// PaymentsQuery.
|
||||||
|
Payments []*MPPayment
|
||||||
|
|
||||||
|
// FirstIndexOffset is the index of the first element in the set of
|
||||||
|
// returned MPPayments. Callers can use this to resume their query
|
||||||
|
// in the event that the slice has too many events to fit into a single
|
||||||
|
// response. The offset can be used to continue reverse pagination.
|
||||||
|
FirstIndexOffset uint64
|
||||||
|
|
||||||
|
// LastIndexOffset is the index of the last element in the set of
|
||||||
|
// returned MPPayments. Callers can use this to resume their query
|
||||||
|
// in the event that the slice has too many events to fit into a single
|
||||||
|
// response. The offset can be used to continue forward pagination.
|
||||||
|
LastIndexOffset uint64
|
||||||
|
|
||||||
|
// TotalCount represents the total number of payments that are currently
|
||||||
|
// stored in the payment database. This will only be set if the
|
||||||
|
// CountTotal field in the query was set to true.
|
||||||
|
TotalCount uint64
|
||||||
|
}
|
||||||
|
|
||||||
// HTLCAttemptInfo contains static information about a specific HTLC attempt
|
// HTLCAttemptInfo contains static information about a specific HTLC attempt
|
||||||
// for a payment. This information is used by the router to handle any errors
|
// for a payment. This information is used by the router to handle any errors
|
||||||
// coming back after an attempt is made, and to query the switch about the
|
// coming back after an attempt is made, and to query the switch about the
|
||||||
@@ -171,7 +239,7 @@ const (
|
|||||||
// reason.
|
// reason.
|
||||||
HTLCFailUnknown HTLCFailReason = 0
|
HTLCFailUnknown HTLCFailReason = 0
|
||||||
|
|
||||||
// HTLCFailUnknown is recorded for htlcs that had a failure message that
|
// HTLCFailUnreadable is recorded for htlcs that had a failure message that
|
||||||
// couldn't be decrypted.
|
// couldn't be decrypted.
|
||||||
HTLCFailUnreadable HTLCFailReason = 1
|
HTLCFailUnreadable HTLCFailReason = 1
|
||||||
|
|
||||||
@@ -241,7 +309,7 @@ type MPPayment struct {
|
|||||||
|
|
||||||
// Info holds all static information about this payment, and is
|
// Info holds all static information about this payment, and is
|
||||||
// populated when the payment is initiated.
|
// populated when the payment is initiated.
|
||||||
Info *PaymentCreationInfo
|
Info *channeldb.PaymentCreationInfo
|
||||||
|
|
||||||
// HTLCs holds the information about individual HTLCs that we send in
|
// HTLCs holds the information about individual HTLCs that we send in
|
||||||
// order to make the payment.
|
// order to make the payment.
|
||||||
@@ -252,7 +320,7 @@ type MPPayment struct {
|
|||||||
//
|
//
|
||||||
// NOTE: Will only be set once the daemon has given up on the payment
|
// NOTE: Will only be set once the daemon has given up on the payment
|
||||||
// altogether.
|
// altogether.
|
||||||
FailureReason *FailureReason
|
FailureReason *channeldb.FailureReason
|
||||||
|
|
||||||
// Status is the current PaymentStatus of this payment.
|
// Status is the current PaymentStatus of this payment.
|
||||||
Status PaymentStatus
|
Status PaymentStatus
|
||||||
@@ -273,7 +341,7 @@ func (m *MPPayment) Terminated() bool {
|
|||||||
// TerminalInfo returns any HTLC settle info recorded. If no settle info is
|
// TerminalInfo returns any HTLC settle info recorded. If no settle info is
|
||||||
// recorded, any payment level failure will be returned. If neither a settle
|
// recorded, any payment level failure will be returned. If neither a settle
|
||||||
// nor a failure is recorded, both return values will be nil.
|
// nor a failure is recorded, both return values will be nil.
|
||||||
func (m *MPPayment) TerminalInfo() (*HTLCAttempt, *FailureReason) {
|
func (m *MPPayment) TerminalInfo() (*HTLCAttempt, *channeldb.FailureReason) {
|
||||||
for _, h := range m.HTLCs {
|
for _, h := range m.HTLCs {
|
||||||
if h.Settle != nil {
|
if h.Settle != nil {
|
||||||
return &h, nil
|
return &h, nil
|
||||||
@@ -350,12 +418,12 @@ func (m *MPPayment) Registrable() error {
|
|||||||
// are settled HTLCs or the payment is failed. If we already have
|
// are settled HTLCs or the payment is failed. If we already have
|
||||||
// settled HTLCs, we won't allow adding more HTLCs.
|
// settled HTLCs, we won't allow adding more HTLCs.
|
||||||
if m.State.HasSettledHTLC {
|
if m.State.HasSettledHTLC {
|
||||||
return paymentsdb.ErrPaymentPendingSettled
|
return ErrPaymentPendingSettled
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the payment is already failed, we won't allow adding more HTLCs.
|
// If the payment is already failed, we won't allow adding more HTLCs.
|
||||||
if m.State.PaymentFailed {
|
if m.State.PaymentFailed {
|
||||||
return paymentsdb.ErrPaymentPendingFailed
|
return ErrPaymentPendingFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise we can add more HTLCs.
|
// Otherwise we can add more HTLCs.
|
||||||
@@ -373,7 +441,7 @@ func (m *MPPayment) setState() error {
|
|||||||
totalAmt := m.Info.Value
|
totalAmt := m.Info.Value
|
||||||
if sentAmt > totalAmt {
|
if sentAmt > totalAmt {
|
||||||
return fmt.Errorf("%w: sent=%v, total=%v",
|
return fmt.Errorf("%w: sent=%v, total=%v",
|
||||||
paymentsdb.ErrSentExceedsTotal, sentAmt, totalAmt)
|
ErrSentExceedsTotal, sentAmt, totalAmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get any terminal info for this payment.
|
// Get any terminal info for this payment.
|
||||||
@@ -452,7 +520,7 @@ func (m *MPPayment) NeedWaitAttempts() (bool, error) {
|
|||||||
case StatusSucceeded:
|
case StatusSucceeded:
|
||||||
return false, fmt.Errorf("%w: parts of the payment "+
|
return false, fmt.Errorf("%w: parts of the payment "+
|
||||||
"already succeeded but still have remaining "+
|
"already succeeded but still have remaining "+
|
||||||
"amount %v", paymentsdb.ErrPaymentInternal,
|
"amount %v", ErrPaymentInternal,
|
||||||
m.State.RemainingAmt)
|
m.State.RemainingAmt)
|
||||||
|
|
||||||
// The payment is failed and we have no inflight HTLCs, no need
|
// The payment is failed and we have no inflight HTLCs, no need
|
||||||
@@ -463,7 +531,7 @@ func (m *MPPayment) NeedWaitAttempts() (bool, error) {
|
|||||||
// Unknown payment status.
|
// Unknown payment status.
|
||||||
default:
|
default:
|
||||||
return false, fmt.Errorf("%w: %s",
|
return false, fmt.Errorf("%w: %s",
|
||||||
paymentsdb.ErrUnknownPaymentStatus, m.Status)
|
ErrUnknownPaymentStatus, m.Status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,7 +542,7 @@ func (m *MPPayment) NeedWaitAttempts() (bool, error) {
|
|||||||
// amount, return an error.
|
// amount, return an error.
|
||||||
case StatusInitiated:
|
case StatusInitiated:
|
||||||
return false, fmt.Errorf("%w: %v",
|
return false, fmt.Errorf("%w: %v",
|
||||||
paymentsdb.ErrPaymentInternal, m.Status)
|
ErrPaymentInternal, m.Status)
|
||||||
|
|
||||||
// If the payment is inflight, we must wait.
|
// If the payment is inflight, we must wait.
|
||||||
//
|
//
|
||||||
@@ -496,12 +564,12 @@ func (m *MPPayment) NeedWaitAttempts() (bool, error) {
|
|||||||
// not be zero because our sentAmt is zero.
|
// not be zero because our sentAmt is zero.
|
||||||
case StatusFailed:
|
case StatusFailed:
|
||||||
return false, fmt.Errorf("%w: %v",
|
return false, fmt.Errorf("%w: %v",
|
||||||
paymentsdb.ErrPaymentInternal, m.Status)
|
ErrPaymentInternal, m.Status)
|
||||||
|
|
||||||
// Unknown payment status.
|
// Unknown payment status.
|
||||||
default:
|
default:
|
||||||
return false, fmt.Errorf("%w: %s",
|
return false, fmt.Errorf("%w: %s",
|
||||||
paymentsdb.ErrUnknownPaymentStatus, m.Status)
|
ErrUnknownPaymentStatus, m.Status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,12 +578,12 @@ func (m *MPPayment) GetState() *MPPaymentState {
|
|||||||
return m.State
|
return m.State
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status returns the current status of the payment.
|
// GetStatus returns the current status of the payment.
|
||||||
func (m *MPPayment) GetStatus() PaymentStatus {
|
func (m *MPPayment) GetStatus() PaymentStatus {
|
||||||
return m.Status
|
return m.Status
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPayment returns all the HTLCs for this payment.
|
// GetHTLCs returns all the HTLCs for this payment.
|
||||||
func (m *MPPayment) GetHTLCs() []HTLCAttempt {
|
func (m *MPPayment) GetHTLCs() []HTLCAttempt {
|
||||||
return m.HTLCs
|
return m.HTLCs
|
||||||
}
|
}
|
||||||
@@ -532,7 +600,7 @@ func (m *MPPayment) AllowMoreAttempts() (bool, error) {
|
|||||||
if m.Status == StatusInitiated {
|
if m.Status == StatusInitiated {
|
||||||
return false, fmt.Errorf("%w: initiated payment has "+
|
return false, fmt.Errorf("%w: initiated payment has "+
|
||||||
"zero remainingAmt",
|
"zero remainingAmt",
|
||||||
paymentsdb.ErrPaymentInternal)
|
ErrPaymentInternal)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, exit early since all other statuses with zero
|
// Otherwise, exit early since all other statuses with zero
|
||||||
@@ -549,7 +617,7 @@ func (m *MPPayment) AllowMoreAttempts() (bool, error) {
|
|||||||
if m.Status == StatusSucceeded {
|
if m.Status == StatusSucceeded {
|
||||||
return false, fmt.Errorf("%w: payment already succeeded but "+
|
return false, fmt.Errorf("%w: payment already succeeded but "+
|
||||||
"still have remaining amount %v",
|
"still have remaining amount %v",
|
||||||
paymentsdb.ErrPaymentInternal, m.State.RemainingAmt)
|
ErrPaymentInternal, m.State.RemainingAmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now check if we can register a new HTLC.
|
// Now check if we can register a new HTLC.
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package channeldb
|
package paymentsdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PaymentStatus represent current status of payment.
|
// PaymentStatus represent current status of payment.
|
||||||
@@ -62,24 +62,24 @@ func (ps PaymentStatus) initializable() error {
|
|||||||
// again in case other goroutines have already been creating HTLCs for
|
// again in case other goroutines have already been creating HTLCs for
|
||||||
// it.
|
// it.
|
||||||
case StatusInitiated:
|
case StatusInitiated:
|
||||||
return paymentsdb.ErrPaymentExists
|
return ErrPaymentExists
|
||||||
|
|
||||||
// We already have an InFlight payment on the network. We will disallow
|
// We already have an InFlight payment on the network. We will disallow
|
||||||
// any new payments.
|
// any new payments.
|
||||||
case StatusInFlight:
|
case StatusInFlight:
|
||||||
return paymentsdb.ErrPaymentInFlight
|
return ErrPaymentInFlight
|
||||||
|
|
||||||
// The payment has been attempted and is succeeded so we won't allow
|
// The payment has been attempted and is succeeded so we won't allow
|
||||||
// creating it again.
|
// creating it again.
|
||||||
case StatusSucceeded:
|
case StatusSucceeded:
|
||||||
return paymentsdb.ErrAlreadyPaid
|
return ErrAlreadyPaid
|
||||||
|
|
||||||
// We allow retrying failed payments.
|
// We allow retrying failed payments.
|
||||||
case StatusFailed:
|
case StatusFailed:
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("%w: %v", paymentsdb.ErrUnknownPaymentStatus,
|
return fmt.Errorf("%w: %v", ErrUnknownPaymentStatus,
|
||||||
ps)
|
ps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,7 +96,7 @@ func (ps PaymentStatus) removable() error {
|
|||||||
// There are still inflight HTLCs and the payment needs to wait for the
|
// There are still inflight HTLCs and the payment needs to wait for the
|
||||||
// final outcomes.
|
// final outcomes.
|
||||||
case StatusInFlight:
|
case StatusInFlight:
|
||||||
return paymentsdb.ErrPaymentInFlight
|
return ErrPaymentInFlight
|
||||||
|
|
||||||
// The payment has been attempted and is succeeded and is allowed to be
|
// The payment has been attempted and is succeeded and is allowed to be
|
||||||
// removed.
|
// removed.
|
||||||
@@ -108,7 +108,7 @@ func (ps PaymentStatus) removable() error {
|
|||||||
return nil
|
return nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("%w: %v", paymentsdb.ErrUnknownPaymentStatus,
|
return fmt.Errorf("%w: %v", ErrUnknownPaymentStatus,
|
||||||
ps)
|
ps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,13 +127,13 @@ func (ps PaymentStatus) updatable() error {
|
|||||||
|
|
||||||
// If the payment has a terminal condition, we won't allow any updates.
|
// If the payment has a terminal condition, we won't allow any updates.
|
||||||
case StatusSucceeded:
|
case StatusSucceeded:
|
||||||
return paymentsdb.ErrPaymentAlreadySucceeded
|
return ErrPaymentAlreadySucceeded
|
||||||
|
|
||||||
case StatusFailed:
|
case StatusFailed:
|
||||||
return paymentsdb.ErrPaymentAlreadyFailed
|
return ErrPaymentAlreadyFailed
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("%w: %v", paymentsdb.ErrUnknownPaymentStatus,
|
return fmt.Errorf("%w: %v", ErrUnknownPaymentStatus,
|
||||||
ps)
|
ps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,7 +173,7 @@ func (ps PaymentStatus) updatable() error {
|
|||||||
// failed` is false, this indicates all the payment's HTLCs have occurred a
|
// failed` is false, this indicates all the payment's HTLCs have occurred a
|
||||||
// temporarily failure and the payment is still in-flight.
|
// temporarily failure and the payment is still in-flight.
|
||||||
func decidePaymentStatus(htlcs []HTLCAttempt,
|
func decidePaymentStatus(htlcs []HTLCAttempt,
|
||||||
reason *FailureReason) (PaymentStatus, error) {
|
reason *channeldb.FailureReason) (PaymentStatus, error) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
inflight bool
|
inflight bool
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package channeldb
|
package paymentsdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,13 +24,13 @@ func TestDecidePaymentStatus(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a test failure reason and get the pointer.
|
// Create a test failure reason and get the pointer.
|
||||||
reason := FailureReasonNoRoute
|
reason := channeldb.FailureReasonNoRoute
|
||||||
failure := &reason
|
failure := &reason
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
htlcs []HTLCAttempt
|
htlcs []HTLCAttempt
|
||||||
reason *FailureReason
|
reason *channeldb.FailureReason
|
||||||
expectedStatus PaymentStatus
|
expectedStatus PaymentStatus
|
||||||
expectedErr error
|
expectedErr error
|
||||||
}{
|
}{
|
||||||
@@ -198,33 +198,33 @@ func TestPaymentStatusActions(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
status: StatusInitiated,
|
status: StatusInitiated,
|
||||||
initErr: paymentsdb.ErrPaymentExists,
|
initErr: ErrPaymentExists,
|
||||||
updateErr: nil,
|
updateErr: nil,
|
||||||
removeErr: nil,
|
removeErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
status: StatusInFlight,
|
status: StatusInFlight,
|
||||||
initErr: paymentsdb.ErrPaymentInFlight,
|
initErr: ErrPaymentInFlight,
|
||||||
updateErr: nil,
|
updateErr: nil,
|
||||||
removeErr: paymentsdb.ErrPaymentInFlight,
|
removeErr: ErrPaymentInFlight,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
status: StatusSucceeded,
|
status: StatusSucceeded,
|
||||||
initErr: paymentsdb.ErrAlreadyPaid,
|
initErr: ErrAlreadyPaid,
|
||||||
updateErr: paymentsdb.ErrPaymentAlreadySucceeded,
|
updateErr: ErrPaymentAlreadySucceeded,
|
||||||
removeErr: nil,
|
removeErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
status: StatusFailed,
|
status: StatusFailed,
|
||||||
initErr: nil,
|
initErr: nil,
|
||||||
updateErr: paymentsdb.ErrPaymentAlreadyFailed,
|
updateErr: ErrPaymentAlreadyFailed,
|
||||||
removeErr: nil,
|
removeErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
status: 0,
|
status: 0,
|
||||||
initErr: paymentsdb.ErrUnknownPaymentStatus,
|
initErr: ErrUnknownPaymentStatus,
|
||||||
updateErr: paymentsdb.ErrUnknownPaymentStatus,
|
updateErr: ErrUnknownPaymentStatus,
|
||||||
removeErr: paymentsdb.ErrUnknownPaymentStatus,
|
removeErr: ErrUnknownPaymentStatus,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,14 +1,21 @@
|
|||||||
package channeldb
|
package paymentsdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
"github.com/lightningnetwork/lnd/record"
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
"github.com/lightningnetwork/lnd/routing/route"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@@ -20,8 +27,472 @@ var (
|
|||||||
0x4f, 0x2f, 0x6f, 0x25, 0x88, 0xa3, 0xef, 0xb9,
|
0x4f, 0x2f, 0x6f, 0x25, 0x88, 0xa3, 0xef, 0xb9,
|
||||||
0x6a, 0x49, 0x18, 0x83, 0x31, 0x98, 0x47, 0x53,
|
0x6a, 0x49, 0x18, 0x83, 0x31, 0x98, 0x47, 0x53,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rev = [chainhash.HashSize]byte{
|
||||||
|
0x51, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
|
||||||
|
0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
|
||||||
|
0x2d, 0xe7, 0x93, 0xe4,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
priv, _ = btcec.NewPrivateKey()
|
||||||
|
pub = priv.PubKey()
|
||||||
|
vertex = route.NewVertex(pub)
|
||||||
|
|
||||||
|
testHop1 = &route.Hop{
|
||||||
|
PubKeyBytes: vertex,
|
||||||
|
ChannelID: 12345,
|
||||||
|
OutgoingTimeLock: 111,
|
||||||
|
AmtToForward: 555,
|
||||||
|
CustomRecords: record.CustomSet{
|
||||||
|
65536: []byte{},
|
||||||
|
80001: []byte{},
|
||||||
|
},
|
||||||
|
MPP: record.NewMPP(32, [32]byte{0x42}),
|
||||||
|
Metadata: []byte{1, 2, 3},
|
||||||
|
}
|
||||||
|
|
||||||
|
testHop2 = &route.Hop{
|
||||||
|
PubKeyBytes: vertex,
|
||||||
|
ChannelID: 12345,
|
||||||
|
OutgoingTimeLock: 111,
|
||||||
|
AmtToForward: 555,
|
||||||
|
LegacyPayload: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
testHop3 = &route.Hop{
|
||||||
|
PubKeyBytes: route.NewVertex(pub),
|
||||||
|
ChannelID: 12345,
|
||||||
|
OutgoingTimeLock: 111,
|
||||||
|
AmtToForward: 555,
|
||||||
|
CustomRecords: record.CustomSet{
|
||||||
|
65536: []byte{},
|
||||||
|
80001: []byte{},
|
||||||
|
},
|
||||||
|
AMP: record.NewAMP([32]byte{0x69}, [32]byte{0x42}, 1),
|
||||||
|
Metadata: []byte{1, 2, 3},
|
||||||
|
}
|
||||||
|
|
||||||
|
testRoute = route.Route{
|
||||||
|
TotalTimeLock: 123,
|
||||||
|
TotalAmount: 1234567,
|
||||||
|
SourcePubKey: vertex,
|
||||||
|
Hops: []*route.Hop{
|
||||||
|
testHop2,
|
||||||
|
testHop1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
testBlindedRoute = route.Route{
|
||||||
|
TotalTimeLock: 150,
|
||||||
|
TotalAmount: 1000,
|
||||||
|
SourcePubKey: vertex,
|
||||||
|
Hops: []*route.Hop{
|
||||||
|
{
|
||||||
|
PubKeyBytes: vertex,
|
||||||
|
ChannelID: 9876,
|
||||||
|
OutgoingTimeLock: 120,
|
||||||
|
AmtToForward: 900,
|
||||||
|
EncryptedData: []byte{1, 3, 3},
|
||||||
|
BlindingPoint: pub,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
PubKeyBytes: vertex,
|
||||||
|
EncryptedData: []byte{3, 2, 1},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
PubKeyBytes: vertex,
|
||||||
|
Metadata: []byte{4, 5, 6},
|
||||||
|
AmtToForward: 500,
|
||||||
|
OutgoingTimeLock: 100,
|
||||||
|
TotalAmtMsat: 500,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// assertRouteEquals compares to routes for equality and returns an error if
|
||||||
|
// they are not equal.
|
||||||
|
func assertRouteEqual(a, b *route.Route) error {
|
||||||
|
if !reflect.DeepEqual(a, b) {
|
||||||
|
return fmt.Errorf("HTLCAttemptInfos don't match: %v vs %v",
|
||||||
|
spew.Sdump(a), spew.Sdump(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestQueryPayments tests retrieval of payments with forwards and reversed
|
||||||
|
// queries.
|
||||||
|
func TestQueryPayments(t *testing.T) {
|
||||||
|
// Define table driven test for QueryPayments.
|
||||||
|
// Test payments have sequence indices [1, 3, 4, 5, 6, 7].
|
||||||
|
// Note that the payment with index 7 has the same payment hash as 6,
|
||||||
|
// and is stored in a nested bucket within payment 6 rather than being
|
||||||
|
// its own entry in the payments bucket. We do this to test retrieval
|
||||||
|
// of legacy payments.
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
query PaymentsQuery
|
||||||
|
firstIndex uint64
|
||||||
|
lastIndex uint64
|
||||||
|
|
||||||
|
// expectedSeqNrs contains the set of sequence numbers we expect
|
||||||
|
// our query to return.
|
||||||
|
expectedSeqNrs []uint64
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "IndexOffset at the end of the payments range",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 7,
|
||||||
|
MaxPayments: 7,
|
||||||
|
Reversed: false,
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
},
|
||||||
|
firstIndex: 0,
|
||||||
|
lastIndex: 0,
|
||||||
|
expectedSeqNrs: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "query in forwards order, start at beginning",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 0,
|
||||||
|
MaxPayments: 2,
|
||||||
|
Reversed: false,
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
},
|
||||||
|
firstIndex: 1,
|
||||||
|
lastIndex: 3,
|
||||||
|
expectedSeqNrs: []uint64{1, 3},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "query in forwards order, start at end, overflow",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 6,
|
||||||
|
MaxPayments: 2,
|
||||||
|
Reversed: false,
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
},
|
||||||
|
firstIndex: 7,
|
||||||
|
lastIndex: 7,
|
||||||
|
expectedSeqNrs: []uint64{7},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "start at offset index outside of payments",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 20,
|
||||||
|
MaxPayments: 2,
|
||||||
|
Reversed: false,
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
},
|
||||||
|
firstIndex: 0,
|
||||||
|
lastIndex: 0,
|
||||||
|
expectedSeqNrs: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "overflow in forwards order",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 4,
|
||||||
|
MaxPayments: math.MaxUint64,
|
||||||
|
Reversed: false,
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
},
|
||||||
|
firstIndex: 5,
|
||||||
|
lastIndex: 7,
|
||||||
|
expectedSeqNrs: []uint64{5, 6, 7},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "start at offset index outside of payments, " +
|
||||||
|
"reversed order",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 9,
|
||||||
|
MaxPayments: 2,
|
||||||
|
Reversed: true,
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
},
|
||||||
|
firstIndex: 6,
|
||||||
|
lastIndex: 7,
|
||||||
|
expectedSeqNrs: []uint64{6, 7},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "query in reverse order, start at end",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 0,
|
||||||
|
MaxPayments: 2,
|
||||||
|
Reversed: true,
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
},
|
||||||
|
firstIndex: 6,
|
||||||
|
lastIndex: 7,
|
||||||
|
expectedSeqNrs: []uint64{6, 7},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "query in reverse order, starting in middle",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 4,
|
||||||
|
MaxPayments: 2,
|
||||||
|
Reversed: true,
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
},
|
||||||
|
firstIndex: 1,
|
||||||
|
lastIndex: 3,
|
||||||
|
expectedSeqNrs: []uint64{1, 3},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "query in reverse order, starting in middle, " +
|
||||||
|
"with underflow",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 4,
|
||||||
|
MaxPayments: 5,
|
||||||
|
Reversed: true,
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
},
|
||||||
|
firstIndex: 1,
|
||||||
|
lastIndex: 3,
|
||||||
|
expectedSeqNrs: []uint64{1, 3},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all payments in reverse, order maintained",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 0,
|
||||||
|
MaxPayments: 7,
|
||||||
|
Reversed: true,
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
},
|
||||||
|
firstIndex: 1,
|
||||||
|
lastIndex: 7,
|
||||||
|
expectedSeqNrs: []uint64{1, 3, 4, 5, 6, 7},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "exclude incomplete payments",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 0,
|
||||||
|
MaxPayments: 7,
|
||||||
|
Reversed: false,
|
||||||
|
IncludeIncomplete: false,
|
||||||
|
},
|
||||||
|
firstIndex: 7,
|
||||||
|
lastIndex: 7,
|
||||||
|
expectedSeqNrs: []uint64{7},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "query payments at index gap",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 1,
|
||||||
|
MaxPayments: 7,
|
||||||
|
Reversed: false,
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
},
|
||||||
|
firstIndex: 3,
|
||||||
|
lastIndex: 7,
|
||||||
|
expectedSeqNrs: []uint64{3, 4, 5, 6, 7},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "query payments reverse before index gap",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 3,
|
||||||
|
MaxPayments: 7,
|
||||||
|
Reversed: true,
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
},
|
||||||
|
firstIndex: 1,
|
||||||
|
lastIndex: 1,
|
||||||
|
expectedSeqNrs: []uint64{1},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "query payments reverse on index gap",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 2,
|
||||||
|
MaxPayments: 7,
|
||||||
|
Reversed: true,
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
},
|
||||||
|
firstIndex: 1,
|
||||||
|
lastIndex: 1,
|
||||||
|
expectedSeqNrs: []uint64{1},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "query payments forward on index gap",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 2,
|
||||||
|
MaxPayments: 2,
|
||||||
|
Reversed: false,
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
},
|
||||||
|
firstIndex: 3,
|
||||||
|
lastIndex: 4,
|
||||||
|
expectedSeqNrs: []uint64{3, 4},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "query in forwards order, with start creation " +
|
||||||
|
"time",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 0,
|
||||||
|
MaxPayments: 2,
|
||||||
|
Reversed: false,
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
CreationDateStart: 5,
|
||||||
|
},
|
||||||
|
firstIndex: 5,
|
||||||
|
lastIndex: 6,
|
||||||
|
expectedSeqNrs: []uint64{5, 6},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "query in forwards order, with start creation " +
|
||||||
|
"time at end, overflow",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 0,
|
||||||
|
MaxPayments: 2,
|
||||||
|
Reversed: false,
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
CreationDateStart: 7,
|
||||||
|
},
|
||||||
|
firstIndex: 7,
|
||||||
|
lastIndex: 7,
|
||||||
|
expectedSeqNrs: []uint64{7},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "query with start and end creation time",
|
||||||
|
query: PaymentsQuery{
|
||||||
|
IndexOffset: 9,
|
||||||
|
MaxPayments: math.MaxUint64,
|
||||||
|
Reversed: true,
|
||||||
|
IncludeIncomplete: true,
|
||||||
|
CreationDateStart: 3,
|
||||||
|
CreationDateEnd: 5,
|
||||||
|
},
|
||||||
|
firstIndex: 3,
|
||||||
|
lastIndex: 5,
|
||||||
|
expectedSeqNrs: []uint64{3, 4, 5},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
paymentDB := NewTestDB(t)
|
||||||
|
|
||||||
|
// Initialize the payment database.
|
||||||
|
paymentDB, err := NewKVPaymentsDB(paymentDB.db)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Make a preliminary query to make sure it's ok to
|
||||||
|
// query when we have no payments.
|
||||||
|
resp, err := paymentDB.QueryPayments(ctx, tt.query)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, resp.Payments, 0)
|
||||||
|
|
||||||
|
// Populate the database with a set of test payments.
|
||||||
|
// We create 6 original payments, deleting the payment
|
||||||
|
// at index 2 so that we cover the case where sequence
|
||||||
|
// numbers are missing. We also add a duplicate payment
|
||||||
|
// to the last payment added to test the legacy case
|
||||||
|
// where we have duplicates in the nested duplicates
|
||||||
|
// bucket.
|
||||||
|
nonDuplicatePayments := 6
|
||||||
|
|
||||||
|
for i := 0; i < nonDuplicatePayments; i++ {
|
||||||
|
// Generate a test payment.
|
||||||
|
info, _, preimg, err := genInfo(t)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create test "+
|
||||||
|
"payment: %v", err)
|
||||||
|
}
|
||||||
|
// Override creation time to allow for testing
|
||||||
|
// of CreationDateStart and CreationDateEnd.
|
||||||
|
info.CreationTime = time.Unix(int64(i+1), 0)
|
||||||
|
|
||||||
|
// Create a new payment entry in the database.
|
||||||
|
err = paymentDB.InitPayment(
|
||||||
|
info.PaymentIdentifier, info,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Immediately delete the payment with index 2.
|
||||||
|
if i == 1 {
|
||||||
|
pmt, err := paymentDB.FetchPayment(
|
||||||
|
info.PaymentIdentifier,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
deletePayment(
|
||||||
|
t, paymentDB.db,
|
||||||
|
info.PaymentIdentifier,
|
||||||
|
pmt.SequenceNum,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are on the last payment entry, add a
|
||||||
|
// duplicate payment with sequence number equal
|
||||||
|
// to the parent payment + 1. Note that
|
||||||
|
// duplicate payments will always be succeeded.
|
||||||
|
if i == (nonDuplicatePayments - 1) {
|
||||||
|
pmt, err := paymentDB.FetchPayment(
|
||||||
|
info.PaymentIdentifier,
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
appendDuplicatePayment(
|
||||||
|
t, paymentDB.db,
|
||||||
|
info.PaymentIdentifier,
|
||||||
|
pmt.SequenceNum+1,
|
||||||
|
preimg,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch all payments in the database.
|
||||||
|
allPayments, err := paymentDB.FetchPayments()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("payments could not be fetched from "+
|
||||||
|
"database: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(allPayments) != 6 {
|
||||||
|
t.Fatalf("Number of payments received does "+
|
||||||
|
"not match expected one. Got %v, "+
|
||||||
|
"want %v.", len(allPayments), 6)
|
||||||
|
}
|
||||||
|
|
||||||
|
querySlice, err := paymentDB.QueryPayments(
|
||||||
|
ctx, tt.query,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if tt.firstIndex != querySlice.FirstIndexOffset ||
|
||||||
|
tt.lastIndex != querySlice.LastIndexOffset {
|
||||||
|
|
||||||
|
t.Errorf("First or last index does not match "+
|
||||||
|
"expected index. Want (%d, %d), "+
|
||||||
|
"got (%d, %d).",
|
||||||
|
tt.firstIndex, tt.lastIndex,
|
||||||
|
querySlice.FirstIndexOffset,
|
||||||
|
querySlice.LastIndexOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(querySlice.Payments) != len(tt.expectedSeqNrs) {
|
||||||
|
t.Errorf("expected: %v payments, got: %v",
|
||||||
|
len(tt.expectedSeqNrs),
|
||||||
|
len(querySlice.Payments))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, seqNr := range tt.expectedSeqNrs {
|
||||||
|
q := querySlice.Payments[i]
|
||||||
|
if seqNr != q.SequenceNum {
|
||||||
|
t.Errorf("sequence numbers do not "+
|
||||||
|
"match, got %v, want %v",
|
||||||
|
q.SequenceNum, seqNr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestLazySessionKeyDeserialize tests that we can read htlc attempt session
|
// TestLazySessionKeyDeserialize tests that we can read htlc attempt session
|
||||||
// keys that were previously serialized as a private key as raw bytes.
|
// keys that were previously serialized as a private key as raw bytes.
|
||||||
func TestLazySessionKeyDeserialize(t *testing.T) {
|
func TestLazySessionKeyDeserialize(t *testing.T) {
|
||||||
@@ -66,35 +537,35 @@ func TestRegistrable(t *testing.T) {
|
|||||||
// Test inflight status with settled HTLC but no failed
|
// Test inflight status with settled HTLC but no failed
|
||||||
// payment.
|
// payment.
|
||||||
status: StatusInFlight,
|
status: StatusInFlight,
|
||||||
registryErr: paymentsdb.ErrPaymentPendingSettled,
|
registryErr: ErrPaymentPendingSettled,
|
||||||
hasSettledHTLC: true,
|
hasSettledHTLC: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Test inflight status with no settled HTLC but failed
|
// Test inflight status with no settled HTLC but failed
|
||||||
// payment.
|
// payment.
|
||||||
status: StatusInFlight,
|
status: StatusInFlight,
|
||||||
registryErr: paymentsdb.ErrPaymentPendingFailed,
|
registryErr: ErrPaymentPendingFailed,
|
||||||
paymentFailed: true,
|
paymentFailed: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Test error state with settled HTLC and failed
|
// Test error state with settled HTLC and failed
|
||||||
// payment.
|
// payment.
|
||||||
status: 0,
|
status: 0,
|
||||||
registryErr: paymentsdb.ErrUnknownPaymentStatus,
|
registryErr: ErrUnknownPaymentStatus,
|
||||||
hasSettledHTLC: true,
|
hasSettledHTLC: true,
|
||||||
paymentFailed: true,
|
paymentFailed: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
status: StatusSucceeded,
|
status: StatusSucceeded,
|
||||||
registryErr: paymentsdb.ErrPaymentAlreadySucceeded,
|
registryErr: ErrPaymentAlreadySucceeded,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
status: StatusFailed,
|
status: StatusFailed,
|
||||||
registryErr: paymentsdb.ErrPaymentAlreadyFailed,
|
registryErr: ErrPaymentAlreadyFailed,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
status: 0,
|
status: 0,
|
||||||
registryErr: paymentsdb.ErrUnknownPaymentStatus,
|
registryErr: ErrUnknownPaymentStatus,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +598,7 @@ func TestPaymentSetState(t *testing.T) {
|
|||||||
|
|
||||||
// Create a test preimage and failure reason.
|
// Create a test preimage and failure reason.
|
||||||
preimage := lntypes.Preimage{1}
|
preimage := lntypes.Preimage{1}
|
||||||
failureReasonError := FailureReasonError
|
failureReasonError := channeldb.FailureReasonError
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -150,7 +621,7 @@ func TestPaymentSetState(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
totalAmt: 1,
|
totalAmt: 1,
|
||||||
errExpected: paymentsdb.ErrSentExceedsTotal,
|
errExpected: ErrSentExceedsTotal,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Test that when the htlc is failed, the fee is not
|
// Test that when the htlc is failed, the fee is not
|
||||||
@@ -223,7 +694,7 @@ func TestPaymentSetState(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Attach the payment info.
|
// Attach the payment info.
|
||||||
info := &PaymentCreationInfo{
|
info := &channeldb.PaymentCreationInfo{
|
||||||
Value: lnwire.MilliSatoshi(tc.totalAmt),
|
Value: lnwire.MilliSatoshi(tc.totalAmt),
|
||||||
}
|
}
|
||||||
tc.payment.Info = info
|
tc.payment.Info = info
|
||||||
@@ -295,7 +766,7 @@ func TestNeedWaitAttempts(t *testing.T) {
|
|||||||
status: StatusSucceeded,
|
status: StatusSucceeded,
|
||||||
remainingAmt: 1000,
|
remainingAmt: 1000,
|
||||||
needWait: false,
|
needWait: false,
|
||||||
expectedErr: paymentsdb.ErrPaymentInternal,
|
expectedErr: ErrPaymentInternal,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Payment is in terminal state, no need to wait.
|
// Payment is in terminal state, no need to wait.
|
||||||
@@ -310,7 +781,7 @@ func TestNeedWaitAttempts(t *testing.T) {
|
|||||||
status: StatusInitiated,
|
status: StatusInitiated,
|
||||||
remainingAmt: 0,
|
remainingAmt: 0,
|
||||||
needWait: false,
|
needWait: false,
|
||||||
expectedErr: paymentsdb.ErrPaymentInternal,
|
expectedErr: ErrPaymentInternal,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// With zero remainingAmt we must wait for the results.
|
// With zero remainingAmt we must wait for the results.
|
||||||
@@ -331,21 +802,21 @@ func TestNeedWaitAttempts(t *testing.T) {
|
|||||||
status: StatusFailed,
|
status: StatusFailed,
|
||||||
remainingAmt: 0,
|
remainingAmt: 0,
|
||||||
needWait: false,
|
needWait: false,
|
||||||
expectedErr: paymentsdb.ErrPaymentInternal,
|
expectedErr: ErrPaymentInternal,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Payment is in an unknown status, return an error.
|
// Payment is in an unknown status, return an error.
|
||||||
status: 0,
|
status: 0,
|
||||||
remainingAmt: 0,
|
remainingAmt: 0,
|
||||||
needWait: false,
|
needWait: false,
|
||||||
expectedErr: paymentsdb.ErrUnknownPaymentStatus,
|
expectedErr: ErrUnknownPaymentStatus,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Payment is in an unknown status, return an error.
|
// Payment is in an unknown status, return an error.
|
||||||
status: 0,
|
status: 0,
|
||||||
remainingAmt: 1000,
|
remainingAmt: 1000,
|
||||||
needWait: false,
|
needWait: false,
|
||||||
expectedErr: paymentsdb.ErrUnknownPaymentStatus,
|
expectedErr: ErrUnknownPaymentStatus,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,7 +824,7 @@ func TestNeedWaitAttempts(t *testing.T) {
|
|||||||
tc := tc
|
tc := tc
|
||||||
|
|
||||||
p := &MPPayment{
|
p := &MPPayment{
|
||||||
Info: &PaymentCreationInfo{
|
Info: &channeldb.PaymentCreationInfo{
|
||||||
PaymentIdentifier: [32]byte{1, 2, 3},
|
PaymentIdentifier: [32]byte{1, 2, 3},
|
||||||
},
|
},
|
||||||
Status: tc.status,
|
Status: tc.status,
|
||||||
@@ -398,7 +869,7 @@ func TestAllowMoreAttempts(t *testing.T) {
|
|||||||
status: StatusInitiated,
|
status: StatusInitiated,
|
||||||
remainingAmt: 0,
|
remainingAmt: 0,
|
||||||
allowMore: false,
|
allowMore: false,
|
||||||
expectedErr: paymentsdb.ErrPaymentInternal,
|
expectedErr: ErrPaymentInternal,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// With zero remainingAmt we don't allow more HTLC
|
// With zero remainingAmt we don't allow more HTLC
|
||||||
@@ -506,7 +977,7 @@ func TestAllowMoreAttempts(t *testing.T) {
|
|||||||
remainingAmt: 1000,
|
remainingAmt: 1000,
|
||||||
hasSettledHTLC: true,
|
hasSettledHTLC: true,
|
||||||
allowMore: false,
|
allowMore: false,
|
||||||
expectedErr: paymentsdb.ErrPaymentInternal,
|
expectedErr: ErrPaymentInternal,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// With the payment failed with no inflight HTLCs, we
|
// With the payment failed with no inflight HTLCs, we
|
||||||
@@ -531,7 +1002,7 @@ func TestAllowMoreAttempts(t *testing.T) {
|
|||||||
tc := tc
|
tc := tc
|
||||||
|
|
||||||
p := &MPPayment{
|
p := &MPPayment{
|
||||||
Info: &PaymentCreationInfo{
|
Info: &channeldb.PaymentCreationInfo{
|
||||||
PaymentIdentifier: [32]byte{1, 2, 3},
|
PaymentIdentifier: [32]byte{1, 2, 3},
|
||||||
},
|
},
|
||||||
Status: tc.status,
|
Status: tc.status,
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package paymentsdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/kvdb"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
kvdb.RunTests(m)
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package paymentsdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/kvdb"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewTestDB is a helper function that creates an BBolt database for testing.
|
||||||
|
func NewTestDB(t *testing.T, opts ...OptionModifier) *KVPaymentsDB {
|
||||||
|
backend, backendCleanup, err := kvdb.GetTestBackend(
|
||||||
|
t.TempDir(), "kvPaymentDB",
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Cleanup(backendCleanup)
|
||||||
|
|
||||||
|
paymentDB, err := NewKVPaymentsDB(backend, opts...)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return paymentDB
|
||||||
|
}
|
||||||
+23
-20
@@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/multimutex"
|
"github.com/lightningnetwork/lnd/multimutex"
|
||||||
|
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||||
"github.com/lightningnetwork/lnd/queue"
|
"github.com/lightningnetwork/lnd/queue"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -13,23 +14,23 @@ import (
|
|||||||
// the payment lifecycle.
|
// the payment lifecycle.
|
||||||
type DBMPPayment interface {
|
type DBMPPayment interface {
|
||||||
// GetState returns the current state of the payment.
|
// GetState returns the current state of the payment.
|
||||||
GetState() *channeldb.MPPaymentState
|
GetState() *paymentsdb.MPPaymentState
|
||||||
|
|
||||||
// Terminated returns true if the payment is in a final state.
|
// Terminated returns true if the payment is in a final state.
|
||||||
Terminated() bool
|
Terminated() bool
|
||||||
|
|
||||||
// GetStatus returns the current status of the payment.
|
// GetStatus returns the current status of the payment.
|
||||||
GetStatus() channeldb.PaymentStatus
|
GetStatus() paymentsdb.PaymentStatus
|
||||||
|
|
||||||
// NeedWaitAttempts specifies whether the payment needs to wait for the
|
// NeedWaitAttempts specifies whether the payment needs to wait for the
|
||||||
// outcome of an attempt.
|
// outcome of an attempt.
|
||||||
NeedWaitAttempts() (bool, error)
|
NeedWaitAttempts() (bool, error)
|
||||||
|
|
||||||
// GetHTLCs returns all HTLCs of this payment.
|
// GetHTLCs returns all HTLCs of this payment.
|
||||||
GetHTLCs() []channeldb.HTLCAttempt
|
GetHTLCs() []paymentsdb.HTLCAttempt
|
||||||
|
|
||||||
// InFlightHTLCs returns all HTLCs that are in flight.
|
// InFlightHTLCs returns all HTLCs that are in flight.
|
||||||
InFlightHTLCs() []channeldb.HTLCAttempt
|
InFlightHTLCs() []paymentsdb.HTLCAttempt
|
||||||
|
|
||||||
// AllowMoreAttempts is used to decide whether we can safely attempt
|
// AllowMoreAttempts is used to decide whether we can safely attempt
|
||||||
// more HTLCs for a given payment state. Return an error if the payment
|
// more HTLCs for a given payment state. Return an error if the payment
|
||||||
@@ -38,7 +39,7 @@ type DBMPPayment interface {
|
|||||||
|
|
||||||
// TerminalInfo returns the settled HTLC attempt or the payment's
|
// TerminalInfo returns the settled HTLC attempt or the payment's
|
||||||
// failure reason.
|
// failure reason.
|
||||||
TerminalInfo() (*channeldb.HTLCAttempt, *channeldb.FailureReason)
|
TerminalInfo() (*paymentsdb.HTLCAttempt, *channeldb.FailureReason)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ControlTower tracks all outgoing payments made, whose primary purpose is to
|
// ControlTower tracks all outgoing payments made, whose primary purpose is to
|
||||||
@@ -57,7 +58,7 @@ type ControlTower interface {
|
|||||||
DeleteFailedAttempts(lntypes.Hash) error
|
DeleteFailedAttempts(lntypes.Hash) error
|
||||||
|
|
||||||
// RegisterAttempt atomically records the provided HTLCAttemptInfo.
|
// RegisterAttempt atomically records the provided HTLCAttemptInfo.
|
||||||
RegisterAttempt(lntypes.Hash, *channeldb.HTLCAttemptInfo) error
|
RegisterAttempt(lntypes.Hash, *paymentsdb.HTLCAttemptInfo) error
|
||||||
|
|
||||||
// SettleAttempt marks the given attempt settled with the preimage. If
|
// SettleAttempt marks the given attempt settled with the preimage. If
|
||||||
// this is a multi shard payment, this might implicitly mean the the
|
// this is a multi shard payment, this might implicitly mean the the
|
||||||
@@ -67,12 +68,12 @@ type ControlTower interface {
|
|||||||
// error to prevent us from making duplicate payments to the same
|
// error to prevent us from making duplicate payments to the same
|
||||||
// payment hash. The provided preimage is atomically saved to the DB
|
// payment hash. The provided preimage is atomically saved to the DB
|
||||||
// for record keeping.
|
// for record keeping.
|
||||||
SettleAttempt(lntypes.Hash, uint64, *channeldb.HTLCSettleInfo) (
|
SettleAttempt(lntypes.Hash, uint64, *paymentsdb.HTLCSettleInfo) (
|
||||||
*channeldb.HTLCAttempt, error)
|
*paymentsdb.HTLCAttempt, error)
|
||||||
|
|
||||||
// FailAttempt marks the given payment attempt failed.
|
// FailAttempt marks the given payment attempt failed.
|
||||||
FailAttempt(lntypes.Hash, uint64, *channeldb.HTLCFailInfo) (
|
FailAttempt(lntypes.Hash, uint64, *paymentsdb.HTLCFailInfo) (
|
||||||
*channeldb.HTLCAttempt, error)
|
*paymentsdb.HTLCAttempt, error)
|
||||||
|
|
||||||
// FetchPayment fetches the payment corresponding to the given payment
|
// FetchPayment fetches the payment corresponding to the given payment
|
||||||
// hash.
|
// hash.
|
||||||
@@ -87,7 +88,7 @@ type ControlTower interface {
|
|||||||
FailPayment(lntypes.Hash, channeldb.FailureReason) error
|
FailPayment(lntypes.Hash, channeldb.FailureReason) error
|
||||||
|
|
||||||
// FetchInFlightPayments returns all payments with status InFlight.
|
// FetchInFlightPayments returns all payments with status InFlight.
|
||||||
FetchInFlightPayments() ([]*channeldb.MPPayment, error)
|
FetchInFlightPayments() ([]*paymentsdb.MPPayment, error)
|
||||||
|
|
||||||
// SubscribePayment subscribes to updates for the payment with the given
|
// SubscribePayment subscribes to updates for the payment with the given
|
||||||
// hash. A first update with the current state of the payment is always
|
// hash. A first update with the current state of the payment is always
|
||||||
@@ -151,7 +152,7 @@ func (s *controlTowerSubscriberImpl) Updates() <-chan interface{} {
|
|||||||
// controlTower is persistent implementation of ControlTower to restrict
|
// controlTower is persistent implementation of ControlTower to restrict
|
||||||
// double payment sending.
|
// double payment sending.
|
||||||
type controlTower struct {
|
type controlTower struct {
|
||||||
db *channeldb.KVPaymentsDB
|
db *paymentsdb.KVPaymentsDB
|
||||||
|
|
||||||
// subscriberIndex is used to provide a unique id for each subscriber
|
// subscriberIndex is used to provide a unique id for each subscriber
|
||||||
// to all payments. This is used to easily remove the subscriber when
|
// to all payments. This is used to easily remove the subscriber when
|
||||||
@@ -168,7 +169,7 @@ type controlTower struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewControlTower creates a new instance of the controlTower.
|
// NewControlTower creates a new instance of the controlTower.
|
||||||
func NewControlTower(db *channeldb.KVPaymentsDB) ControlTower {
|
func NewControlTower(db *paymentsdb.KVPaymentsDB) ControlTower {
|
||||||
return &controlTower{
|
return &controlTower{
|
||||||
db: db,
|
db: db,
|
||||||
subscribersAllPayments: make(
|
subscribersAllPayments: make(
|
||||||
@@ -215,7 +216,7 @@ func (p *controlTower) DeleteFailedAttempts(paymentHash lntypes.Hash) error {
|
|||||||
// RegisterAttempt atomically records the provided HTLCAttemptInfo to the
|
// RegisterAttempt atomically records the provided HTLCAttemptInfo to the
|
||||||
// DB.
|
// DB.
|
||||||
func (p *controlTower) RegisterAttempt(paymentHash lntypes.Hash,
|
func (p *controlTower) RegisterAttempt(paymentHash lntypes.Hash,
|
||||||
attempt *channeldb.HTLCAttemptInfo) error {
|
attempt *paymentsdb.HTLCAttemptInfo) error {
|
||||||
|
|
||||||
p.paymentsMtx.Lock(paymentHash)
|
p.paymentsMtx.Lock(paymentHash)
|
||||||
defer p.paymentsMtx.Unlock(paymentHash)
|
defer p.paymentsMtx.Unlock(paymentHash)
|
||||||
@@ -235,8 +236,8 @@ func (p *controlTower) RegisterAttempt(paymentHash lntypes.Hash,
|
|||||||
// this is a multi shard payment, this might implicitly mean the the
|
// this is a multi shard payment, this might implicitly mean the the
|
||||||
// full payment succeeded.
|
// full payment succeeded.
|
||||||
func (p *controlTower) SettleAttempt(paymentHash lntypes.Hash,
|
func (p *controlTower) SettleAttempt(paymentHash lntypes.Hash,
|
||||||
attemptID uint64, settleInfo *channeldb.HTLCSettleInfo) (
|
attemptID uint64, settleInfo *paymentsdb.HTLCSettleInfo) (
|
||||||
*channeldb.HTLCAttempt, error) {
|
*paymentsdb.HTLCAttempt, error) {
|
||||||
|
|
||||||
p.paymentsMtx.Lock(paymentHash)
|
p.paymentsMtx.Lock(paymentHash)
|
||||||
defer p.paymentsMtx.Unlock(paymentHash)
|
defer p.paymentsMtx.Unlock(paymentHash)
|
||||||
@@ -254,8 +255,8 @@ func (p *controlTower) SettleAttempt(paymentHash lntypes.Hash,
|
|||||||
|
|
||||||
// FailAttempt marks the given payment attempt failed.
|
// FailAttempt marks the given payment attempt failed.
|
||||||
func (p *controlTower) FailAttempt(paymentHash lntypes.Hash,
|
func (p *controlTower) FailAttempt(paymentHash lntypes.Hash,
|
||||||
attemptID uint64, failInfo *channeldb.HTLCFailInfo) (
|
attemptID uint64, failInfo *paymentsdb.HTLCFailInfo) (
|
||||||
*channeldb.HTLCAttempt, error) {
|
*paymentsdb.HTLCAttempt, error) {
|
||||||
|
|
||||||
p.paymentsMtx.Lock(paymentHash)
|
p.paymentsMtx.Lock(paymentHash)
|
||||||
defer p.paymentsMtx.Unlock(paymentHash)
|
defer p.paymentsMtx.Unlock(paymentHash)
|
||||||
@@ -303,7 +304,9 @@ func (p *controlTower) FailPayment(paymentHash lntypes.Hash,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FetchInFlightPayments returns all payments with status InFlight.
|
// FetchInFlightPayments returns all payments with status InFlight.
|
||||||
func (p *controlTower) FetchInFlightPayments() ([]*channeldb.MPPayment, error) {
|
func (p *controlTower) FetchInFlightPayments() ([]*paymentsdb.MPPayment,
|
||||||
|
error) {
|
||||||
|
|
||||||
return p.db.FetchInFlightPayments()
|
return p.db.FetchInFlightPayments()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,7 +389,7 @@ func (p *controlTower) SubscribeAllPayments() (ControlTowerSubscriber, error) {
|
|||||||
// be executed atomically (by means of a lock) with the database update to
|
// be executed atomically (by means of a lock) with the database update to
|
||||||
// guarantee consistency of the notifications.
|
// guarantee consistency of the notifications.
|
||||||
func (p *controlTower) notifySubscribers(paymentHash lntypes.Hash,
|
func (p *controlTower) notifySubscribers(paymentHash lntypes.Hash,
|
||||||
event *channeldb.MPPayment) {
|
event *paymentsdb.MPPayment) {
|
||||||
|
|
||||||
// Get all subscribers for this payment.
|
// Get all subscribers for this payment.
|
||||||
p.subscribersMtx.Lock()
|
p.subscribersMtx.Lock()
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ func TestControlTowerSubscribeUnknown(t *testing.T) {
|
|||||||
|
|
||||||
db := initDB(t)
|
db := initDB(t)
|
||||||
|
|
||||||
paymentDB, err := channeldb.NewKVPaymentsDB(
|
paymentDB, err := paymentsdb.NewKVPaymentsDB(
|
||||||
db,
|
db,
|
||||||
paymentsdb.WithKeepFailedPaymentAttempts(true),
|
paymentsdb.WithKeepFailedPaymentAttempts(true),
|
||||||
)
|
)
|
||||||
@@ -70,7 +70,7 @@ func TestControlTowerSubscribeSuccess(t *testing.T) {
|
|||||||
|
|
||||||
db := initDB(t)
|
db := initDB(t)
|
||||||
|
|
||||||
paymentDB, err := channeldb.NewKVPaymentsDB(db)
|
paymentDB, err := paymentsdb.NewKVPaymentsDB(db)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pControl := NewControlTower(paymentDB)
|
pControl := NewControlTower(paymentDB)
|
||||||
@@ -102,7 +102,7 @@ func TestControlTowerSubscribeSuccess(t *testing.T) {
|
|||||||
require.NoError(t, err, "expected subscribe to succeed, but got")
|
require.NoError(t, err, "expected subscribe to succeed, but got")
|
||||||
|
|
||||||
// Mark the payment as successful.
|
// Mark the payment as successful.
|
||||||
settleInfo := channeldb.HTLCSettleInfo{
|
settleInfo := paymentsdb.HTLCSettleInfo{
|
||||||
Preimage: preimg,
|
Preimage: preimg,
|
||||||
}
|
}
|
||||||
htlcAttempt, err := pControl.SettleAttempt(
|
htlcAttempt, err := pControl.SettleAttempt(
|
||||||
@@ -126,19 +126,19 @@ func TestControlTowerSubscribeSuccess(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, s := range subscribers {
|
for i, s := range subscribers {
|
||||||
var result *channeldb.MPPayment
|
var result *paymentsdb.MPPayment
|
||||||
for result == nil || !result.Terminated() {
|
for result == nil || !result.Terminated() {
|
||||||
select {
|
select {
|
||||||
case item := <-s.Updates():
|
case item := <-s.Updates():
|
||||||
result = item.(*channeldb.MPPayment)
|
result = item.(*paymentsdb.MPPayment)
|
||||||
case <-time.After(testTimeout):
|
case <-time.After(testTimeout):
|
||||||
t.Fatal("timeout waiting for payment result")
|
t.Fatal("timeout waiting for payment result")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Equalf(t, channeldb.StatusSucceeded, result.GetStatus(),
|
require.Equalf(t, paymentsdb.StatusSucceeded, result.GetStatus(),
|
||||||
"subscriber %v failed, want %s, got %s", i,
|
"subscriber %v failed, want %s, got %s", i,
|
||||||
channeldb.StatusSucceeded, result.GetStatus())
|
paymentsdb.StatusSucceeded, result.GetStatus())
|
||||||
|
|
||||||
attempt, _ := result.TerminalInfo()
|
attempt, _ := result.TerminalInfo()
|
||||||
if attempt.Settle.Preimage != preimg {
|
if attempt.Settle.Preimage != preimg {
|
||||||
@@ -192,7 +192,7 @@ func TestKVPaymentsDBSubscribeAllSuccess(t *testing.T) {
|
|||||||
|
|
||||||
db := initDB(t)
|
db := initDB(t)
|
||||||
|
|
||||||
paymentDB, err := channeldb.NewKVPaymentsDB(
|
paymentDB, err := paymentsdb.NewKVPaymentsDB(
|
||||||
db,
|
db,
|
||||||
paymentsdb.WithKeepFailedPaymentAttempts(true),
|
paymentsdb.WithKeepFailedPaymentAttempts(true),
|
||||||
)
|
)
|
||||||
@@ -228,7 +228,7 @@ func TestKVPaymentsDBSubscribeAllSuccess(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Mark the first payment as successful.
|
// Mark the first payment as successful.
|
||||||
settleInfo1 := channeldb.HTLCSettleInfo{
|
settleInfo1 := paymentsdb.HTLCSettleInfo{
|
||||||
Preimage: preimg1,
|
Preimage: preimg1,
|
||||||
}
|
}
|
||||||
htlcAttempt1, err := pControl.SettleAttempt(
|
htlcAttempt1, err := pControl.SettleAttempt(
|
||||||
@@ -241,7 +241,7 @@ func TestKVPaymentsDBSubscribeAllSuccess(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Mark the second payment as successful.
|
// Mark the second payment as successful.
|
||||||
settleInfo2 := channeldb.HTLCSettleInfo{
|
settleInfo2 := paymentsdb.HTLCSettleInfo{
|
||||||
Preimage: preimg2,
|
Preimage: preimg2,
|
||||||
}
|
}
|
||||||
htlcAttempt2, err := pControl.SettleAttempt(
|
htlcAttempt2, err := pControl.SettleAttempt(
|
||||||
@@ -255,14 +255,14 @@ func TestKVPaymentsDBSubscribeAllSuccess(t *testing.T) {
|
|||||||
|
|
||||||
// The two payments will be asserted individually, store the last update
|
// The two payments will be asserted individually, store the last update
|
||||||
// for each payment.
|
// for each payment.
|
||||||
results := make(map[lntypes.Hash]*channeldb.MPPayment)
|
results := make(map[lntypes.Hash]*paymentsdb.MPPayment)
|
||||||
|
|
||||||
// After exactly 6 updates both payments will/should have completed.
|
// After exactly 6 updates both payments will/should have completed.
|
||||||
for i := 0; i < 6; i++ {
|
for i := 0; i < 6; i++ {
|
||||||
select {
|
select {
|
||||||
case item := <-subscription.Updates():
|
case item := <-subscription.Updates():
|
||||||
id := item.(*channeldb.MPPayment).Info.PaymentIdentifier
|
id := item.(*paymentsdb.MPPayment).Info.PaymentIdentifier
|
||||||
results[id] = item.(*channeldb.MPPayment)
|
results[id] = item.(*paymentsdb.MPPayment)
|
||||||
case <-time.After(testTimeout):
|
case <-time.After(testTimeout):
|
||||||
require.Fail(t, "timeout waiting for payment result")
|
require.Fail(t, "timeout waiting for payment result")
|
||||||
}
|
}
|
||||||
@@ -270,7 +270,7 @@ func TestKVPaymentsDBSubscribeAllSuccess(t *testing.T) {
|
|||||||
|
|
||||||
result1 := results[info1.PaymentIdentifier]
|
result1 := results[info1.PaymentIdentifier]
|
||||||
require.Equal(
|
require.Equal(
|
||||||
t, channeldb.StatusSucceeded, result1.GetStatus(),
|
t, paymentsdb.StatusSucceeded, result1.GetStatus(),
|
||||||
"unexpected payment state payment 1",
|
"unexpected payment state payment 1",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -288,7 +288,7 @@ func TestKVPaymentsDBSubscribeAllSuccess(t *testing.T) {
|
|||||||
|
|
||||||
result2 := results[info2.PaymentIdentifier]
|
result2 := results[info2.PaymentIdentifier]
|
||||||
require.Equal(
|
require.Equal(
|
||||||
t, channeldb.StatusSucceeded, result2.GetStatus(),
|
t, paymentsdb.StatusSucceeded, result2.GetStatus(),
|
||||||
"unexpected payment state payment 2",
|
"unexpected payment state payment 2",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -311,7 +311,7 @@ func TestKVPaymentsDBSubscribeAllImmediate(t *testing.T) {
|
|||||||
|
|
||||||
db := initDB(t)
|
db := initDB(t)
|
||||||
|
|
||||||
paymentDB, err := channeldb.NewKVPaymentsDB(
|
paymentDB, err := paymentsdb.NewKVPaymentsDB(
|
||||||
db,
|
db,
|
||||||
paymentsdb.WithKeepFailedPaymentAttempts(true),
|
paymentsdb.WithKeepFailedPaymentAttempts(true),
|
||||||
)
|
)
|
||||||
@@ -339,7 +339,7 @@ func TestKVPaymentsDBSubscribeAllImmediate(t *testing.T) {
|
|||||||
require.NotNil(t, update)
|
require.NotNil(t, update)
|
||||||
require.Equal(
|
require.Equal(
|
||||||
t, info.PaymentIdentifier,
|
t, info.PaymentIdentifier,
|
||||||
update.(*channeldb.MPPayment).Info.PaymentIdentifier,
|
update.(*paymentsdb.MPPayment).Info.PaymentIdentifier,
|
||||||
)
|
)
|
||||||
require.Len(t, subscription.Updates(), 0)
|
require.Len(t, subscription.Updates(), 0)
|
||||||
case <-time.After(testTimeout):
|
case <-time.After(testTimeout):
|
||||||
@@ -354,7 +354,7 @@ func TestKVPaymentsDBUnsubscribeSuccess(t *testing.T) {
|
|||||||
|
|
||||||
db := initDB(t)
|
db := initDB(t)
|
||||||
|
|
||||||
paymentDB, err := channeldb.NewKVPaymentsDB(
|
paymentDB, err := paymentsdb.NewKVPaymentsDB(
|
||||||
db,
|
db,
|
||||||
paymentsdb.WithKeepFailedPaymentAttempts(true),
|
paymentsdb.WithKeepFailedPaymentAttempts(true),
|
||||||
)
|
)
|
||||||
@@ -411,8 +411,8 @@ func TestKVPaymentsDBUnsubscribeSuccess(t *testing.T) {
|
|||||||
subscription2.Close()
|
subscription2.Close()
|
||||||
|
|
||||||
// Register another update.
|
// Register another update.
|
||||||
failInfo := channeldb.HTLCFailInfo{
|
failInfo := paymentsdb.HTLCFailInfo{
|
||||||
Reason: channeldb.HTLCFailInternal,
|
Reason: paymentsdb.HTLCFailInternal,
|
||||||
}
|
}
|
||||||
_, err = pControl.FailAttempt(
|
_, err = pControl.FailAttempt(
|
||||||
info.PaymentIdentifier, attempt.AttemptID, &failInfo,
|
info.PaymentIdentifier, attempt.AttemptID, &failInfo,
|
||||||
@@ -429,7 +429,7 @@ func testKVPaymentsDBSubscribeFail(t *testing.T, registerAttempt,
|
|||||||
|
|
||||||
db := initDB(t)
|
db := initDB(t)
|
||||||
|
|
||||||
paymentDB, err := channeldb.NewKVPaymentsDB(
|
paymentDB, err := paymentsdb.NewKVPaymentsDB(
|
||||||
db,
|
db,
|
||||||
paymentsdb.WithKeepFailedPaymentAttempts(
|
paymentsdb.WithKeepFailedPaymentAttempts(
|
||||||
keepFailedPaymentAttempts,
|
keepFailedPaymentAttempts,
|
||||||
@@ -465,8 +465,8 @@ func testKVPaymentsDBSubscribeFail(t *testing.T, registerAttempt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fail the payment attempt.
|
// Fail the payment attempt.
|
||||||
failInfo := channeldb.HTLCFailInfo{
|
failInfo := paymentsdb.HTLCFailInfo{
|
||||||
Reason: channeldb.HTLCFailInternal,
|
Reason: paymentsdb.HTLCFailInternal,
|
||||||
}
|
}
|
||||||
htlcAttempt, err := pControl.FailAttempt(
|
htlcAttempt, err := pControl.FailAttempt(
|
||||||
info.PaymentIdentifier, attempt.AttemptID, &failInfo,
|
info.PaymentIdentifier, attempt.AttemptID, &failInfo,
|
||||||
@@ -498,17 +498,17 @@ func testKVPaymentsDBSubscribeFail(t *testing.T, registerAttempt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, s := range subscribers {
|
for i, s := range subscribers {
|
||||||
var result *channeldb.MPPayment
|
var result *paymentsdb.MPPayment
|
||||||
for result == nil || !result.Terminated() {
|
for result == nil || !result.Terminated() {
|
||||||
select {
|
select {
|
||||||
case item := <-s.Updates():
|
case item := <-s.Updates():
|
||||||
result = item.(*channeldb.MPPayment)
|
result = item.(*paymentsdb.MPPayment)
|
||||||
case <-time.After(testTimeout):
|
case <-time.After(testTimeout):
|
||||||
t.Fatal("timeout waiting for payment result")
|
t.Fatal("timeout waiting for payment result")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if result.GetStatus() == channeldb.StatusSucceeded {
|
if result.GetStatus() == paymentsdb.StatusSucceeded {
|
||||||
t.Fatal("unexpected payment state")
|
t.Fatal("unexpected payment state")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,9 +533,9 @@ func testKVPaymentsDBSubscribeFail(t *testing.T, registerAttempt,
|
|||||||
len(result.HTLCs))
|
len(result.HTLCs))
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Equalf(t, channeldb.StatusFailed, result.GetStatus(),
|
require.Equalf(t, paymentsdb.StatusFailed, result.GetStatus(),
|
||||||
"subscriber %v failed, want %s, got %s", i,
|
"subscriber %v failed, want %s, got %s", i,
|
||||||
channeldb.StatusFailed, result.GetStatus())
|
paymentsdb.StatusFailed, result.GetStatus())
|
||||||
|
|
||||||
if *result.FailureReason != channeldb.FailureReasonTimeout {
|
if *result.FailureReason != channeldb.FailureReasonTimeout {
|
||||||
t.Fatal("unexpected failure reason")
|
t.Fatal("unexpected failure reason")
|
||||||
@@ -559,7 +559,7 @@ func initDB(t *testing.T) *channeldb.DB {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func genInfo() (*channeldb.PaymentCreationInfo, *channeldb.HTLCAttemptInfo,
|
func genInfo() (*channeldb.PaymentCreationInfo, *paymentsdb.HTLCAttemptInfo,
|
||||||
lntypes.Preimage, error) {
|
lntypes.Preimage, error) {
|
||||||
|
|
||||||
preimage, err := genPreimage()
|
preimage, err := genPreimage()
|
||||||
@@ -572,7 +572,7 @@ func genInfo() (*channeldb.PaymentCreationInfo, *channeldb.HTLCAttemptInfo,
|
|||||||
var hash lntypes.Hash
|
var hash lntypes.Hash
|
||||||
copy(hash[:], rhash[:])
|
copy(hash[:], rhash[:])
|
||||||
|
|
||||||
attempt, err := channeldb.NewHtlcAttempt(
|
attempt, err := paymentsdb.NewHtlcAttempt(
|
||||||
1, priv, testRoute, time.Time{}, &hash,
|
1, priv, testRoute, time.Time{}, &hash,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+33
-33
@@ -252,7 +252,7 @@ type initArgs struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type registerAttemptArgs struct {
|
type registerAttemptArgs struct {
|
||||||
a *channeldb.HTLCAttemptInfo
|
a *paymentsdb.HTLCAttemptInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type settleAttemptArgs struct {
|
type settleAttemptArgs struct {
|
||||||
@@ -260,7 +260,7 @@ type settleAttemptArgs struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type failAttemptArgs struct {
|
type failAttemptArgs struct {
|
||||||
reason *channeldb.HTLCFailInfo
|
reason *paymentsdb.HTLCFailInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type failPaymentArgs struct {
|
type failPaymentArgs struct {
|
||||||
@@ -269,7 +269,7 @@ type failPaymentArgs struct {
|
|||||||
|
|
||||||
type testPayment struct {
|
type testPayment struct {
|
||||||
info channeldb.PaymentCreationInfo
|
info channeldb.PaymentCreationInfo
|
||||||
attempts []channeldb.HTLCAttempt
|
attempts []paymentsdb.HTLCAttempt
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockControlTowerOld struct {
|
type mockControlTowerOld struct {
|
||||||
@@ -355,7 +355,7 @@ func (m *mockControlTowerOld) DeleteFailedAttempts(phash lntypes.Hash) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockControlTowerOld) RegisterAttempt(phash lntypes.Hash,
|
func (m *mockControlTowerOld) RegisterAttempt(phash lntypes.Hash,
|
||||||
a *channeldb.HTLCAttemptInfo) error {
|
a *paymentsdb.HTLCAttemptInfo) error {
|
||||||
|
|
||||||
if m.registerAttempt != nil {
|
if m.registerAttempt != nil {
|
||||||
m.registerAttempt <- registerAttemptArgs{a}
|
m.registerAttempt <- registerAttemptArgs{a}
|
||||||
@@ -400,7 +400,7 @@ func (m *mockControlTowerOld) RegisterAttempt(phash lntypes.Hash,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add attempt to payment.
|
// Add attempt to payment.
|
||||||
p.attempts = append(p.attempts, channeldb.HTLCAttempt{
|
p.attempts = append(p.attempts, paymentsdb.HTLCAttempt{
|
||||||
HTLCAttemptInfo: *a,
|
HTLCAttemptInfo: *a,
|
||||||
})
|
})
|
||||||
m.payments[phash] = p
|
m.payments[phash] = p
|
||||||
@@ -409,8 +409,8 @@ func (m *mockControlTowerOld) RegisterAttempt(phash lntypes.Hash,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockControlTowerOld) SettleAttempt(phash lntypes.Hash,
|
func (m *mockControlTowerOld) SettleAttempt(phash lntypes.Hash,
|
||||||
pid uint64, settleInfo *channeldb.HTLCSettleInfo) (
|
pid uint64, settleInfo *paymentsdb.HTLCSettleInfo) (
|
||||||
*channeldb.HTLCAttempt, error) {
|
*paymentsdb.HTLCAttempt, error) {
|
||||||
|
|
||||||
if m.settleAttempt != nil {
|
if m.settleAttempt != nil {
|
||||||
m.settleAttempt <- settleAttemptArgs{settleInfo.Preimage}
|
m.settleAttempt <- settleAttemptArgs{settleInfo.Preimage}
|
||||||
@@ -442,7 +442,7 @@ func (m *mockControlTowerOld) SettleAttempt(phash lntypes.Hash,
|
|||||||
|
|
||||||
// Mark the payment successful on first settled attempt.
|
// Mark the payment successful on first settled attempt.
|
||||||
m.successful[phash] = struct{}{}
|
m.successful[phash] = struct{}{}
|
||||||
return &channeldb.HTLCAttempt{
|
return &paymentsdb.HTLCAttempt{
|
||||||
Settle: settleInfo,
|
Settle: settleInfo,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -451,7 +451,7 @@ func (m *mockControlTowerOld) SettleAttempt(phash lntypes.Hash,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockControlTowerOld) FailAttempt(phash lntypes.Hash, pid uint64,
|
func (m *mockControlTowerOld) FailAttempt(phash lntypes.Hash, pid uint64,
|
||||||
failInfo *channeldb.HTLCFailInfo) (*channeldb.HTLCAttempt, error) {
|
failInfo *paymentsdb.HTLCFailInfo) (*paymentsdb.HTLCAttempt, error) {
|
||||||
|
|
||||||
if m.failAttempt != nil {
|
if m.failAttempt != nil {
|
||||||
m.failAttempt <- failAttemptArgs{failInfo}
|
m.failAttempt <- failAttemptArgs{failInfo}
|
||||||
@@ -480,7 +480,7 @@ func (m *mockControlTowerOld) FailAttempt(phash lntypes.Hash, pid uint64,
|
|||||||
}
|
}
|
||||||
|
|
||||||
p.attempts[i].Failure = failInfo
|
p.attempts[i].Failure = failInfo
|
||||||
return &channeldb.HTLCAttempt{
|
return &paymentsdb.HTLCAttempt{
|
||||||
Failure: failInfo,
|
Failure: failInfo,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -518,14 +518,14 @@ func (m *mockControlTowerOld) FetchPayment(phash lntypes.Hash) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockControlTowerOld) fetchPayment(phash lntypes.Hash) (
|
func (m *mockControlTowerOld) fetchPayment(phash lntypes.Hash) (
|
||||||
*channeldb.MPPayment, error) {
|
*paymentsdb.MPPayment, error) {
|
||||||
|
|
||||||
p, ok := m.payments[phash]
|
p, ok := m.payments[phash]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, paymentsdb.ErrPaymentNotInitiated
|
return nil, paymentsdb.ErrPaymentNotInitiated
|
||||||
}
|
}
|
||||||
|
|
||||||
mp := &channeldb.MPPayment{
|
mp := &paymentsdb.MPPayment{
|
||||||
Info: &p.info,
|
Info: &p.info,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -545,7 +545,7 @@ func (m *mockControlTowerOld) fetchPayment(phash lntypes.Hash) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockControlTowerOld) FetchInFlightPayments() (
|
func (m *mockControlTowerOld) FetchInFlightPayments() (
|
||||||
[]*channeldb.MPPayment, error) {
|
[]*paymentsdb.MPPayment, error) {
|
||||||
|
|
||||||
if m.fetchInFlight != nil {
|
if m.fetchInFlight != nil {
|
||||||
m.fetchInFlight <- struct{}{}
|
m.fetchInFlight <- struct{}{}
|
||||||
@@ -555,7 +555,7 @@ func (m *mockControlTowerOld) FetchInFlightPayments() (
|
|||||||
defer m.Unlock()
|
defer m.Unlock()
|
||||||
|
|
||||||
// In flight are all payments not successful or failed.
|
// In flight are all payments not successful or failed.
|
||||||
var fl []*channeldb.MPPayment
|
var fl []*paymentsdb.MPPayment
|
||||||
for hash := range m.payments {
|
for hash := range m.payments {
|
||||||
if _, ok := m.successful[hash]; ok {
|
if _, ok := m.successful[hash]; ok {
|
||||||
continue
|
continue
|
||||||
@@ -745,15 +745,15 @@ func (m *mockControlTower) DeleteFailedAttempts(phash lntypes.Hash) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockControlTower) RegisterAttempt(phash lntypes.Hash,
|
func (m *mockControlTower) RegisterAttempt(phash lntypes.Hash,
|
||||||
a *channeldb.HTLCAttemptInfo) error {
|
a *paymentsdb.HTLCAttemptInfo) error {
|
||||||
|
|
||||||
args := m.Called(phash, a)
|
args := m.Called(phash, a)
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockControlTower) SettleAttempt(phash lntypes.Hash,
|
func (m *mockControlTower) SettleAttempt(phash lntypes.Hash,
|
||||||
pid uint64, settleInfo *channeldb.HTLCSettleInfo) (
|
pid uint64, settleInfo *paymentsdb.HTLCSettleInfo) (
|
||||||
*channeldb.HTLCAttempt, error) {
|
*paymentsdb.HTLCAttempt, error) {
|
||||||
|
|
||||||
args := m.Called(phash, pid, settleInfo)
|
args := m.Called(phash, pid, settleInfo)
|
||||||
|
|
||||||
@@ -762,11 +762,11 @@ func (m *mockControlTower) SettleAttempt(phash lntypes.Hash,
|
|||||||
return nil, args.Error(1)
|
return nil, args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return attempt.(*channeldb.HTLCAttempt), args.Error(1)
|
return attempt.(*paymentsdb.HTLCAttempt), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockControlTower) FailAttempt(phash lntypes.Hash, pid uint64,
|
func (m *mockControlTower) FailAttempt(phash lntypes.Hash, pid uint64,
|
||||||
failInfo *channeldb.HTLCFailInfo) (*channeldb.HTLCAttempt, error) {
|
failInfo *paymentsdb.HTLCFailInfo) (*paymentsdb.HTLCAttempt, error) {
|
||||||
|
|
||||||
args := m.Called(phash, pid, failInfo)
|
args := m.Called(phash, pid, failInfo)
|
||||||
|
|
||||||
@@ -775,7 +775,7 @@ func (m *mockControlTower) FailAttempt(phash lntypes.Hash, pid uint64,
|
|||||||
return nil, args.Error(1)
|
return nil, args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return args.Get(0).(*channeldb.HTLCAttempt), args.Error(1)
|
return attempt.(*paymentsdb.HTLCAttempt), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockControlTower) FailPayment(phash lntypes.Hash,
|
func (m *mockControlTower) FailPayment(phash lntypes.Hash,
|
||||||
@@ -800,10 +800,10 @@ func (m *mockControlTower) FetchPayment(phash lntypes.Hash) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockControlTower) FetchInFlightPayments() (
|
func (m *mockControlTower) FetchInFlightPayments() (
|
||||||
[]*channeldb.MPPayment, error) {
|
[]*paymentsdb.MPPayment, error) {
|
||||||
|
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).([]*channeldb.MPPayment), args.Error(1)
|
return args.Get(0).([]*paymentsdb.MPPayment), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockControlTower) SubscribePayment(paymentHash lntypes.Hash) (
|
func (m *mockControlTower) SubscribePayment(paymentHash lntypes.Hash) (
|
||||||
@@ -826,14 +826,14 @@ type mockMPPayment struct {
|
|||||||
|
|
||||||
var _ DBMPPayment = (*mockMPPayment)(nil)
|
var _ DBMPPayment = (*mockMPPayment)(nil)
|
||||||
|
|
||||||
func (m *mockMPPayment) GetState() *channeldb.MPPaymentState {
|
func (m *mockMPPayment) GetState() *paymentsdb.MPPaymentState {
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).(*channeldb.MPPaymentState)
|
return args.Get(0).(*paymentsdb.MPPaymentState)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockMPPayment) GetStatus() channeldb.PaymentStatus {
|
func (m *mockMPPayment) GetStatus() paymentsdb.PaymentStatus {
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).(channeldb.PaymentStatus)
|
return args.Get(0).(paymentsdb.PaymentStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockMPPayment) Terminated() bool {
|
func (m *mockMPPayment) Terminated() bool {
|
||||||
@@ -847,14 +847,14 @@ func (m *mockMPPayment) NeedWaitAttempts() (bool, error) {
|
|||||||
return args.Bool(0), args.Error(1)
|
return args.Bool(0), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockMPPayment) GetHTLCs() []channeldb.HTLCAttempt {
|
func (m *mockMPPayment) GetHTLCs() []paymentsdb.HTLCAttempt {
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).([]channeldb.HTLCAttempt)
|
return args.Get(0).([]paymentsdb.HTLCAttempt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockMPPayment) InFlightHTLCs() []channeldb.HTLCAttempt {
|
func (m *mockMPPayment) InFlightHTLCs() []paymentsdb.HTLCAttempt {
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).([]channeldb.HTLCAttempt)
|
return args.Get(0).([]paymentsdb.HTLCAttempt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockMPPayment) AllowMoreAttempts() (bool, error) {
|
func (m *mockMPPayment) AllowMoreAttempts() (bool, error) {
|
||||||
@@ -862,19 +862,19 @@ func (m *mockMPPayment) AllowMoreAttempts() (bool, error) {
|
|||||||
return args.Bool(0), args.Error(1)
|
return args.Bool(0), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockMPPayment) TerminalInfo() (*channeldb.HTLCAttempt,
|
func (m *mockMPPayment) TerminalInfo() (*paymentsdb.HTLCAttempt,
|
||||||
*channeldb.FailureReason) {
|
*channeldb.FailureReason) {
|
||||||
|
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
settleInfo *channeldb.HTLCAttempt
|
settleInfo *paymentsdb.HTLCAttempt
|
||||||
failureInfo *channeldb.FailureReason
|
failureInfo *channeldb.FailureReason
|
||||||
)
|
)
|
||||||
|
|
||||||
settle := args.Get(0)
|
settle := args.Get(0)
|
||||||
if settle != nil {
|
if settle != nil {
|
||||||
settleInfo = settle.(*channeldb.HTLCAttempt)
|
settleInfo = settle.(*paymentsdb.HTLCAttempt)
|
||||||
}
|
}
|
||||||
|
|
||||||
reason := args.Get(1)
|
reason := args.Get(1)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnutils"
|
"github.com/lightningnetwork/lnd/lnutils"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
|
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
"github.com/lightningnetwork/lnd/routing/route"
|
||||||
"github.com/lightningnetwork/lnd/routing/shards"
|
"github.com/lightningnetwork/lnd/routing/shards"
|
||||||
"github.com/lightningnetwork/lnd/tlv"
|
"github.com/lightningnetwork/lnd/tlv"
|
||||||
@@ -29,7 +30,7 @@ var ErrPaymentLifecycleExiting = errors.New("payment lifecycle exiting")
|
|||||||
// HTLC.
|
// HTLC.
|
||||||
type switchResult struct {
|
type switchResult struct {
|
||||||
// attempt is the HTLC sent to the switch.
|
// attempt is the HTLC sent to the switch.
|
||||||
attempt *channeldb.HTLCAttempt
|
attempt *paymentsdb.HTLCAttempt
|
||||||
|
|
||||||
// result is sent from the switch which contains either a preimage if
|
// result is sent from the switch which contains either a preimage if
|
||||||
// ths HTLC is settled or an error if it's failed.
|
// ths HTLC is settled or an error if it's failed.
|
||||||
@@ -59,7 +60,7 @@ type paymentLifecycle struct {
|
|||||||
// an HTLC attempt, which is always mounted to `p.collectResultAsync`
|
// an HTLC attempt, which is always mounted to `p.collectResultAsync`
|
||||||
// except in unit test, where we use a much simpler resultCollector to
|
// except in unit test, where we use a much simpler resultCollector to
|
||||||
// decouple the test flow for the payment lifecycle.
|
// decouple the test flow for the payment lifecycle.
|
||||||
resultCollector func(attempt *channeldb.HTLCAttempt)
|
resultCollector func(attempt *paymentsdb.HTLCAttempt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newPaymentLifecycle initiates a new payment lifecycle and returns it.
|
// newPaymentLifecycle initiates a new payment lifecycle and returns it.
|
||||||
@@ -386,7 +387,7 @@ func (p *paymentLifecycle) checkContext(ctx context.Context) error {
|
|||||||
// requestRoute is responsible for finding a route to be used to create an HTLC
|
// requestRoute is responsible for finding a route to be used to create an HTLC
|
||||||
// attempt.
|
// attempt.
|
||||||
func (p *paymentLifecycle) requestRoute(
|
func (p *paymentLifecycle) requestRoute(
|
||||||
ps *channeldb.MPPaymentState) (*route.Route, error) {
|
ps *paymentsdb.MPPaymentState) (*route.Route, error) {
|
||||||
|
|
||||||
remainingFees := p.calcFeeBudget(ps.FeesPaid)
|
remainingFees := p.calcFeeBudget(ps.FeesPaid)
|
||||||
|
|
||||||
@@ -455,14 +456,14 @@ type attemptResult struct {
|
|||||||
err error
|
err error
|
||||||
|
|
||||||
// attempt is the attempt structure as recorded in the database.
|
// attempt is the attempt structure as recorded in the database.
|
||||||
attempt *channeldb.HTLCAttempt
|
attempt *paymentsdb.HTLCAttempt
|
||||||
}
|
}
|
||||||
|
|
||||||
// collectResultAsync launches a goroutine that will wait for the result of the
|
// collectResultAsync launches a goroutine that will wait for the result of the
|
||||||
// given HTLC attempt to be available then save its result in a map. Once
|
// given HTLC attempt to be available then save its result in a map. Once
|
||||||
// received, it will send the result returned from the switch to channel
|
// received, it will send the result returned from the switch to channel
|
||||||
// `resultCollected`.
|
// `resultCollected`.
|
||||||
func (p *paymentLifecycle) collectResultAsync(attempt *channeldb.HTLCAttempt) {
|
func (p *paymentLifecycle) collectResultAsync(attempt *paymentsdb.HTLCAttempt) {
|
||||||
log.Debugf("Collecting result for attempt %v in payment %v",
|
log.Debugf("Collecting result for attempt %v in payment %v",
|
||||||
attempt.AttemptID, p.identifier)
|
attempt.AttemptID, p.identifier)
|
||||||
|
|
||||||
@@ -504,7 +505,7 @@ func (p *paymentLifecycle) collectResultAsync(attempt *channeldb.HTLCAttempt) {
|
|||||||
// collectResult waits for the result of the given HTLC attempt to be sent by
|
// collectResult waits for the result of the given HTLC attempt to be sent by
|
||||||
// the switch and returns it.
|
// the switch and returns it.
|
||||||
func (p *paymentLifecycle) collectResult(
|
func (p *paymentLifecycle) collectResult(
|
||||||
attempt *channeldb.HTLCAttempt) (*htlcswitch.PaymentResult, error) {
|
attempt *paymentsdb.HTLCAttempt) (*htlcswitch.PaymentResult, error) {
|
||||||
|
|
||||||
log.Tracef("Collecting result for attempt %v",
|
log.Tracef("Collecting result for attempt %v",
|
||||||
lnutils.SpewLogClosure(attempt))
|
lnutils.SpewLogClosure(attempt))
|
||||||
@@ -581,7 +582,7 @@ func (p *paymentLifecycle) collectResult(
|
|||||||
// by using the route info provided. The `remainingAmt` is used to decide
|
// by using the route info provided. The `remainingAmt` is used to decide
|
||||||
// whether this is the last attempt.
|
// whether this is the last attempt.
|
||||||
func (p *paymentLifecycle) registerAttempt(rt *route.Route,
|
func (p *paymentLifecycle) registerAttempt(rt *route.Route,
|
||||||
remainingAmt lnwire.MilliSatoshi) (*channeldb.HTLCAttempt, error) {
|
remainingAmt lnwire.MilliSatoshi) (*paymentsdb.HTLCAttempt, error) {
|
||||||
|
|
||||||
// If this route will consume the last remaining amount to send
|
// If this route will consume the last remaining amount to send
|
||||||
// to the receiver, this will be our last shard (for now).
|
// to the receiver, this will be our last shard (for now).
|
||||||
@@ -608,7 +609,7 @@ func (p *paymentLifecycle) registerAttempt(rt *route.Route,
|
|||||||
|
|
||||||
// createNewPaymentAttempt creates a new payment attempt from the given route.
|
// createNewPaymentAttempt creates a new payment attempt from the given route.
|
||||||
func (p *paymentLifecycle) createNewPaymentAttempt(rt *route.Route,
|
func (p *paymentLifecycle) createNewPaymentAttempt(rt *route.Route,
|
||||||
lastShard bool) (*channeldb.HTLCAttempt, error) {
|
lastShard bool) (*paymentsdb.HTLCAttempt, error) {
|
||||||
|
|
||||||
// Generate a new key to be used for this attempt.
|
// Generate a new key to be used for this attempt.
|
||||||
sessionKey, err := generateNewSessionKey()
|
sessionKey, err := generateNewSessionKey()
|
||||||
@@ -648,7 +649,7 @@ func (p *paymentLifecycle) createNewPaymentAttempt(rt *route.Route,
|
|||||||
|
|
||||||
// We now have all the information needed to populate the current
|
// We now have all the information needed to populate the current
|
||||||
// attempt information.
|
// attempt information.
|
||||||
return channeldb.NewHtlcAttempt(
|
return paymentsdb.NewHtlcAttempt(
|
||||||
attemptID, sessionKey, *rt, p.router.cfg.Clock.Now(), &hash,
|
attemptID, sessionKey, *rt, p.router.cfg.Clock.Now(), &hash,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -657,7 +658,7 @@ func (p *paymentLifecycle) createNewPaymentAttempt(rt *route.Route,
|
|||||||
// the payment. If this attempt fails, then we'll continue on to the next
|
// the payment. If this attempt fails, then we'll continue on to the next
|
||||||
// available route.
|
// available route.
|
||||||
func (p *paymentLifecycle) sendAttempt(
|
func (p *paymentLifecycle) sendAttempt(
|
||||||
attempt *channeldb.HTLCAttempt) (*attemptResult, error) {
|
attempt *paymentsdb.HTLCAttempt) (*attemptResult, error) {
|
||||||
|
|
||||||
log.Debugf("Sending HTLC attempt(id=%v, total_amt=%v, first_hop_amt=%d"+
|
log.Debugf("Sending HTLC attempt(id=%v, total_amt=%v, first_hop_amt=%d"+
|
||||||
") for payment %v", attempt.AttemptID,
|
") for payment %v", attempt.AttemptID,
|
||||||
@@ -823,7 +824,7 @@ func (p *paymentLifecycle) failPaymentAndAttempt(
|
|||||||
// the error type, the error is either the final outcome of the payment or we
|
// the error type, the error is either the final outcome of the payment or we
|
||||||
// need to continue with an alternative route. A final outcome is indicated by
|
// need to continue with an alternative route. A final outcome is indicated by
|
||||||
// a non-nil reason value.
|
// a non-nil reason value.
|
||||||
func (p *paymentLifecycle) handleSwitchErr(attempt *channeldb.HTLCAttempt,
|
func (p *paymentLifecycle) handleSwitchErr(attempt *paymentsdb.HTLCAttempt,
|
||||||
sendErr error) (*attemptResult, error) {
|
sendErr error) (*attemptResult, error) {
|
||||||
|
|
||||||
internalErrorReason := channeldb.FailureReasonError
|
internalErrorReason := channeldb.FailureReasonError
|
||||||
@@ -1030,34 +1031,34 @@ func (p *paymentLifecycle) failAttempt(attemptID uint64,
|
|||||||
|
|
||||||
// marshallError marshall an error as received from the switch to a structure
|
// marshallError marshall an error as received from the switch to a structure
|
||||||
// that is suitable for database storage.
|
// that is suitable for database storage.
|
||||||
func marshallError(sendError error, time time.Time) *channeldb.HTLCFailInfo {
|
func marshallError(sendError error, time time.Time) *paymentsdb.HTLCFailInfo {
|
||||||
response := &channeldb.HTLCFailInfo{
|
response := &paymentsdb.HTLCFailInfo{
|
||||||
FailTime: time,
|
FailTime: time,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(sendError, htlcswitch.ErrPaymentIDNotFound):
|
case errors.Is(sendError, htlcswitch.ErrPaymentIDNotFound):
|
||||||
response.Reason = channeldb.HTLCFailInternal
|
response.Reason = paymentsdb.HTLCFailInternal
|
||||||
return response
|
return response
|
||||||
|
|
||||||
case errors.Is(sendError, htlcswitch.ErrUnreadableFailureMessage):
|
case errors.Is(sendError, htlcswitch.ErrUnreadableFailureMessage):
|
||||||
response.Reason = channeldb.HTLCFailUnreadable
|
response.Reason = paymentsdb.HTLCFailUnreadable
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
var rtErr htlcswitch.ClearTextError
|
var rtErr htlcswitch.ClearTextError
|
||||||
ok := errors.As(sendError, &rtErr)
|
ok := errors.As(sendError, &rtErr)
|
||||||
if !ok {
|
if !ok {
|
||||||
response.Reason = channeldb.HTLCFailInternal
|
response.Reason = paymentsdb.HTLCFailInternal
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
message := rtErr.WireMessage()
|
message := rtErr.WireMessage()
|
||||||
if message != nil {
|
if message != nil {
|
||||||
response.Reason = channeldb.HTLCFailMessage
|
response.Reason = paymentsdb.HTLCFailMessage
|
||||||
response.Message = message
|
response.Message = message
|
||||||
} else {
|
} else {
|
||||||
response.Reason = channeldb.HTLCFailUnknown
|
response.Reason = paymentsdb.HTLCFailUnknown
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the ClearTextError received is a ForwardingError, the error
|
// If the ClearTextError received is a ForwardingError, the error
|
||||||
@@ -1082,7 +1083,7 @@ func marshallError(sendError error, time time.Time) *channeldb.HTLCFailInfo {
|
|||||||
// enabled, the `Hash` field in their HTLC attempts is nil. In that case, we use
|
// enabled, the `Hash` field in their HTLC attempts is nil. In that case, we use
|
||||||
// the payment hash as the `attempt.Hash` as they are identical.
|
// the payment hash as the `attempt.Hash` as they are identical.
|
||||||
func (p *paymentLifecycle) patchLegacyPaymentHash(
|
func (p *paymentLifecycle) patchLegacyPaymentHash(
|
||||||
a channeldb.HTLCAttempt) channeldb.HTLCAttempt {
|
a paymentsdb.HTLCAttempt) paymentsdb.HTLCAttempt {
|
||||||
|
|
||||||
// Exit early if this is not a legacy attempt.
|
// Exit early if this is not a legacy attempt.
|
||||||
if a.Hash != nil {
|
if a.Hash != nil {
|
||||||
@@ -1134,7 +1135,7 @@ func (p *paymentLifecycle) reloadInflightAttempts() (DBMPPayment, error) {
|
|||||||
|
|
||||||
// reloadPayment returns the latest payment found in the db (control tower).
|
// reloadPayment returns the latest payment found in the db (control tower).
|
||||||
func (p *paymentLifecycle) reloadPayment() (DBMPPayment,
|
func (p *paymentLifecycle) reloadPayment() (DBMPPayment,
|
||||||
*channeldb.MPPaymentState, error) {
|
*paymentsdb.MPPaymentState, error) {
|
||||||
|
|
||||||
// Read the db to get the latest state of the payment.
|
// Read the db to get the latest state of the payment.
|
||||||
payment, err := p.router.cfg.Control.FetchPayment(p.identifier)
|
payment, err := p.router.cfg.Control.FetchPayment(p.identifier)
|
||||||
@@ -1154,7 +1155,7 @@ func (p *paymentLifecycle) reloadPayment() (DBMPPayment,
|
|||||||
|
|
||||||
// handleAttemptResult processes the result of an HTLC attempt returned from
|
// handleAttemptResult processes the result of an HTLC attempt returned from
|
||||||
// the htlcswitch.
|
// the htlcswitch.
|
||||||
func (p *paymentLifecycle) handleAttemptResult(attempt *channeldb.HTLCAttempt,
|
func (p *paymentLifecycle) handleAttemptResult(attempt *paymentsdb.HTLCAttempt,
|
||||||
result *htlcswitch.PaymentResult) (*attemptResult, error) {
|
result *htlcswitch.PaymentResult) (*attemptResult, error) {
|
||||||
|
|
||||||
// If the result has an error, we need to further process it by failing
|
// If the result has an error, we need to further process it by failing
|
||||||
@@ -1179,7 +1180,7 @@ func (p *paymentLifecycle) handleAttemptResult(attempt *channeldb.HTLCAttempt,
|
|||||||
// move the shard to the settled state.
|
// move the shard to the settled state.
|
||||||
htlcAttempt, err := p.router.cfg.Control.SettleAttempt(
|
htlcAttempt, err := p.router.cfg.Control.SettleAttempt(
|
||||||
p.identifier, attempt.AttemptID,
|
p.identifier, attempt.AttemptID,
|
||||||
&channeldb.HTLCSettleInfo{
|
&paymentsdb.HTLCSettleInfo{
|
||||||
Preimage: result.Preimage,
|
Preimage: result.Preimage,
|
||||||
SettleTime: p.router.cfg.Clock.Now(),
|
SettleTime: p.router.cfg.Clock.Now(),
|
||||||
},
|
},
|
||||||
@@ -1204,7 +1205,7 @@ func (p *paymentLifecycle) handleAttemptResult(attempt *channeldb.HTLCAttempt,
|
|||||||
// tower. An attemptResult is returned, indicating the final outcome of this
|
// tower. An attemptResult is returned, indicating the final outcome of this
|
||||||
// HTLC attempt.
|
// HTLC attempt.
|
||||||
func (p *paymentLifecycle) collectAndHandleResult(
|
func (p *paymentLifecycle) collectAndHandleResult(
|
||||||
attempt *channeldb.HTLCAttempt) (*attemptResult, error) {
|
attempt *paymentsdb.HTLCAttempt) (*attemptResult, error) {
|
||||||
|
|
||||||
result, err := p.collectResult(attempt)
|
result, err := p.collectResult(attempt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
|
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||||
"github.com/lightningnetwork/lnd/record"
|
"github.com/lightningnetwork/lnd/record"
|
||||||
"github.com/lightningnetwork/lnd/routing/route"
|
"github.com/lightningnetwork/lnd/routing/route"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
@@ -116,7 +117,7 @@ func newTestPaymentLifecycle(t *testing.T) (*paymentLifecycle, *mockers) {
|
|||||||
|
|
||||||
// Overwrite the collectResultAsync to focus on testing the payment
|
// Overwrite the collectResultAsync to focus on testing the payment
|
||||||
// lifecycle within the goroutine.
|
// lifecycle within the goroutine.
|
||||||
resultCollector := func(attempt *channeldb.HTLCAttempt) {
|
resultCollector := func(attempt *paymentsdb.HTLCAttempt) {
|
||||||
mockers.collectResultsCount++
|
mockers.collectResultsCount++
|
||||||
}
|
}
|
||||||
p.resultCollector = resultCollector
|
p.resultCollector = resultCollector
|
||||||
@@ -147,7 +148,7 @@ func setupTestPaymentLifecycle(t *testing.T) (*paymentLifecycle, *mockers) {
|
|||||||
m.payment, nil,
|
m.payment, nil,
|
||||||
).Once()
|
).Once()
|
||||||
|
|
||||||
htlcs := []channeldb.HTLCAttempt{}
|
htlcs := []paymentsdb.HTLCAttempt{}
|
||||||
m.payment.On("InFlightHTLCs").Return(htlcs).Once()
|
m.payment.On("InFlightHTLCs").Return(htlcs).Once()
|
||||||
|
|
||||||
return p, m
|
return p, m
|
||||||
@@ -258,11 +259,11 @@ func createDummyRoute(t *testing.T, amt lnwire.MilliSatoshi) *route.Route {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func makeSettledAttempt(t *testing.T, total int,
|
func makeSettledAttempt(t *testing.T, total int,
|
||||||
preimage lntypes.Preimage) *channeldb.HTLCAttempt {
|
preimage lntypes.Preimage) *paymentsdb.HTLCAttempt {
|
||||||
|
|
||||||
a := &channeldb.HTLCAttempt{
|
a := &paymentsdb.HTLCAttempt{
|
||||||
HTLCAttemptInfo: makeAttemptInfo(t, total),
|
HTLCAttemptInfo: makeAttemptInfo(t, total),
|
||||||
Settle: &channeldb.HTLCSettleInfo{Preimage: preimage},
|
Settle: &paymentsdb.HTLCSettleInfo{Preimage: preimage},
|
||||||
}
|
}
|
||||||
|
|
||||||
hash := preimage.Hash()
|
hash := preimage.Hash()
|
||||||
@@ -271,18 +272,18 @@ func makeSettledAttempt(t *testing.T, total int,
|
|||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeFailedAttempt(t *testing.T, total int) *channeldb.HTLCAttempt {
|
func makeFailedAttempt(t *testing.T, total int) *paymentsdb.HTLCAttempt {
|
||||||
return &channeldb.HTLCAttempt{
|
return &paymentsdb.HTLCAttempt{
|
||||||
HTLCAttemptInfo: makeAttemptInfo(t, total),
|
HTLCAttemptInfo: makeAttemptInfo(t, total),
|
||||||
Failure: &channeldb.HTLCFailInfo{
|
Failure: &paymentsdb.HTLCFailInfo{
|
||||||
Reason: channeldb.HTLCFailInternal,
|
Reason: paymentsdb.HTLCFailInternal,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeAttemptInfo(t *testing.T, amt int) channeldb.HTLCAttemptInfo {
|
func makeAttemptInfo(t *testing.T, amt int) paymentsdb.HTLCAttemptInfo {
|
||||||
rt := createDummyRoute(t, lnwire.MilliSatoshi(amt))
|
rt := createDummyRoute(t, lnwire.MilliSatoshi(amt))
|
||||||
return channeldb.HTLCAttemptInfo{
|
return paymentsdb.HTLCAttemptInfo{
|
||||||
Route: *rt,
|
Route: *rt,
|
||||||
Hash: &lntypes.Hash{1, 2, 3},
|
Hash: &lntypes.Hash{1, 2, 3},
|
||||||
}
|
}
|
||||||
@@ -378,7 +379,7 @@ func TestRequestRouteSucceed(t *testing.T) {
|
|||||||
p.paySession = paySession
|
p.paySession = paySession
|
||||||
|
|
||||||
// Create a dummy payment state.
|
// Create a dummy payment state.
|
||||||
ps := &channeldb.MPPaymentState{
|
ps := &paymentsdb.MPPaymentState{
|
||||||
NumAttemptsInFlight: 1,
|
NumAttemptsInFlight: 1,
|
||||||
RemainingAmt: 1,
|
RemainingAmt: 1,
|
||||||
FeesPaid: 100,
|
FeesPaid: 100,
|
||||||
@@ -415,7 +416,7 @@ func TestRequestRouteHandleCriticalErr(t *testing.T) {
|
|||||||
p.paySession = paySession
|
p.paySession = paySession
|
||||||
|
|
||||||
// Create a dummy payment state.
|
// Create a dummy payment state.
|
||||||
ps := &channeldb.MPPaymentState{
|
ps := &paymentsdb.MPPaymentState{
|
||||||
NumAttemptsInFlight: 1,
|
NumAttemptsInFlight: 1,
|
||||||
RemainingAmt: 1,
|
RemainingAmt: 1,
|
||||||
FeesPaid: 100,
|
FeesPaid: 100,
|
||||||
@@ -449,7 +450,7 @@ func TestRequestRouteHandleNoRouteErr(t *testing.T) {
|
|||||||
p, m := newTestPaymentLifecycle(t)
|
p, m := newTestPaymentLifecycle(t)
|
||||||
|
|
||||||
// Create a dummy payment state.
|
// Create a dummy payment state.
|
||||||
ps := &channeldb.MPPaymentState{
|
ps := &paymentsdb.MPPaymentState{
|
||||||
NumAttemptsInFlight: 1,
|
NumAttemptsInFlight: 1,
|
||||||
RemainingAmt: 1,
|
RemainingAmt: 1,
|
||||||
FeesPaid: 100,
|
FeesPaid: 100,
|
||||||
@@ -498,7 +499,7 @@ func TestRequestRouteFailPaymentError(t *testing.T) {
|
|||||||
p.paySession = paySession
|
p.paySession = paySession
|
||||||
|
|
||||||
// Create a dummy payment state with zero inflight attempts.
|
// Create a dummy payment state with zero inflight attempts.
|
||||||
ps := &channeldb.MPPaymentState{
|
ps := &paymentsdb.MPPaymentState{
|
||||||
NumAttemptsInFlight: 0,
|
NumAttemptsInFlight: 0,
|
||||||
RemainingAmt: 1,
|
RemainingAmt: 1,
|
||||||
FeesPaid: 100,
|
FeesPaid: 100,
|
||||||
@@ -819,14 +820,14 @@ func TestResumePaymentFailOnTimeout(t *testing.T) {
|
|||||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||||
|
|
||||||
// 2. calls `GetState` and return the state.
|
// 2. calls `GetState` and return the state.
|
||||||
ps := &channeldb.MPPaymentState{
|
ps := &paymentsdb.MPPaymentState{
|
||||||
RemainingAmt: paymentAmt,
|
RemainingAmt: paymentAmt,
|
||||||
}
|
}
|
||||||
m.payment.On("GetState").Return(ps).Once()
|
m.payment.On("GetState").Return(ps).Once()
|
||||||
|
|
||||||
// NOTE: GetStatus is only used to populate the logs which is not
|
// NOTE: GetStatus is only used to populate the logs which is not
|
||||||
// critical, so we loosen the checks on how many times it's been called.
|
// critical, so we loosen the checks on how many times it's been called.
|
||||||
m.payment.On("GetStatus").Return(channeldb.StatusInFlight)
|
m.payment.On("GetStatus").Return(paymentsdb.StatusInFlight)
|
||||||
|
|
||||||
// 3. make the timeout happens instantly and sleep one millisecond to
|
// 3. make the timeout happens instantly and sleep one millisecond to
|
||||||
// make sure it timed out.
|
// make sure it timed out.
|
||||||
@@ -875,7 +876,7 @@ func TestResumePaymentFailOnTimeoutErr(t *testing.T) {
|
|||||||
// NOTE: GetStatus is only used to populate the logs which is
|
// NOTE: GetStatus is only used to populate the logs which is
|
||||||
// not critical so we loosen the checks on how many times it's
|
// not critical so we loosen the checks on how many times it's
|
||||||
// been called.
|
// been called.
|
||||||
m.payment.On("GetStatus").Return(channeldb.StatusInFlight)
|
m.payment.On("GetStatus").Return(paymentsdb.StatusInFlight)
|
||||||
|
|
||||||
// Quit the router to return an error.
|
// Quit the router to return an error.
|
||||||
close(p.router.quit)
|
close(p.router.quit)
|
||||||
@@ -910,14 +911,14 @@ func TestResumePaymentFailContextCancel(t *testing.T) {
|
|||||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||||
|
|
||||||
// 2. calls `GetState` and return the state.
|
// 2. calls `GetState` and return the state.
|
||||||
ps := &channeldb.MPPaymentState{
|
ps := &paymentsdb.MPPaymentState{
|
||||||
RemainingAmt: paymentAmt,
|
RemainingAmt: paymentAmt,
|
||||||
}
|
}
|
||||||
m.payment.On("GetState").Return(ps).Once()
|
m.payment.On("GetState").Return(ps).Once()
|
||||||
|
|
||||||
// NOTE: GetStatus is only used to populate the logs which is not
|
// NOTE: GetStatus is only used to populate the logs which is not
|
||||||
// critical, so we loosen the checks on how many times it's been called.
|
// critical, so we loosen the checks on how many times it's been called.
|
||||||
m.payment.On("GetStatus").Return(channeldb.StatusInFlight)
|
m.payment.On("GetStatus").Return(paymentsdb.StatusInFlight)
|
||||||
|
|
||||||
// 3. Cancel the context and skip the FailPayment error to trigger the
|
// 3. Cancel the context and skip the FailPayment error to trigger the
|
||||||
// context cancellation of the payment.
|
// context cancellation of the payment.
|
||||||
@@ -963,7 +964,7 @@ func TestResumePaymentFailOnStepErr(t *testing.T) {
|
|||||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||||
|
|
||||||
// 2. calls `GetState` and return the state.
|
// 2. calls `GetState` and return the state.
|
||||||
ps := &channeldb.MPPaymentState{
|
ps := &paymentsdb.MPPaymentState{
|
||||||
RemainingAmt: paymentAmt,
|
RemainingAmt: paymentAmt,
|
||||||
}
|
}
|
||||||
m.payment.On("GetState").Return(ps).Once()
|
m.payment.On("GetState").Return(ps).Once()
|
||||||
@@ -971,7 +972,7 @@ func TestResumePaymentFailOnStepErr(t *testing.T) {
|
|||||||
// NOTE: GetStatus is only used to populate the logs which is
|
// NOTE: GetStatus is only used to populate the logs which is
|
||||||
// not critical so we loosen the checks on how many times it's
|
// not critical so we loosen the checks on how many times it's
|
||||||
// been called.
|
// been called.
|
||||||
m.payment.On("GetStatus").Return(channeldb.StatusInFlight)
|
m.payment.On("GetStatus").Return(paymentsdb.StatusInFlight)
|
||||||
|
|
||||||
// 3. decideNextStep now returns an error.
|
// 3. decideNextStep now returns an error.
|
||||||
m.payment.On("AllowMoreAttempts").Return(false, errDummy).Once()
|
m.payment.On("AllowMoreAttempts").Return(false, errDummy).Once()
|
||||||
@@ -1001,7 +1002,7 @@ func TestResumePaymentFailOnRequestRouteErr(t *testing.T) {
|
|||||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||||
|
|
||||||
// 2. calls `GetState` and return the state.
|
// 2. calls `GetState` and return the state.
|
||||||
ps := &channeldb.MPPaymentState{
|
ps := &paymentsdb.MPPaymentState{
|
||||||
RemainingAmt: paymentAmt,
|
RemainingAmt: paymentAmt,
|
||||||
}
|
}
|
||||||
m.payment.On("GetState").Return(ps).Once()
|
m.payment.On("GetState").Return(ps).Once()
|
||||||
@@ -1009,7 +1010,7 @@ func TestResumePaymentFailOnRequestRouteErr(t *testing.T) {
|
|||||||
// NOTE: GetStatus is only used to populate the logs which is
|
// NOTE: GetStatus is only used to populate the logs which is
|
||||||
// not critical so we loosen the checks on how many times it's
|
// not critical so we loosen the checks on how many times it's
|
||||||
// been called.
|
// been called.
|
||||||
m.payment.On("GetStatus").Return(channeldb.StatusInFlight)
|
m.payment.On("GetStatus").Return(paymentsdb.StatusInFlight)
|
||||||
|
|
||||||
// 3. decideNextStep now returns stepProceed.
|
// 3. decideNextStep now returns stepProceed.
|
||||||
m.payment.On("AllowMoreAttempts").Return(true, nil).Once()
|
m.payment.On("AllowMoreAttempts").Return(true, nil).Once()
|
||||||
@@ -1047,7 +1048,7 @@ func TestResumePaymentFailOnRegisterAttemptErr(t *testing.T) {
|
|||||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||||
|
|
||||||
// 2. calls `GetState` and return the state.
|
// 2. calls `GetState` and return the state.
|
||||||
ps := &channeldb.MPPaymentState{
|
ps := &paymentsdb.MPPaymentState{
|
||||||
RemainingAmt: paymentAmt,
|
RemainingAmt: paymentAmt,
|
||||||
}
|
}
|
||||||
m.payment.On("GetState").Return(ps).Once()
|
m.payment.On("GetState").Return(ps).Once()
|
||||||
@@ -1055,7 +1056,7 @@ func TestResumePaymentFailOnRegisterAttemptErr(t *testing.T) {
|
|||||||
// NOTE: GetStatus is only used to populate the logs which is
|
// NOTE: GetStatus is only used to populate the logs which is
|
||||||
// not critical so we loosen the checks on how many times it's
|
// not critical so we loosen the checks on how many times it's
|
||||||
// been called.
|
// been called.
|
||||||
m.payment.On("GetStatus").Return(channeldb.StatusInFlight)
|
m.payment.On("GetStatus").Return(paymentsdb.StatusInFlight)
|
||||||
|
|
||||||
// 3. decideNextStep now returns stepProceed.
|
// 3. decideNextStep now returns stepProceed.
|
||||||
m.payment.On("AllowMoreAttempts").Return(true, nil).Once()
|
m.payment.On("AllowMoreAttempts").Return(true, nil).Once()
|
||||||
@@ -1107,7 +1108,7 @@ func TestResumePaymentFailOnSendAttemptErr(t *testing.T) {
|
|||||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||||
|
|
||||||
// 2. calls `GetState` and return the state.
|
// 2. calls `GetState` and return the state.
|
||||||
ps := &channeldb.MPPaymentState{
|
ps := &paymentsdb.MPPaymentState{
|
||||||
RemainingAmt: paymentAmt,
|
RemainingAmt: paymentAmt,
|
||||||
}
|
}
|
||||||
m.payment.On("GetState").Return(ps).Once()
|
m.payment.On("GetState").Return(ps).Once()
|
||||||
@@ -1115,7 +1116,7 @@ func TestResumePaymentFailOnSendAttemptErr(t *testing.T) {
|
|||||||
// NOTE: GetStatus is only used to populate the logs which is
|
// NOTE: GetStatus is only used to populate the logs which is
|
||||||
// not critical so we loosen the checks on how many times it's
|
// not critical so we loosen the checks on how many times it's
|
||||||
// been called.
|
// been called.
|
||||||
m.payment.On("GetStatus").Return(channeldb.StatusInFlight)
|
m.payment.On("GetStatus").Return(paymentsdb.StatusInFlight)
|
||||||
|
|
||||||
// 3. decideNextStep now returns stepProceed.
|
// 3. decideNextStep now returns stepProceed.
|
||||||
m.payment.On("AllowMoreAttempts").Return(true, nil).Once()
|
m.payment.On("AllowMoreAttempts").Return(true, nil).Once()
|
||||||
@@ -1199,7 +1200,7 @@ func TestResumePaymentSuccess(t *testing.T) {
|
|||||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||||
|
|
||||||
// 1.2. calls `GetState` and return the state.
|
// 1.2. calls `GetState` and return the state.
|
||||||
ps := &channeldb.MPPaymentState{
|
ps := &paymentsdb.MPPaymentState{
|
||||||
RemainingAmt: paymentAmt,
|
RemainingAmt: paymentAmt,
|
||||||
}
|
}
|
||||||
m.payment.On("GetState").Return(ps).Once()
|
m.payment.On("GetState").Return(ps).Once()
|
||||||
@@ -1207,7 +1208,7 @@ func TestResumePaymentSuccess(t *testing.T) {
|
|||||||
// NOTE: GetStatus is only used to populate the logs which is
|
// NOTE: GetStatus is only used to populate the logs which is
|
||||||
// not critical so we loosen the checks on how many times it's
|
// not critical so we loosen the checks on how many times it's
|
||||||
// been called.
|
// been called.
|
||||||
m.payment.On("GetStatus").Return(channeldb.StatusInFlight)
|
m.payment.On("GetStatus").Return(paymentsdb.StatusInFlight)
|
||||||
|
|
||||||
// 1.3. decideNextStep now returns stepProceed.
|
// 1.3. decideNextStep now returns stepProceed.
|
||||||
m.payment.On("AllowMoreAttempts").Return(true, nil).Once()
|
m.payment.On("AllowMoreAttempts").Return(true, nil).Once()
|
||||||
@@ -1300,7 +1301,7 @@ func TestResumePaymentSuccessWithTwoAttempts(t *testing.T) {
|
|||||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||||
|
|
||||||
// 1.2. calls `GetState` and return the state.
|
// 1.2. calls `GetState` and return the state.
|
||||||
ps := &channeldb.MPPaymentState{
|
ps := &paymentsdb.MPPaymentState{
|
||||||
RemainingAmt: paymentAmt,
|
RemainingAmt: paymentAmt,
|
||||||
}
|
}
|
||||||
m.payment.On("GetState").Return(ps).Once()
|
m.payment.On("GetState").Return(ps).Once()
|
||||||
@@ -1308,7 +1309,7 @@ func TestResumePaymentSuccessWithTwoAttempts(t *testing.T) {
|
|||||||
// NOTE: GetStatus is only used to populate the logs which is
|
// NOTE: GetStatus is only used to populate the logs which is
|
||||||
// not critical so we loosen the checks on how many times it's
|
// not critical so we loosen the checks on how many times it's
|
||||||
// been called.
|
// been called.
|
||||||
m.payment.On("GetStatus").Return(channeldb.StatusInFlight)
|
m.payment.On("GetStatus").Return(paymentsdb.StatusInFlight)
|
||||||
|
|
||||||
// 1.3. decideNextStep now returns stepProceed.
|
// 1.3. decideNextStep now returns stepProceed.
|
||||||
m.payment.On("AllowMoreAttempts").Return(true, nil).Once()
|
m.payment.On("AllowMoreAttempts").Return(true, nil).Once()
|
||||||
@@ -1833,7 +1834,7 @@ func TestReloadInflightAttemptsLegacy(t *testing.T) {
|
|||||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||||
|
|
||||||
// 2. calls `InFlightHTLCs` and return the attempt.
|
// 2. calls `InFlightHTLCs` and return the attempt.
|
||||||
attempts := []channeldb.HTLCAttempt{*attempt}
|
attempts := []paymentsdb.HTLCAttempt{*attempt}
|
||||||
m.payment.On("InFlightHTLCs").Return(attempts).Once()
|
m.payment.On("InFlightHTLCs").Return(attempts).Once()
|
||||||
|
|
||||||
// 3. Mock the htlcswitch to return a the result chan.
|
// 3. Mock the htlcswitch to return a the result chan.
|
||||||
|
|||||||
+7
-7
@@ -1038,7 +1038,7 @@ func (r *ChannelRouter) PreparePayment(payment *LightningPayment) (
|
|||||||
// SendToRoute sends a payment using the provided route and fails the payment
|
// SendToRoute sends a payment using the provided route and fails the payment
|
||||||
// when an error is returned from the attempt.
|
// when an error is returned from the attempt.
|
||||||
func (r *ChannelRouter) SendToRoute(htlcHash lntypes.Hash, rt *route.Route,
|
func (r *ChannelRouter) SendToRoute(htlcHash lntypes.Hash, rt *route.Route,
|
||||||
firstHopCustomRecords lnwire.CustomRecords) (*channeldb.HTLCAttempt,
|
firstHopCustomRecords lnwire.CustomRecords) (*paymentsdb.HTLCAttempt,
|
||||||
error) {
|
error) {
|
||||||
|
|
||||||
return r.sendToRoute(htlcHash, rt, false, firstHopCustomRecords)
|
return r.sendToRoute(htlcHash, rt, false, firstHopCustomRecords)
|
||||||
@@ -1048,7 +1048,7 @@ func (r *ChannelRouter) SendToRoute(htlcHash lntypes.Hash, rt *route.Route,
|
|||||||
// the payment ONLY when a terminal error is returned from the attempt.
|
// the payment ONLY when a terminal error is returned from the attempt.
|
||||||
func (r *ChannelRouter) SendToRouteSkipTempErr(htlcHash lntypes.Hash,
|
func (r *ChannelRouter) SendToRouteSkipTempErr(htlcHash lntypes.Hash,
|
||||||
rt *route.Route,
|
rt *route.Route,
|
||||||
firstHopCustomRecords lnwire.CustomRecords) (*channeldb.HTLCAttempt,
|
firstHopCustomRecords lnwire.CustomRecords) (*paymentsdb.HTLCAttempt,
|
||||||
error) {
|
error) {
|
||||||
|
|
||||||
return r.sendToRoute(htlcHash, rt, true, firstHopCustomRecords)
|
return r.sendToRoute(htlcHash, rt, true, firstHopCustomRecords)
|
||||||
@@ -1062,7 +1062,7 @@ func (r *ChannelRouter) SendToRouteSkipTempErr(htlcHash lntypes.Hash,
|
|||||||
// the payment won't be failed unless a terminal error has occurred.
|
// the payment won't be failed unless a terminal error has occurred.
|
||||||
func (r *ChannelRouter) sendToRoute(htlcHash lntypes.Hash, rt *route.Route,
|
func (r *ChannelRouter) sendToRoute(htlcHash lntypes.Hash, rt *route.Route,
|
||||||
skipTempErr bool,
|
skipTempErr bool,
|
||||||
firstHopCustomRecords lnwire.CustomRecords) (*channeldb.HTLCAttempt,
|
firstHopCustomRecords lnwire.CustomRecords) (*paymentsdb.HTLCAttempt,
|
||||||
error) {
|
error) {
|
||||||
|
|
||||||
// Helper function to fail a payment. It makes sure the payment is only
|
// Helper function to fail a payment. It makes sure the payment is only
|
||||||
@@ -1448,7 +1448,7 @@ func (r *ChannelRouter) resumePayments() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// launchPayment is a helper closure that handles resuming the payment.
|
// launchPayment is a helper closure that handles resuming the payment.
|
||||||
launchPayment := func(payment *channeldb.MPPayment) {
|
launchPayment := func(payment *paymentsdb.MPPayment) {
|
||||||
defer r.wg.Done()
|
defer r.wg.Done()
|
||||||
|
|
||||||
// Get the hashes used for the outstanding HTLCs.
|
// Get the hashes used for the outstanding HTLCs.
|
||||||
@@ -1523,7 +1523,7 @@ func (r *ChannelRouter) resumePayments() error {
|
|||||||
// attempt to NOT be saved, resulting a payment being stuck forever. More info:
|
// attempt to NOT be saved, resulting a payment being stuck forever. More info:
|
||||||
// - https://github.com/lightningnetwork/lnd/issues/8146
|
// - https://github.com/lightningnetwork/lnd/issues/8146
|
||||||
// - https://github.com/lightningnetwork/lnd/pull/8174
|
// - https://github.com/lightningnetwork/lnd/pull/8174
|
||||||
func (r *ChannelRouter) failStaleAttempt(a channeldb.HTLCAttempt,
|
func (r *ChannelRouter) failStaleAttempt(a paymentsdb.HTLCAttempt,
|
||||||
payHash lntypes.Hash) {
|
payHash lntypes.Hash) {
|
||||||
|
|
||||||
// We can only fail inflight HTLCs so we skip the settled/failed ones.
|
// We can only fail inflight HTLCs so we skip the settled/failed ones.
|
||||||
@@ -1605,8 +1605,8 @@ func (r *ChannelRouter) failStaleAttempt(a channeldb.HTLCAttempt,
|
|||||||
|
|
||||||
// Fail the attempt in db. If there's an error, there's nothing we can
|
// Fail the attempt in db. If there's an error, there's nothing we can
|
||||||
// do here but logging it.
|
// do here but logging it.
|
||||||
failInfo := &channeldb.HTLCFailInfo{
|
failInfo := &paymentsdb.HTLCFailInfo{
|
||||||
Reason: channeldb.HTLCFailUnknown,
|
Reason: paymentsdb.HTLCFailUnknown,
|
||||||
FailTime: r.cfg.Clock.Now(),
|
FailTime: r.cfg.Clock.Now(),
|
||||||
}
|
}
|
||||||
_, err = r.cfg.Control.FailAttempt(payHash, a.AttemptID, failInfo)
|
_, err = r.cfg.Control.FailAttempt(payHash, a.AttemptID, failInfo)
|
||||||
|
|||||||
+3
-2
@@ -71,6 +71,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnwallet/chanfunding"
|
"github.com/lightningnetwork/lnd/lnwallet/chanfunding"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/macaroons"
|
"github.com/lightningnetwork/lnd/macaroons"
|
||||||
|
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||||
"github.com/lightningnetwork/lnd/peer"
|
"github.com/lightningnetwork/lnd/peer"
|
||||||
"github.com/lightningnetwork/lnd/peernotifier"
|
"github.com/lightningnetwork/lnd/peernotifier"
|
||||||
"github.com/lightningnetwork/lnd/record"
|
"github.com/lightningnetwork/lnd/record"
|
||||||
@@ -5892,7 +5893,7 @@ func (r *rpcServer) dispatchPaymentIntent(
|
|||||||
payment,
|
payment,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
var attempt *channeldb.HTLCAttempt
|
var attempt *paymentsdb.HTLCAttempt
|
||||||
attempt, routerErr = r.server.chanRouter.SendToRoute(
|
attempt, routerErr = r.server.chanRouter.SendToRoute(
|
||||||
payIntent.rHash, payIntent.route, nil,
|
payIntent.rHash, payIntent.route, nil,
|
||||||
)
|
)
|
||||||
@@ -7512,7 +7513,7 @@ func (r *rpcServer) ListPayments(ctx context.Context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
query := channeldb.PaymentsQuery{
|
query := paymentsdb.PaymentsQuery{
|
||||||
IndexOffset: req.IndexOffset,
|
IndexOffset: req.IndexOffset,
|
||||||
MaxPayments: req.MaxPayments,
|
MaxPayments: req.MaxPayments,
|
||||||
Reversed: req.Reversed,
|
Reversed: req.Reversed,
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/lightningnetwork/lnd/nat"
|
"github.com/lightningnetwork/lnd/nat"
|
||||||
"github.com/lightningnetwork/lnd/netann"
|
"github.com/lightningnetwork/lnd/netann"
|
||||||
|
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||||
"github.com/lightningnetwork/lnd/peer"
|
"github.com/lightningnetwork/lnd/peer"
|
||||||
"github.com/lightningnetwork/lnd/peernotifier"
|
"github.com/lightningnetwork/lnd/peernotifier"
|
||||||
"github.com/lightningnetwork/lnd/pool"
|
"github.com/lightningnetwork/lnd/pool"
|
||||||
@@ -339,7 +340,7 @@ type server struct {
|
|||||||
// payments.
|
// payments.
|
||||||
//
|
//
|
||||||
// TODO(ziggie): Replace with interface.
|
// TODO(ziggie): Replace with interface.
|
||||||
kvPaymentsDB *channeldb.KVPaymentsDB
|
kvPaymentsDB *paymentsdb.KVPaymentsDB
|
||||||
|
|
||||||
aliasMgr *aliasmgr.Manager
|
aliasMgr *aliasmgr.Manager
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user