Skip to content

Instantly share code, notes, and snippets.

@w3irdrobot
Created March 27, 2022 15:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save w3irdrobot/3553923e2237e65bbaa4c622c2641a62 to your computer and use it in GitHub Desktop.
Save w3irdrobot/3553923e2237e65bbaa4c622c2641a62 to your computer and use it in GitHub Desktop.
LND Test Extra Hop
From 40fc90640aeef70790012f19054199190294447b Mon Sep 17 00:00:00 2001
From: Alex Sears <me@alexsears.com>
Date: Sun, 27 Mar 2022 11:36:30 -0400
Subject: [PATCH] Add extra hop to single hop invoice test
---
lntest/harness.go | 29 +++++--
lntest/itest/lnd_single_hop_invoice_test.go | 84 ++++++++++++++++++++-
lntest/itest/lnd_test.go | 19 ++++-
3 files changed, 121 insertions(+), 11 deletions(-)
diff --git a/lntest/harness.go b/lntest/harness.go
index 0d8bf520d..c14352926 100644
--- a/lntest/harness.go
+++ b/lntest/harness.go
@@ -61,6 +61,7 @@ type NetworkHarness struct {
// created to be the initial participants of the test network.
Alice *HarnessNode
Bob *HarnessNode
+ Carol *HarnessNode
// embeddedEtcd is set to true if new nodes are to be created with an
// embedded etcd backend instead of just bbolt.
@@ -151,7 +152,7 @@ func (n *NetworkHarness) SetUp(testCase string, lndArgs []string) error {
// their respective RPC clients.
var wg sync.WaitGroup
errChan := make(chan error, 2)
- wg.Add(2)
+ wg.Add(3)
go func() {
defer wg.Done()
node, err := n.NewNode("Alice", lndArgs)
@@ -170,6 +171,15 @@ func (n *NetworkHarness) SetUp(testCase string, lndArgs []string) error {
}
n.Bob = node
}()
+ go func() {
+ defer wg.Done()
+ node, err := n.NewNode("Carol", lndArgs)
+ if err != nil {
+ errChan <- err
+ return
+ }
+ n.Carol = node
+ }()
wg.Wait()
select {
case err := <-errChan:
@@ -183,7 +193,7 @@ func (n *NetworkHarness) SetUp(testCase string, lndArgs []string) error {
addrReq := &lnrpc.NewAddressRequest{
Type: lnrpc.AddressType_WITNESS_PUBKEY_HASH,
}
- clients := []lnrpc.LightningClient{n.Alice, n.Bob}
+ clients := []lnrpc.LightningClient{n.Alice, n.Bob, n.Carol}
for _, client := range clients {
for i := 0; i < 10; i++ {
resp, err := client.NewAddress(ctxb, addrReq)
@@ -216,11 +226,16 @@ func (n *NetworkHarness) SetUp(testCase string, lndArgs []string) error {
return err
}
- // Finally, make a connection between both of the nodes.
+ // Make a connection between both of the nodes.
if err := n.ConnectNodes(ctxb, n.Alice, n.Bob); err != nil {
return err
}
+ // Finally, make a connection between both of the nodes.
+ if err := n.ConnectNodes(ctxb, n.Bob, n.Carol); err != nil {
+ return err
+ }
+
// Now block until both wallets have fully synced up.
expectedBalance := int64(btcutil.SatoshiPerBitcoin * 10)
balReq := &lnrpc.WalletBalanceRequest{}
@@ -239,9 +254,13 @@ out:
if err != nil {
return err
}
-
+ carolResp, err := n.Carol.WalletBalance(ctxb, balReq)
+ if err != nil {
+ return err
+ }
if aliceResp.ConfirmedBalance == expectedBalance &&
- bobResp.ConfirmedBalance == expectedBalance {
+ bobResp.ConfirmedBalance == expectedBalance &&
+ carolResp.ConfirmedBalance == expectedBalance {
break out
}
case <-balanceTimeout:
diff --git a/lntest/itest/lnd_single_hop_invoice_test.go b/lntest/itest/lnd_single_hop_invoice_test.go
index d0ed525bc..5c64de2d5 100644
--- a/lntest/itest/lnd_single_hop_invoice_test.go
+++ b/lntest/itest/lnd_single_hop_invoice_test.go
@@ -25,7 +25,7 @@ func testSingleHopInvoice(net *lntest.NetworkHarness, t *harnessTest) {
// the sole funder of the channel.
ctxt, _ := context.WithTimeout(ctxb, channelOpenTimeout)
chanAmt := btcutil.Amount(100000)
- chanPoint := openChannelAndAssert(
+ a2bChanPoint := openChannelAndAssert(
ctxt, t, net, net.Alice, net.Bob,
lntest.OpenChannelParams{
Amt: chanAmt,
@@ -50,12 +50,12 @@ func testSingleHopInvoice(net *lntest.NetworkHarness, t *harnessTest) {
// Wait for Alice to recognize and advertise the new channel generated
// above.
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
- err = net.Alice.WaitForNetworkChannelOpen(ctxt, chanPoint)
+ err = net.Alice.WaitForNetworkChannelOpen(ctxt, a2bChanPoint)
if err != nil {
t.Fatalf("alice didn't advertise channel before "+
"timeout: %v", err)
}
- err = net.Bob.WaitForNetworkChannelOpen(ctxt, chanPoint)
+ err = net.Bob.WaitForNetworkChannelOpen(ctxt, a2bChanPoint)
if err != nil {
t.Fatalf("bob didn't advertise channel before "+
"timeout: %v", err)
@@ -101,6 +101,82 @@ func testSingleHopInvoice(net *lntest.NetworkHarness, t *harnessTest) {
t.Fatalf(err.Error())
}
+ // Now that the channel is open, create an invoice for Carol which
+ // expects a payment of 1000 satoshis from Bob paid via a particular
+ // preimage.
+ ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout)
+ b2cChanPoint := openChannelAndAssert(
+ ctxt, t, net, net.Bob, net.Carol,
+ lntest.OpenChannelParams{
+ Amt: chanAmt,
+ },
+ )
+
+ preimage = bytes.Repeat([]byte("B"), 32)
+ invoice = &lnrpc.Invoice{
+ Memo: "testing",
+ RPreimage: preimage,
+ Value: paymentAmt,
+ }
+ invoiceResp, err = net.Carol.AddInvoice(ctxb, invoice)
+ if err != nil {
+ t.Fatalf("unable to add invoice: %v", err)
+ }
+
+ // Wait for Bob to recognize and advertise the new channel generated
+ // above.
+ ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
+ err = net.Bob.WaitForNetworkChannelOpen(ctxt, b2cChanPoint)
+ if err != nil {
+ t.Fatalf("bob didn't advertise channel before "+
+ "timeout: %v", err)
+ }
+ err = net.Carol.WaitForNetworkChannelOpen(ctxt, b2cChanPoint)
+ if err != nil {
+ t.Fatalf("carol didn't advertise channel before "+
+ "timeout: %v", err)
+ }
+
+ // With the invoice for Carol added, send a payment towards Bob paying
+ // to the above generated invoice.
+ ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
+ resp = sendAndAssertSuccess(
+ ctxt, t, net.Bob,
+ &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)
+ }
+
+ // Carol's invoice should now be found and marked as settled.
+ payHash = &lnrpc.PaymentHash{
+ RHash: invoiceResp.RHash,
+ }
+ ctxt, _ = context.WithTimeout(ctxt, defaultTimeout)
+ dbInvoice, err = net.Carol.LookupInvoice(ctxt, payHash)
+ if err != nil {
+ t.Fatalf("unable to lookup invoice: %v", err)
+ }
+ if !dbInvoice.Settled { // nolint:staticcheck
+ t.Fatalf("carol's invoice should be marked as settled: %v",
+ spew.Sdump(dbInvoice))
+ }
+
+ // With the payment completed all balance related stats should be
+ // properly updated.
+ err = wait.NoError(
+ assertAmountSentWithIndex(paymentAmt, net.Bob, 1, net.Carol, 0),
+ 3*time.Second,
+ )
+ if err != nil {
+ t.Fatalf(err.Error())
+ }
+
// Create another invoice for Bob, this time leaving off the preimage
// to one will be randomly generated. We'll test the proper
// encoding/decoding of the zpay32 payment requests.
@@ -244,5 +320,5 @@ func testSingleHopInvoice(net *lntest.NetworkHarness, t *harnessTest) {
}
ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout)
- closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint, false)
+ closeChannelAndAssert(ctxt, t, net, net.Alice, a2bChanPoint, false)
}
diff --git a/lntest/itest/lnd_test.go b/lntest/itest/lnd_test.go
index d3a86d4f3..99c05ad96 100644
--- a/lntest/itest/lnd_test.go
+++ b/lntest/itest/lnd_test.go
@@ -4397,6 +4397,21 @@ func findSweepInDetails(t *testing.T, sweepTxid string,
// NOTE: This method assumes that each node only has one channel, and it is the
// channel used to send the payment.
func assertAmountSent(amt btcutil.Amount, sndr, rcvr *lntest.HarnessNode) func() error {
+ return assertAmountSentWithIndex(amt, sndr, 0, rcvr, 0)
+}
+
+// assertAmountSentWithIndex generates a closure which queries listchannels for sndr and
+// rcvr, and asserts that sndr sent amt satoshis, and that rcvr received amt
+// satoshis.
+//
+// NOTE: The indexes are the index of the channel for each side to check
+func assertAmountSentWithIndex(
+ amt btcutil.Amount,
+ sndr *lntest.HarnessNode,
+ sndrIndex int,
+ rcvr *lntest.HarnessNode,
+ rcvrIndex int,
+) func() error {
return func() error {
// Both channels should also have properly accounted from the
// amount that has been sent/received over the channel.
@@ -4408,7 +4423,7 @@ func assertAmountSent(amt btcutil.Amount, sndr, rcvr *lntest.HarnessNode) func()
return fmt.Errorf("unable to query for %s's channel "+
"list: %v", sndr.Name(), err)
}
- sndrSatoshisSent := sndrListChannels.Channels[0].TotalSatoshisSent
+ sndrSatoshisSent := sndrListChannels.Channels[sndrIndex].TotalSatoshisSent
if sndrSatoshisSent != int64(amt) {
return fmt.Errorf("%s's satoshis sent is incorrect "+
"got %v, expected %v", sndr.Name(),
@@ -4421,7 +4436,7 @@ func assertAmountSent(amt btcutil.Amount, sndr, rcvr *lntest.HarnessNode) func()
return fmt.Errorf("unable to query for %s's channel "+
"list: %v", rcvr.Name(), err)
}
- rcvrSatoshisReceived := rcvrListChannels.Channels[0].TotalSatoshisReceived
+ rcvrSatoshisReceived := rcvrListChannels.Channels[rcvrIndex].TotalSatoshisReceived
if rcvrSatoshisReceived != int64(amt) {
return fmt.Errorf("%s's satoshis received is "+
"incorrect got %v, expected %v", rcvr.Name(),
--
2.32.0
Building itest btcd and lnd.
CGO_ENABLED=0 GO111MODULE=on go build -v -tags="rpctest" -o lntest/itest/btcd-itest -ldflags " -X github.com/lightningnetwork/lnd/build.Commit=v0.12.0-beta-522-g40fc90640 -X github.com/lightningnetwork/lnd/build.CommitHash=40fc90640aeef70790012f19054199190294447b -X github.com/lightningnetwork/lnd/build.GoVersion=go1.18 -X github.com/lightningnetwork/lnd/build.RawTags=dev,autopilotrpc,chainrpc,invoicesrpc,routerrpc,signrpc,verrpc,walletrpc,watchtowerrpc,wtclientrpc,rpctest,btcd" github.com/btcsuite/btcd
github.com/btcsuite/btcd
CGO_ENABLED=0 GO111MODULE=on go build -v -tags="dev autopilotrpc chainrpc invoicesrpc routerrpc signrpc verrpc walletrpc watchtowerrpc wtclientrpc rpctest btcd" -o lntest/itest/lnd-itest -ldflags " -X github.com/lightningnetwork/lnd/build.Commit=v0.12.0-beta-522-g40fc90640 -X github.com/lightningnetwork/lnd/build.CommitHash=40fc90640aeef70790012f19054199190294447b -X github.com/lightningnetwork/lnd/build.GoVersion=go1.18 -X github.com/lightningnetwork/lnd/build.RawTags=dev,autopilotrpc,chainrpc,invoicesrpc,routerrpc,signrpc,verrpc,walletrpc,watchtowerrpc,wtclientrpc,rpctest,btcd" github.com/lightningnetwork/lnd/cmd/lnd
github.com/lightningnetwork/lnd/cmd/lnd
Building itest binary for btcd backend.
CGO_ENABLED=0 GO111MODULE=on go test -v ./lntest/itest -tags="dev autopilotrpc chainrpc invoicesrpc routerrpc signrpc verrpc walletrpc watchtowerrpc wtclientrpc rpctest btcd" -c -o lntest/itest/itest.test
Running integration tests with btcd backend.
rm -rf lntest/itest/*.log lntest/itest/.logs-*; date
Sun Mar 27 11:38:28 AM EDT 2022
EXEC_SUFFIX= scripts/itest_part.sh 0 1 -test.run="TestLightningNetworkDaemon/.*-of-.*/.*/single_hop_invoice" -test.timeout=60m
/home/alexsears/projects/github.com/lightningnetwork/lnd/lntest/itest/itest.test -test.v -test.run=TestLightningNetworkDaemon/.*-of-.*/.*/single_hop_invoice -test.timeout=60m -logoutput -goroutinedump -logdir=.logs-tranche0 -lndexec=/home/alexsears/projects/github.com/lightningnetwork/lnd/lntest/itest/lnd-itest -btcdexec=/home/alexsears/projects/github.com/lightningnetwork/lnd/lntest/itest/btcd-itest -splittranches=1 -runtranche=0
=== RUN TestLightningNetworkDaemon
=== RUN TestLightningNetworkDaemon/15-of-78/btcd/single_hop_invoice
--- PASS: TestLightningNetworkDaemon (9.16s)
--- PASS: TestLightningNetworkDaemon/15-of-78/btcd/single_hop_invoice (8.46s)
PASS
lntest/itest/log_check_errors.sh
No itest errors detected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment