Merge pull request #9847 from ziggie1984/refactor-payments-code-04
Refactor Payment PR 4
This commit is contained in:
34 files changed
+1264
-1139
No files matched your search
+35
-10
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
@@ -182,11 +183,6 @@ func WriteElement(w io.Writer, element interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
case paymentIndexType:
|
||||
if err := binary.Write(w, byteOrder, e); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case lnwire.FundingFlag:
|
||||
if err := binary.Write(w, byteOrder, e); err != nil {
|
||||
return err
|
||||
@@ -415,11 +411,6 @@ func ReadElement(r io.Reader, element interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
case *paymentIndexType:
|
||||
if err := binary.Read(r, byteOrder, e); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case *lnwire.FundingFlag:
|
||||
if err := binary.Read(r, byteOrder, e); err != nil {
|
||||
return err
|
||||
@@ -466,3 +457,37 @@ func ReadElements(r io.Reader, elements ...interface{}) error {
|
||||
}
|
||||
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
|
||||
}
|
||||
+7
-6
@@ -203,11 +203,13 @@ var (
|
||||
migration: mig.CreateTLB(payAddrIndexBucket),
|
||||
},
|
||||
{
|
||||
// Initialize payment index bucket which will be used
|
||||
// to index payments by sequence number. This index will
|
||||
// be used to allow more efficient ListPayments queries.
|
||||
number: 15,
|
||||
migration: mig.CreateTLB(paymentsIndexBucket),
|
||||
// This used to be create payment related top-level
|
||||
// buckets, however this is now done by the payment
|
||||
// package.
|
||||
number: 15,
|
||||
migration: func(tx kvdb.RwTx) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
// Add our existing payments to the index bucket created
|
||||
@@ -450,7 +452,6 @@ var dbTopLevelBuckets = [][]byte{
|
||||
invoiceBucket,
|
||||
payAddrIndexBucket,
|
||||
setIDIndexBucket,
|
||||
paymentsIndexBucket,
|
||||
peersBucket,
|
||||
nodeInfoBucket,
|
||||
metaBucket,
|
||||
|
||||
@@ -553,7 +553,7 @@ func (d *DB) QueryInvoices(_ context.Context, q invpkg.InvoiceQuery) (
|
||||
|
||||
// Create a paginator which reads from our add index bucket with
|
||||
// the parameters provided by the invoice query.
|
||||
paginator := newPaginator(
|
||||
paginator := NewPaginator(
|
||||
invoiceAddIndex.ReadCursor(), q.Reversed, q.IndexOffset,
|
||||
q.NumMaxInvoices,
|
||||
)
|
||||
@@ -603,7 +603,7 @@ func (d *DB) QueryInvoices(_ context.Context, q invpkg.InvoiceQuery) (
|
||||
|
||||
// Query our paginator using accumulateInvoices to build up a
|
||||
// set of invoices.
|
||||
if err := paginator.query(accumulateInvoices); err != nil {
|
||||
if err := paginator.Query(accumulateInvoices); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ type paginator struct {
|
||||
totalItems uint64
|
||||
}
|
||||
|
||||
// newPaginator returns a struct which can be used to query an indexed bucket
|
||||
// NewPaginator returns a struct which can be used to query an indexed bucket
|
||||
// in pages.
|
||||
func newPaginator(c kvdb.RCursor, reversed bool,
|
||||
func NewPaginator(c kvdb.RCursor, reversed bool,
|
||||
indexOffset, totalItems uint64) paginator {
|
||||
|
||||
return paginator{
|
||||
@@ -105,14 +105,14 @@ func (p paginator) cursorStart() ([]byte, []byte) {
|
||||
return indexKey, indexValue
|
||||
}
|
||||
|
||||
// query gets the start point for our index offset and iterates through keys
|
||||
// Query gets the start point for our index offset and iterates through keys
|
||||
// in our index until we reach the total number of items required for the query
|
||||
// or we run out of cursor values. This function takes a fetchAndAppend function
|
||||
// which is responsible for looking up the entry at that index, adding the entry
|
||||
// to its set of return items (if desired) and return a boolean which indicates
|
||||
// whether the item was added. This is required to allow the paginator to
|
||||
// determine when the response has the maximum number of required items.
|
||||
func (p paginator) query(fetchAndAppend func(k, v []byte) (bool, error)) error {
|
||||
func (p paginator) Query(fetchAndAppend func(k, v []byte) (bool, error)) error {
|
||||
indexKey, indexValue := p.cursorStart()
|
||||
|
||||
var totalItems int
|
||||
|
||||
@@ -1,162 +0,0 @@
|
||||
package channeldb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
)
|
||||
|
||||
// FailureReason encodes the reason a payment ultimately failed.
|
||||
type FailureReason byte
|
||||
|
||||
const (
|
||||
// FailureReasonTimeout indicates that the payment did timeout before a
|
||||
// successful payment attempt was made.
|
||||
FailureReasonTimeout FailureReason = 0
|
||||
|
||||
// FailureReasonNoRoute indicates no successful route to the
|
||||
// destination was found during path finding.
|
||||
FailureReasonNoRoute FailureReason = 1
|
||||
|
||||
// FailureReasonError indicates that an unexpected error happened during
|
||||
// payment.
|
||||
FailureReasonError FailureReason = 2
|
||||
|
||||
// FailureReasonPaymentDetails indicates that either the hash is unknown
|
||||
// or the final cltv delta or amount is incorrect.
|
||||
FailureReasonPaymentDetails FailureReason = 3
|
||||
|
||||
// FailureReasonInsufficientBalance indicates that we didn't have enough
|
||||
// balance to complete the payment.
|
||||
FailureReasonInsufficientBalance FailureReason = 4
|
||||
|
||||
// FailureReasonCanceled indicates that the payment was canceled by the
|
||||
// user.
|
||||
FailureReasonCanceled FailureReason = 5
|
||||
|
||||
// TODO(joostjager): Add failure reasons for:
|
||||
// LocalLiquidityInsufficient, RemoteCapacityInsufficient.
|
||||
)
|
||||
|
||||
// Error returns a human-readable error string for the FailureReason.
|
||||
func (r FailureReason) Error() string {
|
||||
return r.String()
|
||||
}
|
||||
|
||||
// String returns a human-readable FailureReason.
|
||||
func (r FailureReason) String() string {
|
||||
switch r {
|
||||
case FailureReasonTimeout:
|
||||
return "timeout"
|
||||
case FailureReasonNoRoute:
|
||||
return "no_route"
|
||||
case FailureReasonError:
|
||||
return "error"
|
||||
case FailureReasonPaymentDetails:
|
||||
return "incorrect_payment_details"
|
||||
case FailureReasonInsufficientBalance:
|
||||
return "insufficient_balance"
|
||||
case FailureReasonCanceled:
|
||||
return "canceled"
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// PaymentCreationInfo is the information necessary to have ready when
|
||||
// initiating a payment, moving it into state InFlight.
|
||||
type PaymentCreationInfo struct {
|
||||
// PaymentIdentifier is the hash this payment is paying to in case of
|
||||
// non-AMP payments, and the SetID for AMP payments.
|
||||
PaymentIdentifier lntypes.Hash
|
||||
|
||||
// Value is the amount we are paying.
|
||||
Value lnwire.MilliSatoshi
|
||||
|
||||
// CreationTime is the time when this payment was initiated.
|
||||
CreationTime time.Time
|
||||
|
||||
// PaymentRequest is the full payment request, if any.
|
||||
PaymentRequest []byte
|
||||
|
||||
// FirstHopCustomRecords are the TLV records that are to be sent to the
|
||||
// first hop of this payment. These records will be transmitted via the
|
||||
// wire message only and therefore do not affect the onion payload size.
|
||||
FirstHopCustomRecords lnwire.CustomRecords
|
||||
}
|
||||
|
||||
// String returns a human-readable description of the payment creation info.
|
||||
func (p *PaymentCreationInfo) String() string {
|
||||
return fmt.Sprintf("payment_id=%v, amount=%v, created_at=%v",
|
||||
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
|
||||
// information.
|
||||
KVPaymentsDB *channeldb.KVPaymentsDB
|
||||
KVPaymentsDB *paymentsdb.KVPaymentsDB
|
||||
|
||||
// MacaroonDB is the database that stores macaroon root keys.
|
||||
MacaroonDB kvdb.Backend
|
||||
@@ -1225,7 +1225,7 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
|
||||
cfg.KeepFailedPaymentAttempts,
|
||||
),
|
||||
}
|
||||
kvPaymentsDB, err := channeldb.NewKVPaymentsDB(
|
||||
kvPaymentsDB, err := paymentsdb.NewKVPaymentsDB(
|
||||
dbs.ChanStateDB,
|
||||
paymentsDBOptions...,
|
||||
)
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
sphinx "github.com/lightningnetwork/lightning-onion"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/clock"
|
||||
"github.com/lightningnetwork/lnd/feature"
|
||||
"github.com/lightningnetwork/lnd/fn/v2"
|
||||
@@ -22,6 +21,7 @@ import (
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||
"github.com/lightningnetwork/lnd/record"
|
||||
"github.com/lightningnetwork/lnd/routing"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
@@ -1488,7 +1488,7 @@ func UnmarshalAMP(reqAMP *lnrpc.AMPRecord) (*record.AMP, error) {
|
||||
|
||||
// MarshalHTLCAttempt constructs an RPC HTLCAttempt from the db representation.
|
||||
func (r *RouterBackend) MarshalHTLCAttempt(
|
||||
htlc channeldb.HTLCAttempt) (*lnrpc.HTLCAttempt, error) {
|
||||
htlc paymentsdb.HTLCAttempt) (*lnrpc.HTLCAttempt, error) {
|
||||
|
||||
route, err := r.MarshallRoute(&htlc.Route)
|
||||
if err != nil {
|
||||
@@ -1529,7 +1529,7 @@ func (r *RouterBackend) MarshalHTLCAttempt(
|
||||
|
||||
// marshallHtlcFailure marshalls htlc fail info from the database to its rpc
|
||||
// representation.
|
||||
func marshallHtlcFailure(failure *channeldb.HTLCFailInfo) (*lnrpc.Failure,
|
||||
func marshallHtlcFailure(failure *paymentsdb.HTLCFailInfo) (*lnrpc.Failure,
|
||||
error) {
|
||||
|
||||
rpcFailure := &lnrpc.Failure{
|
||||
@@ -1537,16 +1537,16 @@ func marshallHtlcFailure(failure *channeldb.HTLCFailInfo) (*lnrpc.Failure,
|
||||
}
|
||||
|
||||
switch failure.Reason {
|
||||
case channeldb.HTLCFailUnknown:
|
||||
case paymentsdb.HTLCFailUnknown:
|
||||
rpcFailure.Code = lnrpc.Failure_UNKNOWN_FAILURE
|
||||
|
||||
case channeldb.HTLCFailUnreadable:
|
||||
case paymentsdb.HTLCFailUnreadable:
|
||||
rpcFailure.Code = lnrpc.Failure_UNREADABLE_FAILURE
|
||||
|
||||
case channeldb.HTLCFailInternal:
|
||||
case paymentsdb.HTLCFailInternal:
|
||||
rpcFailure.Code = lnrpc.Failure_INTERNAL_FAILURE
|
||||
|
||||
case channeldb.HTLCFailMessage:
|
||||
case paymentsdb.HTLCFailMessage:
|
||||
err := marshallWireError(failure.Message, rpcFailure)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1743,7 +1743,7 @@ func marshallChannelUpdate(update *lnwire.ChannelUpdate1) *lnrpc.ChannelUpdate {
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
// Fetch the payment's preimage and the total paid in fees.
|
||||
@@ -1813,11 +1813,11 @@ func (r *RouterBackend) MarshallPayment(payment *channeldb.MPPayment) (
|
||||
|
||||
// convertPaymentStatus converts a channeldb.PaymentStatus to the type expected
|
||||
// by the RPC.
|
||||
func convertPaymentStatus(dbStatus channeldb.PaymentStatus, useInit bool) (
|
||||
func convertPaymentStatus(dbStatus paymentsdb.PaymentStatus, useInit bool) (
|
||||
lnrpc.Payment_PaymentStatus, error) {
|
||||
|
||||
switch dbStatus {
|
||||
case channeldb.StatusInitiated:
|
||||
case paymentsdb.StatusInitiated:
|
||||
// If the client understands the new status, return it.
|
||||
if useInit {
|
||||
return lnrpc.Payment_INITIATED, nil
|
||||
@@ -1826,13 +1826,13 @@ func convertPaymentStatus(dbStatus channeldb.PaymentStatus, useInit bool) (
|
||||
// Otherwise remain the old behavior.
|
||||
return lnrpc.Payment_IN_FLIGHT, nil
|
||||
|
||||
case channeldb.StatusInFlight:
|
||||
case paymentsdb.StatusInFlight:
|
||||
return lnrpc.Payment_IN_FLIGHT, nil
|
||||
|
||||
case channeldb.StatusSucceeded:
|
||||
case paymentsdb.StatusSucceeded:
|
||||
return lnrpc.Payment_SUCCEEDED, nil
|
||||
|
||||
case channeldb.StatusFailed:
|
||||
case paymentsdb.StatusFailed:
|
||||
return lnrpc.Payment_FAILED, nil
|
||||
|
||||
default:
|
||||
@@ -1842,7 +1842,7 @@ func convertPaymentStatus(dbStatus channeldb.PaymentStatus, useInit bool) (
|
||||
|
||||
// marshallPaymentFailureReason marshalls the failure reason to the corresponding rpc
|
||||
// type.
|
||||
func marshallPaymentFailureReason(reason *channeldb.FailureReason) (
|
||||
func marshallPaymentFailureReason(reason *paymentsdb.FailureReason) (
|
||||
lnrpc.PaymentFailureReason, error) {
|
||||
|
||||
if reason == nil {
|
||||
@@ -1850,22 +1850,22 @@ func marshallPaymentFailureReason(reason *channeldb.FailureReason) (
|
||||
}
|
||||
|
||||
switch *reason {
|
||||
case channeldb.FailureReasonTimeout:
|
||||
case paymentsdb.FailureReasonTimeout:
|
||||
return lnrpc.PaymentFailureReason_FAILURE_REASON_TIMEOUT, nil
|
||||
|
||||
case channeldb.FailureReasonNoRoute:
|
||||
case paymentsdb.FailureReasonNoRoute:
|
||||
return lnrpc.PaymentFailureReason_FAILURE_REASON_NO_ROUTE, nil
|
||||
|
||||
case channeldb.FailureReasonError:
|
||||
case paymentsdb.FailureReasonError:
|
||||
return lnrpc.PaymentFailureReason_FAILURE_REASON_ERROR, nil
|
||||
|
||||
case channeldb.FailureReasonPaymentDetails:
|
||||
case paymentsdb.FailureReasonPaymentDetails:
|
||||
return lnrpc.PaymentFailureReason_FAILURE_REASON_INCORRECT_PAYMENT_DETAILS, nil
|
||||
|
||||
case channeldb.FailureReasonInsufficientBalance:
|
||||
case paymentsdb.FailureReasonInsufficientBalance:
|
||||
return lnrpc.PaymentFailureReason_FAILURE_REASON_INSUFFICIENT_BALANCE, nil
|
||||
|
||||
case channeldb.FailureReasonCanceled:
|
||||
case paymentsdb.FailureReasonCanceled:
|
||||
return lnrpc.PaymentFailureReason_FAILURE_REASON_CANCELED, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"github.com/lightningnetwork/lnd/aliasmgr"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/fn/v2"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
|
||||
@@ -927,7 +926,7 @@ func (s *Server) SendToRouteV2(ctx context.Context,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var attempt *channeldb.HTLCAttempt
|
||||
var attempt *paymentsdb.HTLCAttempt
|
||||
|
||||
// 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
|
||||
@@ -1449,17 +1448,21 @@ func (s *Server) trackPaymentStream(context context.Context,
|
||||
// No more payment updates.
|
||||
return nil
|
||||
}
|
||||
result := item.(*channeldb.MPPayment)
|
||||
result, ok := item.(*paymentsdb.MPPayment)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected payment type: %T",
|
||||
item)
|
||||
}
|
||||
|
||||
log.Tracef("Payment %v updated to state %v",
|
||||
result.Info.PaymentIdentifier, result.Status)
|
||||
|
||||
// Skip in-flight updates unless requested.
|
||||
if noInflightUpdates {
|
||||
if result.Status == channeldb.StatusInitiated {
|
||||
if result.Status == paymentsdb.StatusInitiated {
|
||||
continue
|
||||
}
|
||||
if result.Status == channeldb.StatusInFlight {
|
||||
if result.Status == paymentsdb.StatusInFlight {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
graphdb "github.com/lightningnetwork/lnd/graph/db"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||
"github.com/lightningnetwork/lnd/queue"
|
||||
"github.com/lightningnetwork/lnd/routing"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
@@ -129,13 +129,13 @@ func TestTrackPaymentsInflightUpdates(t *testing.T) {
|
||||
}()
|
||||
|
||||
// Enqueue some payment updates on the mock.
|
||||
towerMock.queue.ChanIn() <- &channeldb.MPPayment{
|
||||
Info: &channeldb.PaymentCreationInfo{},
|
||||
Status: channeldb.StatusInFlight,
|
||||
towerMock.queue.ChanIn() <- &paymentsdb.MPPayment{
|
||||
Info: &paymentsdb.PaymentCreationInfo{},
|
||||
Status: paymentsdb.StatusInFlight,
|
||||
}
|
||||
towerMock.queue.ChanIn() <- &channeldb.MPPayment{
|
||||
Info: &channeldb.PaymentCreationInfo{},
|
||||
Status: channeldb.StatusSucceeded,
|
||||
towerMock.queue.ChanIn() <- &paymentsdb.MPPayment{
|
||||
Info: &paymentsdb.PaymentCreationInfo{},
|
||||
Status: paymentsdb.StatusSucceeded,
|
||||
}
|
||||
|
||||
// Wait until there's 2 updates or the deadline is exceeded.
|
||||
@@ -191,13 +191,13 @@ func TestTrackPaymentsNoInflightUpdates(t *testing.T) {
|
||||
}()
|
||||
|
||||
// Enqueue some payment updates on the mock.
|
||||
towerMock.queue.ChanIn() <- &channeldb.MPPayment{
|
||||
Info: &channeldb.PaymentCreationInfo{},
|
||||
Status: channeldb.StatusInFlight,
|
||||
towerMock.queue.ChanIn() <- &paymentsdb.MPPayment{
|
||||
Info: &paymentsdb.PaymentCreationInfo{},
|
||||
Status: paymentsdb.StatusInFlight,
|
||||
}
|
||||
towerMock.queue.ChanIn() <- &channeldb.MPPayment{
|
||||
Info: &channeldb.PaymentCreationInfo{},
|
||||
Status: channeldb.StatusSucceeded,
|
||||
towerMock.queue.ChanIn() <- &paymentsdb.MPPayment{
|
||||
Info: &paymentsdb.PaymentCreationInfo{},
|
||||
Status: paymentsdb.StatusSucceeded,
|
||||
}
|
||||
|
||||
// Wait until there's 1 update or the deadline is exceeded.
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
package paymentsdb
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"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:
|
||||
var unknownElementType UnknownElementType
|
||||
if !errors.As(err, &unknownElementType) {
|
||||
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:
|
||||
var unknownElementType UnknownElementType
|
||||
if !errors.As(err, &unknownElementType) {
|
||||
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 (
|
||||
"bytes"
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/lightningnetwork/lnd/kvdb"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
)
|
||||
|
||||
@@ -75,7 +74,7 @@ func fetchDuplicatePaymentStatus(bucket kvdb.RBucket) (PaymentStatus, error) {
|
||||
return StatusInFlight, nil
|
||||
}
|
||||
|
||||
return 0, paymentsdb.ErrPaymentNotInitiated
|
||||
return 0, ErrPaymentNotInitiated
|
||||
}
|
||||
|
||||
func deserializeDuplicateHTLCAttemptInfo(r io.Reader) (
|
||||
@@ -1,4 +1,4 @@
|
||||
package channeldb
|
||||
package paymentsdb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -13,10 +13,10 @@ import (
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/kvdb"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"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/tlv"
|
||||
@@ -127,19 +127,21 @@ type KVPaymentsDB struct {
|
||||
// db is the underlying database implementation.
|
||||
db kvdb.Backend
|
||||
|
||||
// keepFailedPaymentAttempts is a flag that indicates whether we should
|
||||
// keep failed payment attempts in the database.
|
||||
keepFailedPaymentAttempts bool
|
||||
}
|
||||
|
||||
// defaultKVStoreOptions returns the default options for the KV store.
|
||||
func defaultKVStoreOptions() *paymentsdb.StoreOptions {
|
||||
return &paymentsdb.StoreOptions{
|
||||
func defaultKVStoreOptions() *StoreOptions {
|
||||
return &StoreOptions{
|
||||
KeepFailedPaymentAttempts: false,
|
||||
}
|
||||
}
|
||||
|
||||
// NewKVPaymentsDB creates a new KVStore for payments.
|
||||
func NewKVPaymentsDB(db kvdb.Backend,
|
||||
options ...paymentsdb.OptionModifier) (*KVPaymentsDB, error) {
|
||||
options ...OptionModifier) (*KVPaymentsDB, error) {
|
||||
|
||||
opts := defaultKVStoreOptions()
|
||||
for _, applyOption := range options {
|
||||
@@ -158,6 +160,8 @@ func NewKVPaymentsDB(db kvdb.Backend,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// paymentsTopLevelBuckets is a list of top-level buckets that are used for
|
||||
// the payments database when using the kv store.
|
||||
var paymentsTopLevelBuckets = [][]byte{
|
||||
paymentsRootBucket,
|
||||
paymentsIndexBucket,
|
||||
@@ -229,7 +233,7 @@ func (p *KVPaymentsDB) InitPayment(paymentHash lntypes.Hash,
|
||||
|
||||
// Otherwise, if the error is not `ErrPaymentNotInitiated`,
|
||||
// we'll return the error.
|
||||
case !errors.Is(err, paymentsdb.ErrPaymentNotInitiated):
|
||||
case !errors.Is(err, ErrPaymentNotInitiated):
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -403,7 +407,7 @@ func (p *KVPaymentsDB) RegisterAttempt(paymentHash lntypes.Hash,
|
||||
|
||||
// MPP records should not be set for attempts to blinded paths.
|
||||
if isBlinded && mpp != nil {
|
||||
return paymentsdb.ErrMPPRecordInBlindedPayment
|
||||
return ErrMPPRecordInBlindedPayment
|
||||
}
|
||||
|
||||
for _, h := range payment.InFlightHTLCs() {
|
||||
@@ -412,7 +416,7 @@ func (p *KVPaymentsDB) RegisterAttempt(paymentHash lntypes.Hash,
|
||||
// If this is a blinded payment, then no existing HTLCs
|
||||
// should have MPP records.
|
||||
if isBlinded && hMpp != nil {
|
||||
return paymentsdb.ErrMPPRecordInBlindedPayment
|
||||
return ErrMPPRecordInBlindedPayment
|
||||
}
|
||||
|
||||
// If this is a blinded payment, then we just need to
|
||||
@@ -424,7 +428,7 @@ func (p *KVPaymentsDB) RegisterAttempt(paymentHash lntypes.Hash,
|
||||
h.Route.FinalHop().TotalAmtMsat {
|
||||
|
||||
//nolint:ll
|
||||
return paymentsdb.ErrBlindedPaymentTotalAmountMismatch
|
||||
return ErrBlindedPaymentTotalAmountMismatch
|
||||
}
|
||||
|
||||
continue
|
||||
@@ -434,12 +438,12 @@ func (p *KVPaymentsDB) RegisterAttempt(paymentHash lntypes.Hash,
|
||||
// We tried to register a non-MPP attempt for a MPP
|
||||
// payment.
|
||||
case mpp == nil && hMpp != nil:
|
||||
return paymentsdb.ErrMPPayment
|
||||
return ErrMPPayment
|
||||
|
||||
// We tried to register a MPP shard for a non-MPP
|
||||
// payment.
|
||||
case mpp != nil && hMpp == nil:
|
||||
return paymentsdb.ErrNonMPPayment
|
||||
return ErrNonMPPayment
|
||||
|
||||
// Non-MPP payment, nothing more to validate.
|
||||
case mpp == nil:
|
||||
@@ -448,11 +452,11 @@ func (p *KVPaymentsDB) RegisterAttempt(paymentHash lntypes.Hash,
|
||||
|
||||
// Check that MPP options match.
|
||||
if mpp.PaymentAddr() != hMpp.PaymentAddr() {
|
||||
return paymentsdb.ErrMPPPaymentAddrMismatch
|
||||
return ErrMPPPaymentAddrMismatch
|
||||
}
|
||||
|
||||
if mpp.TotalMsat() != hMpp.TotalMsat() {
|
||||
return paymentsdb.ErrMPPTotalAmountMismatch
|
||||
return ErrMPPTotalAmountMismatch
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,14 +465,14 @@ func (p *KVPaymentsDB) RegisterAttempt(paymentHash lntypes.Hash,
|
||||
// attempt.
|
||||
amt := attempt.Route.ReceiverAmt()
|
||||
if !isBlinded && mpp == nil && amt != payment.Info.Value {
|
||||
return paymentsdb.ErrValueMismatch
|
||||
return ErrValueMismatch
|
||||
}
|
||||
|
||||
// Ensure we aren't sending more than the total payment amount.
|
||||
sentAmt, _ := payment.SentAmt()
|
||||
if sentAmt+amt > payment.Info.Value {
|
||||
return fmt.Errorf("%w: attempted=%v, payment amount="+
|
||||
"%v", paymentsdb.ErrValueExceedsAmt,
|
||||
"%v", ErrValueExceedsAmt,
|
||||
sentAmt+amt, payment.Info.Value)
|
||||
}
|
||||
|
||||
@@ -574,12 +578,12 @@ func (p *KVPaymentsDB) updateHtlcKey(paymentHash lntypes.Hash,
|
||||
// Make sure the shard is not already failed or settled.
|
||||
failKey := htlcBucketKey(htlcFailInfoKey, aid)
|
||||
if htlcsBucket.Get(failKey) != nil {
|
||||
return paymentsdb.ErrAttemptAlreadyFailed
|
||||
return ErrAttemptAlreadyFailed
|
||||
}
|
||||
|
||||
settleKey := htlcBucketKey(htlcSettleInfoKey, aid)
|
||||
if htlcsBucket.Get(settleKey) != nil {
|
||||
return paymentsdb.ErrAttemptAlreadySettled
|
||||
return ErrAttemptAlreadySettled
|
||||
}
|
||||
|
||||
// Add or update the key for this htlc.
|
||||
@@ -619,8 +623,8 @@ func (p *KVPaymentsDB) Fail(paymentHash lntypes.Hash,
|
||||
|
||||
prefetchPayment(tx, paymentHash)
|
||||
bucket, err := fetchPaymentBucketUpdate(tx, paymentHash)
|
||||
if errors.Is(err, paymentsdb.ErrPaymentNotInitiated) {
|
||||
updateErr = paymentsdb.ErrPaymentNotInitiated
|
||||
if errors.Is(err, ErrPaymentNotInitiated) {
|
||||
updateErr = ErrPaymentNotInitiated
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return err
|
||||
@@ -631,8 +635,8 @@ func (p *KVPaymentsDB) Fail(paymentHash lntypes.Hash,
|
||||
// failure to the KVPaymentsDB without synchronizing with
|
||||
// other attempts.
|
||||
_, err = fetchPaymentStatus(bucket)
|
||||
if errors.Is(err, paymentsdb.ErrPaymentNotInitiated) {
|
||||
updateErr = paymentsdb.ErrPaymentNotInitiated
|
||||
if errors.Is(err, ErrPaymentNotInitiated) {
|
||||
updateErr = ErrPaymentNotInitiated
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return err
|
||||
@@ -725,12 +729,12 @@ func fetchPaymentBucket(tx kvdb.RTx, paymentHash lntypes.Hash) (
|
||||
|
||||
payments := tx.ReadBucket(paymentsRootBucket)
|
||||
if payments == nil {
|
||||
return nil, paymentsdb.ErrPaymentNotInitiated
|
||||
return nil, ErrPaymentNotInitiated
|
||||
}
|
||||
|
||||
bucket := payments.NestedReadBucket(paymentHash[:])
|
||||
if bucket == nil {
|
||||
return nil, paymentsdb.ErrPaymentNotInitiated
|
||||
return nil, ErrPaymentNotInitiated
|
||||
}
|
||||
|
||||
return bucket, nil
|
||||
@@ -743,12 +747,12 @@ func fetchPaymentBucketUpdate(tx kvdb.RwTx, paymentHash lntypes.Hash) (
|
||||
|
||||
payments := tx.ReadWriteBucket(paymentsRootBucket)
|
||||
if payments == nil {
|
||||
return nil, paymentsdb.ErrPaymentNotInitiated
|
||||
return nil, ErrPaymentNotInitiated
|
||||
}
|
||||
|
||||
bucket := payments.NestedReadWriteBucket(paymentHash[:])
|
||||
if bucket == nil {
|
||||
return nil, paymentsdb.ErrPaymentNotInitiated
|
||||
return nil, ErrPaymentNotInitiated
|
||||
}
|
||||
|
||||
return bucket, nil
|
||||
@@ -805,7 +809,7 @@ func fetchPaymentStatus(bucket kvdb.RBucket) (PaymentStatus, error) {
|
||||
// Creation info should be set for all payments, regardless of state.
|
||||
// If not, it is unknown.
|
||||
if bucket.Get(paymentCreationInfoKey) == nil {
|
||||
return 0, paymentsdb.ErrPaymentNotInitiated
|
||||
return 0, ErrPaymentNotInitiated
|
||||
}
|
||||
|
||||
payment, err := fetchPayment(bucket)
|
||||
@@ -1051,7 +1055,7 @@ func fetchHtlcAttempts(bucket kvdb.RBucket) ([]HTLCAttempt, error) {
|
||||
|
||||
// Sanity check that all htlcs have an attempt info.
|
||||
if attemptInfoCount != len(htlcsMap) {
|
||||
return nil, paymentsdb.ErrNoAttemptInfo
|
||||
return nil, ErrNoAttemptInfo
|
||||
}
|
||||
|
||||
keys := make([]uint64, len(htlcsMap))
|
||||
@@ -1131,9 +1135,9 @@ func fetchFailedHtlcKeys(bucket kvdb.RBucket) ([][]byte, error) {
|
||||
// to a subset of payments by the payments query, containing an offset
|
||||
// index and a maximum number of returned payments.
|
||||
func (p *KVPaymentsDB) QueryPayments(_ context.Context,
|
||||
query PaymentsQuery) (PaymentsResponse, error) {
|
||||
query Query) (Response, error) {
|
||||
|
||||
var resp PaymentsResponse
|
||||
var resp Response
|
||||
|
||||
if err := kvdb.View(p.db, func(tx kvdb.RTx) error {
|
||||
// Get the root payments bucket.
|
||||
@@ -1205,13 +1209,13 @@ func (p *KVPaymentsDB) QueryPayments(_ context.Context,
|
||||
|
||||
// Create a paginator which reads from our sequence index bucket
|
||||
// with the parameters provided by the payments query.
|
||||
paginator := newPaginator(
|
||||
paginator := channeldb.NewPaginator(
|
||||
indexes.ReadCursor(), query.Reversed, query.IndexOffset,
|
||||
query.MaxPayments,
|
||||
)
|
||||
|
||||
// Run a paginated query, adding payments to our response.
|
||||
if err := paginator.query(accumulatePayments); err != nil {
|
||||
if err := paginator.Query(accumulatePayments); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1247,7 +1251,7 @@ func (p *KVPaymentsDB) QueryPayments(_ context.Context,
|
||||
|
||||
return nil
|
||||
}, func() {
|
||||
resp = PaymentsResponse{}
|
||||
resp = Response{}
|
||||
}); err != nil {
|
||||
return resp, err
|
||||
}
|
||||
@@ -1290,7 +1294,7 @@ func fetchPaymentWithSequenceNumber(tx kvdb.RTx, paymentHash lntypes.Hash,
|
||||
// the payment we are actually looking for.
|
||||
seqBytes := bucket.Get(paymentSequenceKey)
|
||||
if seqBytes == nil {
|
||||
return nil, paymentsdb.ErrNoSequenceNumber
|
||||
return nil, ErrNoSequenceNumber
|
||||
}
|
||||
|
||||
// If this top level payment has the sequence number we are looking for,
|
||||
@@ -1305,7 +1309,7 @@ func fetchPaymentWithSequenceNumber(tx kvdb.RTx, paymentHash lntypes.Hash,
|
||||
// find a duplicate payments bucket here, something is wrong.
|
||||
dup := bucket.NestedReadBucket(duplicatePaymentsBucket)
|
||||
if dup == nil {
|
||||
return nil, paymentsdb.ErrNoDuplicateBucket
|
||||
return nil, ErrNoDuplicateBucket
|
||||
}
|
||||
|
||||
var duplicatePayment *MPPayment
|
||||
@@ -1313,7 +1317,7 @@ func fetchPaymentWithSequenceNumber(tx kvdb.RTx, paymentHash lntypes.Hash,
|
||||
subBucket := dup.NestedReadBucket(k)
|
||||
if subBucket == nil {
|
||||
// We one bucket for each duplicate to be found.
|
||||
return paymentsdb.ErrNoDuplicateNestedBucket
|
||||
return ErrNoDuplicateNestedBucket
|
||||
}
|
||||
|
||||
seqBytes := subBucket.Get(duplicatePaymentSequenceKey)
|
||||
@@ -1342,7 +1346,7 @@ func fetchPaymentWithSequenceNumber(tx kvdb.RTx, paymentHash lntypes.Hash,
|
||||
// failed to find the payment with this sequence number; something is
|
||||
// wrong.
|
||||
if duplicatePayment == nil {
|
||||
return nil, paymentsdb.ErrDuplicateNotFound
|
||||
return nil, ErrDuplicateNotFound
|
||||
}
|
||||
|
||||
return duplicatePayment, nil
|
||||
@@ -1,4 +1,4 @@
|
||||
package channeldb
|
||||
package paymentsdb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"github.com/lightningnetwork/lnd/kvdb"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"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/tlv"
|
||||
@@ -64,11 +63,7 @@ func genInfo(t *testing.T) (*PaymentCreationInfo, *HTLCAttemptInfo,
|
||||
func TestKVPaymentsDBSwitchFail(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db, err := MakeTestDB(t)
|
||||
require.NoError(t, err, "unable to init db")
|
||||
|
||||
paymentDB, err := NewKVPaymentsDB(db)
|
||||
require.NoError(t, err)
|
||||
paymentDB := NewTestDB(t)
|
||||
|
||||
info, attempt, preimg, err := genInfo(t)
|
||||
require.NoError(t, err, "unable to generate htlc message")
|
||||
@@ -195,7 +190,7 @@ func TestKVPaymentsDBSwitchFail(t *testing.T) {
|
||||
// Attempt a final payment, which should now fail since the prior
|
||||
// payment succeed.
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -205,11 +200,7 @@ func TestKVPaymentsDBSwitchFail(t *testing.T) {
|
||||
func TestKVPaymentsDBSwitchDoubleSend(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db, err := MakeTestDB(t)
|
||||
require.NoError(t, err, "unable to init db")
|
||||
|
||||
paymentDB, err := NewKVPaymentsDB(db)
|
||||
require.NoError(t, err)
|
||||
paymentDB := NewTestDB(t)
|
||||
|
||||
info, attempt, preimg, err := genInfo(t)
|
||||
require.NoError(t, err, "unable to generate htlc message")
|
||||
@@ -231,7 +222,7 @@ func TestKVPaymentsDBSwitchDoubleSend(t *testing.T) {
|
||||
// payment hash, should result in error indicating that payment has
|
||||
// already been sent.
|
||||
err = paymentDB.InitPayment(info.PaymentIdentifier, info)
|
||||
require.ErrorIs(t, err, paymentsdb.ErrPaymentExists)
|
||||
require.ErrorIs(t, err, ErrPaymentExists)
|
||||
|
||||
// Record an attempt.
|
||||
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, attempt)
|
||||
@@ -249,7 +240,7 @@ func TestKVPaymentsDBSwitchDoubleSend(t *testing.T) {
|
||||
|
||||
// Sends base htlc message which initiate StatusInFlight.
|
||||
err = paymentDB.InitPayment(info.PaymentIdentifier, info)
|
||||
if !errors.Is(err, paymentsdb.ErrPaymentInFlight) {
|
||||
if !errors.Is(err, ErrPaymentInFlight) {
|
||||
t.Fatalf("payment control wrong behaviour: " +
|
||||
"double sending must trigger ErrPaymentInFlight error")
|
||||
}
|
||||
@@ -272,7 +263,7 @@ func TestKVPaymentsDBSwitchDoubleSend(t *testing.T) {
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -282,11 +273,7 @@ func TestKVPaymentsDBSwitchDoubleSend(t *testing.T) {
|
||||
func TestKVPaymentsDBSuccessesWithoutInFlight(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db, err := MakeTestDB(t)
|
||||
require.NoError(t, err, "unable to init db")
|
||||
|
||||
paymentDB, err := NewKVPaymentsDB(db)
|
||||
require.NoError(t, err)
|
||||
paymentDB := NewTestDB(t)
|
||||
|
||||
info, _, preimg, err := genInfo(t)
|
||||
require.NoError(t, err, "unable to generate htlc message")
|
||||
@@ -298,7 +285,7 @@ func TestKVPaymentsDBSuccessesWithoutInFlight(t *testing.T) {
|
||||
Preimage: preimg,
|
||||
},
|
||||
)
|
||||
require.ErrorIs(t, err, paymentsdb.ErrPaymentNotInitiated)
|
||||
require.ErrorIs(t, err, ErrPaymentNotInitiated)
|
||||
}
|
||||
|
||||
// TestKVPaymentsDBFailsWithoutInFlight checks that a strict payment
|
||||
@@ -306,18 +293,16 @@ func TestKVPaymentsDBSuccessesWithoutInFlight(t *testing.T) {
|
||||
func TestKVPaymentsDBFailsWithoutInFlight(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db, err := MakeTestDB(t)
|
||||
require.NoError(t, err, "unable to init db")
|
||||
|
||||
paymentDB, err := NewKVPaymentsDB(db)
|
||||
require.NoError(t, err)
|
||||
paymentDB := NewTestDB(t)
|
||||
|
||||
info, _, _, err := genInfo(t)
|
||||
require.NoError(t, err, "unable to generate htlc message")
|
||||
|
||||
// Calling Fail should return an error.
|
||||
_, err = paymentDB.Fail(info.PaymentIdentifier, FailureReasonNoRoute)
|
||||
require.ErrorIs(t, err, paymentsdb.ErrPaymentNotInitiated)
|
||||
_, err = paymentDB.Fail(
|
||||
info.PaymentIdentifier, FailureReasonNoRoute,
|
||||
)
|
||||
require.ErrorIs(t, err, ErrPaymentNotInitiated)
|
||||
}
|
||||
|
||||
// TestKVPaymentsDBDeleteNonInFlight checks that calling DeletePayments only
|
||||
@@ -325,17 +310,13 @@ func TestKVPaymentsDBFailsWithoutInFlight(t *testing.T) {
|
||||
func TestKVPaymentsDBDeleteNonInFlight(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db, err := MakeTestDB(t)
|
||||
require.NoError(t, err, "unable to init db")
|
||||
paymentDB := NewTestDB(t)
|
||||
|
||||
// Create a sequence number for duplicate payments that will not collide
|
||||
// with the sequence numbers for the payments we create. These values
|
||||
// start at 1, so 9999 is a safe bet for this test.
|
||||
var duplicateSeqNr = 9999
|
||||
|
||||
paymentDB, err := NewKVPaymentsDB(db)
|
||||
require.NoError(t, err)
|
||||
|
||||
payments := []struct {
|
||||
failed bool
|
||||
success bool
|
||||
@@ -531,7 +512,7 @@ func TestKVPaymentsDBDeleteNonInFlight(t *testing.T) {
|
||||
// Finally, check that we only have a single index left in the payment
|
||||
// index bucket.
|
||||
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)
|
||||
|
||||
return index.ForEach(func(k, v []byte) error {
|
||||
@@ -549,11 +530,7 @@ func TestKVPaymentsDBDeleteNonInFlight(t *testing.T) {
|
||||
func TestKVPaymentsDBDeletePayments(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db, err := MakeTestDB(t)
|
||||
require.NoError(t, err, "unable to init db")
|
||||
|
||||
paymentDB, err := NewKVPaymentsDB(db)
|
||||
require.NoError(t, err)
|
||||
paymentDB := NewTestDB(t)
|
||||
|
||||
// Register three payments:
|
||||
// 1. A payment with two failed attempts.
|
||||
@@ -611,11 +588,7 @@ func TestKVPaymentsDBDeletePayments(t *testing.T) {
|
||||
func TestKVPaymentsDBDeleteSinglePayment(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db, err := MakeTestDB(t)
|
||||
require.NoError(t, err, "unable to init db")
|
||||
|
||||
paymentDB, err := NewKVPaymentsDB(db)
|
||||
require.NoError(t, err)
|
||||
paymentDB := NewTestDB(t)
|
||||
|
||||
// Register four payments:
|
||||
// All payments will have one failed HTLC attempt and one HTLC attempt
|
||||
@@ -716,13 +689,7 @@ func TestKVPaymentsDBMultiShard(t *testing.T) {
|
||||
}
|
||||
|
||||
runSubTest := func(t *testing.T, test testCase) {
|
||||
db, err := MakeTestDB(t)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to init db: %v", err)
|
||||
}
|
||||
|
||||
paymentDB, err := NewKVPaymentsDB(db)
|
||||
require.NoError(t, err)
|
||||
paymentDB := NewTestDB(t)
|
||||
|
||||
info, attempt, preimg, err := genInfo(t)
|
||||
if err != nil {
|
||||
@@ -785,7 +752,7 @@ func TestKVPaymentsDBMultiShard(t *testing.T) {
|
||||
b := *attempt
|
||||
b.AttemptID = 3
|
||||
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, &b)
|
||||
require.ErrorIs(t, err, paymentsdb.ErrValueExceedsAmt)
|
||||
require.ErrorIs(t, err, ErrValueExceedsAmt)
|
||||
|
||||
// Fail the second attempt.
|
||||
a := attempts[1]
|
||||
@@ -886,11 +853,11 @@ func TestKVPaymentsDBMultiShard(t *testing.T) {
|
||||
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, &b)
|
||||
if test.settleFirst {
|
||||
require.ErrorIs(
|
||||
t, err, paymentsdb.ErrPaymentPendingSettled,
|
||||
t, err, ErrPaymentPendingSettled,
|
||||
)
|
||||
} else {
|
||||
require.ErrorIs(
|
||||
t, err, paymentsdb.ErrPaymentPendingFailed,
|
||||
t, err, ErrPaymentPendingFailed,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -960,21 +927,21 @@ func TestKVPaymentsDBMultiShard(t *testing.T) {
|
||||
// settled.
|
||||
case test.settleFirst && !test.settleLast:
|
||||
finalStatus = StatusSucceeded
|
||||
registerErr = paymentsdb.ErrPaymentAlreadySucceeded
|
||||
registerErr = ErrPaymentAlreadySucceeded
|
||||
|
||||
case !test.settleFirst && test.settleLast:
|
||||
finalStatus = StatusSucceeded
|
||||
registerErr = paymentsdb.ErrPaymentAlreadySucceeded
|
||||
registerErr = ErrPaymentAlreadySucceeded
|
||||
|
||||
// If both failed, we end up in a failed status.
|
||||
case !test.settleFirst && !test.settleLast:
|
||||
finalStatus = StatusFailed
|
||||
registerErr = paymentsdb.ErrPaymentAlreadyFailed
|
||||
registerErr = ErrPaymentAlreadyFailed
|
||||
|
||||
// Otherwise, the payment has a succeed status.
|
||||
case test.settleFirst && test.settleLast:
|
||||
finalStatus = StatusSucceeded
|
||||
registerErr = paymentsdb.ErrPaymentAlreadySucceeded
|
||||
registerErr = ErrPaymentAlreadySucceeded
|
||||
}
|
||||
|
||||
assertPaymentStatus(
|
||||
@@ -987,7 +954,6 @@ func TestKVPaymentsDBMultiShard(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
subTest := fmt.Sprintf("first=%v, second=%v",
|
||||
test.settleFirst, test.settleLast)
|
||||
|
||||
@@ -1000,11 +966,7 @@ func TestKVPaymentsDBMultiShard(t *testing.T) {
|
||||
func TestKVPaymentsDBMPPRecordValidation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db, err := MakeTestDB(t)
|
||||
require.NoError(t, err, "unable to init db")
|
||||
|
||||
paymentDB, err := NewKVPaymentsDB(db)
|
||||
require.NoError(t, err)
|
||||
paymentDB := NewTestDB(t)
|
||||
|
||||
info, attempt, _, err := genInfo(t)
|
||||
require.NoError(t, err, "unable to generate htlc message")
|
||||
@@ -1031,21 +993,21 @@ func TestKVPaymentsDBMPPRecordValidation(t *testing.T) {
|
||||
b.AttemptID = 1
|
||||
b.Route.FinalHop().MPP = nil
|
||||
_, 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.
|
||||
b.Route.FinalHop().MPP = record.NewMPP(
|
||||
info.Value, [32]byte{2},
|
||||
)
|
||||
_, 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.
|
||||
b.Route.FinalHop().MPP = record.NewMPP(
|
||||
info.Value/2, [32]byte{1},
|
||||
)
|
||||
_, 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
|
||||
// register an MPP attempt if we already registered a non-MPP one.
|
||||
@@ -1067,7 +1029,7 @@ func TestKVPaymentsDBMPPRecordValidation(t *testing.T) {
|
||||
)
|
||||
|
||||
_, err = paymentDB.RegisterAttempt(info.PaymentIdentifier, &b)
|
||||
require.ErrorIs(t, err, paymentsdb.ErrNonMPPayment)
|
||||
require.ErrorIs(t, err, ErrNonMPPayment)
|
||||
}
|
||||
|
||||
// TestDeleteFailedAttempts checks that DeleteFailedAttempts properly removes
|
||||
@@ -1084,16 +1046,9 @@ func TestDeleteFailedAttempts(t *testing.T) {
|
||||
}
|
||||
|
||||
func testDeleteFailedAttempts(t *testing.T, keepFailedPaymentAttempts bool) {
|
||||
db, err := MakeTestDB(t)
|
||||
require.NoError(t, err, "unable to init db")
|
||||
|
||||
paymentDB, err := NewKVPaymentsDB(
|
||||
db,
|
||||
paymentsdb.WithKeepFailedPaymentAttempts(
|
||||
keepFailedPaymentAttempts,
|
||||
),
|
||||
paymentDB := NewTestDB(
|
||||
t, WithKeepFailedPaymentAttempts(keepFailedPaymentAttempts),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Register three payments:
|
||||
// All payments will have one failed HTLC attempt and one HTLC attempt
|
||||
@@ -1177,7 +1132,7 @@ func assertPaymentStatus(t *testing.T, p *KVPaymentsDB,
|
||||
t.Helper()
|
||||
|
||||
payment, err := p.FetchPayment(hash)
|
||||
if errors.Is(err, paymentsdb.ErrPaymentNotInitiated) {
|
||||
if errors.Is(err, ErrPaymentNotInitiated) {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
@@ -1199,7 +1154,8 @@ type htlcStatus struct {
|
||||
// assertPaymentInfo retrieves the payment referred to by hash and verifies the
|
||||
// expected values.
|
||||
func assertPaymentInfo(t *testing.T, p *KVPaymentsDB, hash lntypes.Hash,
|
||||
c *PaymentCreationInfo, f *FailureReason, a *htlcStatus) {
|
||||
c *PaymentCreationInfo, f *FailureReason,
|
||||
a *htlcStatus) {
|
||||
|
||||
t.Helper()
|
||||
|
||||
@@ -1277,7 +1233,7 @@ func fetchPaymentIndexEntry(_ *testing.T, p *KVPaymentsDB,
|
||||
|
||||
indexValue := indexBucket.Get(key)
|
||||
if indexValue == nil {
|
||||
return paymentsdb.ErrNoSequenceNrIndex
|
||||
return ErrNoSequenceNrIndex
|
||||
}
|
||||
|
||||
r := bytes.NewReader(indexValue)
|
||||
@@ -1313,7 +1269,7 @@ func assertPaymentIndex(t *testing.T, p *KVPaymentsDB,
|
||||
// exist.
|
||||
func assertNoIndex(t *testing.T, p *KVPaymentsDB, seqNr uint64) {
|
||||
_, 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,
|
||||
@@ -1439,7 +1395,9 @@ func assertPayments(t *testing.T, paymentDB *KVPaymentsDB,
|
||||
require.Equal(t, payments, p)
|
||||
}
|
||||
|
||||
func makeFakeInfo(t *testing.T) (*PaymentCreationInfo, *HTLCAttemptInfo) {
|
||||
func makeFakeInfo(t *testing.T) (*PaymentCreationInfo,
|
||||
*HTLCAttemptInfo) {
|
||||
|
||||
var preimg lntypes.Preimage
|
||||
copy(preimg[:], rev[:])
|
||||
|
||||
@@ -1552,7 +1510,7 @@ func testSerializeRoute(t *testing.T, route route.Route) {
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
t.Helper()
|
||||
@@ -1587,11 +1545,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
|
||||
// present when we expect it to be.
|
||||
func TestFetchPaymentWithSequenceNumber(t *testing.T) {
|
||||
db, err := MakeTestDB(t)
|
||||
require.NoError(t, err)
|
||||
|
||||
paymentDB, err := NewKVPaymentsDB(db)
|
||||
require.NoError(t, err)
|
||||
paymentDB := NewTestDB(t)
|
||||
|
||||
// Generate a test payment which does not have duplicates.
|
||||
noDuplicates, _, _, err := genInfo(t)
|
||||
@@ -1634,12 +1588,12 @@ func TestFetchPaymentWithSequenceNumber(t *testing.T) {
|
||||
|
||||
// Add two duplicates to our second payment.
|
||||
appendDuplicatePayment(
|
||||
t, db, hasDuplicates.PaymentIdentifier, duplicateOneSeqNr,
|
||||
preimg,
|
||||
t, paymentDB.db, hasDuplicates.PaymentIdentifier,
|
||||
duplicateOneSeqNr, preimg,
|
||||
)
|
||||
appendDuplicatePayment(
|
||||
t, db, hasDuplicates.PaymentIdentifier, duplicateTwoSeqNr,
|
||||
preimg,
|
||||
t, paymentDB.db, hasDuplicates.PaymentIdentifier,
|
||||
duplicateTwoSeqNr, preimg,
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
@@ -1676,23 +1630,22 @@ func TestFetchPaymentWithSequenceNumber(t *testing.T) {
|
||||
name: "lookup non-existent duplicate",
|
||||
paymentHash: hasDuplicates.PaymentIdentifier,
|
||||
sequenceNumber: 999999,
|
||||
expectedErr: paymentsdb.ErrDuplicateNotFound,
|
||||
expectedErr: ErrDuplicateNotFound,
|
||||
},
|
||||
{
|
||||
name: "lookup duplicate, no duplicates " +
|
||||
"bucket",
|
||||
paymentHash: noDuplicates.PaymentIdentifier,
|
||||
sequenceNumber: duplicateTwoSeqNr,
|
||||
expectedErr: paymentsdb.ErrNoDuplicateBucket,
|
||||
expectedErr: ErrNoDuplicateBucket,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
//nolint:ll
|
||||
err := kvdb.Update(
|
||||
db, func(tx walletdb.ReadWriteTx) error {
|
||||
paymentDB.db, func(tx walletdb.ReadWriteTx) error {
|
||||
var seqNrBytes [8]byte
|
||||
byteOrder.PutUint64(
|
||||
seqNrBytes[:],
|
||||
@@ -8,8 +8,6 @@ import (
|
||||
// log is a logger that is initialized with no output filters. This
|
||||
// means the package will not perform any logging by default until the caller
|
||||
// requests it.
|
||||
//
|
||||
//nolint:unused
|
||||
var log btclog.Logger
|
||||
|
||||
// Subsystem defines the logging identifier for this subsystem.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package channeldb
|
||||
package paymentsdb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -15,10 +15,94 @@ import (
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/lnutils"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
)
|
||||
|
||||
// FailureReason encodes the reason a payment ultimately failed.
|
||||
type FailureReason byte
|
||||
|
||||
const (
|
||||
// FailureReasonTimeout indicates that the payment did timeout before a
|
||||
// successful payment attempt was made.
|
||||
FailureReasonTimeout FailureReason = 0
|
||||
|
||||
// FailureReasonNoRoute indicates no successful route to the
|
||||
// destination was found during path finding.
|
||||
FailureReasonNoRoute FailureReason = 1
|
||||
|
||||
// FailureReasonError indicates that an unexpected error happened during
|
||||
// payment.
|
||||
FailureReasonError FailureReason = 2
|
||||
|
||||
// FailureReasonPaymentDetails indicates that either the hash is unknown
|
||||
// or the final cltv delta or amount is incorrect.
|
||||
FailureReasonPaymentDetails FailureReason = 3
|
||||
|
||||
// FailureReasonInsufficientBalance indicates that we didn't have enough
|
||||
// balance to complete the payment.
|
||||
FailureReasonInsufficientBalance FailureReason = 4
|
||||
|
||||
// FailureReasonCanceled indicates that the payment was canceled by the
|
||||
// user.
|
||||
FailureReasonCanceled FailureReason = 5
|
||||
|
||||
// TODO(joostjager): Add failure reasons for:
|
||||
// LocalLiquidityInsufficient, RemoteCapacityInsufficient.
|
||||
)
|
||||
|
||||
// Error returns a human-readable error string for the FailureReason.
|
||||
func (r FailureReason) Error() string {
|
||||
return r.String()
|
||||
}
|
||||
|
||||
// String returns a human-readable FailureReason.
|
||||
func (r FailureReason) String() string {
|
||||
switch r {
|
||||
case FailureReasonTimeout:
|
||||
return "timeout"
|
||||
case FailureReasonNoRoute:
|
||||
return "no_route"
|
||||
case FailureReasonError:
|
||||
return "error"
|
||||
case FailureReasonPaymentDetails:
|
||||
return "incorrect_payment_details"
|
||||
case FailureReasonInsufficientBalance:
|
||||
return "insufficient_balance"
|
||||
case FailureReasonCanceled:
|
||||
return "canceled"
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// PaymentCreationInfo is the information necessary to have ready when
|
||||
// initiating a payment, moving it into state InFlight.
|
||||
type PaymentCreationInfo struct {
|
||||
// PaymentIdentifier is the hash this payment is paying to in case of
|
||||
// non-AMP payments, and the SetID for AMP payments.
|
||||
PaymentIdentifier lntypes.Hash
|
||||
|
||||
// Value is the amount we are paying.
|
||||
Value lnwire.MilliSatoshi
|
||||
|
||||
// CreationTime is the time when this payment was initiated.
|
||||
CreationTime time.Time
|
||||
|
||||
// PaymentRequest is the full payment request, if any.
|
||||
PaymentRequest []byte
|
||||
|
||||
// FirstHopCustomRecords are the TLV records that are to be sent to the
|
||||
// first hop of this payment. These records will be transmitted via the
|
||||
// wire message only and therefore do not affect the onion payload size.
|
||||
FirstHopCustomRecords lnwire.CustomRecords
|
||||
}
|
||||
|
||||
// String returns a human-readable description of the payment creation info.
|
||||
func (p *PaymentCreationInfo) String() string {
|
||||
return fmt.Sprintf("payment_id=%v, amount=%v, created_at=%v",
|
||||
p.PaymentIdentifier, p.Value, p.CreationTime)
|
||||
}
|
||||
|
||||
// HTLCAttemptInfo contains static information about a specific HTLC attempt
|
||||
// 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
|
||||
@@ -171,8 +255,8 @@ const (
|
||||
// reason.
|
||||
HTLCFailUnknown HTLCFailReason = 0
|
||||
|
||||
// HTLCFailUnknown is recorded for htlcs that had a failure message that
|
||||
// couldn't be decrypted.
|
||||
// HTLCFailUnreadable is recorded for htlcs that had a failure message
|
||||
// that couldn't be decrypted.
|
||||
HTLCFailUnreadable HTLCFailReason = 1
|
||||
|
||||
// HTLCFailInternal is recorded for htlcs that failed because of an
|
||||
@@ -350,12 +434,12 @@ func (m *MPPayment) Registrable() error {
|
||||
// are settled HTLCs or the payment is failed. If we already have
|
||||
// settled HTLCs, we won't allow adding more HTLCs.
|
||||
if m.State.HasSettledHTLC {
|
||||
return paymentsdb.ErrPaymentPendingSettled
|
||||
return ErrPaymentPendingSettled
|
||||
}
|
||||
|
||||
// If the payment is already failed, we won't allow adding more HTLCs.
|
||||
if m.State.PaymentFailed {
|
||||
return paymentsdb.ErrPaymentPendingFailed
|
||||
return ErrPaymentPendingFailed
|
||||
}
|
||||
|
||||
// Otherwise we can add more HTLCs.
|
||||
@@ -373,7 +457,7 @@ func (m *MPPayment) setState() error {
|
||||
totalAmt := m.Info.Value
|
||||
if sentAmt > totalAmt {
|
||||
return fmt.Errorf("%w: sent=%v, total=%v",
|
||||
paymentsdb.ErrSentExceedsTotal, sentAmt, totalAmt)
|
||||
ErrSentExceedsTotal, sentAmt, totalAmt)
|
||||
}
|
||||
|
||||
// Get any terminal info for this payment.
|
||||
@@ -452,7 +536,7 @@ func (m *MPPayment) NeedWaitAttempts() (bool, error) {
|
||||
case StatusSucceeded:
|
||||
return false, fmt.Errorf("%w: parts of the payment "+
|
||||
"already succeeded but still have remaining "+
|
||||
"amount %v", paymentsdb.ErrPaymentInternal,
|
||||
"amount %v", ErrPaymentInternal,
|
||||
m.State.RemainingAmt)
|
||||
|
||||
// The payment is failed and we have no inflight HTLCs, no need
|
||||
@@ -463,7 +547,7 @@ func (m *MPPayment) NeedWaitAttempts() (bool, error) {
|
||||
// Unknown payment status.
|
||||
default:
|
||||
return false, fmt.Errorf("%w: %s",
|
||||
paymentsdb.ErrUnknownPaymentStatus, m.Status)
|
||||
ErrUnknownPaymentStatus, m.Status)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,7 +558,7 @@ func (m *MPPayment) NeedWaitAttempts() (bool, error) {
|
||||
// amount, return an error.
|
||||
case StatusInitiated:
|
||||
return false, fmt.Errorf("%w: %v",
|
||||
paymentsdb.ErrPaymentInternal, m.Status)
|
||||
ErrPaymentInternal, m.Status)
|
||||
|
||||
// If the payment is inflight, we must wait.
|
||||
//
|
||||
@@ -496,12 +580,12 @@ func (m *MPPayment) NeedWaitAttempts() (bool, error) {
|
||||
// not be zero because our sentAmt is zero.
|
||||
case StatusFailed:
|
||||
return false, fmt.Errorf("%w: %v",
|
||||
paymentsdb.ErrPaymentInternal, m.Status)
|
||||
ErrPaymentInternal, m.Status)
|
||||
|
||||
// Unknown payment status.
|
||||
default:
|
||||
return false, fmt.Errorf("%w: %s",
|
||||
paymentsdb.ErrUnknownPaymentStatus, m.Status)
|
||||
ErrUnknownPaymentStatus, m.Status)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -510,12 +594,12 @@ func (m *MPPayment) GetState() *MPPaymentState {
|
||||
return m.State
|
||||
}
|
||||
|
||||
// Status returns the current status of the payment.
|
||||
// GetStatus returns the current status of the payment.
|
||||
func (m *MPPayment) GetStatus() PaymentStatus {
|
||||
return m.Status
|
||||
}
|
||||
|
||||
// GetPayment returns all the HTLCs for this payment.
|
||||
// GetHTLCs returns all the HTLCs for this payment.
|
||||
func (m *MPPayment) GetHTLCs() []HTLCAttempt {
|
||||
return m.HTLCs
|
||||
}
|
||||
@@ -532,7 +616,7 @@ func (m *MPPayment) AllowMoreAttempts() (bool, error) {
|
||||
if m.Status == StatusInitiated {
|
||||
return false, fmt.Errorf("%w: initiated payment has "+
|
||||
"zero remainingAmt",
|
||||
paymentsdb.ErrPaymentInternal)
|
||||
ErrPaymentInternal)
|
||||
}
|
||||
|
||||
// Otherwise, exit early since all other statuses with zero
|
||||
@@ -549,7 +633,7 @@ func (m *MPPayment) AllowMoreAttempts() (bool, error) {
|
||||
if m.Status == StatusSucceeded {
|
||||
return false, fmt.Errorf("%w: payment already succeeded but "+
|
||||
"still have remaining amount %v",
|
||||
paymentsdb.ErrPaymentInternal, m.State.RemainingAmt)
|
||||
ErrPaymentInternal, m.State.RemainingAmt)
|
||||
}
|
||||
|
||||
// Now check if we can register a new HTLC.
|
||||
@@ -654,39 +738,6 @@ func deserializeHTLCFailInfo(r io.Reader) (*HTLCFailInfo, error) {
|
||||
return f, 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
|
||||
}
|
||||
|
||||
// generateSphinxPacket generates then encodes a sphinx packet which encodes
|
||||
// the onion route specified by the passed layer 3 route. The blob returned
|
||||
// from this function can immediately be included within an HTLC add packet to
|
||||
@@ -1,9 +1,7 @@
|
||||
package channeldb
|
||||
package paymentsdb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||
)
|
||||
|
||||
// PaymentStatus represent current status of payment.
|
||||
@@ -62,24 +60,24 @@ func (ps PaymentStatus) initializable() error {
|
||||
// again in case other goroutines have already been creating HTLCs for
|
||||
// it.
|
||||
case StatusInitiated:
|
||||
return paymentsdb.ErrPaymentExists
|
||||
return ErrPaymentExists
|
||||
|
||||
// We already have an InFlight payment on the network. We will disallow
|
||||
// any new payments.
|
||||
case StatusInFlight:
|
||||
return paymentsdb.ErrPaymentInFlight
|
||||
return ErrPaymentInFlight
|
||||
|
||||
// The payment has been attempted and is succeeded so we won't allow
|
||||
// creating it again.
|
||||
case StatusSucceeded:
|
||||
return paymentsdb.ErrAlreadyPaid
|
||||
return ErrAlreadyPaid
|
||||
|
||||
// We allow retrying failed payments.
|
||||
case StatusFailed:
|
||||
return nil
|
||||
|
||||
default:
|
||||
return fmt.Errorf("%w: %v", paymentsdb.ErrUnknownPaymentStatus,
|
||||
return fmt.Errorf("%w: %v", ErrUnknownPaymentStatus,
|
||||
ps)
|
||||
}
|
||||
}
|
||||
@@ -96,7 +94,7 @@ func (ps PaymentStatus) removable() error {
|
||||
// There are still inflight HTLCs and the payment needs to wait for the
|
||||
// final outcomes.
|
||||
case StatusInFlight:
|
||||
return paymentsdb.ErrPaymentInFlight
|
||||
return ErrPaymentInFlight
|
||||
|
||||
// The payment has been attempted and is succeeded and is allowed to be
|
||||
// removed.
|
||||
@@ -108,7 +106,7 @@ func (ps PaymentStatus) removable() error {
|
||||
return nil
|
||||
|
||||
default:
|
||||
return fmt.Errorf("%w: %v", paymentsdb.ErrUnknownPaymentStatus,
|
||||
return fmt.Errorf("%w: %v", ErrUnknownPaymentStatus,
|
||||
ps)
|
||||
}
|
||||
}
|
||||
@@ -127,13 +125,13 @@ func (ps PaymentStatus) updatable() error {
|
||||
|
||||
// If the payment has a terminal condition, we won't allow any updates.
|
||||
case StatusSucceeded:
|
||||
return paymentsdb.ErrPaymentAlreadySucceeded
|
||||
return ErrPaymentAlreadySucceeded
|
||||
|
||||
case StatusFailed:
|
||||
return paymentsdb.ErrPaymentAlreadyFailed
|
||||
return ErrPaymentAlreadyFailed
|
||||
|
||||
default:
|
||||
return fmt.Errorf("%w: %v", paymentsdb.ErrUnknownPaymentStatus,
|
||||
return fmt.Errorf("%w: %v", ErrUnknownPaymentStatus,
|
||||
ps)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
package channeldb
|
||||
package paymentsdb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -198,33 +197,33 @@ func TestPaymentStatusActions(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
status: StatusInitiated,
|
||||
initErr: paymentsdb.ErrPaymentExists,
|
||||
initErr: ErrPaymentExists,
|
||||
updateErr: nil,
|
||||
removeErr: nil,
|
||||
},
|
||||
{
|
||||
status: StatusInFlight,
|
||||
initErr: paymentsdb.ErrPaymentInFlight,
|
||||
initErr: ErrPaymentInFlight,
|
||||
updateErr: nil,
|
||||
removeErr: paymentsdb.ErrPaymentInFlight,
|
||||
removeErr: ErrPaymentInFlight,
|
||||
},
|
||||
{
|
||||
status: StatusSucceeded,
|
||||
initErr: paymentsdb.ErrAlreadyPaid,
|
||||
updateErr: paymentsdb.ErrPaymentAlreadySucceeded,
|
||||
initErr: ErrAlreadyPaid,
|
||||
updateErr: ErrPaymentAlreadySucceeded,
|
||||
removeErr: nil,
|
||||
},
|
||||
{
|
||||
status: StatusFailed,
|
||||
initErr: nil,
|
||||
updateErr: paymentsdb.ErrPaymentAlreadyFailed,
|
||||
updateErr: ErrPaymentAlreadyFailed,
|
||||
removeErr: nil,
|
||||
},
|
||||
{
|
||||
status: 0,
|
||||
initErr: paymentsdb.ErrUnknownPaymentStatus,
|
||||
updateErr: paymentsdb.ErrUnknownPaymentStatus,
|
||||
removeErr: paymentsdb.ErrUnknownPaymentStatus,
|
||||
initErr: ErrUnknownPaymentStatus,
|
||||
updateErr: ErrUnknownPaymentStatus,
|
||||
removeErr: ErrUnknownPaymentStatus,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
package channeldb
|
||||
package paymentsdb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"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/stretchr/testify/require"
|
||||
)
|
||||
@@ -20,8 +26,459 @@ var (
|
||||
0x4f, 0x2f, 0x6f, 0x25, 0x88, 0xa3, 0xef, 0xb9,
|
||||
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,
|
||||
}
|
||||
|
||||
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 Query
|
||||
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: Query{
|
||||
IndexOffset: 7,
|
||||
MaxPayments: 7,
|
||||
Reversed: false,
|
||||
IncludeIncomplete: true,
|
||||
},
|
||||
firstIndex: 0,
|
||||
lastIndex: 0,
|
||||
expectedSeqNrs: nil,
|
||||
},
|
||||
{
|
||||
name: "query in forwards order, start at beginning",
|
||||
query: Query{
|
||||
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: Query{
|
||||
IndexOffset: 6,
|
||||
MaxPayments: 2,
|
||||
Reversed: false,
|
||||
IncludeIncomplete: true,
|
||||
},
|
||||
firstIndex: 7,
|
||||
lastIndex: 7,
|
||||
expectedSeqNrs: []uint64{7},
|
||||
},
|
||||
{
|
||||
name: "start at offset index outside of payments",
|
||||
query: Query{
|
||||
IndexOffset: 20,
|
||||
MaxPayments: 2,
|
||||
Reversed: false,
|
||||
IncludeIncomplete: true,
|
||||
},
|
||||
firstIndex: 0,
|
||||
lastIndex: 0,
|
||||
expectedSeqNrs: nil,
|
||||
},
|
||||
{
|
||||
name: "overflow in forwards order",
|
||||
query: Query{
|
||||
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: Query{
|
||||
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: Query{
|
||||
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: Query{
|
||||
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: Query{
|
||||
IndexOffset: 4,
|
||||
MaxPayments: 5,
|
||||
Reversed: true,
|
||||
IncludeIncomplete: true,
|
||||
},
|
||||
firstIndex: 1,
|
||||
lastIndex: 3,
|
||||
expectedSeqNrs: []uint64{1, 3},
|
||||
},
|
||||
{
|
||||
name: "all payments in reverse, order maintained",
|
||||
query: Query{
|
||||
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: Query{
|
||||
IndexOffset: 0,
|
||||
MaxPayments: 7,
|
||||
Reversed: false,
|
||||
IncludeIncomplete: false,
|
||||
},
|
||||
firstIndex: 7,
|
||||
lastIndex: 7,
|
||||
expectedSeqNrs: []uint64{7},
|
||||
},
|
||||
{
|
||||
name: "query payments at index gap",
|
||||
query: Query{
|
||||
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: Query{
|
||||
IndexOffset: 3,
|
||||
MaxPayments: 7,
|
||||
Reversed: true,
|
||||
IncludeIncomplete: true,
|
||||
},
|
||||
firstIndex: 1,
|
||||
lastIndex: 1,
|
||||
expectedSeqNrs: []uint64{1},
|
||||
},
|
||||
{
|
||||
name: "query payments reverse on index gap",
|
||||
query: Query{
|
||||
IndexOffset: 2,
|
||||
MaxPayments: 7,
|
||||
Reversed: true,
|
||||
IncludeIncomplete: true,
|
||||
},
|
||||
firstIndex: 1,
|
||||
lastIndex: 1,
|
||||
expectedSeqNrs: []uint64{1},
|
||||
},
|
||||
{
|
||||
name: "query payments forward on index gap",
|
||||
query: Query{
|
||||
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: Query{
|
||||
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: Query{
|
||||
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: Query{
|
||||
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
|
||||
// keys that were previously serialized as a private key as raw bytes.
|
||||
func TestLazySessionKeyDeserialize(t *testing.T) {
|
||||
@@ -66,35 +523,35 @@ func TestRegistrable(t *testing.T) {
|
||||
// Test inflight status with settled HTLC but no failed
|
||||
// payment.
|
||||
status: StatusInFlight,
|
||||
registryErr: paymentsdb.ErrPaymentPendingSettled,
|
||||
registryErr: ErrPaymentPendingSettled,
|
||||
hasSettledHTLC: true,
|
||||
},
|
||||
{
|
||||
// Test inflight status with no settled HTLC but failed
|
||||
// payment.
|
||||
status: StatusInFlight,
|
||||
registryErr: paymentsdb.ErrPaymentPendingFailed,
|
||||
registryErr: ErrPaymentPendingFailed,
|
||||
paymentFailed: true,
|
||||
},
|
||||
{
|
||||
// Test error state with settled HTLC and failed
|
||||
// payment.
|
||||
status: 0,
|
||||
registryErr: paymentsdb.ErrUnknownPaymentStatus,
|
||||
registryErr: ErrUnknownPaymentStatus,
|
||||
hasSettledHTLC: true,
|
||||
paymentFailed: true,
|
||||
},
|
||||
{
|
||||
status: StatusSucceeded,
|
||||
registryErr: paymentsdb.ErrPaymentAlreadySucceeded,
|
||||
registryErr: ErrPaymentAlreadySucceeded,
|
||||
},
|
||||
{
|
||||
status: StatusFailed,
|
||||
registryErr: paymentsdb.ErrPaymentAlreadyFailed,
|
||||
registryErr: ErrPaymentAlreadyFailed,
|
||||
},
|
||||
{
|
||||
status: 0,
|
||||
registryErr: paymentsdb.ErrUnknownPaymentStatus,
|
||||
registryErr: ErrUnknownPaymentStatus,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -150,7 +607,7 @@ func TestPaymentSetState(t *testing.T) {
|
||||
},
|
||||
},
|
||||
totalAmt: 1,
|
||||
errExpected: paymentsdb.ErrSentExceedsTotal,
|
||||
errExpected: ErrSentExceedsTotal,
|
||||
},
|
||||
{
|
||||
// Test that when the htlc is failed, the fee is not
|
||||
@@ -295,7 +752,7 @@ func TestNeedWaitAttempts(t *testing.T) {
|
||||
status: StatusSucceeded,
|
||||
remainingAmt: 1000,
|
||||
needWait: false,
|
||||
expectedErr: paymentsdb.ErrPaymentInternal,
|
||||
expectedErr: ErrPaymentInternal,
|
||||
},
|
||||
{
|
||||
// Payment is in terminal state, no need to wait.
|
||||
@@ -310,7 +767,7 @@ func TestNeedWaitAttempts(t *testing.T) {
|
||||
status: StatusInitiated,
|
||||
remainingAmt: 0,
|
||||
needWait: false,
|
||||
expectedErr: paymentsdb.ErrPaymentInternal,
|
||||
expectedErr: ErrPaymentInternal,
|
||||
},
|
||||
{
|
||||
// With zero remainingAmt we must wait for the results.
|
||||
@@ -331,21 +788,21 @@ func TestNeedWaitAttempts(t *testing.T) {
|
||||
status: StatusFailed,
|
||||
remainingAmt: 0,
|
||||
needWait: false,
|
||||
expectedErr: paymentsdb.ErrPaymentInternal,
|
||||
expectedErr: ErrPaymentInternal,
|
||||
},
|
||||
{
|
||||
// Payment is in an unknown status, return an error.
|
||||
status: 0,
|
||||
remainingAmt: 0,
|
||||
needWait: false,
|
||||
expectedErr: paymentsdb.ErrUnknownPaymentStatus,
|
||||
expectedErr: ErrUnknownPaymentStatus,
|
||||
},
|
||||
{
|
||||
// Payment is in an unknown status, return an error.
|
||||
status: 0,
|
||||
remainingAmt: 1000,
|
||||
needWait: false,
|
||||
expectedErr: paymentsdb.ErrUnknownPaymentStatus,
|
||||
expectedErr: ErrUnknownPaymentStatus,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -398,7 +855,7 @@ func TestAllowMoreAttempts(t *testing.T) {
|
||||
status: StatusInitiated,
|
||||
remainingAmt: 0,
|
||||
allowMore: false,
|
||||
expectedErr: paymentsdb.ErrPaymentInternal,
|
||||
expectedErr: ErrPaymentInternal,
|
||||
},
|
||||
{
|
||||
// With zero remainingAmt we don't allow more HTLC
|
||||
@@ -506,7 +963,7 @@ func TestAllowMoreAttempts(t *testing.T) {
|
||||
remainingAmt: 1000,
|
||||
hasSettledHTLC: true,
|
||||
allowMore: false,
|
||||
expectedErr: paymentsdb.ErrPaymentInternal,
|
||||
expectedErr: ErrPaymentInternal,
|
||||
},
|
||||
{
|
||||
// With the payment failed with no inflight HTLCs, we
|
||||
@@ -0,0 +1,69 @@
|
||||
package paymentsdb
|
||||
|
||||
// Query represents a query to the payments database starting or ending
|
||||
// at a certain offset index. The number of retrieved records can be limited.
|
||||
type Query 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
|
||||
}
|
||||
|
||||
// Response 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 Response struct {
|
||||
// Payments is the set of payments returned from the database for the
|
||||
// Query.
|
||||
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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
+27
-25
@@ -3,9 +3,9 @@ package routing
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/multimutex"
|
||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||
"github.com/lightningnetwork/lnd/queue"
|
||||
)
|
||||
|
||||
@@ -13,23 +13,23 @@ import (
|
||||
// the payment lifecycle.
|
||||
type DBMPPayment interface {
|
||||
// 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() bool
|
||||
|
||||
// GetStatus returns the current status of the payment.
|
||||
GetStatus() channeldb.PaymentStatus
|
||||
GetStatus() paymentsdb.PaymentStatus
|
||||
|
||||
// NeedWaitAttempts specifies whether the payment needs to wait for the
|
||||
// outcome of an attempt.
|
||||
NeedWaitAttempts() (bool, error)
|
||||
|
||||
// GetHTLCs returns all HTLCs of this payment.
|
||||
GetHTLCs() []channeldb.HTLCAttempt
|
||||
GetHTLCs() []paymentsdb.HTLCAttempt
|
||||
|
||||
// InFlightHTLCs returns all HTLCs that are in flight.
|
||||
InFlightHTLCs() []channeldb.HTLCAttempt
|
||||
InFlightHTLCs() []paymentsdb.HTLCAttempt
|
||||
|
||||
// AllowMoreAttempts is used to decide whether we can safely attempt
|
||||
// more HTLCs for a given payment state. Return an error if the payment
|
||||
@@ -38,7 +38,7 @@ type DBMPPayment interface {
|
||||
|
||||
// TerminalInfo returns the settled HTLC attempt or the payment's
|
||||
// failure reason.
|
||||
TerminalInfo() (*channeldb.HTLCAttempt, *channeldb.FailureReason)
|
||||
TerminalInfo() (*paymentsdb.HTLCAttempt, *paymentsdb.FailureReason)
|
||||
}
|
||||
|
||||
// ControlTower tracks all outgoing payments made, whose primary purpose is to
|
||||
@@ -49,7 +49,7 @@ type DBMPPayment interface {
|
||||
type ControlTower interface {
|
||||
// This method checks that no succeeded payment exist for this payment
|
||||
// hash.
|
||||
InitPayment(lntypes.Hash, *channeldb.PaymentCreationInfo) error
|
||||
InitPayment(lntypes.Hash, *paymentsdb.PaymentCreationInfo) error
|
||||
|
||||
// DeleteFailedAttempts removes all failed HTLCs from the db. It should
|
||||
// be called for a given payment whenever all inflight htlcs are
|
||||
@@ -57,7 +57,7 @@ type ControlTower interface {
|
||||
DeleteFailedAttempts(lntypes.Hash) error
|
||||
|
||||
// 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
|
||||
// this is a multi shard payment, this might implicitly mean the the
|
||||
@@ -67,12 +67,12 @@ type ControlTower interface {
|
||||
// error to prevent us from making duplicate payments to the same
|
||||
// payment hash. The provided preimage is atomically saved to the DB
|
||||
// for record keeping.
|
||||
SettleAttempt(lntypes.Hash, uint64, *channeldb.HTLCSettleInfo) (
|
||||
*channeldb.HTLCAttempt, error)
|
||||
SettleAttempt(lntypes.Hash, uint64, *paymentsdb.HTLCSettleInfo) (
|
||||
*paymentsdb.HTLCAttempt, error)
|
||||
|
||||
// FailAttempt marks the given payment attempt failed.
|
||||
FailAttempt(lntypes.Hash, uint64, *channeldb.HTLCFailInfo) (
|
||||
*channeldb.HTLCAttempt, error)
|
||||
FailAttempt(lntypes.Hash, uint64, *paymentsdb.HTLCFailInfo) (
|
||||
*paymentsdb.HTLCAttempt, error)
|
||||
|
||||
// FetchPayment fetches the payment corresponding to the given payment
|
||||
// hash.
|
||||
@@ -84,10 +84,10 @@ type ControlTower interface {
|
||||
// invoking this method, InitPayment should return nil on its next call
|
||||
// for this payment hash, allowing the user to make a subsequent
|
||||
// payment.
|
||||
FailPayment(lntypes.Hash, channeldb.FailureReason) error
|
||||
FailPayment(lntypes.Hash, paymentsdb.FailureReason) error
|
||||
|
||||
// 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
|
||||
// hash. A first update with the current state of the payment is always
|
||||
@@ -151,7 +151,7 @@ func (s *controlTowerSubscriberImpl) Updates() <-chan interface{} {
|
||||
// controlTower is persistent implementation of ControlTower to restrict
|
||||
// double payment sending.
|
||||
type controlTower struct {
|
||||
db *channeldb.KVPaymentsDB
|
||||
db *paymentsdb.KVPaymentsDB
|
||||
|
||||
// subscriberIndex is used to provide a unique id for each subscriber
|
||||
// to all payments. This is used to easily remove the subscriber when
|
||||
@@ -168,7 +168,7 @@ type controlTower struct {
|
||||
}
|
||||
|
||||
// NewControlTower creates a new instance of the controlTower.
|
||||
func NewControlTower(db *channeldb.KVPaymentsDB) ControlTower {
|
||||
func NewControlTower(db *paymentsdb.KVPaymentsDB) ControlTower {
|
||||
return &controlTower{
|
||||
db: db,
|
||||
subscribersAllPayments: make(
|
||||
@@ -184,7 +184,7 @@ func NewControlTower(db *channeldb.KVPaymentsDB) ControlTower {
|
||||
// method returns successfully, the payment is guaranteed to be in the
|
||||
// Initiated state.
|
||||
func (p *controlTower) InitPayment(paymentHash lntypes.Hash,
|
||||
info *channeldb.PaymentCreationInfo) error {
|
||||
info *paymentsdb.PaymentCreationInfo) error {
|
||||
|
||||
err := p.db.InitPayment(paymentHash, info)
|
||||
if err != nil {
|
||||
@@ -215,7 +215,7 @@ func (p *controlTower) DeleteFailedAttempts(paymentHash lntypes.Hash) error {
|
||||
// RegisterAttempt atomically records the provided HTLCAttemptInfo to the
|
||||
// DB.
|
||||
func (p *controlTower) RegisterAttempt(paymentHash lntypes.Hash,
|
||||
attempt *channeldb.HTLCAttemptInfo) error {
|
||||
attempt *paymentsdb.HTLCAttemptInfo) error {
|
||||
|
||||
p.paymentsMtx.Lock(paymentHash)
|
||||
defer p.paymentsMtx.Unlock(paymentHash)
|
||||
@@ -235,8 +235,8 @@ func (p *controlTower) RegisterAttempt(paymentHash lntypes.Hash,
|
||||
// this is a multi shard payment, this might implicitly mean the the
|
||||
// full payment succeeded.
|
||||
func (p *controlTower) SettleAttempt(paymentHash lntypes.Hash,
|
||||
attemptID uint64, settleInfo *channeldb.HTLCSettleInfo) (
|
||||
*channeldb.HTLCAttempt, error) {
|
||||
attemptID uint64, settleInfo *paymentsdb.HTLCSettleInfo) (
|
||||
*paymentsdb.HTLCAttempt, error) {
|
||||
|
||||
p.paymentsMtx.Lock(paymentHash)
|
||||
defer p.paymentsMtx.Unlock(paymentHash)
|
||||
@@ -254,8 +254,8 @@ func (p *controlTower) SettleAttempt(paymentHash lntypes.Hash,
|
||||
|
||||
// FailAttempt marks the given payment attempt failed.
|
||||
func (p *controlTower) FailAttempt(paymentHash lntypes.Hash,
|
||||
attemptID uint64, failInfo *channeldb.HTLCFailInfo) (
|
||||
*channeldb.HTLCAttempt, error) {
|
||||
attemptID uint64, failInfo *paymentsdb.HTLCFailInfo) (
|
||||
*paymentsdb.HTLCAttempt, error) {
|
||||
|
||||
p.paymentsMtx.Lock(paymentHash)
|
||||
defer p.paymentsMtx.Unlock(paymentHash)
|
||||
@@ -286,7 +286,7 @@ func (p *controlTower) FetchPayment(paymentHash lntypes.Hash) (
|
||||
// NOTE: This method will overwrite the failure reason if the payment is already
|
||||
// failed.
|
||||
func (p *controlTower) FailPayment(paymentHash lntypes.Hash,
|
||||
reason channeldb.FailureReason) error {
|
||||
reason paymentsdb.FailureReason) error {
|
||||
|
||||
p.paymentsMtx.Lock(paymentHash)
|
||||
defer p.paymentsMtx.Unlock(paymentHash)
|
||||
@@ -303,7 +303,9 @@ func (p *controlTower) FailPayment(paymentHash lntypes.Hash,
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
@@ -386,7 +388,7 @@ func (p *controlTower) SubscribeAllPayments() (ControlTowerSubscriber, error) {
|
||||
// be executed atomically (by means of a lock) with the database update to
|
||||
// guarantee consistency of the notifications.
|
||||
func (p *controlTower) notifySubscribers(paymentHash lntypes.Hash,
|
||||
event *channeldb.MPPayment) {
|
||||
event *paymentsdb.MPPayment) {
|
||||
|
||||
// Get all subscribers for this payment.
|
||||
p.subscribersMtx.Lock()
|
||||
|
||||
@@ -50,7 +50,7 @@ func TestControlTowerSubscribeUnknown(t *testing.T) {
|
||||
|
||||
db := initDB(t)
|
||||
|
||||
paymentDB, err := channeldb.NewKVPaymentsDB(
|
||||
paymentDB, err := paymentsdb.NewKVPaymentsDB(
|
||||
db,
|
||||
paymentsdb.WithKeepFailedPaymentAttempts(true),
|
||||
)
|
||||
@@ -70,7 +70,7 @@ func TestControlTowerSubscribeSuccess(t *testing.T) {
|
||||
|
||||
db := initDB(t)
|
||||
|
||||
paymentDB, err := channeldb.NewKVPaymentsDB(db)
|
||||
paymentDB, err := paymentsdb.NewKVPaymentsDB(db)
|
||||
require.NoError(t, err)
|
||||
|
||||
pControl := NewControlTower(paymentDB)
|
||||
@@ -102,7 +102,7 @@ func TestControlTowerSubscribeSuccess(t *testing.T) {
|
||||
require.NoError(t, err, "expected subscribe to succeed, but got")
|
||||
|
||||
// Mark the payment as successful.
|
||||
settleInfo := channeldb.HTLCSettleInfo{
|
||||
settleInfo := paymentsdb.HTLCSettleInfo{
|
||||
Preimage: preimg,
|
||||
}
|
||||
htlcAttempt, err := pControl.SettleAttempt(
|
||||
@@ -126,19 +126,27 @@ func TestControlTowerSubscribeSuccess(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, s := range subscribers {
|
||||
var result *channeldb.MPPayment
|
||||
var result *paymentsdb.MPPayment
|
||||
for result == nil || !result.Terminated() {
|
||||
select {
|
||||
case item := <-s.Updates():
|
||||
result = item.(*channeldb.MPPayment)
|
||||
payment, ok := item.(*paymentsdb.MPPayment)
|
||||
require.True(
|
||||
t, ok, "unexpected payment type: %T",
|
||||
item)
|
||||
|
||||
result = payment
|
||||
|
||||
case <-time.After(testTimeout):
|
||||
t.Fatal("timeout waiting for payment result")
|
||||
}
|
||||
}
|
||||
|
||||
require.Equalf(t, channeldb.StatusSucceeded, result.GetStatus(),
|
||||
"subscriber %v failed, want %s, got %s", i,
|
||||
channeldb.StatusSucceeded, result.GetStatus())
|
||||
require.Equalf(t, paymentsdb.StatusSucceeded,
|
||||
result.GetStatus(), "subscriber %v failed, want %s, "+
|
||||
"got %s", i, paymentsdb.StatusSucceeded,
|
||||
result.GetStatus(),
|
||||
)
|
||||
|
||||
attempt, _ := result.TerminalInfo()
|
||||
if attempt.Settle.Preimage != preimg {
|
||||
@@ -192,7 +200,7 @@ func TestKVPaymentsDBSubscribeAllSuccess(t *testing.T) {
|
||||
|
||||
db := initDB(t)
|
||||
|
||||
paymentDB, err := channeldb.NewKVPaymentsDB(
|
||||
paymentDB, err := paymentsdb.NewKVPaymentsDB(
|
||||
db,
|
||||
paymentsdb.WithKeepFailedPaymentAttempts(true),
|
||||
)
|
||||
@@ -228,7 +236,7 @@ func TestKVPaymentsDBSubscribeAllSuccess(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Mark the first payment as successful.
|
||||
settleInfo1 := channeldb.HTLCSettleInfo{
|
||||
settleInfo1 := paymentsdb.HTLCSettleInfo{
|
||||
Preimage: preimg1,
|
||||
}
|
||||
htlcAttempt1, err := pControl.SettleAttempt(
|
||||
@@ -241,7 +249,7 @@ func TestKVPaymentsDBSubscribeAllSuccess(t *testing.T) {
|
||||
)
|
||||
|
||||
// Mark the second payment as successful.
|
||||
settleInfo2 := channeldb.HTLCSettleInfo{
|
||||
settleInfo2 := paymentsdb.HTLCSettleInfo{
|
||||
Preimage: preimg2,
|
||||
}
|
||||
htlcAttempt2, err := pControl.SettleAttempt(
|
||||
@@ -255,14 +263,20 @@ func TestKVPaymentsDBSubscribeAllSuccess(t *testing.T) {
|
||||
|
||||
// The two payments will be asserted individually, store the last update
|
||||
// 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.
|
||||
for i := 0; i < 6; i++ {
|
||||
select {
|
||||
case item := <-subscription.Updates():
|
||||
id := item.(*channeldb.MPPayment).Info.PaymentIdentifier
|
||||
results[id] = item.(*channeldb.MPPayment)
|
||||
payment, ok := item.(*paymentsdb.MPPayment)
|
||||
require.True(
|
||||
t, ok, "unexpected payment type: %T",
|
||||
item)
|
||||
|
||||
id := payment.Info.PaymentIdentifier
|
||||
results[id] = payment
|
||||
|
||||
case <-time.After(testTimeout):
|
||||
require.Fail(t, "timeout waiting for payment result")
|
||||
}
|
||||
@@ -270,7 +284,7 @@ func TestKVPaymentsDBSubscribeAllSuccess(t *testing.T) {
|
||||
|
||||
result1 := results[info1.PaymentIdentifier]
|
||||
require.Equal(
|
||||
t, channeldb.StatusSucceeded, result1.GetStatus(),
|
||||
t, paymentsdb.StatusSucceeded, result1.GetStatus(),
|
||||
"unexpected payment state payment 1",
|
||||
)
|
||||
|
||||
@@ -288,7 +302,7 @@ func TestKVPaymentsDBSubscribeAllSuccess(t *testing.T) {
|
||||
|
||||
result2 := results[info2.PaymentIdentifier]
|
||||
require.Equal(
|
||||
t, channeldb.StatusSucceeded, result2.GetStatus(),
|
||||
t, paymentsdb.StatusSucceeded, result2.GetStatus(),
|
||||
"unexpected payment state payment 2",
|
||||
)
|
||||
|
||||
@@ -311,7 +325,7 @@ func TestKVPaymentsDBSubscribeAllImmediate(t *testing.T) {
|
||||
|
||||
db := initDB(t)
|
||||
|
||||
paymentDB, err := channeldb.NewKVPaymentsDB(
|
||||
paymentDB, err := paymentsdb.NewKVPaymentsDB(
|
||||
db,
|
||||
paymentsdb.WithKeepFailedPaymentAttempts(true),
|
||||
)
|
||||
@@ -337,11 +351,17 @@ func TestKVPaymentsDBSubscribeAllImmediate(t *testing.T) {
|
||||
select {
|
||||
case update := <-subscription.Updates():
|
||||
require.NotNil(t, update)
|
||||
payment, ok := update.(*paymentsdb.MPPayment)
|
||||
if !ok {
|
||||
t.Fatalf("unexpected payment type: %T", update)
|
||||
}
|
||||
|
||||
require.Equal(
|
||||
t, info.PaymentIdentifier,
|
||||
update.(*channeldb.MPPayment).Info.PaymentIdentifier,
|
||||
payment.Info.PaymentIdentifier,
|
||||
)
|
||||
require.Len(t, subscription.Updates(), 0)
|
||||
|
||||
case <-time.After(testTimeout):
|
||||
require.Fail(t, "timeout waiting for payment result")
|
||||
}
|
||||
@@ -354,7 +374,7 @@ func TestKVPaymentsDBUnsubscribeSuccess(t *testing.T) {
|
||||
|
||||
db := initDB(t)
|
||||
|
||||
paymentDB, err := channeldb.NewKVPaymentsDB(
|
||||
paymentDB, err := paymentsdb.NewKVPaymentsDB(
|
||||
db,
|
||||
paymentsdb.WithKeepFailedPaymentAttempts(true),
|
||||
)
|
||||
@@ -411,8 +431,8 @@ func TestKVPaymentsDBUnsubscribeSuccess(t *testing.T) {
|
||||
subscription2.Close()
|
||||
|
||||
// Register another update.
|
||||
failInfo := channeldb.HTLCFailInfo{
|
||||
Reason: channeldb.HTLCFailInternal,
|
||||
failInfo := paymentsdb.HTLCFailInfo{
|
||||
Reason: paymentsdb.HTLCFailInternal,
|
||||
}
|
||||
_, err = pControl.FailAttempt(
|
||||
info.PaymentIdentifier, attempt.AttemptID, &failInfo,
|
||||
@@ -429,7 +449,7 @@ func testKVPaymentsDBSubscribeFail(t *testing.T, registerAttempt,
|
||||
|
||||
db := initDB(t)
|
||||
|
||||
paymentDB, err := channeldb.NewKVPaymentsDB(
|
||||
paymentDB, err := paymentsdb.NewKVPaymentsDB(
|
||||
db,
|
||||
paymentsdb.WithKeepFailedPaymentAttempts(
|
||||
keepFailedPaymentAttempts,
|
||||
@@ -465,8 +485,8 @@ func testKVPaymentsDBSubscribeFail(t *testing.T, registerAttempt,
|
||||
}
|
||||
|
||||
// Fail the payment attempt.
|
||||
failInfo := channeldb.HTLCFailInfo{
|
||||
Reason: channeldb.HTLCFailInternal,
|
||||
failInfo := paymentsdb.HTLCFailInfo{
|
||||
Reason: paymentsdb.HTLCFailInternal,
|
||||
}
|
||||
htlcAttempt, err := pControl.FailAttempt(
|
||||
info.PaymentIdentifier, attempt.AttemptID, &failInfo,
|
||||
@@ -481,7 +501,7 @@ func testKVPaymentsDBSubscribeFail(t *testing.T, registerAttempt,
|
||||
|
||||
// Mark the payment as failed.
|
||||
err = pControl.FailPayment(
|
||||
info.PaymentIdentifier, channeldb.FailureReasonTimeout,
|
||||
info.PaymentIdentifier, paymentsdb.FailureReasonTimeout,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -498,17 +518,22 @@ func testKVPaymentsDBSubscribeFail(t *testing.T, registerAttempt,
|
||||
}
|
||||
|
||||
for i, s := range subscribers {
|
||||
var result *channeldb.MPPayment
|
||||
var result *paymentsdb.MPPayment
|
||||
for result == nil || !result.Terminated() {
|
||||
select {
|
||||
case item := <-s.Updates():
|
||||
result = item.(*channeldb.MPPayment)
|
||||
payment, ok := item.(*paymentsdb.MPPayment)
|
||||
require.True(
|
||||
t, ok, "unexpected payment type: %T",
|
||||
item)
|
||||
|
||||
result = payment
|
||||
case <-time.After(testTimeout):
|
||||
t.Fatal("timeout waiting for payment result")
|
||||
}
|
||||
}
|
||||
|
||||
if result.GetStatus() == channeldb.StatusSucceeded {
|
||||
if result.GetStatus() == paymentsdb.StatusSucceeded {
|
||||
t.Fatal("unexpected payment state")
|
||||
}
|
||||
|
||||
@@ -533,11 +558,11 @@ func testKVPaymentsDBSubscribeFail(t *testing.T, registerAttempt,
|
||||
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,
|
||||
channeldb.StatusFailed, result.GetStatus())
|
||||
paymentsdb.StatusFailed, result.GetStatus())
|
||||
|
||||
if *result.FailureReason != channeldb.FailureReasonTimeout {
|
||||
if *result.FailureReason != paymentsdb.FailureReasonTimeout {
|
||||
t.Fatal("unexpected failure reason")
|
||||
}
|
||||
|
||||
@@ -559,7 +584,7 @@ func initDB(t *testing.T) *channeldb.DB {
|
||||
)
|
||||
}
|
||||
|
||||
func genInfo() (*channeldb.PaymentCreationInfo, *channeldb.HTLCAttemptInfo,
|
||||
func genInfo() (*paymentsdb.PaymentCreationInfo, *paymentsdb.HTLCAttemptInfo,
|
||||
lntypes.Preimage, error) {
|
||||
|
||||
preimage, err := genPreimage()
|
||||
@@ -572,14 +597,14 @@ func genInfo() (*channeldb.PaymentCreationInfo, *channeldb.HTLCAttemptInfo,
|
||||
var hash lntypes.Hash
|
||||
copy(hash[:], rhash[:])
|
||||
|
||||
attempt, err := channeldb.NewHtlcAttempt(
|
||||
attempt, err := paymentsdb.NewHtlcAttempt(
|
||||
1, priv, testRoute, time.Time{}, &hash,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, lntypes.Preimage{}, err
|
||||
}
|
||||
|
||||
return &channeldb.PaymentCreationInfo{
|
||||
return &paymentsdb.PaymentCreationInfo{
|
||||
PaymentIdentifier: rhash,
|
||||
Value: testRoute.ReceiverAmt(),
|
||||
CreationTime: time.Unix(time.Now().Unix(), 0),
|
||||
|
||||
@@ -11,11 +11,11 @@ import (
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btclog/v2"
|
||||
"github.com/btcsuite/btcwallet/walletdb"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/clock"
|
||||
"github.com/lightningnetwork/lnd/fn/v2"
|
||||
"github.com/lightningnetwork/lnd/kvdb"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"github.com/lightningnetwork/lnd/tlv"
|
||||
)
|
||||
@@ -617,7 +617,7 @@ func (m *MissionControl) GetPairHistorySnapshot(
|
||||
// payment attempts need to be made.
|
||||
func (m *MissionControl) ReportPaymentFail(paymentID uint64, rt *route.Route,
|
||||
failureSourceIdx *int, failure lnwire.FailureMessage) (
|
||||
*channeldb.FailureReason, error) {
|
||||
*paymentsdb.FailureReason, error) {
|
||||
|
||||
timestamp := m.cfg.clock.Now()
|
||||
|
||||
@@ -649,7 +649,7 @@ func (m *MissionControl) ReportPaymentSuccess(paymentID uint64,
|
||||
// processPaymentResult stores a payment result in the mission control store and
|
||||
// updates mission control's in-memory state.
|
||||
func (m *MissionControl) processPaymentResult(result *paymentResult) (
|
||||
*channeldb.FailureReason, error) {
|
||||
*paymentsdb.FailureReason, error) {
|
||||
|
||||
// Store complete result in database.
|
||||
m.store.AddResult(result)
|
||||
@@ -667,7 +667,7 @@ func (m *MissionControl) processPaymentResult(result *paymentResult) (
|
||||
// estimates. It returns a bool indicating whether this error is a final error
|
||||
// and no further payment attempts need to be made.
|
||||
func (m *MissionControl) applyPaymentResult(
|
||||
result *paymentResult) *channeldb.FailureReason {
|
||||
result *paymentResult) *paymentsdb.FailureReason {
|
||||
|
||||
// Interpret result.
|
||||
i := interpretResult(&result.route.Val, result.failure.ValOpt())
|
||||
|
||||
+51
-50
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/fn/v2"
|
||||
"github.com/lightningnetwork/lnd/graph/db/models"
|
||||
"github.com/lightningnetwork/lnd/htlcswitch"
|
||||
@@ -134,12 +133,12 @@ var _ MissionControlQuerier = (*mockMissionControlOld)(nil)
|
||||
func (m *mockMissionControlOld) ReportPaymentFail(
|
||||
paymentID uint64, rt *route.Route,
|
||||
failureSourceIdx *int, failure lnwire.FailureMessage) (
|
||||
*channeldb.FailureReason, error) {
|
||||
*paymentsdb.FailureReason, error) {
|
||||
|
||||
// Report a permanent failure if this is an error caused
|
||||
// by incorrect details.
|
||||
if failure.Code() == lnwire.CodeIncorrectOrUnknownPaymentDetails {
|
||||
reason := channeldb.FailureReasonPaymentDetails
|
||||
reason := paymentsdb.FailureReasonPaymentDetails
|
||||
return &reason, nil
|
||||
}
|
||||
|
||||
@@ -248,11 +247,11 @@ func (m *mockPayerOld) CleanStore(pids map[uint64]struct{}) error {
|
||||
}
|
||||
|
||||
type initArgs struct {
|
||||
c *channeldb.PaymentCreationInfo
|
||||
c *paymentsdb.PaymentCreationInfo
|
||||
}
|
||||
|
||||
type registerAttemptArgs struct {
|
||||
a *channeldb.HTLCAttemptInfo
|
||||
a *paymentsdb.HTLCAttemptInfo
|
||||
}
|
||||
|
||||
type settleAttemptArgs struct {
|
||||
@@ -260,22 +259,22 @@ type settleAttemptArgs struct {
|
||||
}
|
||||
|
||||
type failAttemptArgs struct {
|
||||
reason *channeldb.HTLCFailInfo
|
||||
reason *paymentsdb.HTLCFailInfo
|
||||
}
|
||||
|
||||
type failPaymentArgs struct {
|
||||
reason channeldb.FailureReason
|
||||
reason paymentsdb.FailureReason
|
||||
}
|
||||
|
||||
type testPayment struct {
|
||||
info channeldb.PaymentCreationInfo
|
||||
attempts []channeldb.HTLCAttempt
|
||||
info paymentsdb.PaymentCreationInfo
|
||||
attempts []paymentsdb.HTLCAttempt
|
||||
}
|
||||
|
||||
type mockControlTowerOld struct {
|
||||
payments map[lntypes.Hash]*testPayment
|
||||
successful map[lntypes.Hash]struct{}
|
||||
failed map[lntypes.Hash]channeldb.FailureReason
|
||||
failed map[lntypes.Hash]paymentsdb.FailureReason
|
||||
|
||||
init chan initArgs
|
||||
registerAttempt chan registerAttemptArgs
|
||||
@@ -293,12 +292,12 @@ func makeMockControlTower() *mockControlTowerOld {
|
||||
return &mockControlTowerOld{
|
||||
payments: make(map[lntypes.Hash]*testPayment),
|
||||
successful: make(map[lntypes.Hash]struct{}),
|
||||
failed: make(map[lntypes.Hash]channeldb.FailureReason),
|
||||
failed: make(map[lntypes.Hash]paymentsdb.FailureReason),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mockControlTowerOld) InitPayment(phash lntypes.Hash,
|
||||
c *channeldb.PaymentCreationInfo) error {
|
||||
c *paymentsdb.PaymentCreationInfo) error {
|
||||
|
||||
if m.init != nil {
|
||||
m.init <- initArgs{c}
|
||||
@@ -355,7 +354,7 @@ func (m *mockControlTowerOld) DeleteFailedAttempts(phash lntypes.Hash) error {
|
||||
}
|
||||
|
||||
func (m *mockControlTowerOld) RegisterAttempt(phash lntypes.Hash,
|
||||
a *channeldb.HTLCAttemptInfo) error {
|
||||
a *paymentsdb.HTLCAttemptInfo) error {
|
||||
|
||||
if m.registerAttempt != nil {
|
||||
m.registerAttempt <- registerAttemptArgs{a}
|
||||
@@ -400,7 +399,7 @@ func (m *mockControlTowerOld) RegisterAttempt(phash lntypes.Hash,
|
||||
}
|
||||
|
||||
// Add attempt to payment.
|
||||
p.attempts = append(p.attempts, channeldb.HTLCAttempt{
|
||||
p.attempts = append(p.attempts, paymentsdb.HTLCAttempt{
|
||||
HTLCAttemptInfo: *a,
|
||||
})
|
||||
m.payments[phash] = p
|
||||
@@ -409,8 +408,8 @@ func (m *mockControlTowerOld) RegisterAttempt(phash lntypes.Hash,
|
||||
}
|
||||
|
||||
func (m *mockControlTowerOld) SettleAttempt(phash lntypes.Hash,
|
||||
pid uint64, settleInfo *channeldb.HTLCSettleInfo) (
|
||||
*channeldb.HTLCAttempt, error) {
|
||||
pid uint64, settleInfo *paymentsdb.HTLCSettleInfo) (
|
||||
*paymentsdb.HTLCAttempt, error) {
|
||||
|
||||
if m.settleAttempt != nil {
|
||||
m.settleAttempt <- settleAttemptArgs{settleInfo.Preimage}
|
||||
@@ -442,7 +441,8 @@ func (m *mockControlTowerOld) SettleAttempt(phash lntypes.Hash,
|
||||
|
||||
// Mark the payment successful on first settled attempt.
|
||||
m.successful[phash] = struct{}{}
|
||||
return &channeldb.HTLCAttempt{
|
||||
|
||||
return &paymentsdb.HTLCAttempt{
|
||||
Settle: settleInfo,
|
||||
}, nil
|
||||
}
|
||||
@@ -451,7 +451,7 @@ func (m *mockControlTowerOld) SettleAttempt(phash lntypes.Hash,
|
||||
}
|
||||
|
||||
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 {
|
||||
m.failAttempt <- failAttemptArgs{failInfo}
|
||||
@@ -480,7 +480,8 @@ func (m *mockControlTowerOld) FailAttempt(phash lntypes.Hash, pid uint64,
|
||||
}
|
||||
|
||||
p.attempts[i].Failure = failInfo
|
||||
return &channeldb.HTLCAttempt{
|
||||
|
||||
return &paymentsdb.HTLCAttempt{
|
||||
Failure: failInfo,
|
||||
}, nil
|
||||
}
|
||||
@@ -489,7 +490,7 @@ func (m *mockControlTowerOld) FailAttempt(phash lntypes.Hash, pid uint64,
|
||||
}
|
||||
|
||||
func (m *mockControlTowerOld) FailPayment(phash lntypes.Hash,
|
||||
reason channeldb.FailureReason) error {
|
||||
reason paymentsdb.FailureReason) error {
|
||||
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
@@ -518,14 +519,14 @@ 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]
|
||||
if !ok {
|
||||
return nil, paymentsdb.ErrPaymentNotInitiated
|
||||
}
|
||||
|
||||
mp := &channeldb.MPPayment{
|
||||
mp := &paymentsdb.MPPayment{
|
||||
Info: &p.info,
|
||||
}
|
||||
|
||||
@@ -545,7 +546,7 @@ func (m *mockControlTowerOld) fetchPayment(phash lntypes.Hash) (
|
||||
}
|
||||
|
||||
func (m *mockControlTowerOld) FetchInFlightPayments() (
|
||||
[]*channeldb.MPPayment, error) {
|
||||
[]*paymentsdb.MPPayment, error) {
|
||||
|
||||
if m.fetchInFlight != nil {
|
||||
m.fetchInFlight <- struct{}{}
|
||||
@@ -555,7 +556,7 @@ func (m *mockControlTowerOld) FetchInFlightPayments() (
|
||||
defer m.Unlock()
|
||||
|
||||
// In flight are all payments not successful or failed.
|
||||
var fl []*channeldb.MPPayment
|
||||
var fl []*paymentsdb.MPPayment
|
||||
for hash := range m.payments {
|
||||
if _, ok := m.successful[hash]; ok {
|
||||
continue
|
||||
@@ -664,7 +665,7 @@ var _ MissionControlQuerier = (*mockMissionControl)(nil)
|
||||
func (m *mockMissionControl) ReportPaymentFail(
|
||||
paymentID uint64, rt *route.Route,
|
||||
failureSourceIdx *int, failure lnwire.FailureMessage) (
|
||||
*channeldb.FailureReason, error) {
|
||||
*paymentsdb.FailureReason, error) {
|
||||
|
||||
args := m.Called(paymentID, rt, failureSourceIdx, failure)
|
||||
|
||||
@@ -673,7 +674,7 @@ func (m *mockMissionControl) ReportPaymentFail(
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
|
||||
return args.Get(0).(*channeldb.FailureReason), args.Error(1)
|
||||
return args.Get(0).(*paymentsdb.FailureReason), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockMissionControl) ReportPaymentSuccess(paymentID uint64,
|
||||
@@ -733,7 +734,7 @@ type mockControlTower struct {
|
||||
var _ ControlTower = (*mockControlTower)(nil)
|
||||
|
||||
func (m *mockControlTower) InitPayment(phash lntypes.Hash,
|
||||
c *channeldb.PaymentCreationInfo) error {
|
||||
c *paymentsdb.PaymentCreationInfo) error {
|
||||
|
||||
args := m.Called(phash, c)
|
||||
return args.Error(0)
|
||||
@@ -745,15 +746,15 @@ func (m *mockControlTower) DeleteFailedAttempts(phash lntypes.Hash) error {
|
||||
}
|
||||
|
||||
func (m *mockControlTower) RegisterAttempt(phash lntypes.Hash,
|
||||
a *channeldb.HTLCAttemptInfo) error {
|
||||
a *paymentsdb.HTLCAttemptInfo) error {
|
||||
|
||||
args := m.Called(phash, a)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func (m *mockControlTower) SettleAttempt(phash lntypes.Hash,
|
||||
pid uint64, settleInfo *channeldb.HTLCSettleInfo) (
|
||||
*channeldb.HTLCAttempt, error) {
|
||||
pid uint64, settleInfo *paymentsdb.HTLCSettleInfo) (
|
||||
*paymentsdb.HTLCAttempt, error) {
|
||||
|
||||
args := m.Called(phash, pid, settleInfo)
|
||||
|
||||
@@ -762,11 +763,11 @@ func (m *mockControlTower) SettleAttempt(phash lntypes.Hash,
|
||||
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,
|
||||
failInfo *channeldb.HTLCFailInfo) (*channeldb.HTLCAttempt, error) {
|
||||
failInfo *paymentsdb.HTLCFailInfo) (*paymentsdb.HTLCAttempt, error) {
|
||||
|
||||
args := m.Called(phash, pid, failInfo)
|
||||
|
||||
@@ -775,11 +776,11 @@ func (m *mockControlTower) FailAttempt(phash lntypes.Hash, pid uint64,
|
||||
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,
|
||||
reason channeldb.FailureReason) error {
|
||||
reason paymentsdb.FailureReason) error {
|
||||
|
||||
args := m.Called(phash, reason)
|
||||
return args.Error(0)
|
||||
@@ -800,10 +801,10 @@ func (m *mockControlTower) FetchPayment(phash lntypes.Hash) (
|
||||
}
|
||||
|
||||
func (m *mockControlTower) FetchInFlightPayments() (
|
||||
[]*channeldb.MPPayment, error) {
|
||||
[]*paymentsdb.MPPayment, error) {
|
||||
|
||||
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) (
|
||||
@@ -826,14 +827,14 @@ type mockMPPayment struct {
|
||||
|
||||
var _ DBMPPayment = (*mockMPPayment)(nil)
|
||||
|
||||
func (m *mockMPPayment) GetState() *channeldb.MPPaymentState {
|
||||
func (m *mockMPPayment) GetState() *paymentsdb.MPPaymentState {
|
||||
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()
|
||||
return args.Get(0).(channeldb.PaymentStatus)
|
||||
return args.Get(0).(paymentsdb.PaymentStatus)
|
||||
}
|
||||
|
||||
func (m *mockMPPayment) Terminated() bool {
|
||||
@@ -847,14 +848,14 @@ func (m *mockMPPayment) NeedWaitAttempts() (bool, error) {
|
||||
return args.Bool(0), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockMPPayment) GetHTLCs() []channeldb.HTLCAttempt {
|
||||
func (m *mockMPPayment) GetHTLCs() []paymentsdb.HTLCAttempt {
|
||||
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()
|
||||
return args.Get(0).([]channeldb.HTLCAttempt)
|
||||
return args.Get(0).([]paymentsdb.HTLCAttempt)
|
||||
}
|
||||
|
||||
func (m *mockMPPayment) AllowMoreAttempts() (bool, error) {
|
||||
@@ -862,24 +863,24 @@ func (m *mockMPPayment) AllowMoreAttempts() (bool, error) {
|
||||
return args.Bool(0), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *mockMPPayment) TerminalInfo() (*channeldb.HTLCAttempt,
|
||||
*channeldb.FailureReason) {
|
||||
func (m *mockMPPayment) TerminalInfo() (*paymentsdb.HTLCAttempt,
|
||||
*paymentsdb.FailureReason) {
|
||||
|
||||
args := m.Called()
|
||||
|
||||
var (
|
||||
settleInfo *channeldb.HTLCAttempt
|
||||
failureInfo *channeldb.FailureReason
|
||||
settleInfo *paymentsdb.HTLCAttempt
|
||||
failureInfo *paymentsdb.FailureReason
|
||||
)
|
||||
|
||||
settle := args.Get(0)
|
||||
if settle != nil {
|
||||
settleInfo = settle.(*channeldb.HTLCAttempt)
|
||||
settleInfo = settle.(*paymentsdb.HTLCAttempt)
|
||||
}
|
||||
|
||||
reason := args.Get(1)
|
||||
if reason != nil {
|
||||
failureInfo = reason.(*channeldb.FailureReason)
|
||||
failureInfo = reason.(*paymentsdb.FailureReason)
|
||||
}
|
||||
|
||||
return settleInfo, failureInfo
|
||||
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
sphinx "github.com/lightningnetwork/lightning-onion"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/fn/v2"
|
||||
"github.com/lightningnetwork/lnd/graph/db/models"
|
||||
"github.com/lightningnetwork/lnd/htlcswitch"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/lnutils"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"github.com/lightningnetwork/lnd/routing/shards"
|
||||
"github.com/lightningnetwork/lnd/tlv"
|
||||
@@ -29,7 +29,7 @@ var ErrPaymentLifecycleExiting = errors.New("payment lifecycle exiting")
|
||||
// HTLC.
|
||||
type switchResult struct {
|
||||
// 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
|
||||
// ths HTLC is settled or an error if it's failed.
|
||||
@@ -59,7 +59,7 @@ type paymentLifecycle struct {
|
||||
// an HTLC attempt, which is always mounted to `p.collectResultAsync`
|
||||
// except in unit test, where we use a much simpler resultCollector to
|
||||
// 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.
|
||||
@@ -352,13 +352,13 @@ func (p *paymentLifecycle) checkContext(ctx context.Context) error {
|
||||
// user-provided timeout was reached, or the context was
|
||||
// canceled, either to a manual cancellation or due to an
|
||||
// unknown error.
|
||||
var reason channeldb.FailureReason
|
||||
var reason paymentsdb.FailureReason
|
||||
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
|
||||
reason = channeldb.FailureReasonTimeout
|
||||
reason = paymentsdb.FailureReasonTimeout
|
||||
log.Warnf("Payment attempt not completed before "+
|
||||
"context timeout, id=%s", p.identifier.String())
|
||||
} else {
|
||||
reason = channeldb.FailureReasonCanceled
|
||||
reason = paymentsdb.FailureReasonCanceled
|
||||
log.Warnf("Payment attempt context canceled, id=%s",
|
||||
p.identifier.String())
|
||||
}
|
||||
@@ -386,7 +386,7 @@ func (p *paymentLifecycle) checkContext(ctx context.Context) error {
|
||||
// requestRoute is responsible for finding a route to be used to create an HTLC
|
||||
// attempt.
|
||||
func (p *paymentLifecycle) requestRoute(
|
||||
ps *channeldb.MPPaymentState) (*route.Route, error) {
|
||||
ps *paymentsdb.MPPaymentState) (*route.Route, error) {
|
||||
|
||||
remainingFees := p.calcFeeBudget(ps.FeesPaid)
|
||||
|
||||
@@ -455,14 +455,14 @@ type attemptResult struct {
|
||||
err error
|
||||
|
||||
// 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
|
||||
// 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
|
||||
// `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",
|
||||
attempt.AttemptID, p.identifier)
|
||||
|
||||
@@ -504,7 +504,7 @@ func (p *paymentLifecycle) collectResultAsync(attempt *channeldb.HTLCAttempt) {
|
||||
// collectResult waits for the result of the given HTLC attempt to be sent by
|
||||
// the switch and returns it.
|
||||
func (p *paymentLifecycle) collectResult(
|
||||
attempt *channeldb.HTLCAttempt) (*htlcswitch.PaymentResult, error) {
|
||||
attempt *paymentsdb.HTLCAttempt) (*htlcswitch.PaymentResult, error) {
|
||||
|
||||
log.Tracef("Collecting result for attempt %v",
|
||||
lnutils.SpewLogClosure(attempt))
|
||||
@@ -581,7 +581,7 @@ func (p *paymentLifecycle) collectResult(
|
||||
// by using the route info provided. The `remainingAmt` is used to decide
|
||||
// whether this is the last attempt.
|
||||
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
|
||||
// to the receiver, this will be our last shard (for now).
|
||||
@@ -608,7 +608,7 @@ func (p *paymentLifecycle) registerAttempt(rt *route.Route,
|
||||
|
||||
// createNewPaymentAttempt creates a new payment attempt from the given 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.
|
||||
sessionKey, err := generateNewSessionKey()
|
||||
@@ -648,7 +648,7 @@ func (p *paymentLifecycle) createNewPaymentAttempt(rt *route.Route,
|
||||
|
||||
// We now have all the information needed to populate the current
|
||||
// attempt information.
|
||||
return channeldb.NewHtlcAttempt(
|
||||
return paymentsdb.NewHtlcAttempt(
|
||||
attemptID, sessionKey, *rt, p.router.cfg.Clock.Now(), &hash,
|
||||
)
|
||||
}
|
||||
@@ -657,7 +657,7 @@ func (p *paymentLifecycle) createNewPaymentAttempt(rt *route.Route,
|
||||
// the payment. If this attempt fails, then we'll continue on to the next
|
||||
// available route.
|
||||
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"+
|
||||
") for payment %v", attempt.AttemptID,
|
||||
@@ -794,7 +794,7 @@ func (p *paymentLifecycle) amendFirstHopData(rt *route.Route) error {
|
||||
// failAttemptAndPayment fails both the payment and its attempt via the
|
||||
// router's control tower, which marks the payment as failed in db.
|
||||
func (p *paymentLifecycle) failPaymentAndAttempt(
|
||||
attemptID uint64, reason *channeldb.FailureReason,
|
||||
attemptID uint64, reason *paymentsdb.FailureReason,
|
||||
sendErr error) (*attemptResult, error) {
|
||||
|
||||
log.Errorf("Payment %v failed: final_outcome=%v, raw_err=%v",
|
||||
@@ -823,10 +823,10 @@ func (p *paymentLifecycle) failPaymentAndAttempt(
|
||||
// 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
|
||||
// a non-nil reason value.
|
||||
func (p *paymentLifecycle) handleSwitchErr(attempt *channeldb.HTLCAttempt,
|
||||
func (p *paymentLifecycle) handleSwitchErr(attempt *paymentsdb.HTLCAttempt,
|
||||
sendErr error) (*attemptResult, error) {
|
||||
|
||||
internalErrorReason := channeldb.FailureReasonError
|
||||
internalErrorReason := paymentsdb.FailureReasonError
|
||||
attemptID := attempt.AttemptID
|
||||
|
||||
// reportAndFail is a helper closure that reports the failure to the
|
||||
@@ -1030,34 +1030,34 @@ func (p *paymentLifecycle) failAttempt(attemptID uint64,
|
||||
|
||||
// marshallError marshall an error as received from the switch to a structure
|
||||
// that is suitable for database storage.
|
||||
func marshallError(sendError error, time time.Time) *channeldb.HTLCFailInfo {
|
||||
response := &channeldb.HTLCFailInfo{
|
||||
func marshallError(sendError error, time time.Time) *paymentsdb.HTLCFailInfo {
|
||||
response := &paymentsdb.HTLCFailInfo{
|
||||
FailTime: time,
|
||||
}
|
||||
|
||||
switch {
|
||||
case errors.Is(sendError, htlcswitch.ErrPaymentIDNotFound):
|
||||
response.Reason = channeldb.HTLCFailInternal
|
||||
response.Reason = paymentsdb.HTLCFailInternal
|
||||
return response
|
||||
|
||||
case errors.Is(sendError, htlcswitch.ErrUnreadableFailureMessage):
|
||||
response.Reason = channeldb.HTLCFailUnreadable
|
||||
response.Reason = paymentsdb.HTLCFailUnreadable
|
||||
return response
|
||||
}
|
||||
|
||||
var rtErr htlcswitch.ClearTextError
|
||||
ok := errors.As(sendError, &rtErr)
|
||||
if !ok {
|
||||
response.Reason = channeldb.HTLCFailInternal
|
||||
response.Reason = paymentsdb.HTLCFailInternal
|
||||
return response
|
||||
}
|
||||
|
||||
message := rtErr.WireMessage()
|
||||
if message != nil {
|
||||
response.Reason = channeldb.HTLCFailMessage
|
||||
response.Reason = paymentsdb.HTLCFailMessage
|
||||
response.Message = message
|
||||
} else {
|
||||
response.Reason = channeldb.HTLCFailUnknown
|
||||
response.Reason = paymentsdb.HTLCFailUnknown
|
||||
}
|
||||
|
||||
// If the ClearTextError received is a ForwardingError, the error
|
||||
@@ -1082,7 +1082,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
|
||||
// the payment hash as the `attempt.Hash` as they are identical.
|
||||
func (p *paymentLifecycle) patchLegacyPaymentHash(
|
||||
a channeldb.HTLCAttempt) channeldb.HTLCAttempt {
|
||||
a paymentsdb.HTLCAttempt) paymentsdb.HTLCAttempt {
|
||||
|
||||
// Exit early if this is not a legacy attempt.
|
||||
if a.Hash != nil {
|
||||
@@ -1134,7 +1134,7 @@ func (p *paymentLifecycle) reloadInflightAttempts() (DBMPPayment, error) {
|
||||
|
||||
// reloadPayment returns the latest payment found in the db (control tower).
|
||||
func (p *paymentLifecycle) reloadPayment() (DBMPPayment,
|
||||
*channeldb.MPPaymentState, error) {
|
||||
*paymentsdb.MPPaymentState, error) {
|
||||
|
||||
// Read the db to get the latest state of the payment.
|
||||
payment, err := p.router.cfg.Control.FetchPayment(p.identifier)
|
||||
@@ -1154,7 +1154,7 @@ func (p *paymentLifecycle) reloadPayment() (DBMPPayment,
|
||||
|
||||
// handleAttemptResult processes the result of an HTLC attempt returned from
|
||||
// the htlcswitch.
|
||||
func (p *paymentLifecycle) handleAttemptResult(attempt *channeldb.HTLCAttempt,
|
||||
func (p *paymentLifecycle) handleAttemptResult(attempt *paymentsdb.HTLCAttempt,
|
||||
result *htlcswitch.PaymentResult) (*attemptResult, error) {
|
||||
|
||||
// If the result has an error, we need to further process it by failing
|
||||
@@ -1179,7 +1179,7 @@ func (p *paymentLifecycle) handleAttemptResult(attempt *channeldb.HTLCAttempt,
|
||||
// move the shard to the settled state.
|
||||
htlcAttempt, err := p.router.cfg.Control.SettleAttempt(
|
||||
p.identifier, attempt.AttemptID,
|
||||
&channeldb.HTLCSettleInfo{
|
||||
&paymentsdb.HTLCSettleInfo{
|
||||
Preimage: result.Preimage,
|
||||
SettleTime: p.router.cfg.Clock.Now(),
|
||||
},
|
||||
@@ -1204,7 +1204,7 @@ func (p *paymentLifecycle) handleAttemptResult(attempt *channeldb.HTLCAttempt,
|
||||
// tower. An attemptResult is returned, indicating the final outcome of this
|
||||
// HTLC attempt.
|
||||
func (p *paymentLifecycle) collectAndHandleResult(
|
||||
attempt *channeldb.HTLCAttempt) (*attemptResult, error) {
|
||||
attempt *paymentsdb.HTLCAttempt) (*attemptResult, error) {
|
||||
|
||||
result, err := p.collectResult(attempt)
|
||||
if err != nil {
|
||||
|
||||
@@ -8,13 +8,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/fn/v2"
|
||||
"github.com/lightningnetwork/lnd/htlcswitch"
|
||||
"github.com/lightningnetwork/lnd/lnmock"
|
||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"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/stretchr/testify/mock"
|
||||
@@ -116,7 +116,7 @@ func newTestPaymentLifecycle(t *testing.T) (*paymentLifecycle, *mockers) {
|
||||
|
||||
// Overwrite the collectResultAsync to focus on testing the payment
|
||||
// lifecycle within the goroutine.
|
||||
resultCollector := func(attempt *channeldb.HTLCAttempt) {
|
||||
resultCollector := func(attempt *paymentsdb.HTLCAttempt) {
|
||||
mockers.collectResultsCount++
|
||||
}
|
||||
p.resultCollector = resultCollector
|
||||
@@ -147,7 +147,7 @@ func setupTestPaymentLifecycle(t *testing.T) (*paymentLifecycle, *mockers) {
|
||||
m.payment, nil,
|
||||
).Once()
|
||||
|
||||
htlcs := []channeldb.HTLCAttempt{}
|
||||
htlcs := []paymentsdb.HTLCAttempt{}
|
||||
m.payment.On("InFlightHTLCs").Return(htlcs).Once()
|
||||
|
||||
return p, m
|
||||
@@ -258,11 +258,11 @@ func createDummyRoute(t *testing.T, amt lnwire.MilliSatoshi) *route.Route {
|
||||
}
|
||||
|
||||
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),
|
||||
Settle: &channeldb.HTLCSettleInfo{Preimage: preimage},
|
||||
Settle: &paymentsdb.HTLCSettleInfo{Preimage: preimage},
|
||||
}
|
||||
|
||||
hash := preimage.Hash()
|
||||
@@ -271,18 +271,18 @@ func makeSettledAttempt(t *testing.T, total int,
|
||||
return a
|
||||
}
|
||||
|
||||
func makeFailedAttempt(t *testing.T, total int) *channeldb.HTLCAttempt {
|
||||
return &channeldb.HTLCAttempt{
|
||||
func makeFailedAttempt(t *testing.T, total int) *paymentsdb.HTLCAttempt {
|
||||
return &paymentsdb.HTLCAttempt{
|
||||
HTLCAttemptInfo: makeAttemptInfo(t, total),
|
||||
Failure: &channeldb.HTLCFailInfo{
|
||||
Reason: channeldb.HTLCFailInternal,
|
||||
Failure: &paymentsdb.HTLCFailInfo{
|
||||
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))
|
||||
return channeldb.HTLCAttemptInfo{
|
||||
return paymentsdb.HTLCAttemptInfo{
|
||||
Route: *rt,
|
||||
Hash: &lntypes.Hash{1, 2, 3},
|
||||
}
|
||||
@@ -302,7 +302,7 @@ func TestCheckTimeoutTimedOut(t *testing.T) {
|
||||
// Mock the control tower's `FailPayment` method.
|
||||
ct := &mockControlTower{}
|
||||
ct.On("FailPayment",
|
||||
p.identifier, channeldb.FailureReasonTimeout).Return(nil)
|
||||
p.identifier, paymentsdb.FailureReasonTimeout).Return(nil)
|
||||
|
||||
// Mount the mocked control tower.
|
||||
p.router.cfg.Control = ct
|
||||
@@ -323,7 +323,7 @@ func TestCheckTimeoutTimedOut(t *testing.T) {
|
||||
// Mock `FailPayment` to return a dummy error.
|
||||
ct = &mockControlTower{}
|
||||
ct.On("FailPayment",
|
||||
p.identifier, channeldb.FailureReasonTimeout).Return(errDummy)
|
||||
p.identifier, paymentsdb.FailureReasonTimeout).Return(errDummy)
|
||||
|
||||
// Mount the mocked control tower.
|
||||
p.router.cfg.Control = ct
|
||||
@@ -378,7 +378,7 @@ func TestRequestRouteSucceed(t *testing.T) {
|
||||
p.paySession = paySession
|
||||
|
||||
// Create a dummy payment state.
|
||||
ps := &channeldb.MPPaymentState{
|
||||
ps := &paymentsdb.MPPaymentState{
|
||||
NumAttemptsInFlight: 1,
|
||||
RemainingAmt: 1,
|
||||
FeesPaid: 100,
|
||||
@@ -415,7 +415,7 @@ func TestRequestRouteHandleCriticalErr(t *testing.T) {
|
||||
p.paySession = paySession
|
||||
|
||||
// Create a dummy payment state.
|
||||
ps := &channeldb.MPPaymentState{
|
||||
ps := &paymentsdb.MPPaymentState{
|
||||
NumAttemptsInFlight: 1,
|
||||
RemainingAmt: 1,
|
||||
FeesPaid: 100,
|
||||
@@ -449,7 +449,7 @@ func TestRequestRouteHandleNoRouteErr(t *testing.T) {
|
||||
p, m := newTestPaymentLifecycle(t)
|
||||
|
||||
// Create a dummy payment state.
|
||||
ps := &channeldb.MPPaymentState{
|
||||
ps := &paymentsdb.MPPaymentState{
|
||||
NumAttemptsInFlight: 1,
|
||||
RemainingAmt: 1,
|
||||
FeesPaid: 100,
|
||||
@@ -467,7 +467,7 @@ func TestRequestRouteHandleNoRouteErr(t *testing.T) {
|
||||
|
||||
// The payment should be failed with reason no route.
|
||||
m.control.On("FailPayment",
|
||||
p.identifier, channeldb.FailureReasonNoRoute,
|
||||
p.identifier, paymentsdb.FailureReasonNoRoute,
|
||||
).Return(nil).Once()
|
||||
|
||||
result, err := p.requestRoute(ps)
|
||||
@@ -498,7 +498,7 @@ func TestRequestRouteFailPaymentError(t *testing.T) {
|
||||
p.paySession = paySession
|
||||
|
||||
// Create a dummy payment state with zero inflight attempts.
|
||||
ps := &channeldb.MPPaymentState{
|
||||
ps := &paymentsdb.MPPaymentState{
|
||||
NumAttemptsInFlight: 0,
|
||||
RemainingAmt: 1,
|
||||
FeesPaid: 100,
|
||||
@@ -819,14 +819,14 @@ func TestResumePaymentFailOnTimeout(t *testing.T) {
|
||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||
|
||||
// 2. calls `GetState` and return the state.
|
||||
ps := &channeldb.MPPaymentState{
|
||||
ps := &paymentsdb.MPPaymentState{
|
||||
RemainingAmt: paymentAmt,
|
||||
}
|
||||
m.payment.On("GetState").Return(ps).Once()
|
||||
|
||||
// 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.
|
||||
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
|
||||
// make sure it timed out.
|
||||
@@ -837,7 +837,7 @@ func TestResumePaymentFailOnTimeout(t *testing.T) {
|
||||
|
||||
// 4. the payment should be failed with reason timeout.
|
||||
m.control.On("FailPayment",
|
||||
p.identifier, channeldb.FailureReasonTimeout,
|
||||
p.identifier, paymentsdb.FailureReasonTimeout,
|
||||
).Return(nil).Once()
|
||||
|
||||
// 5. decideNextStep now returns stepExit.
|
||||
@@ -848,7 +848,7 @@ func TestResumePaymentFailOnTimeout(t *testing.T) {
|
||||
m.control.On("DeleteFailedAttempts", p.identifier).Return(nil).Once()
|
||||
|
||||
// 7. the payment returns the failed reason.
|
||||
reason := channeldb.FailureReasonTimeout
|
||||
reason := paymentsdb.FailureReasonTimeout
|
||||
m.payment.On("TerminalInfo").Return(nil, &reason)
|
||||
|
||||
// Send the payment and assert it failed with the timeout reason.
|
||||
@@ -875,7 +875,7 @@ func TestResumePaymentFailOnTimeoutErr(t *testing.T) {
|
||||
// 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.
|
||||
m.payment.On("GetStatus").Return(channeldb.StatusInFlight)
|
||||
m.payment.On("GetStatus").Return(paymentsdb.StatusInFlight)
|
||||
|
||||
// Quit the router to return an error.
|
||||
close(p.router.quit)
|
||||
@@ -910,21 +910,21 @@ func TestResumePaymentFailContextCancel(t *testing.T) {
|
||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||
|
||||
// 2. calls `GetState` and return the state.
|
||||
ps := &channeldb.MPPaymentState{
|
||||
ps := &paymentsdb.MPPaymentState{
|
||||
RemainingAmt: paymentAmt,
|
||||
}
|
||||
m.payment.On("GetState").Return(ps).Once()
|
||||
|
||||
// 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.
|
||||
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
|
||||
// context cancellation of the payment.
|
||||
cancel()
|
||||
|
||||
m.control.On(
|
||||
"FailPayment", p.identifier, channeldb.FailureReasonCanceled,
|
||||
"FailPayment", p.identifier, paymentsdb.FailureReasonCanceled,
|
||||
).Return(nil).Once()
|
||||
|
||||
// 4. decideNextStep now returns stepExit.
|
||||
@@ -935,7 +935,7 @@ func TestResumePaymentFailContextCancel(t *testing.T) {
|
||||
m.control.On("DeleteFailedAttempts", p.identifier).Return(nil).Once()
|
||||
|
||||
// 6. We will observe FailureReasonError if the context was cancelled.
|
||||
reason := channeldb.FailureReasonError
|
||||
reason := paymentsdb.FailureReasonError
|
||||
m.payment.On("TerminalInfo").Return(nil, &reason)
|
||||
|
||||
// Send the payment and assert it failed with the timeout reason.
|
||||
@@ -963,7 +963,7 @@ func TestResumePaymentFailOnStepErr(t *testing.T) {
|
||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||
|
||||
// 2. calls `GetState` and return the state.
|
||||
ps := &channeldb.MPPaymentState{
|
||||
ps := &paymentsdb.MPPaymentState{
|
||||
RemainingAmt: paymentAmt,
|
||||
}
|
||||
m.payment.On("GetState").Return(ps).Once()
|
||||
@@ -971,7 +971,7 @@ func TestResumePaymentFailOnStepErr(t *testing.T) {
|
||||
// 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.
|
||||
m.payment.On("GetStatus").Return(channeldb.StatusInFlight)
|
||||
m.payment.On("GetStatus").Return(paymentsdb.StatusInFlight)
|
||||
|
||||
// 3. decideNextStep now returns an error.
|
||||
m.payment.On("AllowMoreAttempts").Return(false, errDummy).Once()
|
||||
@@ -1001,7 +1001,7 @@ func TestResumePaymentFailOnRequestRouteErr(t *testing.T) {
|
||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||
|
||||
// 2. calls `GetState` and return the state.
|
||||
ps := &channeldb.MPPaymentState{
|
||||
ps := &paymentsdb.MPPaymentState{
|
||||
RemainingAmt: paymentAmt,
|
||||
}
|
||||
m.payment.On("GetState").Return(ps).Once()
|
||||
@@ -1009,7 +1009,7 @@ func TestResumePaymentFailOnRequestRouteErr(t *testing.T) {
|
||||
// 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.
|
||||
m.payment.On("GetStatus").Return(channeldb.StatusInFlight)
|
||||
m.payment.On("GetStatus").Return(paymentsdb.StatusInFlight)
|
||||
|
||||
// 3. decideNextStep now returns stepProceed.
|
||||
m.payment.On("AllowMoreAttempts").Return(true, nil).Once()
|
||||
@@ -1047,7 +1047,7 @@ func TestResumePaymentFailOnRegisterAttemptErr(t *testing.T) {
|
||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||
|
||||
// 2. calls `GetState` and return the state.
|
||||
ps := &channeldb.MPPaymentState{
|
||||
ps := &paymentsdb.MPPaymentState{
|
||||
RemainingAmt: paymentAmt,
|
||||
}
|
||||
m.payment.On("GetState").Return(ps).Once()
|
||||
@@ -1055,7 +1055,7 @@ func TestResumePaymentFailOnRegisterAttemptErr(t *testing.T) {
|
||||
// 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.
|
||||
m.payment.On("GetStatus").Return(channeldb.StatusInFlight)
|
||||
m.payment.On("GetStatus").Return(paymentsdb.StatusInFlight)
|
||||
|
||||
// 3. decideNextStep now returns stepProceed.
|
||||
m.payment.On("AllowMoreAttempts").Return(true, nil).Once()
|
||||
@@ -1107,7 +1107,7 @@ func TestResumePaymentFailOnSendAttemptErr(t *testing.T) {
|
||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||
|
||||
// 2. calls `GetState` and return the state.
|
||||
ps := &channeldb.MPPaymentState{
|
||||
ps := &paymentsdb.MPPaymentState{
|
||||
RemainingAmt: paymentAmt,
|
||||
}
|
||||
m.payment.On("GetState").Return(ps).Once()
|
||||
@@ -1115,7 +1115,7 @@ func TestResumePaymentFailOnSendAttemptErr(t *testing.T) {
|
||||
// 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.
|
||||
m.payment.On("GetStatus").Return(channeldb.StatusInFlight)
|
||||
m.payment.On("GetStatus").Return(paymentsdb.StatusInFlight)
|
||||
|
||||
// 3. decideNextStep now returns stepProceed.
|
||||
m.payment.On("AllowMoreAttempts").Return(true, nil).Once()
|
||||
@@ -1161,7 +1161,7 @@ func TestResumePaymentFailOnSendAttemptErr(t *testing.T) {
|
||||
// which we'd fail the payment, cancel the shard and fail the attempt.
|
||||
//
|
||||
// `FailPayment` should be called with an internal reason.
|
||||
reason := channeldb.FailureReasonError
|
||||
reason := paymentsdb.FailureReasonError
|
||||
m.control.On("FailPayment", p.identifier, reason).Return(nil).Once()
|
||||
|
||||
// `CancelShard` should be called with the attemptID.
|
||||
@@ -1199,7 +1199,7 @@ func TestResumePaymentSuccess(t *testing.T) {
|
||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||
|
||||
// 1.2. calls `GetState` and return the state.
|
||||
ps := &channeldb.MPPaymentState{
|
||||
ps := &paymentsdb.MPPaymentState{
|
||||
RemainingAmt: paymentAmt,
|
||||
}
|
||||
m.payment.On("GetState").Return(ps).Once()
|
||||
@@ -1207,7 +1207,7 @@ func TestResumePaymentSuccess(t *testing.T) {
|
||||
// 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.
|
||||
m.payment.On("GetStatus").Return(channeldb.StatusInFlight)
|
||||
m.payment.On("GetStatus").Return(paymentsdb.StatusInFlight)
|
||||
|
||||
// 1.3. decideNextStep now returns stepProceed.
|
||||
m.payment.On("AllowMoreAttempts").Return(true, nil).Once()
|
||||
@@ -1300,7 +1300,7 @@ func TestResumePaymentSuccessWithTwoAttempts(t *testing.T) {
|
||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||
|
||||
// 1.2. calls `GetState` and return the state.
|
||||
ps := &channeldb.MPPaymentState{
|
||||
ps := &paymentsdb.MPPaymentState{
|
||||
RemainingAmt: paymentAmt,
|
||||
}
|
||||
m.payment.On("GetState").Return(ps).Once()
|
||||
@@ -1308,7 +1308,7 @@ func TestResumePaymentSuccessWithTwoAttempts(t *testing.T) {
|
||||
// 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.
|
||||
m.payment.On("GetStatus").Return(channeldb.StatusInFlight)
|
||||
m.payment.On("GetStatus").Return(paymentsdb.StatusInFlight)
|
||||
|
||||
// 1.3. decideNextStep now returns stepProceed.
|
||||
m.payment.On("AllowMoreAttempts").Return(true, nil).Once()
|
||||
@@ -1452,7 +1452,7 @@ func TestCollectResultExitOnErr(t *testing.T) {
|
||||
// which we'd fail the payment, cancel the shard and fail the attempt.
|
||||
//
|
||||
// `FailPayment` should be called with an internal reason.
|
||||
reason := channeldb.FailureReasonError
|
||||
reason := paymentsdb.FailureReasonError
|
||||
m.control.On("FailPayment", p.identifier, reason).Return(nil).Once()
|
||||
|
||||
// `CancelShard` should be called with the attemptID.
|
||||
@@ -1498,7 +1498,7 @@ func TestCollectResultExitOnResultErr(t *testing.T) {
|
||||
// which we'd fail the payment, cancel the shard and fail the attempt.
|
||||
//
|
||||
// `FailPayment` should be called with an internal reason.
|
||||
reason := channeldb.FailureReasonError
|
||||
reason := paymentsdb.FailureReasonError
|
||||
m.control.On("FailPayment", p.identifier, reason).Return(nil).Once()
|
||||
|
||||
// `CancelShard` should be called with the attemptID.
|
||||
@@ -1833,7 +1833,7 @@ func TestReloadInflightAttemptsLegacy(t *testing.T) {
|
||||
m.control.On("FetchPayment", p.identifier).Return(m.payment, nil).Once()
|
||||
|
||||
// 2. calls `InFlightHTLCs` and return the attempt.
|
||||
attempts := []channeldb.HTLCAttempt{*attempt}
|
||||
attempts := []paymentsdb.HTLCAttempt{*attempt}
|
||||
m.payment.On("InFlightHTLCs").Return(attempts).Once()
|
||||
|
||||
// 3. Mock the htlcswitch to return a the result chan.
|
||||
|
||||
@@ -5,12 +5,12 @@ import (
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btclog/v2"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
graphdb "github.com/lightningnetwork/lnd/graph/db"
|
||||
"github.com/lightningnetwork/lnd/graph/db/models"
|
||||
"github.com/lightningnetwork/lnd/lnutils"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/netann"
|
||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
)
|
||||
|
||||
@@ -104,7 +104,7 @@ func (e noRouteError) Error() string {
|
||||
}
|
||||
|
||||
// FailureReason converts a path finding error into a payment-level failure.
|
||||
func (e noRouteError) FailureReason() channeldb.FailureReason {
|
||||
func (e noRouteError) FailureReason() paymentsdb.FailureReason {
|
||||
switch e {
|
||||
case
|
||||
errNoTlvPayload,
|
||||
@@ -114,13 +114,13 @@ func (e noRouteError) FailureReason() channeldb.FailureReason {
|
||||
errUnknownRequiredFeature,
|
||||
errMissingDependentFeature:
|
||||
|
||||
return channeldb.FailureReasonNoRoute
|
||||
return paymentsdb.FailureReasonNoRoute
|
||||
|
||||
case errInsufficientBalance:
|
||||
return channeldb.FailureReasonInsufficientBalance
|
||||
return paymentsdb.FailureReasonInsufficientBalance
|
||||
|
||||
default:
|
||||
return channeldb.FailureReasonError
|
||||
return paymentsdb.FailureReasonError
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,17 +5,17 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/fn/v2"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"github.com/lightningnetwork/lnd/tlv"
|
||||
)
|
||||
|
||||
// Instantiate variables to allow taking a reference from the failure reason.
|
||||
var (
|
||||
reasonError = channeldb.FailureReasonError
|
||||
reasonIncorrectDetails = channeldb.FailureReasonPaymentDetails
|
||||
reasonError = paymentsdb.FailureReasonError
|
||||
reasonIncorrectDetails = paymentsdb.FailureReasonPaymentDetails
|
||||
)
|
||||
|
||||
// pairResult contains the result of the interpretation of a payment attempt for
|
||||
@@ -70,7 +70,7 @@ type interpretedResult struct {
|
||||
// finalFailureReason is set to a non-nil value if it makes no more
|
||||
// sense to start another payment attempt. It will contain the reason
|
||||
// why.
|
||||
finalFailureReason *channeldb.FailureReason
|
||||
finalFailureReason *paymentsdb.FailureReason
|
||||
|
||||
// policyFailure is set to a node pair if there is a policy failure on
|
||||
// that connection. This is used to control the second chance logic for
|
||||
|
||||
+12
-13
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/lightningnetwork/lnd/amp"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/clock"
|
||||
"github.com/lightningnetwork/lnd/fn/v2"
|
||||
"github.com/lightningnetwork/lnd/graph/db/models"
|
||||
@@ -175,7 +174,7 @@ type MissionControlQuerier interface {
|
||||
// need to be made.
|
||||
ReportPaymentFail(attemptID uint64, rt *route.Route,
|
||||
failureSourceIdx *int, failure lnwire.FailureMessage) (
|
||||
*channeldb.FailureReason, error)
|
||||
*paymentsdb.FailureReason, error)
|
||||
|
||||
// ReportPaymentSuccess reports a successful payment to mission control
|
||||
// as input for future probability estimates.
|
||||
@@ -999,7 +998,7 @@ func (r *ChannelRouter) PreparePayment(payment *LightningPayment) (
|
||||
// already in-flight.
|
||||
//
|
||||
// TODO(roasbeef): store records as part of creation info?
|
||||
info := &channeldb.PaymentCreationInfo{
|
||||
info := &paymentsdb.PaymentCreationInfo{
|
||||
PaymentIdentifier: payment.Identifier(),
|
||||
Value: payment.Amount,
|
||||
CreationTime: r.cfg.Clock.Now(),
|
||||
@@ -1038,7 +1037,7 @@ func (r *ChannelRouter) PreparePayment(payment *LightningPayment) (
|
||||
// SendToRoute sends a payment using the provided route and fails the payment
|
||||
// when an error is returned from the attempt.
|
||||
func (r *ChannelRouter) SendToRoute(htlcHash lntypes.Hash, rt *route.Route,
|
||||
firstHopCustomRecords lnwire.CustomRecords) (*channeldb.HTLCAttempt,
|
||||
firstHopCustomRecords lnwire.CustomRecords) (*paymentsdb.HTLCAttempt,
|
||||
error) {
|
||||
|
||||
return r.sendToRoute(htlcHash, rt, false, firstHopCustomRecords)
|
||||
@@ -1048,7 +1047,7 @@ func (r *ChannelRouter) SendToRoute(htlcHash lntypes.Hash, rt *route.Route,
|
||||
// the payment ONLY when a terminal error is returned from the attempt.
|
||||
func (r *ChannelRouter) SendToRouteSkipTempErr(htlcHash lntypes.Hash,
|
||||
rt *route.Route,
|
||||
firstHopCustomRecords lnwire.CustomRecords) (*channeldb.HTLCAttempt,
|
||||
firstHopCustomRecords lnwire.CustomRecords) (*paymentsdb.HTLCAttempt,
|
||||
error) {
|
||||
|
||||
return r.sendToRoute(htlcHash, rt, true, firstHopCustomRecords)
|
||||
@@ -1062,13 +1061,13 @@ func (r *ChannelRouter) SendToRouteSkipTempErr(htlcHash lntypes.Hash,
|
||||
// the payment won't be failed unless a terminal error has occurred.
|
||||
func (r *ChannelRouter) sendToRoute(htlcHash lntypes.Hash, rt *route.Route,
|
||||
skipTempErr bool,
|
||||
firstHopCustomRecords lnwire.CustomRecords) (*channeldb.HTLCAttempt,
|
||||
firstHopCustomRecords lnwire.CustomRecords) (*paymentsdb.HTLCAttempt,
|
||||
error) {
|
||||
|
||||
// Helper function to fail a payment. It makes sure the payment is only
|
||||
// failed once so that the failure reason is not overwritten.
|
||||
failPayment := func(paymentIdentifier lntypes.Hash,
|
||||
reason channeldb.FailureReason) error {
|
||||
reason paymentsdb.FailureReason) error {
|
||||
|
||||
payment, fetchErr := r.cfg.Control.FetchPayment(
|
||||
paymentIdentifier,
|
||||
@@ -1122,7 +1121,7 @@ func (r *ChannelRouter) sendToRoute(htlcHash lntypes.Hash, rt *route.Route,
|
||||
|
||||
// Record this payment hash with the ControlTower, ensuring it is not
|
||||
// already in-flight.
|
||||
info := &channeldb.PaymentCreationInfo{
|
||||
info := &paymentsdb.PaymentCreationInfo{
|
||||
PaymentIdentifier: paymentIdentifier,
|
||||
Value: amt,
|
||||
CreationTime: r.cfg.Clock.Now(),
|
||||
@@ -1191,7 +1190,7 @@ func (r *ChannelRouter) sendToRoute(htlcHash lntypes.Hash, rt *route.Route,
|
||||
// Since for SendToRoute we won't retry in case the shard fails, we'll
|
||||
// mark the payment failed with the control tower immediately if the
|
||||
// skipTempErr is false.
|
||||
reason := channeldb.FailureReasonError
|
||||
reason := paymentsdb.FailureReasonError
|
||||
|
||||
// If we failed to send the HTLC, we need to further decide if we want
|
||||
// to fail the payment.
|
||||
@@ -1448,7 +1447,7 @@ func (r *ChannelRouter) resumePayments() error {
|
||||
}
|
||||
|
||||
// launchPayment is a helper closure that handles resuming the payment.
|
||||
launchPayment := func(payment *channeldb.MPPayment) {
|
||||
launchPayment := func(payment *paymentsdb.MPPayment) {
|
||||
defer r.wg.Done()
|
||||
|
||||
// Get the hashes used for the outstanding HTLCs.
|
||||
@@ -1523,7 +1522,7 @@ func (r *ChannelRouter) resumePayments() error {
|
||||
// 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/pull/8174
|
||||
func (r *ChannelRouter) failStaleAttempt(a channeldb.HTLCAttempt,
|
||||
func (r *ChannelRouter) failStaleAttempt(a paymentsdb.HTLCAttempt,
|
||||
payHash lntypes.Hash) {
|
||||
|
||||
// We can only fail inflight HTLCs so we skip the settled/failed ones.
|
||||
@@ -1605,8 +1604,8 @@ func (r *ChannelRouter) failStaleAttempt(a channeldb.HTLCAttempt,
|
||||
|
||||
// Fail the attempt in db. If there's an error, there's nothing we can
|
||||
// do here but logging it.
|
||||
failInfo := &channeldb.HTLCFailInfo{
|
||||
Reason: channeldb.HTLCFailUnknown,
|
||||
failInfo := &paymentsdb.HTLCFailInfo{
|
||||
Reason: paymentsdb.HTLCFailUnknown,
|
||||
FailTime: r.cfg.Clock.Now(),
|
||||
}
|
||||
_, err = r.cfg.Control.FailAttempt(payHash, a.AttemptID, failInfo)
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
sphinx "github.com/lightningnetwork/lightning-onion"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/clock"
|
||||
"github.com/lightningnetwork/lnd/fn/v2"
|
||||
"github.com/lightningnetwork/lnd/graph"
|
||||
@@ -32,6 +31,7 @@ import (
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"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/zpay32"
|
||||
@@ -1091,7 +1091,7 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
|
||||
|
||||
// The final error returned should also indicate that the peer wasn't
|
||||
// online (the last error we returned).
|
||||
require.Equal(t, channeldb.FailureReasonNoRoute, err)
|
||||
require.Equal(t, paymentsdb.FailureReasonNoRoute, err)
|
||||
|
||||
// Inspect the two attempts that were made before the payment failed.
|
||||
p, err := ctx.router.cfg.Control.FetchPayment(*payment.paymentHash)
|
||||
@@ -2429,7 +2429,7 @@ func TestSendToRouteSkipTempErrPermanentFailure(t *testing.T) {
|
||||
mock.Anything, mock.Anything, mock.Anything,
|
||||
).Return(permErr)
|
||||
|
||||
failureReason := channeldb.FailureReasonPaymentDetails
|
||||
failureReason := paymentsdb.FailureReasonPaymentDetails
|
||||
missionControl.On("ReportPaymentFail",
|
||||
mock.Anything, rt, mock.Anything, mock.Anything,
|
||||
).Return(&failureReason, nil)
|
||||
|
||||
+3
-2
@@ -71,6 +71,7 @@ import (
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chanfunding"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/macaroons"
|
||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||
"github.com/lightningnetwork/lnd/peer"
|
||||
"github.com/lightningnetwork/lnd/peernotifier"
|
||||
"github.com/lightningnetwork/lnd/record"
|
||||
@@ -5892,7 +5893,7 @@ func (r *rpcServer) dispatchPaymentIntent(
|
||||
payment,
|
||||
)
|
||||
} else {
|
||||
var attempt *channeldb.HTLCAttempt
|
||||
var attempt *paymentsdb.HTLCAttempt
|
||||
attempt, routerErr = r.server.chanRouter.SendToRoute(
|
||||
payIntent.rHash, payIntent.route, nil,
|
||||
)
|
||||
@@ -7512,7 +7513,7 @@ func (r *rpcServer) ListPayments(ctx context.Context,
|
||||
}
|
||||
}
|
||||
|
||||
query := channeldb.PaymentsQuery{
|
||||
query := paymentsdb.Query{
|
||||
IndexOffset: req.IndexOffset,
|
||||
MaxPayments: req.MaxPayments,
|
||||
Reversed: req.Reversed,
|
||||
|
||||
@@ -65,6 +65,7 @@ import (
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/nat"
|
||||
"github.com/lightningnetwork/lnd/netann"
|
||||
paymentsdb "github.com/lightningnetwork/lnd/payments/db"
|
||||
"github.com/lightningnetwork/lnd/peer"
|
||||
"github.com/lightningnetwork/lnd/peernotifier"
|
||||
"github.com/lightningnetwork/lnd/pool"
|
||||
@@ -339,7 +340,7 @@ type server struct {
|
||||
// payments.
|
||||
//
|
||||
// TODO(ziggie): Replace with interface.
|
||||
kvPaymentsDB *channeldb.KVPaymentsDB
|
||||
kvPaymentsDB *paymentsdb.KVPaymentsDB
|
||||
|
||||
aliasMgr *aliasmgr.Manager
|
||||
|
||||
|
||||
Reference in new issue
Block a user