Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
18f03ec
sqldb: add index and comment to payment tables
ziggie1984 Oct 15, 2025
c908b52
multi: add relevant queries for QueryPayments implemenation
ziggie1984 Oct 12, 2025
52d466f
paymentsdb: add new internal error
ziggie1984 Oct 12, 2025
353160c
paymentsdb: implement QueryPayments for sql backend
ziggie1984 Oct 12, 2025
fc4ce67
paymentsdb: implement FetchPayment for sql backend
ziggie1984 Oct 15, 2025
0849296
docs: add release-notes
ziggie1984 Oct 12, 2025
ed5622c
sqldb: add queries for deleting a payment and attempts
ziggie1984 Oct 15, 2025
215490c
paymentsdb: implement DeletePayment for sql backend
ziggie1984 Oct 15, 2025
3a39bdc
paymentsdb: implement DeleteFailedAttempts for sql backend
ziggie1984 Oct 15, 2025
1aae195
sqldb+paymentsdb: add queries to insert all relavant data
ziggie1984 Oct 15, 2025
f6f2ee3
paymentsdb: implement InitPayment for sql backend
ziggie1984 Oct 15, 2025
53b47ea
paymentsdb: implement RegisterAttempt for sql backend
ziggie1984 Oct 15, 2025
b3f3627
paymentsdb: implement SettleAttempt for sql backend
ziggie1984 Oct 15, 2025
6145682
docs: add release-notes
ziggie1984 Oct 15, 2025
1005816
paymentsdb: add harness to run payment db agnostic tests
ziggie1984 Oct 15, 2025
3b1dd2a
paymentsdb: refactor test helpers
ziggie1984 Oct 15, 2025
3362dce
paymentsdb: make QueryPayments test db agnostic
ziggie1984 Oct 15, 2025
b43f2c8
multi: implement Fail method for sql backend
ziggie1984 Oct 15, 2025
39a9aaa
paymentsdb: implement DeletePayments for sql backend
ziggie1984 Oct 15, 2025
4e0c0fe
paymentsdb: implement FailAttempt for sql backend
ziggie1984 Oct 15, 2025
2c806ea
paymentsdb: implement FetchInFlightPayments for sql backend
ziggie1984 Oct 15, 2025
d245664
paymentsdb: fix test case before testing sql backend
ziggie1984 Oct 15, 2025
492a34f
paymentsdb: remove kvstore from sql db implementation
ziggie1984 Oct 15, 2025
4f7c9bd
paymentsdb: test all db agnostic tests for all backends
ziggie1984 Oct 15, 2025
9bb4fef
itest: fix list_payments accuracy edge case
ziggie1984 Oct 15, 2025
a8d7e85
docs: add release-notes
ziggie1984 Oct 16, 2025
cfc8277
mulit: fix linter
ziggie1984 Oct 16, 2025
192302e
paymentsdb: add firstcustom records to unit tests
ziggie1984 Oct 17, 2025
bdbcc54
paymentsdb: add more comments
ziggie1984 Oct 17, 2025
0b7036e
multi: thread context through DeletePayment
ziggie1984 Oct 20, 2025
148d415
multi: thread context through DeletePayments
ziggie1984 Oct 20, 2025
19d7386
multi: thread context through FetchPayment
ziggie1984 Oct 20, 2025
37d2aa7
multi: thread context through FetchInflightPayments
ziggie1984 Oct 20, 2025
602d379
multi: thread context through InitPayment
ziggie1984 Oct 20, 2025
82e20d7
multi: thread context through RegisterAttempt method
ziggie1984 Oct 20, 2025
4a27dbc
multi: thread context through SettleAttempt
ziggie1984 Oct 21, 2025
6b88d04
multi: thread context through FailAttempt
ziggie1984 Oct 21, 2025
ac70d70
multi: thread context through Fail payment functions
ziggie1984 Oct 21, 2025
b1d6078
multi: thread context through DeleteFailedAttempts
ziggie1984 Oct 21, 2025
bc81c3a
docs: add release notes
ziggie1984 Oct 21, 2025
cb2b374
routing: Add context to requestRoute
ziggie1984 Oct 21, 2025
8eafaec
multi: thread context through payment lifecyle functions
ziggie1984 Oct 21, 2025
be71aef
routing: Thread context through failPaymentAndAttempt
ziggie1984 Oct 21, 2025
03c6ed7
routing: add context to failAttempt
ziggie1984 Oct 21, 2025
54341c6
routing: add context to reloadInflightAttempts
ziggie1984 Oct 21, 2025
e765b3a
routing: add context to reloadPayment method
ziggie1984 Oct 21, 2025
7e67836
docs: add release-notes
ziggie1984 Oct 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/release-notes/release-notes-0.21.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@
refacotor the payment related LND code to make it more modular.
* Implement the SQL backend for the [payments
database](https://github.com/lightningnetwork/lnd/pull/9147)
* Implement query methods for the [payments db
SQL Backend](https://github.com/lightningnetwork/lnd/pull/10287)
* Implement insert methods for the [payments db
SQL Backend](https://github.com/lightningnetwork/lnd/pull/10291)
* Finalize SQL payments implementation [enabling unit and itests
for SQL backend](https://github.com/lightningnetwork/lnd/pull/10292)
* [Thread context through payment
db functions Part 1](https://github.com/lightningnetwork/lnd/pull/10307)
* [Thread context through payment
db functions Part 2](https://github.com/lightningnetwork/lnd/pull/10308)


## Code Health

Expand Down
59 changes: 43 additions & 16 deletions itest/lnd_payment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -504,61 +504,86 @@ func testListPayments(ht *lntest.HarnessTest) {
expected bool
}

// Create test cases to check the timestamp filters.
createCases := func(createTimeSeconds uint64) []testCase {
// Create test cases with proper rounding for start and end dates.
createCases := func(startTimeSeconds,
endTimeSeconds uint64) []testCase {

return []testCase{
{
// Use a start date same as the creation date
// should return us the item.
// (truncated) should return us the item.
name: "exact start date",
startDate: createTimeSeconds,
startDate: startTimeSeconds,
expected: true,
},
{
// Use an earlier start date should return us
// the item.
name: "earlier start date",
startDate: createTimeSeconds - 1,
startDate: startTimeSeconds - 1,
expected: true,
},
{
// Use a future start date should return us
// nothing.
name: "future start date",
startDate: createTimeSeconds + 1,
startDate: startTimeSeconds + 1,
expected: false,
},
{
// Use an end date same as the creation date
// should return us the item.
// (ceiling) should return us the item.
name: "exact end date",
endDate: createTimeSeconds,
endDate: endTimeSeconds,
expected: true,
},
{
// Use an end date in the future should return
// us the item.
name: "future end date",
endDate: createTimeSeconds + 1,
endDate: endTimeSeconds + 1,
expected: true,
},
{
// Use an earlier end date should return us
// nothing.
name: "earlier end date",
endDate: createTimeSeconds - 1,
name: "earlier end date",
// The native sql backend has a higher
// precision than the kv backend, the native sql
// backend uses microseconds, the kv backend
// when filtering uses seconds so we need to
// subtract 2 seconds to ensure the payment is
// not included.
// We could also truncate before inserting
// into the sql db but I rather relax this test
// here.
endDate: endTimeSeconds - 2,
expected: false,
},
}
}

// Get the payment creation time in seconds.
paymentCreateSeconds := uint64(
p.CreationTimeNs / time.Second.Nanoseconds(),
// Get the payment creation time in seconds, using different approaches
// for start and end date comparisons to avoid rounding issues.
creationTime := time.Unix(0, p.CreationTimeNs)

// For start date comparisons: use truncation (floor) to include
// payments from the beginning of that second.
paymentCreateSecondsStart := uint64(
creationTime.Truncate(time.Second).Unix(),
)

// For end date comparisons: use ceiling to include payments up to the
// end of that second.
paymentCreateSecondsEnd := uint64(
(p.CreationTimeNs + time.Second.Nanoseconds() - 1) /
time.Second.Nanoseconds(),
)

// Create test cases from the payment creation time.
testCases := createCases(paymentCreateSeconds)
testCases := createCases(
paymentCreateSecondsStart, paymentCreateSecondsEnd,
)

// We now check the timestamp filters in `ListPayments`.
for _, tc := range testCases {
Expand All @@ -578,7 +603,9 @@ func testListPayments(ht *lntest.HarnessTest) {
}

// Create test cases from the invoice creation time.
testCases = createCases(uint64(invoice.CreationDate))
testCases = createCases(
uint64(invoice.CreationDate), uint64(invoice.CreationDate),
)

// We now do the same check for `ListInvoices`.
for _, tc := range testCases {
Expand Down
2 changes: 2 additions & 0 deletions lnrpc/routerrpc/router_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -1745,6 +1745,8 @@ func (r *RouterBackend) MarshallPayment(payment *paymentsdb.MPPayment) (
// If any of the htlcs have settled, extract a valid
// preimage.
if htlc.Settle != nil {
// For AMP payments all hashes will be different so we
// will depict the last htlc preimage.
preimage = htlc.Settle.Preimage
fee += htlc.Route.TotalFees()
}
Expand Down
4 changes: 2 additions & 2 deletions lnrpc/routerrpc/router_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -936,11 +936,11 @@ func (s *Server) SendToRouteV2(ctx context.Context,
// db.
if req.SkipTempErr {
attempt, err = s.cfg.Router.SendToRouteSkipTempErr(
hash, route, firstHopRecords,
ctx, hash, route, firstHopRecords,
)
} else {
attempt, err = s.cfg.Router.SendToRoute(
hash, route, firstHopRecords,
ctx, hash, route, firstHopRecords,
)
}
if attempt != nil {
Expand Down
4 changes: 4 additions & 0 deletions payments/db/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,8 @@ var (
// NOTE: Only used for the kv backend.
ErrNoSequenceNrIndex = errors.New("payment sequence number index " +
"does not exist")

// errMaxPaymentsReached is used internally to signal that the maximum
// number of payments has been reached during a paginated query.
errMaxPaymentsReached = errors.New("max payments reached")
)
26 changes: 16 additions & 10 deletions payments/db/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,24 @@ type PaymentReader interface {

// FetchPayment fetches the payment corresponding to the given payment
// hash.
FetchPayment(paymentHash lntypes.Hash) (*MPPayment, error)
FetchPayment(ctx context.Context,
paymentHash lntypes.Hash) (*MPPayment, error)

// FetchInFlightPayments returns all payments with status InFlight.
FetchInFlightPayments() ([]*MPPayment, error)
FetchInFlightPayments(ctx context.Context) ([]*MPPayment, error)
}

// PaymentWriter represents the interface to write operations to the payments
// database.
type PaymentWriter interface {
// DeletePayment deletes a payment from the DB given its payment hash.
DeletePayment(paymentHash lntypes.Hash, failedAttemptsOnly bool) error
DeletePayment(ctx context.Context, paymentHash lntypes.Hash,
failedAttemptsOnly bool) error

// DeletePayments deletes all payments from the DB given the specified
// flags.
DeletePayments(failedOnly, failedAttemptsOnly bool) (int, error)
DeletePayments(ctx context.Context, failedOnly,
failedAttemptsOnly bool) (int, error)

PaymentControl
}
Expand All @@ -58,10 +61,11 @@ type PaymentControl interface {
// exists in the database before creating a new payment. However, it
// should allow the user making a subsequent payment if the payment is
// in a Failed state.
InitPayment(lntypes.Hash, *PaymentCreationInfo) error
InitPayment(context.Context, lntypes.Hash, *PaymentCreationInfo) error

// RegisterAttempt atomically records the provided HTLCAttemptInfo.
RegisterAttempt(lntypes.Hash, *HTLCAttemptInfo) (*MPPayment, error)
RegisterAttempt(context.Context, lntypes.Hash,
*HTLCAttemptInfo) (*MPPayment, error)

// SettleAttempt marks the given attempt settled with the preimage. If
// this is a multi shard payment, this might implicitly mean the
Expand All @@ -71,23 +75,25 @@ type PaymentControl interface {
// error to prevent us from making duplicate payments to the same
// payment hash. The provided preimage is atomically saved to the DB
// for record keeping.
SettleAttempt(lntypes.Hash, uint64, *HTLCSettleInfo) (*MPPayment, error)
SettleAttempt(context.Context, lntypes.Hash, uint64,
*HTLCSettleInfo) (*MPPayment, error)

// FailAttempt marks the given payment attempt failed.
FailAttempt(lntypes.Hash, uint64, *HTLCFailInfo) (*MPPayment, error)
FailAttempt(context.Context, lntypes.Hash, uint64,
*HTLCFailInfo) (*MPPayment, error)

// Fail transitions a payment into the Failed state, and records
// the ultimate reason the payment failed. Note that this should only
// be called when all active attempts are already failed. After
// invoking this method, InitPayment should return nil on its next call
// for this payment hash, allowing the user to make a subsequent
// payment.
Fail(lntypes.Hash, FailureReason) (*MPPayment, error)
Fail(context.Context, lntypes.Hash, FailureReason) (*MPPayment, error)

// DeleteFailedAttempts removes all failed HTLCs from the db. It should
// be called for a given payment whenever all inflight htlcs are
// completed, and the payment has reached a final terminal state.
DeleteFailedAttempts(lntypes.Hash) error
DeleteFailedAttempts(context.Context, lntypes.Hash) error
}

// DBMPPayment is an interface that represents the payment state during a
Expand Down
28 changes: 16 additions & 12 deletions payments/db/kv_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func initKVStore(db kvdb.Backend) error {
// making sure it does not already exist as an in-flight payment. When this
// method returns successfully, the payment is guaranteed to be in the InFlight
// state.
func (p *KVStore) InitPayment(paymentHash lntypes.Hash,
func (p *KVStore) InitPayment(_ context.Context, paymentHash lntypes.Hash,
info *PaymentCreationInfo) error {

// Obtain a new sequence number for this payment. This is used
Expand Down Expand Up @@ -290,10 +290,12 @@ func (p *KVStore) InitPayment(paymentHash lntypes.Hash,

// DeleteFailedAttempts deletes all failed htlcs for a payment if configured
// by the KVStore db.
func (p *KVStore) DeleteFailedAttempts(hash lntypes.Hash) error {
func (p *KVStore) DeleteFailedAttempts(ctx context.Context,
hash lntypes.Hash) error {

if !p.keepFailedPaymentAttempts {
const failedHtlcsOnly = true
err := p.DeletePayment(hash, failedHtlcsOnly)
err := p.DeletePayment(ctx, hash, failedHtlcsOnly)
if err != nil {
return err
}
Expand Down Expand Up @@ -357,7 +359,7 @@ func deserializePaymentIndex(r io.Reader) (lntypes.Hash, error) {

// RegisterAttempt atomically records the provided HTLCAttemptInfo to the
// DB.
func (p *KVStore) RegisterAttempt(paymentHash lntypes.Hash,
func (p *KVStore) RegisterAttempt(_ context.Context, paymentHash lntypes.Hash,
attempt *HTLCAttemptInfo) (*MPPayment, error) {

// Serialize the information before opening the db transaction.
Expand Down Expand Up @@ -428,7 +430,7 @@ func (p *KVStore) RegisterAttempt(paymentHash lntypes.Hash,
// After invoking this method, InitPayment should always return an error to
// prevent us from making duplicate payments to the same payment hash. The
// provided preimage is atomically saved to the DB for record keeping.
func (p *KVStore) SettleAttempt(hash lntypes.Hash,
func (p *KVStore) SettleAttempt(_ context.Context, hash lntypes.Hash,
attemptID uint64, settleInfo *HTLCSettleInfo) (*MPPayment, error) {

var b bytes.Buffer
Expand All @@ -441,7 +443,7 @@ func (p *KVStore) SettleAttempt(hash lntypes.Hash,
}

// FailAttempt marks the given payment attempt failed.
func (p *KVStore) FailAttempt(hash lntypes.Hash,
func (p *KVStore) FailAttempt(_ context.Context, hash lntypes.Hash,
attemptID uint64, failInfo *HTLCFailInfo) (*MPPayment, error) {

var b bytes.Buffer
Expand Down Expand Up @@ -526,7 +528,7 @@ func (p *KVStore) updateHtlcKey(paymentHash lntypes.Hash,
// payment failed. After invoking this method, InitPayment should return nil on
// its next call for this payment hash, allowing the switch to make a
// subsequent payment.
func (p *KVStore) Fail(paymentHash lntypes.Hash,
func (p *KVStore) Fail(_ context.Context, paymentHash lntypes.Hash,
reason FailureReason) (*MPPayment, error) {

var (
Expand Down Expand Up @@ -583,8 +585,8 @@ func (p *KVStore) Fail(paymentHash lntypes.Hash,
}

// FetchPayment returns information about a payment from the database.
func (p *KVStore) FetchPayment(paymentHash lntypes.Hash) (
*MPPayment, error) {
func (p *KVStore) FetchPayment(_ context.Context,
paymentHash lntypes.Hash) (*MPPayment, error) {

var payment *MPPayment
err := kvdb.View(p.db, func(tx kvdb.RTx) error {
Expand Down Expand Up @@ -739,7 +741,9 @@ func fetchPaymentStatus(bucket kvdb.RBucket) (PaymentStatus, error) {
}

// FetchInFlightPayments returns all payments with status InFlight.
func (p *KVStore) FetchInFlightPayments() ([]*MPPayment, error) {
func (p *KVStore) FetchInFlightPayments(_ context.Context) ([]*MPPayment,
error) {

var (
inFlights []*MPPayment
start = time.Now()
Expand Down Expand Up @@ -1273,7 +1277,7 @@ func fetchPaymentWithSequenceNumber(tx kvdb.RTx, paymentHash lntypes.Hash,
// DeletePayment deletes a payment from the DB given its payment hash. If
// failedHtlcsOnly is set, only failed HTLC attempts of the payment will be
// deleted.
func (p *KVStore) DeletePayment(paymentHash lntypes.Hash,
func (p *KVStore) DeletePayment(_ context.Context, paymentHash lntypes.Hash,
failedHtlcsOnly bool) error {

return kvdb.Update(p.db, func(tx kvdb.RwTx) error {
Expand Down Expand Up @@ -1370,7 +1374,7 @@ func (p *KVStore) DeletePayment(paymentHash lntypes.Hash,
// failedHtlcsOnly is set, the payment itself won't be deleted, only failed HTLC
// attempts. The method returns the number of deleted payments, which is always
// 0 if failedHtlcsOnly is set.
func (p *KVStore) DeletePayments(failedOnly,
func (p *KVStore) DeletePayments(_ context.Context, failedOnly,
failedHtlcsOnly bool) (int, error) {

var numPayments int
Expand Down
Loading
Loading