diff --git a/channeldb/db.go b/channeldb/db.go index 18a66c46e..bf170e2ba 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 ce2d960b6..e4d9ffffa 100644 --- a/channeldb/invoice_test.go +++ b/channeldb/invoice_test.go @@ -2,6 +2,7 @@ package channeldb import ( "bytes" + "context" "crypto/rand" "fmt" "math" @@ -151,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 @@ -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 @@ -288,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. @@ -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) } @@ -314,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. @@ -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) } @@ -356,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. @@ -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,29 +384,30 @@ 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) } // 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. 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) } @@ -424,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} @@ -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") @@ -504,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. @@ -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 @@ -681,10 +692,11 @@ 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") - _, 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) } @@ -836,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 @@ -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, @@ -1003,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 @@ -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) @@ -1063,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. @@ -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 { @@ -1121,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 @@ -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) } @@ -1551,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} @@ -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 { @@ -1628,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) @@ -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)) @@ -1829,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) @@ -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) } @@ -1848,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. @@ -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) } @@ -2189,22 +2214,24 @@ 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)) 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), ) @@ -2245,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. @@ -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) } @@ -2983,25 +3013,26 @@ 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. 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) } @@ -3066,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) @@ -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 1567c4183..d7016ff33 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 e1cbb1173..86653c675 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 49e1f913a..45cd75735 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 19105a77e..7acac67ec 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/docs/release-notes/release-notes-0.18.0.md b/docs/release-notes/release-notes-0.18.0.md index 1f701cb6f..2bf472de9 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 diff --git a/htlcswitch/interfaces.go b/htlcswitch/interfaces.go index 304f4a595..1ce4ffb2e 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 37e306559..9c07cd53c 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 fe593c9c5..9b0453dea 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 28f3d9e2c..2d507f01b 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 649570d2c..da36e214c 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 f717afd4e..36bc0ea48 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 a9a5e3831..e58ad4cdb 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 1b93b8f24..f91777f3d 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 7c59da883..f300e4380 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 0c9ddf042..b62538543 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 02bbde2b3..d8f99c91d 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