diff --git a/lntest/itest/list_on_test.go b/lntest/itest/list_on_test.go index 514edba19..3d5635b00 100644 --- a/lntest/itest/list_on_test.go +++ b/lntest/itest/list_on_test.go @@ -361,4 +361,8 @@ var allTestCasesTemp = []*lntemp.TestCase{ Name: "stateless init", TestFunc: testStatelessInit, }, + { + Name: "single hop invoice", + TestFunc: testSingleHopInvoice, + }, } diff --git a/lntest/itest/lnd_single_hop_invoice_test.go b/lntest/itest/lnd_single_hop_invoice_test.go index 74f377458..ce75c42d0 100644 --- a/lntest/itest/lnd_single_hop_invoice_test.go +++ b/lntest/itest/lnd_single_hop_invoice_test.go @@ -2,35 +2,34 @@ package itest import ( "bytes" - "context" "encoding/hex" - "time" "github.com/btcsuite/btcd/btcutil" - "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc" - "github.com/lightningnetwork/lnd/lntest" - "github.com/lightningnetwork/lnd/lntest/wait" + "github.com/lightningnetwork/lnd/lntemp" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/record" "github.com/stretchr/testify/require" ) -func testSingleHopInvoice(net *lntest.NetworkHarness, t *harnessTest) { - ctxb := context.Background() - - // Open a channel with 100k satoshis between Alice and Bob with Alice being - // the sole funder of the channel. +func testSingleHopInvoice(ht *lntemp.HarnessTest) { + // Open a channel with 100k satoshis between Alice and Bob with Alice + // being the sole funder of the channel. chanAmt := btcutil.Amount(100000) - chanPoint := openChannelAndAssert( - t, net, net.Alice, net.Bob, - lntest.OpenChannelParams{ - Amt: chanAmt, - }, + alice, bob := ht.Alice, ht.Bob + cp := ht.OpenChannel( + alice, bob, lntemp.OpenChannelParams{Amt: chanAmt}, ) + // assertAmountPaid is a helper closure that asserts the amount paid by + // Alice and received by Bob are expected. + assertAmountPaid := func(expected int64) { + ht.AssertAmountPaid("alice -> bob", alice, cp, expected, 0) + ht.AssertAmountPaid("bob <- alice", bob, cp, 0, expected) + } + // Now that the channel is open, create an invoice for Bob which // expects a payment of 1000 satoshis from Alice paid via a particular // preimage. @@ -41,61 +40,20 @@ func testSingleHopInvoice(net *lntest.NetworkHarness, t *harnessTest) { RPreimage: preimage, Value: paymentAmt, } - invoiceResp, err := net.Bob.AddInvoice(ctxb, invoice) - if err != nil { - t.Fatalf("unable to add invoice: %v", err) - } - - // Wait for Alice to recognize and advertise the new channel generated - // above. - err = net.Alice.WaitForNetworkChannelOpen(chanPoint) - if err != nil { - t.Fatalf("alice didn't advertise channel before "+ - "timeout: %v", err) - } - err = net.Bob.WaitForNetworkChannelOpen(chanPoint) - if err != nil { - t.Fatalf("bob didn't advertise channel before "+ - "timeout: %v", err) - } + invoiceResp := bob.RPC.AddInvoice(invoice) // With the invoice for Bob added, send a payment towards Alice paying // to the above generated invoice. - resp := sendAndAssertSuccess( - t, net.Alice, &routerrpc.SendPaymentRequest{ - PaymentRequest: invoiceResp.PaymentRequest, - TimeoutSeconds: 60, - FeeLimitMsat: noFeeLimitMsat, - }, - ) - if hex.EncodeToString(preimage) != resp.PaymentPreimage { - t.Fatalf("preimage mismatch: expected %v, got %v", preimage, - resp.PaymentPreimage) - } + ht.CompletePaymentRequests(alice, []string{invoiceResp.PaymentRequest}) // Bob's invoice should now be found and marked as settled. - payHash := &lnrpc.PaymentHash{ - RHash: invoiceResp.RHash, - } - ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) - dbInvoice, err := net.Bob.LookupInvoice(ctxt, payHash) - if err != nil { - t.Fatalf("unable to lookup invoice: %v", err) - } - if !dbInvoice.Settled { // nolint:staticcheck - t.Fatalf("bob's invoice should be marked as settled: %v", - spew.Sdump(dbInvoice)) - } + dbInvoice := bob.RPC.LookupInvoice(invoiceResp.RHash) + require.Equal(ht, lnrpc.Invoice_SETTLED, dbInvoice.State, + "bob's invoice should be marked as settled") // With the payment completed all balance related stats should be // properly updated. - err = wait.NoError( - assertAmountSent(paymentAmt, net.Alice, net.Bob), - 3*time.Second, - ) - if err != nil { - t.Fatalf(err.Error()) - } + assertAmountPaid(paymentAmt) // Create another invoice for Bob, this time leaving off the preimage // to one will be randomly generated. We'll test the proper @@ -104,92 +62,58 @@ func testSingleHopInvoice(net *lntest.NetworkHarness, t *harnessTest) { Memo: "test3", Value: paymentAmt, } - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - invoiceResp, err = net.Bob.AddInvoice(ctxt, invoice) - if err != nil { - t.Fatalf("unable to add invoice: %v", err) - } + invoiceResp = bob.RPC.AddInvoice(invoice) // Next send another payment, but this time using a zpay32 encoded // invoice rather than manually specifying the payment details. - sendAndAssertSuccess( - t, net.Alice, &routerrpc.SendPaymentRequest{ - PaymentRequest: invoiceResp.PaymentRequest, - TimeoutSeconds: 60, - FeeLimitMsat: noFeeLimitMsat, - }, - ) + ht.CompletePaymentRequests(alice, []string{invoiceResp.PaymentRequest}) // The second payment should also have succeeded, with the balances // being update accordingly. - err = wait.NoError( - assertAmountSent(2*paymentAmt, net.Alice, net.Bob), - 3*time.Second, - ) - if err != nil { - t.Fatalf(err.Error()) - } + assertAmountPaid(paymentAmt * 2) // Next send a keysend payment. keySendPreimage := lntypes.Preimage{3, 4, 5, 11} keySendHash := keySendPreimage.Hash() - sendAndAssertSuccess( - t, net.Alice, &routerrpc.SendPaymentRequest{ - Dest: net.Bob.PubKey[:], - Amt: paymentAmt, - FinalCltvDelta: 40, - PaymentHash: keySendHash[:], - DestCustomRecords: map[uint64][]byte{ - record.KeySendType: keySendPreimage[:], - }, - TimeoutSeconds: 60, - FeeLimitMsat: noFeeLimitMsat, + req := &routerrpc.SendPaymentRequest{ + Dest: bob.PubKey[:], + Amt: paymentAmt, + FinalCltvDelta: 40, + PaymentHash: keySendHash[:], + DestCustomRecords: map[uint64][]byte{ + record.KeySendType: keySendPreimage[:], }, - ) + TimeoutSeconds: 60, + FeeLimitMsat: noFeeLimitMsat, + } + ht.SendPaymentAssertSettled(alice, req) // The keysend payment should also have succeeded, with the balances // being update accordingly. - err = wait.NoError( - assertAmountSent(3*paymentAmt, net.Alice, net.Bob), - 3*time.Second, - ) - if err != nil { - t.Fatalf(err.Error()) - } + assertAmountPaid(paymentAmt * 3) // Assert that the invoice has the proper AMP fields set, since the // legacy keysend payment should have been promoted into an AMP payment // internally. - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - keysendInvoice, err := net.Bob.LookupInvoice( - ctxt, &lnrpc.PaymentHash{ - RHash: keySendHash[:], - }, - ) - require.NoError(t.t, err) - require.Equal(t.t, 1, len(keysendInvoice.Htlcs)) + keysendInvoice := bob.RPC.LookupInvoice(keySendHash[:]) + require.Len(ht, keysendInvoice.Htlcs, 1) htlc := keysendInvoice.Htlcs[0] - require.Equal(t.t, uint64(0), htlc.MppTotalAmtMsat) - require.Nil(t.t, htlc.Amp) + require.Zero(ht, htlc.MppTotalAmtMsat) + require.Nil(ht, htlc.Amp) // Now create an invoice and specify routing hints. // We will test that the routing hints are encoded properly. hintChannel := lnwire.ShortChannelID{BlockHeight: 10} - bobPubKey := hex.EncodeToString(net.Bob.PubKey[:]) - hints := []*lnrpc.RouteHint{ - { - HopHints: []*lnrpc.HopHint{ - { - NodeId: bobPubKey, - ChanId: hintChannel.ToUint64(), - FeeBaseMsat: 1, - FeeProportionalMillionths: 1000000, - CltvExpiryDelta: 20, - }, - }, - }, + bobPubKey := hex.EncodeToString(bob.PubKey[:]) + hint := &lnrpc.HopHint{ + NodeId: bobPubKey, + ChanId: hintChannel.ToUint64(), + FeeBaseMsat: 1, + FeeProportionalMillionths: 1000000, + CltvExpiryDelta: 20, } + hints := []*lnrpc.RouteHint{{HopHints: []*lnrpc.HopHint{hint}}} invoice = &lnrpc.Invoice{ Memo: "hints", @@ -197,43 +121,21 @@ func testSingleHopInvoice(net *lntest.NetworkHarness, t *harnessTest) { RouteHints: hints, } - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - invoiceResp, err = net.Bob.AddInvoice(ctxt, invoice) - if err != nil { - t.Fatalf("unable to add invoice: %v", err) - } - payreq, err := net.Bob.DecodePayReq(ctxt, &lnrpc.PayReqString{PayReq: invoiceResp.PaymentRequest}) - if err != nil { - t.Fatalf("failed to decode payment request %v", err) - } - if len(payreq.RouteHints) != 1 { - t.Fatalf("expected one routing hint") - } + invoiceResp = bob.RPC.AddInvoice(invoice) + payreq := bob.RPC.DecodePayReq(invoiceResp.PaymentRequest) + require.Len(ht, payreq.RouteHints, 1, "expected one routing hint") routingHint := payreq.RouteHints[0] - if len(routingHint.HopHints) != 1 { - t.Fatalf("expected one hop hint") - } - hopHint := routingHint.HopHints[0] - if hopHint.FeeProportionalMillionths != 1000000 { - t.Fatalf("wrong FeeProportionalMillionths %v", - hopHint.FeeProportionalMillionths) - } - if hopHint.NodeId != bobPubKey { - t.Fatalf("wrong NodeId %v", - hopHint.NodeId) - } - if hopHint.ChanId != hintChannel.ToUint64() { - t.Fatalf("wrong ChanId %v", - hopHint.ChanId) - } - if hopHint.FeeBaseMsat != 1 { - t.Fatalf("wrong FeeBaseMsat %v", - hopHint.FeeBaseMsat) - } - if hopHint.CltvExpiryDelta != 20 { - t.Fatalf("wrong CltvExpiryDelta %v", - hopHint.CltvExpiryDelta) - } + require.Len(ht, routingHint.HopHints, 1, "expected one hop hint") - closeChannelAndAssert(t, net, net.Alice, chanPoint, false) + hopHint := routingHint.HopHints[0] + require.EqualValues(ht, 1000000, hopHint.FeeProportionalMillionths, + "wrong FeeProportionalMillionths") + require.Equal(ht, bobPubKey, hopHint.NodeId, "wrong NodeId") + require.Equal(ht, hintChannel.ToUint64(), hopHint.ChanId, + "wrong ChanId") + require.EqualValues(ht, 1, hopHint.FeeBaseMsat, "wrong FeeBaseMsat") + require.EqualValues(ht, 20, hopHint.CltvExpiryDelta, + "wrong CltvExpiryDelta") + + ht.CloseChannel(alice, cp) } diff --git a/lntest/itest/lnd_test_list_on_test.go b/lntest/itest/lnd_test_list_on_test.go index c6da53385..f91382ab8 100644 --- a/lntest/itest/lnd_test_list_on_test.go +++ b/lntest/itest/lnd_test_list_on_test.go @@ -4,10 +4,6 @@ package itest var allTestCases = []*testCase{ - { - name: "single hop invoice", - test: testSingleHopInvoice, - }, { name: "multiple channel creation and update subscription", test: testBasicChannelCreationAndUpdates,