From 43d1d1f4f2a11dfacbc94cb31d3bebfb40fd8b20 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Fri, 29 Jun 2018 18:07:55 -0700 Subject: [PATCH] test: extend testInvoiceSubscriptions to test historical notification dispatch --- lnd_test.go | 141 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 135 insertions(+), 6 deletions(-) diff --git a/lnd_test.go b/lnd_test.go index 47c07aa8..f232397f 100644 --- a/lnd_test.go +++ b/lnd_test.go @@ -19,6 +19,7 @@ import ( "reflect" "crypto/rand" + "crypto/sha256" prand "math/rand" "github.com/btcsuite/btclog" @@ -3452,10 +3453,11 @@ func testSendToRouteErrorPropagation(net *lntest.NetworkHarness, t *harnessTest) t.Fatalf("alice didn't advertise her channel: %v", err) } - // Create a new nodes (Carol and Charlie), load her with some funds, then establish - // a connection between Carol and Charlie with a channel that has - // identical capacity to the one created above.Then we will get route via queryroutes call - // which will be fake route for Alice -> Bob graph. + // Create a new nodes (Carol and Charlie), load her with some funds, + // then establish a connection between Carol and Charlie with a channel + // that has identical capacity to the one created above.Then we will + // get route via queryroutes call which will be fake route for Alice -> + // Bob graph. // // The network topology should now look like: Alice -> Bob; Carol -> Charlie. carol, err := net.NewNode("Carol", nil) @@ -4298,17 +4300,18 @@ func testInvoiceSubscriptions(net *lntest.NetworkHarness, t *harnessTest) { if err != nil { t.Fatalf("unable to add invoice: %v", err) } + lastAddIndex := invoiceResp.AddIndex // Create a new invoice subscription client for Bob, the notification // should be dispatched shortly below. req := &lnrpc.InvoiceSubscription{} - ctx, cancelFunc := context.WithCancel(context.Background()) + ctx, cancelInvoiceSubscription := context.WithCancel(context.Background()) bobInvoiceSubscription, err := net.Bob.SubscribeInvoices(ctx, req) if err != nil { t.Fatalf("unable to subscribe to bob's invoice updates: %v", err) } - defer cancelFunc() + var settleIndex uint64 quit := make(chan struct{}) updateSent := make(chan struct{}) go func() { @@ -4338,6 +4341,12 @@ func testInvoiceSubscriptions(net *lntest.NetworkHarness, t *harnessTest) { invoice.RPreimage, invoiceUpdate.RPreimage) } + if invoiceUpdate.SettleIndex == 0 { + t.Fatalf("invoice should have settle index") + } + + settleIndex = invoiceUpdate.SettleIndex + close(updateSent) }() @@ -4375,6 +4384,126 @@ func testInvoiceSubscriptions(net *lntest.NetworkHarness, t *harnessTest) { case <-updateSent: // Fall through on success } + // With the base case working, we'll now cancel Bob's current + // subscription in order to exercise the backlog fill behavior. + cancelInvoiceSubscription() + + // We'll now add 3 more invoices to Bob's invoice registry. + const numInvoices = 3 + newInvoices := make([]*lnrpc.Invoice, numInvoices) + payReqs := make([]string, numInvoices) + for i := 0; i < numInvoices; i++ { + preimage := bytes.Repeat([]byte{byte(90 + 1 + i)}, 32) + invoice := &lnrpc.Invoice{ + Memo: "testing", + RPreimage: preimage, + Value: paymentAmt, + } + resp, err := net.Bob.AddInvoice(ctxb, invoice) + if err != nil { + t.Fatalf("unable to add invoice: %v", err) + } + + newInvoices[i] = invoice + payReqs[i] = resp.PaymentRequest + } + + // Now that the set of invoices has been added, we'll re-register for + // streaming invoice notifications for Bob, this time specifying the + // add invoice of the last prior invoice. + req = &lnrpc.InvoiceSubscription{ + AddIndex: lastAddIndex, + } + ctx, cancelInvoiceSubscription = context.WithCancel(context.Background()) + bobInvoiceSubscription, err = net.Bob.SubscribeInvoices(ctx, req) + if err != nil { + t.Fatalf("unable to subscribe to bob's invoice updates: %v", err) + } + + // Since we specified a value of the prior add index above, we should + // now immediately get the invoices we just added as we should get the + // backlog of notifications. + for i := 0; i < numInvoices; i++ { + invoiceUpdate, err := bobInvoiceSubscription.Recv() + if err != nil { + t.Fatalf("unable to receive subscription") + } + + // We should now get the ith invoice we added, as they should + // be returned in order. + if invoiceUpdate.Settled { + t.Fatalf("should have only received add events") + } + originalInvoice := newInvoices[i] + rHash := sha256.Sum256(originalInvoice.RPreimage[:]) + if !bytes.Equal(invoiceUpdate.RHash, rHash[:]) { + t.Fatalf("invoices have mismatched payment hashes: "+ + "expected %x, got %x", rHash[:], + invoiceUpdate.RHash) + } + } + + cancelInvoiceSubscription() + + // We'll now have Bob settle out the remainder of these invoices so we + // can test that all settled invoices are properly notified. + ctxt, _ = context.WithTimeout(ctxb, timeout) + err = completePaymentRequests( + ctxt, net.Alice, payReqs, true, + ) + if err != nil { + t.Fatalf("unable to send payment: %v", err) + } + + // With the set of invoices paid, we'll now cancel the old + // subscription, and create a new one for Bob, this time using the + // settle index to obtain the backlog of settled invoices. + req = &lnrpc.InvoiceSubscription{ + SettleIndex: settleIndex, + } + ctx, cancelInvoiceSubscription = context.WithCancel(context.Background()) + bobInvoiceSubscription, err = net.Bob.SubscribeInvoices(ctx, req) + if err != nil { + t.Fatalf("unable to subscribe to bob's invoice updates: %v", err) + } + + defer cancelInvoiceSubscription() + + // As we specified the index of the past settle index, we should now + // receive notifications for the three HTLCs that we just settled. As + // the order that the HTLCs will be settled in is partially randomized, + // we'll use a map to assert that the proper set has been settled. + settledInvoices := make(map[[32]byte]struct{}) + for _, invoice := range newInvoices { + rHash := sha256.Sum256(invoice.RPreimage[:]) + settledInvoices[rHash] = struct{}{} + } + for i := 0; i < numInvoices; i++ { + invoiceUpdate, err := bobInvoiceSubscription.Recv() + if err != nil { + t.Fatalf("unable to receive subscription") + } + + // We should now get the ith invoice we added, as they should + // be returned in order. + if !invoiceUpdate.Settled { + t.Fatalf("should have only received settle events") + } + + var rHash [32]byte + copy(rHash[:], invoiceUpdate.RHash) + if _, ok := settledInvoices[rHash]; !ok { + t.Fatalf("unknown invoice settled: %x", rHash) + } + + delete(settledInvoices, rHash) + } + + // At this point, all the invoices should be fully settled. + if len(settledInvoices) != 0 { + t.Fatalf("not all invoices settled") + } + ctxt, _ = context.WithTimeout(ctxb, timeout) closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint, false) }