From f766268e8c7cf9dd332aaac55c45e9be999cc39d Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 4 May 2022 11:23:58 +0200 Subject: [PATCH] lnwallet/test: test against bitcoind-rpc-polling backend --- lnwallet/test/bitcoind/bitcoind_test.go | 12 ++- lnwallet/test/test_interface.go | 119 +++++++++++++++++++++++- 2 files changed, 124 insertions(+), 7 deletions(-) diff --git a/lnwallet/test/bitcoind/bitcoind_test.go b/lnwallet/test/bitcoind/bitcoind_test.go index a5df25281..b63ff9258 100644 --- a/lnwallet/test/bitcoind/bitcoind_test.go +++ b/lnwallet/test/bitcoind/bitcoind_test.go @@ -6,8 +6,14 @@ import ( lnwallettest "github.com/lightningnetwork/lnd/lnwallet/test" ) -// TestLightningWallet tests LightningWallet powered by bitcoind against our -// suite of interface tests. -func TestLightningWallet(t *testing.T) { +// TestLightningWalletBitcoindZMQ tests LightningWallet powered by bitcoind, +// using its ZMQ interface, against our suite of interface tests. +func TestLightningWalletBitcoindZMQ(t *testing.T) { lnwallettest.TestLightningWallet(t, "bitcoind") } + +// TestLightningWalletBitcoindRPCPolling tests LightningWallet powered by +// bitcoind, using its RPC interface, against our suite of interface tests. +func TestLightningWalletBitcoindRPCPolling(t *testing.T) { + lnwallettest.TestLightningWallet(t, "bitcoind-rpc-polling") +} diff --git a/lnwallet/test/test_interface.go b/lnwallet/test/test_interface.go index d5e496035..2a99c7287 100644 --- a/lnwallet/test/test_interface.go +++ b/lnwallet/test/test_interface.go @@ -6,7 +6,6 @@ import ( "encoding/hex" "fmt" "io/ioutil" - "math/rand" "net" "os" "os/exec" @@ -14,6 +13,7 @@ import ( "reflect" "runtime" "strings" + "sync/atomic" "testing" "time" @@ -96,6 +96,35 @@ var ( defaultMaxLocalCsvDelay uint16 = 10000 ) +var ( + // lastPort is the last port determined to be free for use by a new + // bitcoind server. It should be used atomically. + lastPort uint32 = 1024 +) + +// getFreePort returns the first port that is available for listening by a new +// embedded etcd server. It panics if no port is found and the maximum available +// TCP port is reached. +func getFreePort() int { + port := atomic.AddUint32(&lastPort, 1) + for port < 65535 { + // If there are no errors while attempting to listen on this + // port, close the socket and return it as available. + addr := fmt.Sprintf("127.0.0.1:%d", port) + l, err := net.Listen("tcp4", addr) + if err == nil { + err := l.Close() + if err == nil { + return int(port) + } + } + port = atomic.AddUint32(&lastPort, 1) + } + + // No ports available? Must be a mistake. + panic("no ports available for listening") +} + // assertProperBalance asserts than the total value of the unspent outputs // within the wallet are *exactly* amount. If unable to retrieve the current // balance, or the assertion fails, the test will halt with a fatal error. @@ -3377,7 +3406,7 @@ func runTests(t *testing.T, walletDriver *lnwallet.WalletDriver, zmqBlockHost := "ipc:///" + tempBitcoindDir + "/blocks.socket" zmqTxHost := "ipc:///" + tempBitcoindDir + "/tx.socket" defer os.RemoveAll(tempBitcoindDir) - rpcPort := rand.Int()%(65536-1024) + 1024 + rpcPort := getFreePort() bitcoind := exec.Command( "bitcoind", "-datadir="+tempBitcoindDir, @@ -3396,8 +3425,18 @@ func runTests(t *testing.T, walletDriver *lnwallet.WalletDriver, if err != nil { t.Fatalf("couldn't start bitcoind: %v", err) } - defer bitcoind.Wait() - defer bitcoind.Process.Kill() + + // Sanity check to ensure that the process did in fact + // start. + if bitcoind.Process == nil { + t.Fatalf("bitcoind cmd Process is not set " + + "after Start") + } + + defer func() { + _ = bitcoind.Process.Kill() + _ = bitcoind.Wait() + }() // Wait for the bitcoind instance to start up. @@ -3435,6 +3474,78 @@ func runTests(t *testing.T, walletDriver *lnwallet.WalletDriver, // Bob. aliceClient = chainConn.NewBitcoindClient() bobClient = chainConn.NewBitcoindClient() + + case "bitcoind-rpc-polling": + // Start a bitcoind instance. + tempBitcoindDir, err := ioutil.TempDir("", "bitcoind") + if err != nil { + t.Fatalf("unable to create temp directory: %v", err) + } + defer os.RemoveAll(tempBitcoindDir) + rpcPort := getFreePort() + bitcoind := exec.Command( + "bitcoind", + "-datadir="+tempBitcoindDir, + "-regtest", + "-connect="+miningNode.P2PAddress(), + "-txindex", + "-rpcauth=weks:469e9bb14ab2360f8e226efed5ca6f"+ + "d$507c670e800a95284294edb5773b05544b"+ + "220110063096c221be9933c82d38e1", + fmt.Sprintf("-rpcport=%d", rpcPort), + "-disablewallet", + ) + err = bitcoind.Start() + if err != nil { + t.Fatalf("couldn't start bitcoind: %v", err) + } + defer func() { + _ = bitcoind.Process.Kill() + _ = bitcoind.Wait() + }() + + // Sanity check to ensure that the process did in fact + // start. + if bitcoind.Process == nil { + t.Fatalf("bitcoind cmd Process is not set " + + "after Start") + } + + // Wait for the bitcoind instance to start up. + host := fmt.Sprintf("127.0.0.1:%d", rpcPort) + var chainConn *chain.BitcoindConn + err = wait.NoError(func() error { + chainConn, err = chain.NewBitcoindConn(&chain.BitcoindConfig{ + ChainParams: netParams, + Host: host, + User: "weks", + Pass: "weks", + PollingConfig: &chain.PollingConfig{ + BlockPollingInterval: time.Millisecond * 20, + TxPollingInterval: time.Millisecond * 20, + }, + // Fields only required for pruned nodes, not + // needed for these tests. + Dialer: nil, + PrunedModeMaxPeers: 0, + }) + if err != nil { + return err + } + + return chainConn.Start() + }, 10*time.Second) + if err != nil { + t.Fatalf("unable to establish connection to "+ + "bitcoind: %v", err) + } + defer chainConn.Stop() + + // Create a btcwallet bitcoind client for both Alice and + // Bob. + aliceClient = chainConn.NewBitcoindClient() + bobClient = chainConn.NewBitcoindClient() + default: t.Fatalf("unknown chain driver: %v", backEnd) }