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