From cfc2710c585f091c482a9a48dead1163e75d2e95 Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Thu, 5 Oct 2023 21:04:54 +0200 Subject: [PATCH 1/3] multi: extend InvoiceDB methods with a context argument This commit adds a context to InvoiceDB's methods. Along this refactor we also extend InvoiceRegistry methods with contexts where it makes sense. This change is essential to be able to provide kvdb and sqldb implementations for InvoiceDB. --- channeldb/invoice_test.go | 227 +++++++++++++++------------ channeldb/invoices.go | 34 ++-- contractcourt/channel_arbitrator.go | 3 +- contractcourt/interfaces.go | 3 +- contractcourt/mock_registry_test.go | 6 +- htlcswitch/interfaces.go | 8 +- htlcswitch/link_test.go | 80 +++++++--- htlcswitch/mock.go | 23 +-- htlcswitch/switch_test.go | 5 +- htlcswitch/test_utils.go | 9 +- invoices/interface.go | 22 ++- invoices/invoiceregistry.go | 78 +++++---- invoices/invoiceregistry_test.go | 208 ++++++++++++------------ lnrpc/invoicesrpc/addinvoice.go | 6 +- lnrpc/invoicesrpc/invoices_server.go | 12 +- rpcserver.go | 6 +- 16 files changed, 422 insertions(+), 308 deletions(-) diff --git a/channeldb/invoice_test.go b/channeldb/invoice_test.go index ce2d960b6e..b840c37535 100644 --- a/channeldb/invoice_test.go +++ b/channeldb/invoice_test.go @@ -2,6 +2,7 @@ package channeldb import ( "bytes" + "context" "crypto/rand" "fmt" "math" @@ -177,17 +178,18 @@ func testInvoiceWorkflow(t *testing.T, test invWorkflowTest) { ref = invpkg.InvoiceRefByHash(payHash) } + ctxb := context.Background() // Add the invoice to the database, this should succeed as there aren't // any existing invoices within the database with the same payment // hash. - if _, err := db.AddInvoice(fakeInvoice, invPayHash); err != nil { + if _, err := db.AddInvoice(ctxb, fakeInvoice, invPayHash); err != nil { t.Fatalf("unable to find invoice: %v", err) } // Attempt to retrieve the invoice which was just added to the // database. It should be found, and the invoice returned should be // identical to the one created above. - dbInvoice, err := db.LookupInvoice(ref) + dbInvoice, err := db.LookupInvoice(ctxb, ref) if !test.queryPayAddr && !test.queryPayHash { require.ErrorIs(t, err, invpkg.ErrInvoiceNotFound) return @@ -210,9 +212,9 @@ func testInvoiceWorkflow(t *testing.T, test invWorkflowTest) { // now have the settled bit toggle to true and a non-default // SettledDate payAmt := fakeInvoice.Terms.Value * 2 - _, err = db.UpdateInvoice(ref, nil, getUpdateInvoice(payAmt)) + _, err = db.UpdateInvoice(ctxb, ref, nil, getUpdateInvoice(payAmt)) require.NoError(t, err, "unable to settle invoice") - dbInvoice2, err := db.LookupInvoice(ref) + dbInvoice2, err := db.LookupInvoice(ctxb, ref) require.NoError(t, err, "unable to fetch invoice") if dbInvoice2.State != invpkg.ContractSettled { t.Fatalf("invoice should now be settled but isn't") @@ -234,14 +236,14 @@ func testInvoiceWorkflow(t *testing.T, test invWorkflowTest) { // Attempt to insert generated above again, this should fail as // duplicates are rejected by the processing logic. - _, err = db.AddInvoice(fakeInvoice, payHash) + _, err = db.AddInvoice(ctxb, fakeInvoice, payHash) require.ErrorIs(t, err, invpkg.ErrDuplicateInvoice) // Attempt to look up a non-existent invoice, this should also fail but // with a "not found" error. var fakeHash [32]byte fakeRef := invpkg.InvoiceRefByHash(fakeHash) - _, err = db.LookupInvoice(fakeRef) + _, err = db.LookupInvoice(ctxb, fakeRef) require.ErrorIs(t, err, invpkg.ErrInvoiceNotFound) // Add 10 random invoices. @@ -256,7 +258,7 @@ func testInvoiceWorkflow(t *testing.T, test invWorkflowTest) { } hash := invoice.Terms.PaymentPreimage.Hash() - if _, err := db.AddInvoice(invoice, hash); err != nil { + if _, err := db.AddInvoice(ctxb, invoice, hash); err != nil { t.Fatalf("unable to add invoice %v", err) } @@ -270,7 +272,7 @@ func testInvoiceWorkflow(t *testing.T, test invWorkflowTest) { PendingOnly: false, } - response, err := db.QueryInvoices(query) + response, err := db.QueryInvoices(ctxb, query) require.NoError(t, err, "invoice query failed") // The retrieve list of invoices should be identical as since we're @@ -299,14 +301,16 @@ func TestAddDuplicatePayAddr(t *testing.T) { require.NoError(t, err) invoice2.Terms.PaymentAddr = invoice1.Terms.PaymentAddr + ctxb := context.Background() + // First insert should succeed. inv1Hash := invoice1.Terms.PaymentPreimage.Hash() - _, err = db.AddInvoice(invoice1, inv1Hash) + _, err = db.AddInvoice(ctxb, invoice1, inv1Hash) require.NoError(t, err) // Second insert should fail with duplicate payment addr. inv2Hash := invoice2.Terms.PaymentPreimage.Hash() - _, err = db.AddInvoice(invoice2, inv2Hash) + _, err = db.AddInvoice(ctxb, invoice2, inv2Hash) require.Error(t, err, invpkg.ErrDuplicatePayAddr) } @@ -326,14 +330,16 @@ func TestAddDuplicateKeysendPayAddr(t *testing.T) { require.NoError(t, err) invoice2.Terms.PaymentAddr = invpkg.BlankPayAddr + ctxb := context.Background() + // Inserting both should succeed without a duplicate payment address // failure. inv1Hash := invoice1.Terms.PaymentPreimage.Hash() - _, err = db.AddInvoice(invoice1, inv1Hash) + _, err = db.AddInvoice(ctxb, invoice1, inv1Hash) require.NoError(t, err) inv2Hash := invoice2.Terms.PaymentPreimage.Hash() - _, err = db.AddInvoice(invoice2, inv2Hash) + _, err = db.AddInvoice(ctxb, invoice2, inv2Hash) require.NoError(t, err) // Querying for each should succeed. Here we use hash+addr refs since @@ -341,12 +347,12 @@ func TestAddDuplicateKeysendPayAddr(t *testing.T) { // invoices, so if both succeed we can be assured they aren't included // in the payment address index. ref1 := invpkg.InvoiceRefByHashAndAddr(inv1Hash, invpkg.BlankPayAddr) - dbInv1, err := db.LookupInvoice(ref1) + dbInv1, err := db.LookupInvoice(ctxb, ref1) require.NoError(t, err) require.Equal(t, invoice1, &dbInv1) ref2 := invpkg.InvoiceRefByHashAndAddr(inv2Hash, invpkg.BlankPayAddr) - dbInv2, err := db.LookupInvoice(ref2) + dbInv2, err := db.LookupInvoice(ctxb, ref2) require.NoError(t, err) require.Equal(t, invoice2, &dbInv2) } @@ -365,7 +371,9 @@ func TestFailInvoiceLookupMPPPayAddrOnly(t *testing.T) { payHash := invoice.Terms.PaymentPreimage.Hash() payAddr := invoice.Terms.PaymentAddr - _, err = db.AddInvoice(invoice, payHash) + + ctxb := context.Background() + _, err = db.AddInvoice(ctxb, invoice, payHash) require.NoError(t, err) // Modify the queried payment hash to be invalid. @@ -376,7 +384,7 @@ func TestFailInvoiceLookupMPPPayAddrOnly(t *testing.T) { // legacy/MPP invoices, as this guarantees that the preimage is valid // for the given HTLC. ref := invpkg.InvoiceRefByHashAndAddr(payHash, payAddr) - _, err = db.LookupInvoice(ref) + _, err = db.LookupInvoice(ctxb, ref) require.Equal(t, invpkg.ErrInvoiceNotFound, err) } @@ -390,15 +398,16 @@ func TestInvRefEquivocation(t *testing.T) { invoice1, err := randInvoice(1000) require.NoError(t, err) + ctxb := context.Background() inv1Hash := invoice1.Terms.PaymentPreimage.Hash() - _, err = db.AddInvoice(invoice1, inv1Hash) + _, err = db.AddInvoice(ctxb, invoice1, inv1Hash) require.NoError(t, err) invoice2, err := randInvoice(2000) require.NoError(t, err) inv2Hash := invoice2.Terms.PaymentPreimage.Hash() - _, err = db.AddInvoice(invoice2, inv2Hash) + _, err = db.AddInvoice(ctxb, invoice2, inv2Hash) require.NoError(t, err) // Now, query using invoice 1's payment address, but invoice 2's payment @@ -407,7 +416,7 @@ func TestInvRefEquivocation(t *testing.T) { ref := invpkg.InvoiceRefByHashAndAddr( inv2Hash, invoice1.Terms.PaymentAddr, ) - _, err = db.LookupInvoice(ref) + _, err = db.LookupInvoice(ctxb, ref) require.Error(t, err, invpkg.ErrInvRefEquivocation) // The same error should be returned when updating an equivocating @@ -415,7 +424,7 @@ func TestInvRefEquivocation(t *testing.T) { nop := func(_ *invpkg.Invoice) (*invpkg.InvoiceUpdateDesc, error) { return nil, nil } - _, err = db.UpdateInvoice(ref, nil, nop) + _, err = db.UpdateInvoice(ctxb, ref, nil, nop) require.Error(t, err, invpkg.ErrInvRefEquivocation) } @@ -439,7 +448,8 @@ func TestInvoiceCancelSingleHtlc(t *testing.T) { }, } - if _, err := db.AddInvoice(testInvoice, paymentHash); err != nil { + ctxb := context.Background() + if _, err := db.AddInvoice(ctxb, testInvoice, paymentHash); err != nil { t.Fatalf("unable to find invoice: %v", err) } @@ -467,7 +477,7 @@ func TestInvoiceCancelSingleHtlc(t *testing.T) { } ref := invpkg.InvoiceRefByHash(paymentHash) - invoice, err := db.UpdateInvoice(ref, nil, callback) + invoice, err := db.UpdateInvoice(ctxb, ref, nil, callback) require.NoError(t, err, "unable to add invoice htlc") if len(invoice.Htlcs) != 1 { t.Fatalf("expected the htlc to be added") @@ -488,7 +498,7 @@ func TestInvoiceCancelSingleHtlc(t *testing.T) { } // Cancel the htlc again. - invoice, err = db.UpdateInvoice(ref, nil, callback) + invoice, err = db.UpdateInvoice(ctxb, ref, nil, callback) require.NoError(t, err, "unable to cancel htlc") if len(invoice.Htlcs) != 1 { t.Fatalf("expected the htlc to be present") @@ -516,9 +526,10 @@ func TestInvoiceCancelSingleHtlcAMP(t *testing.T) { // preimages. invoice.Terms.Features = ampFeatures + ctxb := context.Background() preimage := *invoice.Terms.PaymentPreimage payHash := preimage.Hash() - _, err = db.AddInvoice(invoice, payHash) + _, err = db.AddInvoice(ctxb, invoice, payHash) require.Nil(t, err) // Add two HTLC sets, one with one HTLC and the other with two. @@ -531,19 +542,19 @@ func TestInvoiceCancelSingleHtlcAMP(t *testing.T) { // The first set ID with a single HTLC added. _, err = db.UpdateInvoice( - ref, (*invpkg.SetID)(setID1), + ctxb, ref, (*invpkg.SetID)(setID1), updateAcceptAMPHtlc(0, amt, setID1, true), ) require.Nil(t, err) // The second set ID with two HTLCs added. _, err = db.UpdateInvoice( - ref, (*invpkg.SetID)(setID2), + ctxb, ref, (*invpkg.SetID)(setID2), updateAcceptAMPHtlc(1, amt, setID2, true), ) require.Nil(t, err) dbInvoice, err := db.UpdateInvoice( - ref, (*invpkg.SetID)(setID2), + ctxb, ref, (*invpkg.SetID)(setID2), updateAcceptAMPHtlc(2, amt, setID2, true), ) require.Nil(t, err) @@ -567,10 +578,10 @@ func TestInvoiceCancelSingleHtlcAMP(t *testing.T) { // Now we'll cancel a single invoice, and assert that the amount paid // is decremented, and the state for that HTLC set reflects that is // been cancelled. - _, err = db.UpdateInvoice(ref, (*invpkg.SetID)(setID1), callback) + _, err = db.UpdateInvoice(ctxb, ref, (*invpkg.SetID)(setID1), callback) require.NoError(t, err, "unable to cancel htlc") - freshInvoice, err := db.LookupInvoice(ref) + freshInvoice, err := db.LookupInvoice(ctxb, ref) require.Nil(t, err) dbInvoice = &freshInvoice @@ -614,7 +625,7 @@ func TestInvoiceCancelSingleHtlcAMP(t *testing.T) { // Next, we'll cancel the _other_ HTLCs active, but we'll do them one // by one. - _, err = db.UpdateInvoice(ref, (*invpkg.SetID)(setID2), + _, err = db.UpdateInvoice(ctxb, ref, (*invpkg.SetID)(setID2), func(invoice *invpkg.Invoice) (*invpkg.InvoiceUpdateDesc, error) { @@ -628,7 +639,7 @@ func TestInvoiceCancelSingleHtlcAMP(t *testing.T) { }) require.NoError(t, err, "unable to cancel htlc") - freshInvoice, err = db.LookupInvoice(ref) + freshInvoice, err = db.LookupInvoice(ctxb, ref) require.Nil(t, err) dbInvoice = &freshInvoice @@ -657,10 +668,10 @@ func TestInvoiceCancelSingleHtlcAMP(t *testing.T) { // Now we'll cancel the final HTLC, which should cause all the active // HTLCs to transition to the cancelled state. - _, err = db.UpdateInvoice(ref, (*invpkg.SetID)(setID2), callback) + _, err = db.UpdateInvoice(ctxb, ref, (*invpkg.SetID)(setID2), callback) require.NoError(t, err, "unable to cancel htlc") - freshInvoice, err = db.LookupInvoice(ref) + freshInvoice, err = db.LookupInvoice(ctxb, ref) require.Nil(t, err) dbInvoice = &freshInvoice @@ -684,7 +695,8 @@ func TestInvoiceAddTimeSeries(t *testing.T) { db, err := MakeTestDB(t, OptionClock(testClock)) require.NoError(t, err, "unable to make test db") - _, err = db.InvoicesAddedSince(0) + ctxb := context.Background() + _, err = db.InvoicesAddedSince(ctxb, 0) require.NoError(t, err) // We'll start off by creating 20 random invoices, and inserting them @@ -699,8 +711,8 @@ func TestInvoiceAddTimeSeries(t *testing.T) { } paymentHash := invoice.Terms.PaymentPreimage.Hash() - - if _, err := db.AddInvoice(invoice, paymentHash); err != nil { + _, err = db.AddInvoice(ctxb, invoice, paymentHash) + if err != nil { t.Fatalf("unable to add invoice %v", err) } @@ -743,7 +755,7 @@ func TestInvoiceAddTimeSeries(t *testing.T) { } for i, query := range addQueries { - resp, err := db.InvoicesAddedSince(query.sinceAddIndex) + resp, err := db.InvoicesAddedSince(ctxb, query.sinceAddIndex) if err != nil { t.Fatalf("unable to query: %v", err) } @@ -758,7 +770,7 @@ func TestInvoiceAddTimeSeries(t *testing.T) { } } - _, err = db.InvoicesSettledSince(0) + _, err = db.InvoicesSettledSince(ctxb, 0) require.NoError(t, err) var settledInvoices []invpkg.Invoice @@ -771,7 +783,7 @@ func TestInvoiceAddTimeSeries(t *testing.T) { ref := invpkg.InvoiceRefByHash(paymentHash) _, err := db.UpdateInvoice( - ref, nil, getUpdateInvoice(invoice.Terms.Value), + ctxb, ref, nil, getUpdateInvoice(invoice.Terms.Value), ) if err != nil { t.Fatalf("unable to settle invoice: %v", err) @@ -812,7 +824,9 @@ func TestInvoiceAddTimeSeries(t *testing.T) { } for i, query := range settleQueries { - resp, err := db.InvoicesSettledSince(query.sinceSettleIndex) + resp, err := db.InvoicesSettledSince( + ctxb, query.sinceSettleIndex, + ) if err != nil { t.Fatalf("unable to query: %v", err) } @@ -848,9 +862,10 @@ func TestSettleIndexAmpPayments(t *testing.T) { // Add the invoice to the DB, we use a dummy payment hash here but the // invoice will have a valid payment address set. + ctxb := context.Background() preimage := *testInvoice.Terms.PaymentPreimage payHash := preimage.Hash() - _, err = db.AddInvoice(testInvoice, payHash) + _, err = db.AddInvoice(ctxb, testInvoice, payHash) require.Nil(t, err) // Now that we have the invoice, we'll simulate 3 different HTLC sets @@ -864,17 +879,17 @@ func TestSettleIndexAmpPayments(t *testing.T) { payHash, testInvoice.Terms.PaymentAddr, ) _, err = db.UpdateInvoice( - ref, (*invpkg.SetID)(setID1), + ctxb, ref, (*invpkg.SetID)(setID1), updateAcceptAMPHtlc(1, amt, setID1, true), ) require.Nil(t, err) _, err = db.UpdateInvoice( - ref, (*invpkg.SetID)(setID2), + ctxb, ref, (*invpkg.SetID)(setID2), updateAcceptAMPHtlc(2, amt, setID2, true), ) require.Nil(t, err) _, err = db.UpdateInvoice( - ref, (*invpkg.SetID)(setID3), + ctxb, ref, (*invpkg.SetID)(setID3), updateAcceptAMPHtlc(3, amt, setID3, true), ) require.Nil(t, err) @@ -888,7 +903,7 @@ func TestSettleIndexAmpPayments(t *testing.T) { refNoHtlcs := invpkg.InvoiceRefByAddrBlankHtlc( testInvoice.Terms.PaymentAddr, ) - invoiceNoHTLCs, err := db.LookupInvoice(refNoHtlcs) + invoiceNoHTLCs, err := db.LookupInvoice(ctxb, refNoHtlcs) require.Nil(t, err) require.Equal(t, 0, len(invoiceNoHTLCs.Htlcs)) @@ -897,7 +912,7 @@ func TestSettleIndexAmpPayments(t *testing.T) { // above. for i, setID := range []*[32]byte{setID1, setID2, setID3} { refFiltered := invpkg.InvoiceRefBySetIDFiltered(*setID) - invoiceFiltered, err := db.LookupInvoice(refFiltered) + invoiceFiltered, err := db.LookupInvoice(ctxb, refFiltered) require.Nil(t, err) // Only a single HTLC should be present. @@ -915,21 +930,21 @@ func TestSettleIndexAmpPayments(t *testing.T) { // Now that we know the invoices are in the proper state, we'll settle // them on by one in distinct updates. _, err = db.UpdateInvoice( - ref, (*invpkg.SetID)(setID1), + ctxb, ref, (*invpkg.SetID)(setID1), getUpdateInvoiceAMPSettle( setID1, preimage, models.CircuitKey{HtlcID: 1}, ), ) require.Nil(t, err) _, err = db.UpdateInvoice( - ref, (*invpkg.SetID)(setID2), + ctxb, ref, (*invpkg.SetID)(setID2), getUpdateInvoiceAMPSettle( setID2, preimage, models.CircuitKey{HtlcID: 2}, ), ) require.Nil(t, err) _, err = db.UpdateInvoice( - ref, (*invpkg.SetID)(setID3), + ctxb, ref, (*invpkg.SetID)(setID3), getUpdateInvoiceAMPSettle( setID3, preimage, models.CircuitKey{HtlcID: 3}, ), @@ -940,14 +955,14 @@ func TestSettleIndexAmpPayments(t *testing.T) { // settle index was updated properly by obtaining all the currently // settled invoices in the time series. We use a value of 1 here to // ensure we get _all_ the invoices back. - settledInvoices, err := db.InvoicesSettledSince(1) + settledInvoices, err := db.InvoicesSettledSince(ctxb, 1) require.Nil(t, err) // To get around the settle index quirk, we'll fetch the very first // invoice in the HTLC filtered mode and append it to the set of // invoices. firstInvoice, err := db.LookupInvoice( - invpkg.InvoiceRefBySetIDFiltered(*setID1), + ctxb, invpkg.InvoiceRefBySetIDFiltered(*setID1), ) require.Nil(t, err) settledInvoices = append( @@ -982,13 +997,13 @@ func TestSettleIndexAmpPayments(t *testing.T) { // If we attempt to look up the invoice by the payment addr, with all // the HTLCs, the main invoice should have 3 HTLCs present. refWithHtlcs := invpkg.InvoiceRefByAddr(testInvoice.Terms.PaymentAddr) - invoiceWithHTLCs, err := db.LookupInvoice(refWithHtlcs) + invoiceWithHTLCs, err := db.LookupInvoice(ctxb, refWithHtlcs) require.Nil(t, err) require.Equal(t, numInvoices, len(invoiceWithHTLCs.Htlcs)) // Finally, delete the invoice. If we query again, then nothing should // be found. - err = db.DeleteInvoice([]invpkg.InvoiceDeleteRef{ + err = db.DeleteInvoice(ctxb, []invpkg.InvoiceDeleteRef{ { PayHash: payHash, PayAddr: &testInvoice.Terms.PaymentAddr, @@ -1028,8 +1043,9 @@ func TestScanInvoices(t *testing.T) { return nil } + ctxb := context.Background() // With an empty DB we expect to not scan any invoices. - require.NoError(t, db.ScanInvoices(scanFunc, reset)) + require.NoError(t, db.ScanInvoices(ctxb, scanFunc, reset)) require.Equal(t, 0, len(invoices)) require.Equal(t, 0, callCount) require.Equal(t, 1, resetCount) @@ -1046,12 +1062,12 @@ func TestScanInvoices(t *testing.T) { paymentHash := invoice.Terms.PaymentPreimage.Hash() testInvoices[paymentHash] = invoice - _, err = db.AddInvoice(invoice, paymentHash) + _, err = db.AddInvoice(ctxb, invoice, paymentHash) require.NoError(t, err) } resetCount = 0 - require.NoError(t, db.ScanInvoices(scanFunc, reset)) + require.NoError(t, db.ScanInvoices(ctxb, scanFunc, reset)) require.Equal(t, numInvoices, callCount) require.Equal(t, testInvoices, invoices) require.Equal(t, 1, resetCount) @@ -1073,13 +1089,16 @@ func TestDuplicateSettleInvoice(t *testing.T) { payHash := invoice.Terms.PaymentPreimage.Hash() - if _, err := db.AddInvoice(invoice, payHash); err != nil { + ctxb := context.Background() + if _, err := db.AddInvoice(ctxb, invoice, payHash); err != nil { t.Fatalf("unable to add invoice %v", err) } // With the invoice in the DB, we'll now attempt to settle the invoice. ref := invpkg.InvoiceRefByHash(payHash) - dbInvoice, err := db.UpdateInvoice(ref, nil, getUpdateInvoice(amt)) + dbInvoice, err := db.UpdateInvoice( + ctxb, ref, nil, getUpdateInvoice(amt), + ) require.NoError(t, err, "unable to settle invoice") // We'll update what we expect the settle invoice to be so that our @@ -1103,7 +1122,7 @@ func TestDuplicateSettleInvoice(t *testing.T) { // If we try to settle the invoice again, then we should get the very // same invoice back, but with an error this time. - dbInvoice, err = db.UpdateInvoice(ref, nil, getUpdateInvoice(amt)) + dbInvoice, err = db.UpdateInvoice(ctxb, ref, nil, getUpdateInvoice(amt)) require.ErrorIs(t, err, invpkg.ErrInvoiceAlreadySettled) if dbInvoice == nil { @@ -1132,6 +1151,7 @@ func TestQueryInvoices(t *testing.T) { var invoices []invpkg.Invoice var pendingInvoices []invpkg.Invoice + ctxb := context.Background() for i := 1; i <= numInvoices; i++ { amt := lnwire.MilliSatoshi(i) invoice, err := randInvoice(amt) @@ -1144,7 +1164,9 @@ func TestQueryInvoices(t *testing.T) { paymentHash := invoice.Terms.PaymentPreimage.Hash() - if _, err := db.AddInvoice(invoice, paymentHash); err != nil { + if _, err := db.AddInvoice( + ctxb, invoice, paymentHash, + ); err != nil { t.Fatalf("unable to add invoice: %v", err) } @@ -1152,7 +1174,7 @@ func TestQueryInvoices(t *testing.T) { if i%2 == 0 { ref := invpkg.InvoiceRefByHash(paymentHash) _, err := db.UpdateInvoice( - ref, nil, getUpdateInvoice(amt), + ctxb, ref, nil, getUpdateInvoice(amt), ) if err != nil { t.Fatalf("unable to settle invoice: %v", err) @@ -1500,7 +1522,7 @@ func TestQueryInvoices(t *testing.T) { } for i, testCase := range testCases { - response, err := db.QueryInvoices(testCase.query) + response, err := db.QueryInvoices(ctxb, testCase.query) if err != nil { t.Fatalf("unable to query invoice database: %v", err) } @@ -1566,7 +1588,8 @@ func TestCustomRecords(t *testing.T) { }, } - if _, err := db.AddInvoice(testInvoice, paymentHash); err != nil { + ctxb := context.Background() + if _, err := db.AddInvoice(ctxb, testInvoice, paymentHash); err != nil { t.Fatalf("unable to add invoice: %v", err) } @@ -1598,12 +1621,12 @@ func TestCustomRecords(t *testing.T) { }, nil } - _, err = db.UpdateInvoice(ref, nil, callback) + _, err = db.UpdateInvoice(ctxb, ref, nil, callback) require.NoError(t, err, "unable to add invoice htlc") // Retrieve the invoice from that database and verify that the custom // records are present. - dbInvoice, err := db.LookupInvoice(ref) + dbInvoice, err := db.LookupInvoice(ctxb, ref) require.NoError(t, err, "unable to lookup invoice") if len(dbInvoice.Htlcs) != 1 { @@ -1638,8 +1661,9 @@ func testInvoiceHtlcAMPFields(t *testing.T, isAMP bool) { testInvoice.Terms.Features = ampFeatures } + ctxb := context.Background() payHash := testInvoice.Terms.PaymentPreimage.Hash() - _, err = db.AddInvoice(testInvoice, payHash) + _, err = db.AddInvoice(ctxb, testInvoice, payHash) require.Nil(t, err) // Accept an htlc with custom records on this invoice. @@ -1679,12 +1703,12 @@ func testInvoiceHtlcAMPFields(t *testing.T, isAMP bool) { } ref := invpkg.InvoiceRefByHash(payHash) - _, err = db.UpdateInvoice(ref, nil, callback) + _, err = db.UpdateInvoice(ctxb, ref, nil, callback) require.Nil(t, err) // Retrieve the invoice from that database and verify that the AMP // fields are as expected. - dbInvoice, err := db.LookupInvoice(ref) + dbInvoice, err := db.LookupInvoice(ctxb, ref) require.Nil(t, err) require.Equal(t, 1, len(dbInvoice.Htlcs)) @@ -1839,7 +1863,7 @@ func TestAddInvoiceWithHTLCs(t *testing.T) { testInvoice.Htlcs[key] = &invpkg.InvoiceHTLC{} payHash := testInvoice.Terms.PaymentPreimage.Hash() - _, err = db.AddInvoice(testInvoice, payHash) + _, err = db.AddInvoice(context.Background(), testInvoice, payHash) require.Equal(t, invpkg.ErrInvoiceHasHtlcs, err) } @@ -1860,9 +1884,10 @@ func TestSetIDIndex(t *testing.T) { // preimages. invoice.Terms.Features = ampFeatures + ctxb := context.Background() preimage := *invoice.Terms.PaymentPreimage payHash := preimage.Hash() - _, err = db.AddInvoice(invoice, payHash) + _, err = db.AddInvoice(ctxb, invoice, payHash) require.Nil(t, err) setID := &[32]byte{1} @@ -1873,7 +1898,7 @@ func TestSetIDIndex(t *testing.T) { payHash, invoice.Terms.PaymentAddr, ) dbInvoice, err := db.UpdateInvoice( - ref, (*invpkg.SetID)(setID), + ctxb, ref, (*invpkg.SetID)(setID), updateAcceptAMPHtlc(0, amt, setID, true), ) require.Nil(t, err) @@ -1901,7 +1926,7 @@ func TestSetIDIndex(t *testing.T) { // Now lookup the invoice by set id and see that we get the same one. refBySetID := invpkg.InvoiceRefBySetID(*setID) - dbInvoiceBySetID, err := db.LookupInvoice(refBySetID) + dbInvoiceBySetID, err := db.LookupInvoice(ctxb, refBySetID) require.Nil(t, err) require.Equal(t, invoice, &dbInvoiceBySetID) @@ -1915,14 +1940,14 @@ func TestSetIDIndex(t *testing.T) { invoice2.Terms.Features = ampFeatures payHash2 := invoice2.Terms.PaymentPreimage.Hash() - _, err = db.AddInvoice(invoice2, payHash2) + _, err = db.AddInvoice(ctxb, invoice2, payHash2) require.Nil(t, err) ref2 := invpkg.InvoiceRefByHashAndAddr( payHash2, invoice2.Terms.PaymentAddr, ) _, err = db.UpdateInvoice( - ref2, (*invpkg.SetID)(setID), + ctxb, ref2, (*invpkg.SetID)(setID), updateAcceptAMPHtlc(0, amt, setID, true), ) require.Equal(t, invpkg.ErrDuplicateSetID{SetID: *setID}, err) @@ -1932,12 +1957,12 @@ func TestSetIDIndex(t *testing.T) { setID2 := &[32]byte{2} _, err = db.UpdateInvoice( - ref, (*invpkg.SetID)(setID2), + ctxb, ref, (*invpkg.SetID)(setID2), updateAcceptAMPHtlc(1, amt, setID2, false), ) require.Nil(t, err) dbInvoice, err = db.UpdateInvoice( - ref, (*invpkg.SetID)(setID2), + ctxb, ref, (*invpkg.SetID)(setID2), updateAcceptAMPHtlc(2, amt, setID2, false), ) require.Nil(t, err) @@ -1972,7 +1997,7 @@ func TestSetIDIndex(t *testing.T) { // Since UpdateInvoice will only return the sub-set of updated HTLcs, // we'll query again to ensure we get the full set of HTLCs returned. - freshInvoice, err := db.LookupInvoice(ref) + freshInvoice, err := db.LookupInvoice(ctxb, ref) require.Nil(t, err) dbInvoice = &freshInvoice @@ -1982,14 +2007,14 @@ func TestSetIDIndex(t *testing.T) { // Now lookup the invoice by second set id and see that we get the same // index, including the htlcs under the first set id. refBySetID = invpkg.InvoiceRefBySetID(*setID2) - dbInvoiceBySetID, err = db.LookupInvoice(refBySetID) + dbInvoiceBySetID, err = db.LookupInvoice(ctxb, refBySetID) require.Nil(t, err) require.Equal(t, invoice, &dbInvoiceBySetID) // Now attempt to settle a non-existent HTLC set, this set ID is the // zero setID so it isn't used for anything internally. _, err = db.UpdateInvoice( - ref, nil, + ctxb, ref, nil, getUpdateInvoiceAMPSettle( &[32]byte{}, [32]byte{}, models.CircuitKey{HtlcID: 99}, @@ -2001,14 +2026,14 @@ func TestSetIDIndex(t *testing.T) { // the accepted state and shouldn't be canceled, since we permit an // invoice to be settled multiple times. _, err = db.UpdateInvoice( - ref, (*invpkg.SetID)(setID), + ctxb, ref, (*invpkg.SetID)(setID), getUpdateInvoiceAMPSettle( setID, preimage, models.CircuitKey{HtlcID: 0}, ), ) require.Nil(t, err) - freshInvoice, err = db.LookupInvoice(ref) + freshInvoice, err = db.LookupInvoice(ctxb, ref) require.Nil(t, err) dbInvoice = &freshInvoice @@ -2033,7 +2058,7 @@ func TestSetIDIndex(t *testing.T) { // If we try to settle the same set ID again, then we should get an // error, as it's already been settled. _, err = db.UpdateInvoice( - ref, (*invpkg.SetID)(setID), + ctxb, ref, (*invpkg.SetID)(setID), getUpdateInvoiceAMPSettle( setID, preimage, models.CircuitKey{HtlcID: 0}, ), @@ -2045,7 +2070,7 @@ func TestSetIDIndex(t *testing.T) { // settle an invoice with a new setID after one has already been fully // settled. _, err = db.UpdateInvoice( - ref, (*invpkg.SetID)(setID2), + ctxb, ref, (*invpkg.SetID)(setID2), getUpdateInvoiceAMPSettle( setID2, preimage, models.CircuitKey{HtlcID: 1}, models.CircuitKey{HtlcID: 2}, @@ -2053,7 +2078,7 @@ func TestSetIDIndex(t *testing.T) { ) require.Nil(t, err) - freshInvoice, err = db.LookupInvoice(ref) + freshInvoice, err = db.LookupInvoice(ctxb, ref) require.Nil(t, err) dbInvoice = &freshInvoice @@ -2077,7 +2102,7 @@ func TestSetIDIndex(t *testing.T) { // Lastly, querying for an unknown set id should fail. refUnknownSetID := invpkg.InvoiceRefBySetID([32]byte{}) - _, err = db.LookupInvoice(refUnknownSetID) + _, err = db.LookupInvoice(ctxb, refUnknownSetID) require.Equal(t, invpkg.ErrInvoiceNotFound, err) } @@ -2195,16 +2220,18 @@ func TestUnexpectedInvoicePreimage(t *testing.T) { invoice, err := randInvoice(lnwire.MilliSatoshi(100)) require.NoError(t, err) + ctxb := context.Background() + // Add a random invoice indexed by payment hash and payment addr. paymentHash := invoice.Terms.PaymentPreimage.Hash() - _, err = db.AddInvoice(invoice, paymentHash) + _, err = db.AddInvoice(ctxb, invoice, paymentHash) require.NoError(t, err) // Attempt to update the invoice by pay addr only. This will fail since, // in order to settle an MPP invoice, the InvoiceRef must present a // payment hash against which to validate the preimage. _, err = db.UpdateInvoice( - invpkg.InvoiceRefByAddr(invoice.Terms.PaymentAddr), nil, + ctxb, invpkg.InvoiceRefByAddr(invoice.Terms.PaymentAddr), nil, getUpdateInvoice(invoice.Terms.Value), ) @@ -2260,7 +2287,8 @@ func testUpdateHTLCPreimages(t *testing.T, test updateHTLCPreimageTestCase) { // preimages. invoice.Terms.Features = ampFeatures - _, err = db.AddInvoice(invoice, payHash) + ctxb := context.Background() + _, err = db.AddInvoice(ctxb, invoice, payHash) require.Nil(t, err) setID := &[32]byte{1} @@ -2269,7 +2297,7 @@ func testUpdateHTLCPreimages(t *testing.T, test updateHTLCPreimageTestCase) { // invoice. ref := invpkg.InvoiceRefByAddr(invoice.Terms.PaymentAddr) dbInvoice, err := db.UpdateInvoice( - ref, (*invpkg.SetID)(setID), + ctxb, ref, (*invpkg.SetID)(setID), updateAcceptAMPHtlc(0, amt, setID, true), ) require.Nil(t, err) @@ -2305,7 +2333,9 @@ func testUpdateHTLCPreimages(t *testing.T, test updateHTLCPreimageTestCase) { } // Now settle the HTLC set and assert the resulting error. - _, err = db.UpdateInvoice(ref, (*invpkg.SetID)(setID), updateInvoice) + _, err = db.UpdateInvoice( + ctxb, ref, (*invpkg.SetID)(setID), updateInvoice, + ) require.Equal(t, test.expError, err) } @@ -2990,18 +3020,19 @@ func TestDeleteInvoices(t *testing.T) { numInvoices := 3 invoicesToDelete := make([]invpkg.InvoiceDeleteRef, numInvoices) + ctxb := context.Background() for i := 0; i < numInvoices; i++ { invoice, err := randInvoice(lnwire.MilliSatoshi(i + 1)) require.NoError(t, err) paymentHash := invoice.Terms.PaymentPreimage.Hash() - addIndex, err := db.AddInvoice(invoice, paymentHash) + addIndex, err := db.AddInvoice(ctxb, invoice, paymentHash) require.NoError(t, err) // Settle the second invoice. if i == 1 { invoice, err = db.UpdateInvoice( - invpkg.InvoiceRefByHash(paymentHash), nil, + ctxb, invpkg.InvoiceRefByHash(paymentHash), nil, getUpdateInvoice(invoice.Terms.Value), ) require.NoError(t, err, "unable to settle invoice") @@ -3026,14 +3057,14 @@ func TestDeleteInvoices(t *testing.T) { } // Check that we really have 3 invoices. - response, err := db.QueryInvoices(query) + response, err := db.QueryInvoices(ctxb, query) require.NoError(t, err) require.Equal(t, count, len(response.Invoices)) } // XOR one byte of one of the references' hash and attempt to delete. invoicesToDelete[0].PayHash[2] ^= 3 - require.Error(t, db.DeleteInvoice(invoicesToDelete)) + require.Error(t, db.DeleteInvoice(ctxb, invoicesToDelete)) assertInvoiceCount(3) // Restore the hash. @@ -3042,7 +3073,7 @@ func TestDeleteInvoices(t *testing.T) { // XOR the second invoice's payment settle index as it is settled, and // attempt to delete. invoicesToDelete[1].SettleIndex ^= 11 - require.Error(t, db.DeleteInvoice(invoicesToDelete)) + require.Error(t, db.DeleteInvoice(ctxb, invoicesToDelete)) assertInvoiceCount(3) // Restore the settle index. @@ -3050,14 +3081,14 @@ func TestDeleteInvoices(t *testing.T) { // XOR the add index for one of the references and attempt to delete. invoicesToDelete[2].AddIndex ^= 13 - require.Error(t, db.DeleteInvoice(invoicesToDelete)) + require.Error(t, db.DeleteInvoice(ctxb, invoicesToDelete)) assertInvoiceCount(3) // Restore the add index. invoicesToDelete[2].AddIndex ^= 13 // Delete should succeed with all the valid references. - require.NoError(t, db.DeleteInvoice(invoicesToDelete)) + require.NoError(t, db.DeleteInvoice(ctxb, invoicesToDelete)) assertInvoiceCount(0) } @@ -3081,7 +3112,7 @@ func TestAddInvoiceInvalidFeatureDeps(t *testing.T) { ) hash := invoice.Terms.PaymentPreimage.Hash() - _, err = db.AddInvoice(invoice, hash) + _, err = db.AddInvoice(context.Background(), invoice, hash) require.Error(t, err, feature.NewErrMissingFeatureDep( lnwire.PaymentAddrOptional, )) diff --git a/channeldb/invoices.go b/channeldb/invoices.go index 1567c41837..d7016ff334 100644 --- a/channeldb/invoices.go +++ b/channeldb/invoices.go @@ -2,6 +2,7 @@ package channeldb import ( "bytes" + "context" "encoding/binary" "errors" "fmt" @@ -140,8 +141,8 @@ const ( // insertion will be aborted and rejected due to the strict policy banning any // duplicate payment hashes. A side effect of this function is that it sets // AddIndex on newInvoice. -func (d *DB) AddInvoice(newInvoice *invpkg.Invoice, paymentHash lntypes.Hash) ( - uint64, error) { +func (d *DB) AddInvoice(_ context.Context, newInvoice *invpkg.Invoice, + paymentHash lntypes.Hash) (uint64, error) { if err := invpkg.ValidateInvoice(newInvoice, paymentHash); err != nil { return 0, err @@ -229,8 +230,8 @@ func (d *DB) AddInvoice(newInvoice *invpkg.Invoice, paymentHash lntypes.Hash) ( // // NOTE: The index starts from 1, as a result. We enforce that specifying a // value below the starting index value is a noop. -func (d *DB) InvoicesAddedSince(sinceAddIndex uint64) ([]invpkg.Invoice, - error) { +func (d *DB) InvoicesAddedSince(_ context.Context, sinceAddIndex uint64) ( + []invpkg.Invoice, error) { var newInvoices []invpkg.Invoice @@ -293,7 +294,9 @@ func (d *DB) InvoicesAddedSince(sinceAddIndex uint64) ([]invpkg.Invoice, // full invoice is returned. Before setting the incoming HTLC, the values // SHOULD be checked to ensure the payer meets the agreed upon contractual // terms of the payment. -func (d *DB) LookupInvoice(ref invpkg.InvoiceRef) (invpkg.Invoice, error) { +func (d *DB) LookupInvoice(_ context.Context, ref invpkg.InvoiceRef) ( + invpkg.Invoice, error) { + var invoice invpkg.Invoice err := kvdb.View(d, func(tx kvdb.RTx) error { invoices := tx.ReadBucket(invoiceBucket) @@ -434,7 +437,9 @@ func fetchInvoiceNumByRef(invoiceIndex, payAddrIndex, setIDIndex kvdb.RBucket, // for each invoice with its respective payment hash. Additionally a reset() // closure is passed which is used to reset/initialize partial results and also // to signal if the kvdb.View transaction has been retried. -func (d *DB) ScanInvoices(scanFunc invpkg.InvScanFunc, reset func()) error { +func (d *DB) ScanInvoices(_ context.Context, scanFunc invpkg.InvScanFunc, + reset func()) error { + return kvdb.View(d, func(tx kvdb.RTx) error { invoices := tx.ReadBucket(invoiceBucket) if invoices == nil { @@ -477,8 +482,8 @@ func (d *DB) ScanInvoices(scanFunc invpkg.InvScanFunc, reset func()) error { // QueryInvoices allows a caller to query the invoice database for invoices // within the specified add index range. -func (d *DB) QueryInvoices(q invpkg.InvoiceQuery) (invpkg.InvoiceSlice, - error) { +func (d *DB) QueryInvoices(_ context.Context, q invpkg.InvoiceQuery) ( + invpkg.InvoiceSlice, error) { var ( resp invpkg.InvoiceSlice @@ -594,8 +599,9 @@ func (d *DB) QueryInvoices(q invpkg.InvoiceQuery) (invpkg.InvoiceSlice, // The update is performed inside the same database transaction that fetches the // invoice and is therefore atomic. The fields to update are controlled by the // supplied callback. -func (d *DB) UpdateInvoice(ref invpkg.InvoiceRef, setIDHint *invpkg.SetID, - callback invpkg.InvoiceUpdateCallback) (*invpkg.Invoice, error) { +func (d *DB) UpdateInvoice(_ context.Context, ref invpkg.InvoiceRef, + setIDHint *invpkg.SetID, callback invpkg.InvoiceUpdateCallback) ( + *invpkg.Invoice, error) { var updatedInvoice *invpkg.Invoice err := kvdb.Update(d, func(tx kvdb.RwTx) error { @@ -648,8 +654,8 @@ func (d *DB) UpdateInvoice(ref invpkg.InvoiceRef, setIDHint *invpkg.SetID, // // NOTE: The index starts from 1, as a result. We enforce that specifying a // value below the starting index value is a noop. -func (d *DB) InvoicesSettledSince(sinceSettleIndex uint64) ([]invpkg.Invoice, - error) { +func (d *DB) InvoicesSettledSince(_ context.Context, sinceSettleIndex uint64) ( + []invpkg.Invoice, error) { var settledInvoices []invpkg.Invoice @@ -2699,7 +2705,9 @@ func delAMPSettleIndex(invoiceNum []byte, invoices, // DeleteInvoice attempts to delete the passed invoices from the database in // one transaction. The passed delete references hold all keys required to // delete the invoices without also needing to deserialze them. -func (d *DB) DeleteInvoice(invoicesToDelete []invpkg.InvoiceDeleteRef) error { +func (d *DB) DeleteInvoice(_ context.Context, + invoicesToDelete []invpkg.InvoiceDeleteRef) error { + err := kvdb.Update(d, func(tx kvdb.RwTx) error { invoices := tx.ReadWriteBucket(invoiceBucket) if invoices == nil { diff --git a/contractcourt/channel_arbitrator.go b/contractcourt/channel_arbitrator.go index e1cbb11730..86653c675b 100644 --- a/contractcourt/channel_arbitrator.go +++ b/contractcourt/channel_arbitrator.go @@ -2,6 +2,7 @@ package contractcourt import ( "bytes" + "context" "errors" "fmt" "math" @@ -1885,7 +1886,7 @@ func (c *ChannelArbitrator) isPreimageAvailable(hash lntypes.Hash) (bool, // than the invoice cltv delta. We don't want to go to chain only to // have the incoming contest resolver decide that we don't want to // settle this invoice. - invoice, err := c.cfg.Registry.LookupInvoice(hash) + invoice, err := c.cfg.Registry.LookupInvoice(context.Background(), hash) switch err { case nil: case invoices.ErrInvoiceNotFound, invoices.ErrNoInvoicesCreated: diff --git a/contractcourt/interfaces.go b/contractcourt/interfaces.go index 49e1f913aa..45cd75735a 100644 --- a/contractcourt/interfaces.go +++ b/contractcourt/interfaces.go @@ -1,6 +1,7 @@ package contractcourt import ( + "context" "io" "github.com/btcsuite/btcd/wire" @@ -19,7 +20,7 @@ import ( type Registry interface { // LookupInvoice attempts to look up an invoice according to its 32 // byte payment hash. - LookupInvoice(lntypes.Hash) (invoices.Invoice, error) + LookupInvoice(context.Context, lntypes.Hash) (invoices.Invoice, error) // NotifyExitHopHtlc attempts to mark an invoice as settled. If the // invoice is a debug invoice, then this method is a noop as debug diff --git a/contractcourt/mock_registry_test.go b/contractcourt/mock_registry_test.go index 19105a77e9..7acac67ec5 100644 --- a/contractcourt/mock_registry_test.go +++ b/contractcourt/mock_registry_test.go @@ -1,6 +1,8 @@ package contractcourt import ( + "context" + "github.com/lightningnetwork/lnd/channeldb/models" "github.com/lightningnetwork/lnd/invoices" "github.com/lightningnetwork/lnd/lntypes" @@ -39,8 +41,8 @@ func (r *mockRegistry) NotifyExitHopHtlc(payHash lntypes.Hash, func (r *mockRegistry) HodlUnsubscribeAll(subscriber chan<- interface{}) {} -func (r *mockRegistry) LookupInvoice(lntypes.Hash) (invoices.Invoice, - error) { +func (r *mockRegistry) LookupInvoice(context.Context, lntypes.Hash) ( + invoices.Invoice, error) { return invoices.Invoice{}, invoices.ErrInvoiceNotFound } diff --git a/htlcswitch/interfaces.go b/htlcswitch/interfaces.go index 304f4a5957..1ce4ffb2e5 100644 --- a/htlcswitch/interfaces.go +++ b/htlcswitch/interfaces.go @@ -1,6 +1,8 @@ package htlcswitch import ( + "context" + "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb/models" @@ -17,7 +19,7 @@ import ( type InvoiceDatabase interface { // LookupInvoice attempts to look up an invoice according to its 32 // byte payment hash. - LookupInvoice(lntypes.Hash) (invoices.Invoice, error) + LookupInvoice(context.Context, lntypes.Hash) (invoices.Invoice, error) // NotifyExitHopHtlc attempts to mark an invoice as settled. If the // invoice is a debug invoice, then this method is a noop as debug @@ -33,10 +35,10 @@ type InvoiceDatabase interface { // CancelInvoice attempts to cancel the invoice corresponding to the // passed payment hash. - CancelInvoice(payHash lntypes.Hash) error + CancelInvoice(ctx context.Context, payHash lntypes.Hash) error // SettleHodlInvoice settles a hold invoice. - SettleHodlInvoice(preimage lntypes.Preimage) error + SettleHodlInvoice(ctx context.Context, preimage lntypes.Preimage) error // HodlUnsubscribeAll unsubscribes from all htlc resolutions. HodlUnsubscribeAll(subscriber chan<- interface{}) diff --git a/htlcswitch/link_test.go b/htlcswitch/link_test.go index 37e306559d..9c07cd53c1 100644 --- a/htlcswitch/link_test.go +++ b/htlcswitch/link_test.go @@ -2,6 +2,7 @@ package htlcswitch import ( "bytes" + "context" "crypto/rand" "crypto/sha256" "encoding/binary" @@ -483,7 +484,9 @@ func TestChannelLinkSingleHopPayment(t *testing.T) { // Check that alice invoice was settled and bandwidth of HTLC // links was changed. - invoice, err := receiver.registry.LookupInvoice(rhash) + invoice, err := receiver.registry.LookupInvoice( + context.Background(), rhash, + ) require.NoError(t, err, "unable to get invoice") if invoice.State != invpkg.ContractSettled { t.Fatal("alice invoice wasn't settled") @@ -601,7 +604,9 @@ func testChannelLinkMultiHopPayment(t *testing.T, // Check that Carol invoice was settled and bandwidth of HTLC // links were changed. - invoice, err := receiver.registry.LookupInvoice(rhash) + invoice, err := receiver.registry.LookupInvoice( + context.Background(), rhash, + ) require.NoError(t, err, "unable to get invoice") if invoice.State != invpkg.ContractSettled { t.Fatal("carol invoice haven't been settled") @@ -710,7 +715,9 @@ func TestChannelLinkCancelFullCommitment(t *testing.T) { // invoice registry at this point, so we poll until we are able // to settle. err = wait.NoError(func() error { - return n.bobServer.registry.SettleHodlInvoice(preimage) + return n.bobServer.registry.SettleHodlInvoice( + context.Background(), preimage, + ) }, time.Minute) if err != nil { t.Fatal(err) @@ -1177,7 +1184,9 @@ func TestUpdateForwardingPolicy(t *testing.T) { // Carol's invoice should now be shown as settled as the payment // succeeded. - invoice, err := n.carolServer.registry.LookupInvoice(payResp) + invoice, err := n.carolServer.registry.LookupInvoice( + context.Background(), payResp, + ) require.NoError(t, err, "unable to get invoice") if invoice.State != invpkg.ContractSettled { t.Fatal("carol invoice haven't been settled") @@ -1331,7 +1340,9 @@ func TestChannelLinkMultiHopInsufficientPayment(t *testing.T) { // Check that alice invoice wasn't settled and bandwidth of htlc // links hasn't been changed. - invoice, err := receiver.registry.LookupInvoice(rhash) + invoice, err := receiver.registry.LookupInvoice( + context.Background(), rhash, + ) require.NoError(t, err, "unable to get invoice") if invoice.State == invpkg.ContractSettled { t.Fatal("carol invoice have been settled") @@ -1509,7 +1520,9 @@ func TestChannelLinkMultiHopUnknownNextHop(t *testing.T) { // Check that alice invoice wasn't settled and bandwidth of htlc // links hasn't been changed. - invoice, err := receiver.registry.LookupInvoice(rhash) + invoice, err := receiver.registry.LookupInvoice( + context.Background(), rhash, + ) require.NoError(t, err, "unable to get invoice") if invoice.State == invpkg.ContractSettled { t.Fatal("carol invoice have been settled") @@ -1617,7 +1630,9 @@ func TestChannelLinkMultiHopDecodeError(t *testing.T) { // Check that alice invoice wasn't settled and bandwidth of htlc // links hasn't been changed. - invoice, err := receiver.registry.LookupInvoice(rhash) + invoice, err := receiver.registry.LookupInvoice( + context.Background(), rhash, + ) require.NoError(t, err, "unable to get invoice") if invoice.State == invpkg.ContractSettled { t.Fatal("carol invoice have been settled") @@ -2406,10 +2421,11 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) { ) require.NoError(t, err, "unable to create payment") + ctxb := context.Background() // We must add the invoice to the registry, such that Alice expects // this payment. err = coreLink.cfg.Registry.(*mockInvoiceRegistry).AddInvoice( - *invoice, htlc.PaymentHash, + ctxb, *invoice, htlc.PaymentHash, ) require.NoError(t, err, "unable to add invoice to registry") @@ -2501,7 +2517,7 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) { ) require.NoError(t, err, "unable to create payment") err = coreLink.cfg.Registry.(*mockInvoiceRegistry).AddInvoice( - *invoice, htlc.PaymentHash, + ctxb, *invoice, htlc.PaymentHash, ) require.NoError(t, err, "unable to add invoice to registry") @@ -3625,7 +3641,9 @@ func TestChannelRetransmission(t *testing.T) { // Check that alice invoice wasn't settled and // bandwidth of htlc links hasn't been changed. - invoice, err = receiver.registry.LookupInvoice(rhash) + invoice, err = receiver.registry.LookupInvoice( + context.Background(), rhash, + ) if err != nil { err = fmt.Errorf( "unable to get invoice: %w", err, @@ -4098,7 +4116,9 @@ func TestChannelLinkAcceptDuplicatePayment(t *testing.T) { t.Fatal(err) } - err = n.carolServer.registry.AddInvoice(*invoice, htlc.PaymentHash) + err = n.carolServer.registry.AddInvoice( + context.Background(), *invoice, htlc.PaymentHash, + ) require.NoError(t, err, "unable to add invoice in carol registry") // With the invoice now added to Carol's registry, we'll send the @@ -4186,7 +4206,9 @@ func TestChannelLinkAcceptOverpay(t *testing.T) { // Even though we sent 2x what was asked for, Carol should still have // accepted the payment and marked it as settled. - invoice, err := receiver.registry.LookupInvoice(rhash) + invoice, err := receiver.registry.LookupInvoice( + context.Background(), rhash, + ) require.NoError(t, err, "unable to get invoice") if invoice.State != invpkg.ContractSettled { t.Fatal("carol invoice haven't been settled") @@ -4503,7 +4525,7 @@ func generateHtlc(t *testing.T, coreLink *channelLink, // We must add the invoice to the registry, such that Alice // expects this payment. err := coreLink.cfg.Registry.(*mockInvoiceRegistry).AddInvoice( - *invoice, htlc.PaymentHash, + context.Background(), *invoice, htlc.PaymentHash, ) require.NoError(t, err, "unable to add invoice to registry") @@ -5847,7 +5869,7 @@ func TestChannelLinkCanceledInvoice(t *testing.T) { // Cancel the invoice at bob's end. hash := invoice.Terms.PaymentPreimage.Hash() - err = n.bobServer.registry.CancelInvoice(hash) + err = n.bobServer.registry.CancelInvoice(context.Background(), hash) if err != nil { t.Fatal(err) } @@ -5964,7 +5986,9 @@ func TestChannelLinkHoldInvoiceSettle(t *testing.T) { t.Fatal(err) } - err = ctx.n.bobServer.registry.SettleHodlInvoice(ctx.preimage) + err = ctx.n.bobServer.registry.SettleHodlInvoice( + context.Background(), ctx.preimage, + ) if err != nil { t.Fatal(err) } @@ -6008,7 +6032,9 @@ func TestChannelLinkHoldInvoiceCancel(t *testing.T) { t.Fatal(err) } - err = ctx.n.bobServer.registry.CancelInvoice(ctx.hash) + err = ctx.n.bobServer.registry.CancelInvoice( + context.Background(), ctx.hash, + ) if err != nil { t.Fatal(err) } @@ -6062,7 +6088,7 @@ func TestChannelLinkHoldInvoiceRestart(t *testing.T) { // We must add the invoice to the registry, such that Alice // expects this payment. err = registry.AddInvoice( - *invoice, htlc.PaymentHash, + context.Background(), *invoice, htlc.PaymentHash, ) require.NoError(t, err, "unable to add invoice to registry") @@ -6097,7 +6123,7 @@ func TestChannelLinkHoldInvoiceRestart(t *testing.T) { <-registry.settleChan // Settle the invoice with the preimage. - err = registry.SettleHodlInvoice(*preimage) + err = registry.SettleHodlInvoice(context.Background(), *preimage) require.NoError(t, err, "settle hodl invoice") // Expect alice to send a settle and commitsig message to bob. @@ -6154,11 +6180,12 @@ func TestChannelLinkRevocationWindowRegular(t *testing.T) { htlc1, invoice1 := generateHtlcAndInvoice(t, 0) htlc2, invoice2 := generateHtlcAndInvoice(t, 1) + ctxb := context.Background() // We must add the invoice to the registry, such that Alice // expects this payment. - err = registry.AddInvoice(*invoice1, htlc1.PaymentHash) + err = registry.AddInvoice(ctxb, *invoice1, htlc1.PaymentHash) require.NoError(t, err, "unable to add invoice to registry") - err = registry.AddInvoice(*invoice2, htlc2.PaymentHash) + err = registry.AddInvoice(ctxb, *invoice2, htlc2.PaymentHash) require.NoError(t, err, "unable to add invoice to registry") // Lock in htlc 1 on both sides. @@ -6238,11 +6265,12 @@ func TestChannelLinkRevocationWindowHodl(t *testing.T) { invoice2.Terms.PaymentPreimage = nil invoice2.HodlInvoice = true + ctxb := context.Background() // We must add the invoices to the registry, such that Alice // expects the payments. - err = registry.AddInvoice(*invoice1, htlc1.PaymentHash) + err = registry.AddInvoice(ctxb, *invoice1, htlc1.PaymentHash) require.NoError(t, err, "unable to add invoice to registry") - err = registry.AddInvoice(*invoice2, htlc2.PaymentHash) + err = registry.AddInvoice(ctxb, *invoice2, htlc2.PaymentHash) require.NoError(t, err, "unable to add invoice to registry") ctx := linkTestContext{ @@ -6281,7 +6309,7 @@ func TestChannelLinkRevocationWindowHodl(t *testing.T) { } // Settle invoice 1 with the preimage. - err = registry.SettleHodlInvoice(*preimage1) + err = registry.SettleHodlInvoice(ctxb, *preimage1) require.NoError(t, err, "settle hodl invoice") // Expect alice to send a settle and commitsig message to bob. Bob does @@ -6290,7 +6318,7 @@ func TestChannelLinkRevocationWindowHodl(t *testing.T) { ctx.receiveCommitSigAliceToBob(1) // Settle invoice 2 with the preimage. - err = registry.SettleHodlInvoice(*preimage2) + err = registry.SettleHodlInvoice(ctxb, *preimage2) require.NoError(t, err, "settle hodl invoice") // Expect alice to send a settle for htlc 2. @@ -6634,7 +6662,9 @@ func TestPipelineSettle(t *testing.T) { // Add the invoice to Alice's registry so she expects it. aliceReg := alice.coreLink.cfg.Registry.(*mockInvoiceRegistry) - err = aliceReg.AddInvoice(*invoice1, htlc1.PaymentHash) + err = aliceReg.AddInvoice( + context.Background(), *invoice1, htlc1.PaymentHash, + ) require.NoError(t, err) // <---add----- diff --git a/htlcswitch/mock.go b/htlcswitch/mock.go index fe593c9c52..9b0453dea9 100644 --- a/htlcswitch/mock.go +++ b/htlcswitch/mock.go @@ -2,6 +2,7 @@ package htlcswitch import ( "bytes" + "context" "crypto/sha256" "encoding/binary" "fmt" @@ -979,16 +980,16 @@ func newMockRegistry(minDelta uint32) *mockInvoiceRegistry { } } -func (i *mockInvoiceRegistry) LookupInvoice(rHash lntypes.Hash) ( - invoices.Invoice, error) { +func (i *mockInvoiceRegistry) LookupInvoice(ctx context.Context, + rHash lntypes.Hash) (invoices.Invoice, error) { - return i.registry.LookupInvoice(rHash) + return i.registry.LookupInvoice(ctx, rHash) } func (i *mockInvoiceRegistry) SettleHodlInvoice( - preimage lntypes.Preimage) error { + ctx context.Context, preimage lntypes.Preimage) error { - return i.registry.SettleHodlInvoice(preimage) + return i.registry.SettleHodlInvoice(ctx, preimage) } func (i *mockInvoiceRegistry) NotifyExitHopHtlc(rhash lntypes.Hash, @@ -1010,14 +1011,16 @@ func (i *mockInvoiceRegistry) NotifyExitHopHtlc(rhash lntypes.Hash, return event, nil } -func (i *mockInvoiceRegistry) CancelInvoice(payHash lntypes.Hash) error { - return i.registry.CancelInvoice(payHash) +func (i *mockInvoiceRegistry) CancelInvoice(ctx context.Context, + payHash lntypes.Hash) error { + + return i.registry.CancelInvoice(ctx, payHash) } -func (i *mockInvoiceRegistry) AddInvoice(invoice invoices.Invoice, - paymentHash lntypes.Hash) error { +func (i *mockInvoiceRegistry) AddInvoice(ctx context.Context, + invoice invoices.Invoice, paymentHash lntypes.Hash) error { - _, err := i.registry.AddInvoice(&invoice, paymentHash) + _, err := i.registry.AddInvoice(ctx, &invoice, paymentHash) return err } diff --git a/htlcswitch/switch_test.go b/htlcswitch/switch_test.go index 28f3d9e2c8..2d507f01b9 100644 --- a/htlcswitch/switch_test.go +++ b/htlcswitch/switch_test.go @@ -1,6 +1,7 @@ package htlcswitch import ( + "context" "crypto/rand" "crypto/sha256" "fmt" @@ -3564,7 +3565,9 @@ func (n *threeHopNetwork) sendThreeHopPayment(t *testing.T) (*lnwire.UpdateAddHT t.Fatal(err) } - err = n.carolServer.registry.AddInvoice(*invoice, htlc.PaymentHash) + err = n.carolServer.registry.AddInvoice( + context.Background(), *invoice, htlc.PaymentHash, + ) require.NoError(t, err, "unable to add invoice in carol registry") if err := n.aliceServer.htlcSwitch.SendHTLC( diff --git a/htlcswitch/test_utils.go b/htlcswitch/test_utils.go index 649570d2cd..da36e214cd 100644 --- a/htlcswitch/test_utils.go +++ b/htlcswitch/test_utils.go @@ -2,6 +2,7 @@ package htlcswitch import ( "bytes" + "context" crand "crypto/rand" "crypto/sha256" "encoding/binary" @@ -780,7 +781,9 @@ func preparePayment(sendingPeer, receivingPeer lnpeer.Peer, // Check who is last in the route and add invoice to server registry. hash := invoice.Terms.PaymentPreimage.Hash() - if err := receiver.registry.AddInvoice(*invoice, hash); err != nil { + if err := receiver.registry.AddInvoice( + context.Background(), *invoice, hash, + ); err != nil { return nil, nil, err } @@ -1338,7 +1341,9 @@ func (n *twoHopNetwork) makeHoldPayment(sendingPeer, receivingPeer lnpeer.Peer, } // Check who is last in the route and add invoice to server registry. - if err := receiver.registry.AddInvoice(*invoice, rhash); err != nil { + if err := receiver.registry.AddInvoice( + context.Background(), *invoice, rhash, + ); err != nil { paymentErr <- err return paymentErr } diff --git a/invoices/interface.go b/invoices/interface.go index f717afd4e7..36bc0ea480 100644 --- a/invoices/interface.go +++ b/invoices/interface.go @@ -1,6 +1,7 @@ package invoices import ( + "context" "time" "github.com/lightningnetwork/lnd/channeldb/models" @@ -21,7 +22,8 @@ type InvoiceDB interface { // // NOTE: A side effect of this function is that it sets AddIndex on // newInvoice. - AddInvoice(invoice *Invoice, paymentHash lntypes.Hash) (uint64, error) + AddInvoice(ctx context.Context, invoice *Invoice, + paymentHash lntypes.Hash) (uint64, error) // InvoicesAddedSince can be used by callers to seek into the event // time series of all the invoices added in the database. The specified @@ -31,7 +33,8 @@ type InvoiceDB interface { // // NOTE: The index starts from 1, as a result. We enforce that // specifying a value below the starting index value is a noop. - InvoicesAddedSince(sinceAddIndex uint64) ([]Invoice, error) + InvoicesAddedSince(ctx context.Context, sinceAddIndex uint64) ( + []Invoice, error) // LookupInvoice attempts to look up an invoice according to its 32 byte // payment hash. If an invoice which can settle the HTLC identified by @@ -40,7 +43,7 @@ type InvoiceDB interface { // Before setting the incoming HTLC, the values SHOULD be checked to // ensure the payer meets the agreed upon contractual terms of the // payment. - LookupInvoice(ref InvoiceRef) (Invoice, error) + LookupInvoice(ctx context.Context, ref InvoiceRef) (Invoice, error) // ScanInvoices scans through all invoices and calls the passed scanFunc // for each invoice with its respective payment hash. Additionally a @@ -50,11 +53,12 @@ type InvoiceDB interface { // // TODO(positiveblue): abstract this functionality so it makes sense for // other backends like sql. - ScanInvoices(scanFunc InvScanFunc, reset func()) error + ScanInvoices(ctx context.Context, scanFunc InvScanFunc, + reset func()) error // QueryInvoices allows a caller to query the invoice database for // invoices within the specified add index range. - QueryInvoices(q InvoiceQuery) (InvoiceSlice, error) + QueryInvoices(ctx context.Context, q InvoiceQuery) (InvoiceSlice, error) // UpdateInvoice attempts to update an invoice corresponding to the // passed payment hash. If an invoice matching the passed payment hash @@ -67,7 +71,7 @@ type InvoiceDB interface { // // TODO(positiveblue): abstract this functionality so it makes sense for // other backends like sql. - UpdateInvoice(ref InvoiceRef, setIDHint *SetID, + UpdateInvoice(ctx context.Context, ref InvoiceRef, setIDHint *SetID, callback InvoiceUpdateCallback) (*Invoice, error) // InvoicesSettledSince can be used by callers to catch up any settled @@ -77,13 +81,15 @@ type InvoiceDB interface { // // NOTE: The index starts from 1, as a result. We enforce that // specifying a value below the starting index value is a noop. - InvoicesSettledSince(sinceSettleIndex uint64) ([]Invoice, error) + InvoicesSettledSince(ctx context.Context, sinceSettleIndex uint64) ( + []Invoice, error) // DeleteInvoice attempts to delete the passed invoices from the // database in one transaction. The passed delete references hold all // keys required to delete the invoices without also needing to // deserialze them. - DeleteInvoice(invoicesToDelete []InvoiceDeleteRef) error + DeleteInvoice(ctx context.Context, + invoicesToDelete []InvoiceDeleteRef) error } // Payload abstracts access to any additional fields provided in the final hop's diff --git a/invoices/invoiceregistry.go b/invoices/invoiceregistry.go index a9a5e3831f..e58ad4cdbe 100644 --- a/invoices/invoiceregistry.go +++ b/invoices/invoiceregistry.go @@ -1,6 +1,7 @@ package invoices import ( + "context" "errors" "fmt" "sync" @@ -179,7 +180,7 @@ func NewRegistry(idb InvoiceDB, expiryWatcher *InvoiceExpiryWatcher, // scanInvoicesOnStart will scan all invoices on start and add active invoices // to the invoice expiry watcher while also attempting to delete all canceled // invoices. -func (i *InvoiceRegistry) scanInvoicesOnStart() error { +func (i *InvoiceRegistry) scanInvoicesOnStart(ctx context.Context) error { var ( pending []invoiceExpiry removable []InvoiceDeleteRef @@ -225,7 +226,7 @@ func (i *InvoiceRegistry) scanInvoicesOnStart() error { return nil } - err := i.idb.ScanInvoices(scanFunc, reset) + err := i.idb.ScanInvoices(ctx, scanFunc, reset) if err != nil { return err } @@ -237,7 +238,7 @@ func (i *InvoiceRegistry) scanInvoicesOnStart() error { if len(removable) > 0 { log.Infof("Attempting to delete %v canceled invoices", len(removable)) - if err := i.idb.DeleteInvoice(removable); err != nil { + if err := i.idb.DeleteInvoice(ctx, removable); err != nil { log.Warnf("Deleting canceled invoices failed: %v", err) } else { log.Infof("Deleted %v canceled invoices", @@ -252,7 +253,9 @@ func (i *InvoiceRegistry) scanInvoicesOnStart() error { func (i *InvoiceRegistry) Start() error { // Start InvoiceExpiryWatcher and prepopulate it with existing active // invoices. - err := i.expiryWatcher.Start(i.cancelInvoiceImpl) + err := i.expiryWatcher.Start(func(hash lntypes.Hash, force bool) error { + return i.cancelInvoiceImpl(context.Background(), hash, force) + }) if err != nil { return err } @@ -264,7 +267,7 @@ func (i *InvoiceRegistry) Start() error { // Now scan all pending and removable invoices to the expiry watcher or // delete them. - err = i.scanInvoicesOnStart() + err = i.scanInvoicesOnStart(context.Background()) if err != nil { _ = i.Stop() return err @@ -484,15 +487,15 @@ func (i *InvoiceRegistry) dispatchToClients(event *invoiceEvent) { // deliverBacklogEvents will attempts to query the invoice database for any // notifications that the client has missed since it reconnected last. -func (i *InvoiceRegistry) deliverBacklogEvents( +func (i *InvoiceRegistry) deliverBacklogEvents(ctx context.Context, client *InvoiceSubscription) error { - addEvents, err := i.idb.InvoicesAddedSince(client.addIndex) + addEvents, err := i.idb.InvoicesAddedSince(ctx, client.addIndex) if err != nil { return err } - settleEvents, err := i.idb.InvoicesSettledSince(client.settleIndex) + settleEvents, err := i.idb.InvoicesSettledSince(ctx, client.settleIndex) if err != nil { return err } @@ -536,10 +539,10 @@ func (i *InvoiceRegistry) deliverBacklogEvents( // invoice subscribers will always receive the current state right after // subscribing. Only in case the invoice does not yet exist, nothing is sent // yet. -func (i *InvoiceRegistry) deliverSingleBacklogEvents( +func (i *InvoiceRegistry) deliverSingleBacklogEvents(ctx context.Context, client *SingleInvoiceSubscription) error { - invoice, err := i.idb.LookupInvoice(client.invoiceRef) + invoice, err := i.idb.LookupInvoice(ctx, client.invoiceRef) // It is possible that the invoice does not exist yet, but the client is // already watching it in anticipation. @@ -579,7 +582,7 @@ func (i *InvoiceRegistry) deliverSingleBacklogEvents( // addIndex of the newly created invoice which monotonically increases for each // new invoice added. A side effect of this function is that it also sets // AddIndex on the invoice argument. -func (i *InvoiceRegistry) AddInvoice(invoice *Invoice, +func (i *InvoiceRegistry) AddInvoice(ctx context.Context, invoice *Invoice, paymentHash lntypes.Hash) (uint64, error) { i.Lock() @@ -587,7 +590,7 @@ func (i *InvoiceRegistry) AddInvoice(invoice *Invoice, ref := InvoiceRefByHash(paymentHash) log.Debugf("Invoice%v: added with terms %v", ref, invoice.Terms) - addIndex, err := i.idb.AddInvoice(invoice, paymentHash) + addIndex, err := i.idb.AddInvoice(ctx, invoice, paymentHash) if err != nil { i.Unlock() return 0, err @@ -613,17 +616,21 @@ func (i *InvoiceRegistry) AddInvoice(invoice *Invoice, // then we're able to pull the funds pending within an HTLC. // // TODO(roasbeef): ignore if settled? -func (i *InvoiceRegistry) LookupInvoice(rHash lntypes.Hash) (Invoice, error) { +func (i *InvoiceRegistry) LookupInvoice(ctx context.Context, + rHash lntypes.Hash) (Invoice, error) { + // We'll check the database to see if there's an existing matching // invoice. ref := InvoiceRefByHash(rHash) - return i.idb.LookupInvoice(ref) + return i.idb.LookupInvoice(ctx, ref) } // LookupInvoiceByRef looks up an invoice by the given reference, if found // then we're able to pull the funds pending within an HTLC. -func (i *InvoiceRegistry) LookupInvoiceByRef(ref InvoiceRef) (Invoice, error) { - return i.idb.LookupInvoice(ref) +func (i *InvoiceRegistry) LookupInvoiceByRef(ctx context.Context, + ref InvoiceRef) (Invoice, error) { + + return i.idb.LookupInvoice(ctx, ref) } // startHtlcTimer starts a new timer via the invoice registry main loop that @@ -723,7 +730,8 @@ func (i *InvoiceRegistry) cancelSingleHtlc(invoiceRef InvoiceRef, // no invoice update is performed, we can return early. setID := (*SetID)(invoiceRef.SetID()) var updated bool - invoice, err := i.idb.UpdateInvoice(invoiceRef, setID, + invoice, err := i.idb.UpdateInvoice( + context.Background(), invoiceRef, setID, func(invoice *Invoice) ( *InvoiceUpdateDesc, error) { @@ -830,7 +838,7 @@ func (i *InvoiceRegistry) processKeySend(ctx invoiceUpdateCtx) error { // Insert invoice into database. Ignore duplicates, because this // may be a replay. - _, err = i.AddInvoice(invoice, ctx.hash) + _, err = i.AddInvoice(context.Background(), invoice, ctx.hash) if err != nil && !errors.Is(err, ErrDuplicateInvoice) { return err } @@ -888,7 +896,7 @@ func (i *InvoiceRegistry) processAMP(ctx invoiceUpdateCtx) error { // Insert invoice into database. Ignore duplicates payment hashes and // payment addrs, this may be a replay or a different HTLC for the AMP // invoice. - _, err := i.AddInvoice(invoice, ctx.hash) + _, err := i.AddInvoice(context.Background(), invoice, ctx.hash) isDuplicatedInvoice := errors.Is(err, ErrDuplicateInvoice) isDuplicatedPayAddr := errors.Is(err, ErrDuplicatePayAddr) switch { @@ -1045,7 +1053,9 @@ func (i *InvoiceRegistry) notifyExitHopHtlcLocked( invoiceRef := ctx.invoiceRef() setID := (*SetID)(ctx.setID()) - invoice, err := i.idb.UpdateInvoice(invoiceRef, setID, callback) + invoice, err := i.idb.UpdateInvoice( + context.Background(), invoiceRef, setID, callback, + ) var duplicateSetIDErr ErrDuplicateSetID if errors.As(err, &duplicateSetIDErr) { @@ -1228,7 +1238,9 @@ func (i *InvoiceRegistry) notifyExitHopHtlcLocked( } // SettleHodlInvoice sets the preimage of a hodl invoice. -func (i *InvoiceRegistry) SettleHodlInvoice(preimage lntypes.Preimage) error { +func (i *InvoiceRegistry) SettleHodlInvoice(ctx context.Context, + preimage lntypes.Preimage) error { + i.Lock() defer i.Unlock() @@ -1255,7 +1267,7 @@ func (i *InvoiceRegistry) SettleHodlInvoice(preimage lntypes.Preimage) error { hash := preimage.Hash() invoiceRef := InvoiceRefByHash(hash) - invoice, err := i.idb.UpdateInvoice(invoiceRef, nil, updateInvoice) + invoice, err := i.idb.UpdateInvoice(ctx, invoiceRef, nil, updateInvoice) if err != nil { log.Errorf("SettleHodlInvoice with preimage %v: %v", preimage, err) @@ -1290,8 +1302,10 @@ func (i *InvoiceRegistry) SettleHodlInvoice(preimage lntypes.Preimage) error { // CancelInvoice attempts to cancel the invoice corresponding to the passed // payment hash. -func (i *InvoiceRegistry) CancelInvoice(payHash lntypes.Hash) error { - return i.cancelInvoiceImpl(payHash, true) +func (i *InvoiceRegistry) CancelInvoice(ctx context.Context, + payHash lntypes.Hash) error { + + return i.cancelInvoiceImpl(ctx, payHash, true) } // shouldCancel examines the state of an invoice and whether we want to @@ -1312,8 +1326,8 @@ func shouldCancel(state ContractState, cancelAccepted bool) bool { // payment hash. Accepted invoices will only be canceled if explicitly // requested to do so. It notifies subscribing links and resolvers that // the associated htlcs were canceled if they change state. -func (i *InvoiceRegistry) cancelInvoiceImpl(payHash lntypes.Hash, - cancelAccepted bool) error { +func (i *InvoiceRegistry) cancelInvoiceImpl(ctx context.Context, + payHash lntypes.Hash, cancelAccepted bool) error { i.Lock() defer i.Unlock() @@ -1338,7 +1352,7 @@ func (i *InvoiceRegistry) cancelInvoiceImpl(payHash lntypes.Hash, } invoiceRef := InvoiceRefByHash(payHash) - invoice, err := i.idb.UpdateInvoice(invoiceRef, nil, updateInvoice) + invoice, err := i.idb.UpdateInvoice(ctx, invoiceRef, nil, updateInvoice) // Implement idempotency by returning success if the invoice was already // canceled. @@ -1391,7 +1405,7 @@ func (i *InvoiceRegistry) cancelInvoiceImpl(payHash lntypes.Hash, deleteRef.PayAddr = &invoice.Terms.PaymentAddr } - err = i.idb.DeleteInvoice([]InvoiceDeleteRef{deleteRef}) + err = i.idb.DeleteInvoice(ctx, []InvoiceDeleteRef{deleteRef}) // If by any chance deletion failed, then log it instead of // returning the error, as the invoice itself has already been // canceled. @@ -1522,7 +1536,7 @@ func (i *invoiceSubscriptionKit) notify(event *invoiceEvent) error { // added. The invoiceIndex parameter is a streaming "checkpoint". We'll start // by first sending out all new events with an invoice index _greater_ than // this value. Afterwards, we'll send out real-time notifications. -func (i *InvoiceRegistry) SubscribeNotifications( +func (i *InvoiceRegistry) SubscribeNotifications(ctx context.Context, addIndex, settleIndex uint64) (*InvoiceSubscription, error) { client := &InvoiceSubscription{ @@ -1612,7 +1626,7 @@ func (i *InvoiceRegistry) SubscribeNotifications( // Query the database to see if based on the provided addIndex and // settledIndex we need to deliver any backlog notifications. - err := i.deliverBacklogEvents(client) + err := i.deliverBacklogEvents(ctx, client) if err != nil { return nil, err } @@ -1624,7 +1638,7 @@ func (i *InvoiceRegistry) SubscribeNotifications( // SubscribeSingleInvoice returns an SingleInvoiceSubscription which allows the // caller to receive async notifications for a specific invoice. -func (i *InvoiceRegistry) SubscribeSingleInvoice( +func (i *InvoiceRegistry) SubscribeSingleInvoice(ctx context.Context, hash lntypes.Hash) (*SingleInvoiceSubscription, error) { client := &SingleInvoiceSubscription{ @@ -1686,7 +1700,7 @@ func (i *InvoiceRegistry) SubscribeSingleInvoice( i.singleNotificationClients[client.id] = client i.notificationClientMux.Unlock() - err := i.deliverSingleBacklogEvents(client) + err := i.deliverSingleBacklogEvents(ctx, client) if err != nil { return nil, err } diff --git a/invoices/invoiceregistry_test.go b/invoices/invoiceregistry_test.go index 1b93b8f249..f91777f3d4 100644 --- a/invoices/invoiceregistry_test.go +++ b/invoices/invoiceregistry_test.go @@ -1,6 +1,7 @@ package invoices_test import ( + "context" "crypto/rand" "math" "testing" @@ -23,13 +24,14 @@ func TestSettleInvoice(t *testing.T) { ctx := newTestContext(t, nil) - allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0) + ctxb := context.Background() + allSubscriptions, err := ctx.registry.SubscribeNotifications(ctxb, 0, 0) require.Nil(t, err) defer allSubscriptions.Cancel() // Subscribe to the not yet existing invoice. subscription, err := ctx.registry.SubscribeSingleInvoice( - testInvoicePaymentHash, + ctxb, testInvoicePaymentHash, ) if err != nil { t.Fatal(err) @@ -41,7 +43,7 @@ func TestSettleInvoice(t *testing.T) { // Add the invoice. testInvoice := newInvoice(t, false) addIdx, err := ctx.registry.AddInvoice( - testInvoice, testInvoicePaymentHash, + ctxb, testInvoice, testInvoicePaymentHash, ) if err != nil { t.Fatal(err) @@ -174,7 +176,7 @@ func TestSettleInvoice(t *testing.T) { // Check that settled amount is equal to the sum of values of the htlcs // 0 and 1. - inv, err := ctx.registry.LookupInvoice(testInvoicePaymentHash) + inv, err := ctx.registry.LookupInvoice(ctxb, testInvoicePaymentHash) if err != nil { t.Fatal(err) } @@ -184,7 +186,7 @@ func TestSettleInvoice(t *testing.T) { } // Try to cancel. - err = ctx.registry.CancelInvoice(testInvoicePaymentHash) + err = ctx.registry.CancelInvoice(ctxb, testInvoicePaymentHash) require.ErrorIs(t, err, invpkg.ErrInvoiceAlreadySettled) // As this is a direct settle, we expect nothing on the hodl chan. @@ -205,31 +207,30 @@ func testCancelInvoice(t *testing.T, gc bool) { cfg.GcCanceledInvoicesOnTheFly = gc ctx := newTestContext(t, &cfg) - allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0) + ctxb := context.Background() + allSubscriptions, err := ctx.registry.SubscribeNotifications(ctxb, 0, 0) require.Nil(t, err) defer allSubscriptions.Cancel() // Try to cancel the not yet existing invoice. This should fail. - err = ctx.registry.CancelInvoice(testInvoicePaymentHash) + err = ctx.registry.CancelInvoice(ctxb, testInvoicePaymentHash) require.ErrorIs(t, err, invpkg.ErrInvoiceNotFound) // Subscribe to the not yet existing invoice. subscription, err := ctx.registry.SubscribeSingleInvoice( - testInvoicePaymentHash, + ctxb, testInvoicePaymentHash, ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer subscription.Cancel() require.Equal(t, subscription.PayHash(), &testInvoicePaymentHash) // Add the invoice. testInvoice := newInvoice(t, false) - _, err = ctx.registry.AddInvoice(testInvoice, testInvoicePaymentHash) - if err != nil { - t.Fatal(err) - } + _, err = ctx.registry.AddInvoice( + ctxb, testInvoice, testInvoicePaymentHash, + ) + require.NoError(t, err) // We expect the open state to be sent to the single invoice subscriber. select { @@ -258,10 +259,8 @@ func testCancelInvoice(t *testing.T, gc bool) { } // Cancel invoice. - err = ctx.registry.CancelInvoice(testInvoicePaymentHash) - if err != nil { - t.Fatal(err) - } + err = ctx.registry.CancelInvoice(ctxb, testInvoicePaymentHash) + require.NoError(t, err) // We expect the canceled state to be sent to the single invoice // subscriber. @@ -280,7 +279,7 @@ func testCancelInvoice(t *testing.T, gc bool) { if gc { // Check that the invoice has been deleted from the db. _, err = ctx.idb.LookupInvoice( - invpkg.InvoiceRefByHash(testInvoicePaymentHash), + ctxb, invpkg.InvoiceRefByHash(testInvoicePaymentHash), ) require.Error(t, err) } @@ -291,7 +290,7 @@ func testCancelInvoice(t *testing.T, gc bool) { // Try to cancel again. Expect that we report ErrInvoiceNotFound if the // invoice has been garbage collected (since the invoice has been // deleted when it was canceled), and no error otherwise. - err = ctx.registry.CancelInvoice(testInvoicePaymentHash) + err = ctx.registry.CancelInvoice(ctxb, testInvoicePaymentHash) if gc { require.Error(t, err, invpkg.ErrInvoiceNotFound) @@ -366,32 +365,27 @@ func TestSettleHoldInvoice(t *testing.T) { registry := invpkg.NewRegistry(idb, expiryWatcher, &cfg) err = registry.Start() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer registry.Stop() - allSubscriptions, err := registry.SubscribeNotifications(0, 0) + ctxb := context.Background() + allSubscriptions, err := registry.SubscribeNotifications(ctxb, 0, 0) require.Nil(t, err) defer allSubscriptions.Cancel() // Subscribe to the not yet existing invoice. subscription, err := registry.SubscribeSingleInvoice( - testInvoicePaymentHash, + ctxb, testInvoicePaymentHash, ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer subscription.Cancel() require.Equal(t, subscription.PayHash(), &testInvoicePaymentHash) // Add the invoice. invoice := newInvoice(t, true) - _, err = registry.AddInvoice(invoice, testInvoicePaymentHash) - if err != nil { - t.Fatal(err) - } + _, err = registry.AddInvoice(ctxb, invoice, testInvoicePaymentHash) + require.NoError(t, err) // We expect the open state to be sent to the single invoice subscriber. update := <-subscription.Updates @@ -475,10 +469,8 @@ func TestSettleHoldInvoice(t *testing.T) { } // Settling with preimage should succeed. - err = registry.SettleHodlInvoice(testInvoicePreimage) - if err != nil { - t.Fatal("expected set preimage to succeed") - } + err = registry.SettleHodlInvoice(ctxb, testInvoicePreimage) + require.NoError(t, err, "expected set preimage to succeed") htlcResolution, _ := (<-hodlChan).(invpkg.HtlcResolution) require.NotNil(t, htlcResolution) @@ -507,14 +499,14 @@ func TestSettleHoldInvoice(t *testing.T) { } // Idempotency. - err = registry.SettleHodlInvoice(testInvoicePreimage) + err = registry.SettleHodlInvoice(ctxb, testInvoicePreimage) require.ErrorIs(t, err, invpkg.ErrInvoiceAlreadySettled) // Try to cancel. - err = registry.CancelInvoice(testInvoicePaymentHash) - if err == nil { - t.Fatal("expected cancellation of a settled invoice to fail") - } + err = registry.CancelInvoice(ctxb, testInvoicePaymentHash) + require.Error( + t, err, "expected cancellation of a settled invoice to fail", + ) } // TestCancelHoldInvoice tests canceling of a hold invoice and related @@ -545,12 +537,12 @@ func TestCancelHoldInvoice(t *testing.T) { require.NoError(t, registry.Stop()) }) + ctxb := context.Background() + // Add the invoice. invoice := newInvoice(t, true) - _, err = registry.AddInvoice(invoice, testInvoicePaymentHash) - if err != nil { - t.Fatal(err) - } + _, err = registry.AddInvoice(ctxb, invoice, testInvoicePaymentHash) + require.NoError(t, err) amtPaid := lnwire.MilliSatoshi(100000) hodlChan := make(chan interface{}, 1) @@ -569,10 +561,8 @@ func TestCancelHoldInvoice(t *testing.T) { } // Cancel invoice. - err = registry.CancelInvoice(testInvoicePaymentHash) - if err != nil { - t.Fatal("cancel invoice failed") - } + err = registry.CancelInvoice(ctxb, testInvoicePaymentHash) + require.NoError(t, err, "cancel invoice failed") htlcResolution, _ := (<-hodlChan).(invpkg.HtlcResolution) require.NotNil(t, htlcResolution) @@ -642,8 +632,10 @@ func testKeySend(t *testing.T, keySendEnabled bool) { cfg.AcceptKeySend = keySendEnabled ctx := newTestContext(t, &cfg) - allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0) - require.Nil(t, err) + allSubscriptions, err := ctx.registry.SubscribeNotifications( + context.Background(), 0, 0, + ) + require.NoError(t, err) defer allSubscriptions.Cancel() hodlChan := make(chan interface{}, 1) @@ -772,8 +764,9 @@ func testHoldKeysend(t *testing.T, timeoutKeysend bool) { cfg.KeysendHoldTime = holdDuration ctx := newTestContext(t, &cfg) - allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0) - require.Nil(t, err) + ctxb := context.Background() + allSubscriptions, err := ctx.registry.SubscribeNotifications(ctxb, 0, 0) + require.NoError(t, err) defer allSubscriptions.Cancel() hodlChan := make(chan interface{}, 1) @@ -840,8 +833,8 @@ func testHoldKeysend(t *testing.T, timeoutKeysend bool) { } // Settle keysend payment manually. - require.Nil(t, ctx.registry.SettleHodlInvoice( - *newInvoice.Terms.PaymentPreimage, + require.NoError(t, ctx.registry.SettleHodlInvoice( + ctxb, *newInvoice.Terms.PaymentPreimage, )) // We expect a settled notification to be sent out. @@ -857,13 +850,14 @@ func TestMppPayment(t *testing.T) { defer timeout()() ctx := newTestContext(t, nil) + ctxb := context.Background() // Add the invoice. testInvoice := newInvoice(t, false) - _, err := ctx.registry.AddInvoice(testInvoice, testInvoicePaymentHash) - if err != nil { - t.Fatal(err) - } + _, err := ctx.registry.AddInvoice( + ctxb, testInvoice, testInvoicePaymentHash, + ) + require.NoError(t, err) mppPayload := &mockPayload{ mpp: record.NewMPP(testInvoiceAmount, [32]byte{}), @@ -933,10 +927,8 @@ func TestMppPayment(t *testing.T) { // Check that settled amount is equal to the sum of values of the htlcs // 2 and 3. - inv, err := ctx.registry.LookupInvoice(testInvoicePaymentHash) - if err != nil { - t.Fatal(err) - } + inv, err := ctx.registry.LookupInvoice(ctxb, testInvoicePaymentHash) + require.NoError(t, err) if inv.State != invpkg.ContractSettled { t.Fatal("expected invoice to be settled") } @@ -952,17 +944,16 @@ func TestMppPayment(t *testing.T) { func TestMppPaymentWithOverpayment(t *testing.T) { t.Parallel() + ctxb := context.Background() f := func(overpaymentRand uint64) bool { ctx := newTestContext(t, nil) // Add the invoice. testInvoice := newInvoice(t, false) _, err := ctx.registry.AddInvoice( - testInvoice, testInvoicePaymentHash, + ctxb, testInvoice, testInvoicePaymentHash, ) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) mppPayload := &mockPayload{ mpp: record.NewMPP(testInvoiceAmount, [32]byte{}), @@ -1009,10 +1000,10 @@ func TestMppPaymentWithOverpayment(t *testing.T) { // Check that settled amount is equal to the sum of values of // the htlcs 1 and 2. - inv, err := ctx.registry.LookupInvoice(testInvoicePaymentHash) - if err != nil { - t.Fatal(err) - } + inv, err := ctx.registry.LookupInvoice( + ctxb, testInvoicePaymentHash, + ) + require.NoError(t, err) if inv.State != invpkg.ContractSettled { t.Fatal("expected invoice to be settled") } @@ -1050,10 +1041,12 @@ func TestInvoiceExpiryWithRegistry(t *testing.T) { t, testTime, 0, numExpired, numPending, ) + ctxb := context.Background() + var expectedCancellations []lntypes.Hash expiredInvoices := existingInvoices.expiredInvoices for paymentHash, expiredInvoice := range expiredInvoices { - _, err := idb.AddInvoice(expiredInvoice, paymentHash) + _, err := idb.AddInvoice(ctxb, expiredInvoice, paymentHash) require.NoError(t, err) expectedCancellations = append( expectedCancellations, paymentHash, @@ -1062,7 +1055,7 @@ func TestInvoiceExpiryWithRegistry(t *testing.T) { pendingInvoices := existingInvoices.pendingInvoices for paymentHash, pendingInvoice := range pendingInvoices { - _, err := idb.AddInvoice(pendingInvoice, paymentHash) + _, err := idb.AddInvoice(ctxb, pendingInvoice, paymentHash) require.NoError(t, err) } @@ -1078,24 +1071,20 @@ func TestInvoiceExpiryWithRegistry(t *testing.T) { var invoicesThatWillCancel []lntypes.Hash for paymentHash, pendingInvoice := range newInvoices.pendingInvoices { - _, err := registry.AddInvoice(pendingInvoice, paymentHash) + _, err := registry.AddInvoice(ctxb, pendingInvoice, paymentHash) + require.NoError(t, err) invoicesThatWillCancel = append( invoicesThatWillCancel, paymentHash, ) - if err != nil { - t.Fatal(err) - } } // Check that they are really not canceled until before the clock is // advanced. for i := range invoicesThatWillCancel { invoice, err := registry.LookupInvoice( - invoicesThatWillCancel[i], + ctxb, invoicesThatWillCancel[i], ) - if err != nil { - t.Fatalf("cannot find invoice: %v", err) - } + require.NoError(t, err, "cannot find invoice") if invoice.State == invpkg.ContractCanceled { t.Fatalf("expected pending invoice, got canceled") @@ -1115,7 +1104,7 @@ func TestInvoiceExpiryWithRegistry(t *testing.T) { canceled := func() bool { for i := range expectedCancellations { invoice, err := registry.LookupInvoice( - expectedCancellations[i], + ctxb, expectedCancellations[i], ) require.NoError(t, err) @@ -1162,6 +1151,8 @@ func TestOldInvoiceRemovalOnStart(t *testing.T) { t, testTime, 0, numExpired, numPending, ) + ctxb := context.Background() + i := 0 for paymentHash, invoice := range existingInvoices.expiredInvoices { // Mark half of the invoices as settled, the other half as @@ -1172,7 +1163,7 @@ func TestOldInvoiceRemovalOnStart(t *testing.T) { invoice.State = invpkg.ContractCanceled } - _, err := idb.AddInvoice(invoice, paymentHash) + _, err := idb.AddInvoice(ctxb, invoice, paymentHash) require.NoError(t, err) i++ } @@ -1186,7 +1177,7 @@ func TestOldInvoiceRemovalOnStart(t *testing.T) { NumMaxInvoices: math.MaxUint64, } - response, err := idb.QueryInvoices(query) + response, err := idb.QueryInvoices(ctxb, query) require.NoError(t, err) // Save all settled invoices for our expectation set. @@ -1202,7 +1193,7 @@ func TestOldInvoiceRemovalOnStart(t *testing.T) { require.NoError(t, err, "cannot start the registry") // Perform a scan query to collect all invoices. - response, err = idb.QueryInvoices(query) + response, err = idb.QueryInvoices(ctxb, query) require.NoError(t, err) // Check that we really only kept the settled invoices after the @@ -1248,7 +1239,10 @@ func testHeightExpiryWithRegistry(t *testing.T, numParts int, settle bool) { testInvoice.HodlInvoice = true testInvoice.PaymentRequest = []byte{1, 2, 3} - _, err := ctx.registry.AddInvoice(testInvoice, testInvoicePaymentHash) + ctxb := context.Background() + _, err := ctx.registry.AddInvoice( + ctxb, testInvoice, testInvoicePaymentHash, + ) require.NoError(t, err) payLoad := testPayload @@ -1275,7 +1269,9 @@ func testHeightExpiryWithRegistry(t *testing.T, numParts int, settle bool) { } require.Eventually(t, func() bool { - inv, err := ctx.registry.LookupInvoice(testInvoicePaymentHash) + inv, err := ctx.registry.LookupInvoice( + ctxb, testInvoicePaymentHash, + ) require.NoError(t, err) return inv.State == invpkg.ContractAccepted @@ -1299,7 +1295,7 @@ func testHeightExpiryWithRegistry(t *testing.T, numParts int, settle bool) { // If we want to settle our invoice in this test, we do so now. if settle { - err = ctx.registry.SettleHodlInvoice(testInvoicePreimage) + err = ctx.registry.SettleHodlInvoice(ctxb, testInvoicePreimage) require.NoError(t, err) for i := 0; i < numParts; i++ { @@ -1333,7 +1329,7 @@ func testHeightExpiryWithRegistry(t *testing.T, numParts int, settle bool) { // Finally, lookup the invoice and assert that we have the state we // expect. - inv, err := ctx.registry.LookupInvoice(testInvoicePaymentHash) + inv, err := ctx.registry.LookupInvoice(ctxb, testInvoicePaymentHash) require.NoError(t, err) require.Equal(t, expectedState, inv.State, "expected "+ "hold invoice: %v, got: %v", expectedState, inv.State) @@ -1352,7 +1348,10 @@ func TestMultipleSetHeightExpiry(t *testing.T) { // Add a hold invoice. testInvoice := newInvoice(t, true) - _, err := ctx.registry.AddInvoice(testInvoice, testInvoicePaymentHash) + ctxb := context.Background() + _, err := ctx.registry.AddInvoice( + ctxb, testInvoice, testInvoicePaymentHash, + ) require.NoError(t, err) mppPayload := &mockPayload{ @@ -1409,7 +1408,7 @@ func TestMultipleSetHeightExpiry(t *testing.T) { // Assert that we've reached an accepted state because the invoice has // been paid with a complete set. - inv, err := ctx.registry.LookupInvoice(testInvoicePaymentHash) + inv, err := ctx.registry.LookupInvoice(ctxb, testInvoicePaymentHash) require.NoError(t, err) require.Equal(t, invpkg.ContractAccepted, inv.State, "expected "+ "hold invoice accepted") @@ -1421,7 +1420,9 @@ func TestMultipleSetHeightExpiry(t *testing.T) { } require.Eventuallyf(t, func() bool { - inv, err := ctx.registry.LookupInvoice(testInvoicePaymentHash) + inv, err := ctx.registry.LookupInvoice( + ctxb, testInvoicePaymentHash, + ) require.NoError(t, err) return inv.State == invpkg.ContractCanceled @@ -1435,14 +1436,15 @@ func TestSettleInvoicePaymentAddrRequired(t *testing.T) { t.Parallel() ctx := newTestContext(t, nil) + ctxb := context.Background() - allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0) - require.Nil(t, err) + allSubscriptions, err := ctx.registry.SubscribeNotifications(ctxb, 0, 0) + require.NoError(t, err) defer allSubscriptions.Cancel() // Subscribe to the not yet existing invoice. subscription, err := ctx.registry.SubscribeSingleInvoice( - testInvoicePaymentHash, + ctxb, testInvoicePaymentHash, ) require.NoError(t, err) defer subscription.Cancel() @@ -1467,7 +1469,7 @@ func TestSettleInvoicePaymentAddrRequired(t *testing.T) { // Add the invoice, which requires the MPP payload to always be // included due to its set of feature bits. addIdx, err := ctx.registry.AddInvoice( - invoice, testInvoicePaymentHash, + ctxb, invoice, testInvoicePaymentHash, ) require.NoError(t, err) require.Equal(t, int(addIdx), 1) @@ -1523,14 +1525,15 @@ func TestSettleInvoicePaymentAddrRequiredOptionalGrace(t *testing.T) { t.Parallel() ctx := newTestContext(t, nil) + ctxb := context.Background() - allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0) - require.Nil(t, err) + allSubscriptions, err := ctx.registry.SubscribeNotifications(ctxb, 0, 0) + require.NoError(t, err) defer allSubscriptions.Cancel() // Subscribe to the not yet existing invoice. subscription, err := ctx.registry.SubscribeSingleInvoice( - testInvoicePaymentHash, + ctxb, testInvoicePaymentHash, ) require.NoError(t, err) defer subscription.Cancel() @@ -1556,7 +1559,7 @@ func TestSettleInvoicePaymentAddrRequiredOptionalGrace(t *testing.T) { // Add the invoice, which does not require the MPP payload to always be // included due to its set of feature bits. addIdx, err := ctx.registry.AddInvoice( - invoice, testInvoicePaymentHash, + ctxb, invoice, testInvoicePaymentHash, ) require.NoError(t, err) require.Equal(t, int(addIdx), 1) @@ -1725,8 +1728,9 @@ func testSpontaneousAmpPayment( cfg := defaultRegistryConfig() cfg.AcceptAMP = ampEnabled ctx := newTestContext(t, &cfg) + ctxb := context.Background() - allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0) + allSubscriptions, err := ctx.registry.SubscribeNotifications(ctxb, 0, 0) require.Nil(t, err) defer allSubscriptions.Cancel() diff --git a/lnrpc/invoicesrpc/addinvoice.go b/lnrpc/invoicesrpc/addinvoice.go index 7c59da883f..f300e43804 100644 --- a/lnrpc/invoicesrpc/addinvoice.go +++ b/lnrpc/invoicesrpc/addinvoice.go @@ -47,8 +47,8 @@ const ( // AddInvoiceConfig contains dependencies for invoice creation. type AddInvoiceConfig struct { // AddInvoice is called to add the invoice to the registry. - AddInvoice func(invoice *invoices.Invoice, paymentHash lntypes.Hash) ( - uint64, error) + AddInvoice func(ctx context.Context, invoice *invoices.Invoice, + paymentHash lntypes.Hash) (uint64, error) // IsChannelActive is used to generate valid hop hints. IsChannelActive func(chanID lnwire.ChannelID) bool @@ -478,7 +478,7 @@ func AddInvoice(ctx context.Context, cfg *AddInvoiceConfig, ) // With all sanity checks passed, write the invoice to the database. - _, err = cfg.AddInvoice(newInvoice, paymentHash) + _, err = cfg.AddInvoice(ctx, newInvoice, paymentHash) if err != nil { return nil, nil, err } diff --git a/lnrpc/invoicesrpc/invoices_server.go b/lnrpc/invoicesrpc/invoices_server.go index 0c9ddf042d..b62538543d 100644 --- a/lnrpc/invoicesrpc/invoices_server.go +++ b/lnrpc/invoicesrpc/invoices_server.go @@ -238,7 +238,9 @@ func (s *Server) SubscribeSingleInvoice(req *SubscribeSingleInvoiceRequest, return err } - invoiceClient, err := s.cfg.InvoiceRegistry.SubscribeSingleInvoice(hash) + invoiceClient, err := s.cfg.InvoiceRegistry.SubscribeSingleInvoice( + updateStream.Context(), hash, + ) if err != nil { return err } @@ -287,7 +289,7 @@ func (s *Server) SettleInvoice(ctx context.Context, return nil, err } - err = s.cfg.InvoiceRegistry.SettleHodlInvoice(preimage) + err = s.cfg.InvoiceRegistry.SettleHodlInvoice(ctx, preimage) if err != nil && !errors.Is(err, invoices.ErrInvoiceAlreadySettled) { return nil, err } @@ -306,7 +308,7 @@ func (s *Server) CancelInvoice(ctx context.Context, return nil, err } - err = s.cfg.InvoiceRegistry.CancelInvoice(paymentHash) + err = s.cfg.InvoiceRegistry.CancelInvoice(ctx, paymentHash) if err != nil { return nil, err } @@ -433,7 +435,9 @@ func (s *Server) LookupInvoiceV2(ctx context.Context, // Attempt to locate the invoice, returning a nice "not found" error if // we can't find it in the database. - invoice, err := s.cfg.InvoiceRegistry.LookupInvoiceByRef(invoiceRef) + invoice, err := s.cfg.InvoiceRegistry.LookupInvoiceByRef( + ctx, invoiceRef, + ) switch { case errors.Is(err, invoices.ErrInvoiceNotFound): return nil, status.Error(codes.NotFound, err.Error()) diff --git a/rpcserver.go b/rpcserver.go index 02bbde2b3b..d8f99c91d0 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -5663,7 +5663,7 @@ func (r *rpcServer) LookupInvoice(ctx context.Context, rpcsLog.Tracef("[lookupinvoice] searching for invoice %x", payHash[:]) - invoice, err := r.server.invoices.LookupInvoice(payHash) + invoice, err := r.server.invoices.LookupInvoice(ctx, payHash) switch { case errors.Is(err, invoices.ErrInvoiceNotFound): return nil, status.Error(codes.NotFound, err.Error()) @@ -5726,7 +5726,7 @@ func (r *rpcServer) ListInvoices(ctx context.Context, q.CreationDateEnd = time.Unix(int64(req.CreationDateEnd), 0) } - invoiceSlice, err := r.server.miscDB.QueryInvoices(q) + invoiceSlice, err := r.server.miscDB.QueryInvoices(ctx, q) if err != nil { return nil, fmt.Errorf("unable to query invoices: %v", err) } @@ -5757,7 +5757,7 @@ func (r *rpcServer) SubscribeInvoices(req *lnrpc.InvoiceSubscription, updateStream lnrpc.Lightning_SubscribeInvoicesServer) error { invoiceClient, err := r.server.invoices.SubscribeNotifications( - req.AddIndex, req.SettleIndex, + updateStream.Context(), req.AddIndex, req.SettleIndex, ) if err != nil { return err From 2e8f1cca23849a63f3fcb773f9c2952ded2d4047 Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Fri, 6 Oct 2023 15:18:37 +0200 Subject: [PATCH 2/3] channeldb: restrict invoice tests to only use an InvoiceDB instance --- channeldb/db.go | 9 +++++++++ channeldb/invoice_test.go | 40 +++++++++++++++++++-------------------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/channeldb/db.go b/channeldb/db.go index 18a66c46e0..bf170e2ba3 100644 --- a/channeldb/db.go +++ b/channeldb/db.go @@ -28,6 +28,7 @@ import ( "github.com/lightningnetwork/lnd/channeldb/migration31" "github.com/lightningnetwork/lnd/channeldb/migration_01_to_11" "github.com/lightningnetwork/lnd/clock" + "github.com/lightningnetwork/lnd/invoices" "github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/routing/route" @@ -1824,6 +1825,14 @@ func (c *ChannelStateDB) PutOnchainFinalHtlcOutcome( }, func() {}) } +// MakeTestInvoiceDB is used to create a test invoice database for testing +// purposes. It simply calls into MakeTestDB so the same modifiers can be used. +func MakeTestInvoiceDB(t *testing.T, modifiers ...OptionModifier) ( + invoices.InvoiceDB, error) { + + return MakeTestDB(t, modifiers...) +} + // MakeTestDB creates a new instance of the ChannelDB for testing purposes. // A callback which cleans up the created temporary directories is also // returned and intended to be executed after the test completes. diff --git a/channeldb/invoice_test.go b/channeldb/invoice_test.go index b840c37535..e4d9ffffac 100644 --- a/channeldb/invoice_test.go +++ b/channeldb/invoice_test.go @@ -152,7 +152,7 @@ func TestInvoiceWorkflow(t *testing.T) { } func testInvoiceWorkflow(t *testing.T, test invWorkflowTest) { - db, err := MakeTestDB(t) + db, err := MakeTestInvoiceDB(t) require.NoError(t, err, "unable to make test db") // Create a fake invoice which we'll use several times in the tests @@ -290,7 +290,7 @@ func testInvoiceWorkflow(t *testing.T, test invWorkflowTest) { // TestAddDuplicatePayAddr asserts that the payment addresses of inserted // invoices are unique. func TestAddDuplicatePayAddr(t *testing.T) { - db, err := MakeTestDB(t) + db, err := MakeTestInvoiceDB(t) require.NoError(t, err) // Create two invoices with the same payment addr. @@ -318,7 +318,7 @@ func TestAddDuplicatePayAddr(t *testing.T) { // addresses to be inserted if they are blank to support JIT legacy keysend // invoices. func TestAddDuplicateKeysendPayAddr(t *testing.T) { - db, err := MakeTestDB(t) + db, err := MakeTestInvoiceDB(t) require.NoError(t, err) // Create two invoices with the same _blank_ payment addr. @@ -362,7 +362,7 @@ func TestAddDuplicateKeysendPayAddr(t *testing.T) { // ensures that the HTLC's payment hash always matches the payment hash in the // returned invoice. func TestFailInvoiceLookupMPPPayAddrOnly(t *testing.T) { - db, err := MakeTestDB(t) + db, err := MakeTestInvoiceDB(t) require.NoError(t, err) // Create and insert a random invoice. @@ -391,7 +391,7 @@ func TestFailInvoiceLookupMPPPayAddrOnly(t *testing.T) { // TestInvRefEquivocation asserts that retrieving or updating an invoice using // an equivocating InvoiceRef results in ErrInvRefEquivocation. func TestInvRefEquivocation(t *testing.T) { - db, err := MakeTestDB(t) + db, err := MakeTestInvoiceDB(t) require.NoError(t, err) // Add two random invoices. @@ -433,7 +433,7 @@ func TestInvRefEquivocation(t *testing.T) { func TestInvoiceCancelSingleHtlc(t *testing.T) { t.Parallel() - db, err := MakeTestDB(t) + db, err := MakeTestInvoiceDB(t) require.NoError(t, err, "unable to make test db") preimage := lntypes.Preimage{1} @@ -514,7 +514,7 @@ func TestInvoiceCancelSingleHtlc(t *testing.T) { func TestInvoiceCancelSingleHtlcAMP(t *testing.T) { t.Parallel() - db, err := MakeTestDB(t, OptionClock(testClock)) + db, err := MakeTestInvoiceDB(t, OptionClock(testClock)) require.NoError(t, err, "unable to make test db: %v", err) // We'll start out by creating an invoice and writing it to the DB. @@ -692,7 +692,7 @@ func TestInvoiceCancelSingleHtlcAMP(t *testing.T) { func TestInvoiceAddTimeSeries(t *testing.T) { t.Parallel() - db, err := MakeTestDB(t, OptionClock(testClock)) + db, err := MakeTestInvoiceDB(t, OptionClock(testClock)) require.NoError(t, err, "unable to make test db") ctxb := context.Background() @@ -850,7 +850,7 @@ func TestSettleIndexAmpPayments(t *testing.T) { t.Parallel() testClock := clock.NewTestClock(testNow) - db, err := MakeTestDB(t, OptionClock(testClock)) + db, err := MakeTestInvoiceDB(t, OptionClock(testClock)) require.Nil(t, err) // First, we'll make a sample invoice that'll be paid to several times @@ -1018,7 +1018,7 @@ func TestSettleIndexAmpPayments(t *testing.T) { func TestScanInvoices(t *testing.T) { t.Parallel() - db, err := MakeTestDB(t) + db, err := MakeTestInvoiceDB(t) require.NoError(t, err, "unable to make test db") var invoices map[lntypes.Hash]*invpkg.Invoice @@ -1079,7 +1079,7 @@ func TestScanInvoices(t *testing.T) { func TestDuplicateSettleInvoice(t *testing.T) { t.Parallel() - db, err := MakeTestDB(t, OptionClock(testClock)) + db, err := MakeTestInvoiceDB(t, OptionClock(testClock)) require.NoError(t, err, "unable to make test db") // We'll start out by creating an invoice and writing it to the DB. @@ -1140,7 +1140,7 @@ func TestDuplicateSettleInvoice(t *testing.T) { func TestQueryInvoices(t *testing.T) { t.Parallel() - db, err := MakeTestDB(t, OptionClock(testClock)) + db, err := MakeTestInvoiceDB(t, OptionClock(testClock)) require.NoError(t, err, "unable to make test db") // To begin the test, we'll add 50 invoices to the database. We'll @@ -1573,7 +1573,7 @@ func getUpdateInvoice(amt lnwire.MilliSatoshi) invpkg.InvoiceUpdateCallback { func TestCustomRecords(t *testing.T) { t.Parallel() - db, err := MakeTestDB(t) + db, err := MakeTestInvoiceDB(t) require.NoError(t, err, "unable to make test db") preimage := lntypes.Preimage{1} @@ -1651,7 +1651,7 @@ func TestInvoiceHtlcAMPFields(t *testing.T) { } func testInvoiceHtlcAMPFields(t *testing.T, isAMP bool) { - db, err := MakeTestDB(t) + db, err := MakeTestInvoiceDB(t) require.Nil(t, err) testInvoice, err := randInvoice(1000) @@ -1853,7 +1853,7 @@ func TestHTLCSet(t *testing.T) { // TestAddInvoiceWithHTLCs asserts that you can't insert an invoice that already // has HTLCs. func TestAddInvoiceWithHTLCs(t *testing.T) { - db, err := MakeTestDB(t) + db, err := MakeTestInvoiceDB(t) require.Nil(t, err) testInvoice, err := randInvoice(1000) @@ -1872,7 +1872,7 @@ func TestAddInvoiceWithHTLCs(t *testing.T) { // that invoices with duplicate set ids are disallowed. func TestSetIDIndex(t *testing.T) { testClock := clock.NewTestClock(testNow) - db, err := MakeTestDB(t, OptionClock(testClock)) + db, err := MakeTestInvoiceDB(t, OptionClock(testClock)) require.Nil(t, err) // We'll start out by creating an invoice and writing it to the DB. @@ -2214,7 +2214,7 @@ func getUpdateInvoiceAMPSettle(setID *[32]byte, preimage [32]byte, func TestUnexpectedInvoicePreimage(t *testing.T) { t.Parallel() - db, err := MakeTestDB(t) + db, err := MakeTestInvoiceDB(t) require.NoError(t, err, "unable to make test db") invoice, err := randInvoice(lnwire.MilliSatoshi(100)) @@ -2272,7 +2272,7 @@ func TestUpdateHTLCPreimages(t *testing.T) { } func testUpdateHTLCPreimages(t *testing.T, test updateHTLCPreimageTestCase) { - db, err := MakeTestDB(t) + db, err := MakeTestInvoiceDB(t) require.NoError(t, err, "unable to make test db") // We'll start out by creating an invoice and writing it to the DB. @@ -3013,7 +3013,7 @@ func testUpdateHTLC(t *testing.T, test updateHTLCTest) { func TestDeleteInvoices(t *testing.T) { t.Parallel() - db, err := MakeTestDB(t) + db, err := MakeTestInvoiceDB(t) require.NoError(t, err, "unable to make test db") // Add some invoices to the test db. @@ -3097,7 +3097,7 @@ func TestDeleteInvoices(t *testing.T) { func TestAddInvoiceInvalidFeatureDeps(t *testing.T) { t.Parallel() - db, err := MakeTestDB(t) + db, err := MakeTestInvoiceDB(t) require.NoError(t, err, "unable to make test db") invoice, err := randInvoice(500) From aa859728020db13baed42cda044b6067ac250d87 Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Wed, 11 Oct 2023 09:23:57 +0200 Subject: [PATCH 3/3] docs: update release notes for 0.18.0 --- docs/release-notes/release-notes-0.18.0.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/release-notes/release-notes-0.18.0.md b/docs/release-notes/release-notes-0.18.0.md index 1f701cb6ff..2bf472de95 100644 --- a/docs/release-notes/release-notes-0.18.0.md +++ b/docs/release-notes/release-notes-0.18.0.md @@ -64,11 +64,18 @@ ## BOLT Spec Updates ## Testing ## Database + +* [Add context to InvoiceDB + methods](https://github.com/lightningnetwork/lnd/pull/8066). This change adds + a context parameter to all `InvoiceDB` methods which is a pre-requisite for + the SQL implementation. + ## Code Health ## Tooling and Documentation # Contributors (Alphabetical Order) +* Andras Banki-Horvath * Carla Kirk-Cohen * Elle Mouton * Yong Yu