Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[itests] Bitcoind integration test #1583

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ env:
- RACE=true
- ITEST=true
- NEUTRINO_ITEST=true
- BITCOIND_ITEST=true
- COVER=true

sudo: required
Expand All @@ -35,6 +36,9 @@ script:
# Run neutrino integration tests.
- 'if [ "$NEUTRINO_ITEST" = true ]; then make travis-itest backend=neutrino; fi'

# Run bitcoind integration tests.
- 'if [ "$BITCOIND_ITEST" = true ]; then make travis-itest backend=bitcoind; fi'

# Run unit tests and generate coverage report.
- 'if [ "$COVER" = true ]; then make travis-cover; fi'

Expand Down
185 changes: 185 additions & 0 deletions lntest/bitcoind.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
// +build bitcoind

package lntest

import (
"fmt"
"io/ioutil"
"math/rand"
"os"
"os/exec"
"path/filepath"
"time"

"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/rpcclient"
)

// logDir is the name of the temporary log directory.
const logDir = "./.backendlogs"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC, this is defined elsewhere already?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is re-defined since it is behind a different build flag.


// BitcoindBackendConfig is an implementation of the BackendConfig interface
// backed by a Bitcoind node.
type BitcoindBackendConfig struct {
rpcHost string
rpcUser string
rpcPass string
zmqBlockPath string
zmqTxPath string
p2pPort int
rpcClient *rpcclient.Client

// minerAddr is the p2p address of the miner to connect to.
minerAddr string
}

// A compile time assertion to ensure BitcoindBackendConfig meets the
// BackendConfig interface.
var _ BackendConfig = (*BitcoindBackendConfig)(nil)

// GenArgs returns the arguments needed to be passed to LND at startup for
// using this node as a chain backend.
func (b BitcoindBackendConfig) GenArgs() []string {
var args []string
args = append(args, "--bitcoin.node=bitcoind")
args = append(args, fmt.Sprintf("--bitcoind.rpchost=%v", b.rpcHost))
args = append(args, fmt.Sprintf("--bitcoind.rpcuser=%v", b.rpcUser))
args = append(args, fmt.Sprintf("--bitcoind.rpcpass=%v", b.rpcPass))
args = append(args, fmt.Sprintf("--bitcoind.zmqpubrawblock=%v",
b.zmqBlockPath))
args = append(args, fmt.Sprintf("--bitcoind.zmqpubrawtx=%v",
b.zmqTxPath))

return args
}

// ConnectMiner is called to establish a connection to the test miner.
func (b BitcoindBackendConfig) ConnectMiner() error {
return b.rpcClient.AddNode(b.minerAddr, rpcclient.ANAdd)
}

// DisconnectMiner is called to disconnect the miner.
func (b BitcoindBackendConfig) DisconnectMiner() error {
return b.rpcClient.AddNode(b.minerAddr, rpcclient.ANRemove)
}

// Name returns the name of the backend type.
func (b BitcoindBackendConfig) Name() string {
return "bitcoind"
}

// NewBackend starts a bitcoind node and returns a BitoindBackendConfig for
// that node.
func NewBackend(miner string, netParams *chaincfg.Params) (
*BitcoindBackendConfig, func(), error) {

if netParams != &chaincfg.RegressionNetParams {
return nil, nil, fmt.Errorf("only regtest supported")
}

if err := os.MkdirAll(logDir, 0700); err != nil {
return nil, nil, err
}

logFile, err := filepath.Abs(logDir + "/bitcoind.log")
wpaulino marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, nil, err
}

tempBitcoindDir, err := ioutil.TempDir("", "bitcoind")
if err != nil {
return nil, nil,
fmt.Errorf("unable to create temp directory: %v", err)
}

zmqBlockPath := "ipc:///" + tempBitcoindDir + "/blocks.socket"
zmqTxPath := "ipc:///" + tempBitcoindDir + "/txs.socket"
rpcPort := rand.Int()%(65536-1024) + 1024
p2pPort := rand.Int()%(65536-1024) + 1024

bitcoind := exec.Command(
"bitcoind",
"-datadir="+tempBitcoindDir,
"-debug",
"-regtest",
"-txindex",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we run without this? Would ensure that the fallback path (no txindex, scan manually) is tested instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could run it with both options, though this would significantly increase the running time of the current integration tests. On the other hand, we properly test both variants in the unit tests of the notifier.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could randomize it lol

"-whitelist=127.0.0.1", // whitelist localhost to speed up relay
wpaulino marked this conversation as resolved.
Show resolved Hide resolved
"-rpcauth=weks:469e9bb14ab2360f8e226efed5ca6f"+
"d$507c670e800a95284294edb5773b05544b"+
"220110063096c221be9933c82d38e1",
fmt.Sprintf("-rpcport=%d", rpcPort),
fmt.Sprintf("-port=%d", p2pPort),
"-disablewallet",
"-zmqpubrawblock="+zmqBlockPath,
"-zmqpubrawtx="+zmqTxPath,
"-debuglogfile="+logFile,
)

err = bitcoind.Start()
if err != nil {
os.RemoveAll(tempBitcoindDir)
return nil, nil, fmt.Errorf("couldn't start bitcoind: %v", err)
}

cleanUp := func() {
bitcoind.Process.Kill()
bitcoind.Wait()

// After shutting down the chain backend, we'll make a copy of
// the log file before deleting the temporary log dir.
err := CopyFile("./output_bitcoind_chainbackend.log", logFile)
if err != nil {
fmt.Printf("unable to copy file: %v\n", err)
}
if err = os.RemoveAll(logDir); err != nil {
fmt.Printf("Cannot remove dir %s: %v\n", logDir, err)
}

os.RemoveAll(tempBitcoindDir)
}

// Allow process to start.
time.Sleep(1 * time.Second)

rpcHost := fmt.Sprintf("127.0.0.1:%d", rpcPort)
rpcUser := "weks"
rpcPass := "weks"

rpcCfg := rpcclient.ConnConfig{
Host: rpcHost,
User: rpcUser,
Pass: rpcPass,
DisableConnectOnNew: true,
DisableAutoReconnect: false,
DisableTLS: true,
HTTPPostMode: true,
}

client, err := rpcclient.New(&rpcCfg, nil)
if err != nil {
cleanUp()
return nil, nil, fmt.Errorf("unable to create rpc client: %v",
err)
}

// We start by adding the miner to the bitcoind addnode list. We do
// this instead of connecting using command line flags, because it will
// allow us to disconnect the miner using the AddNode command later.
if err := client.AddNode(miner, rpcclient.ANAdd); err != nil {
cleanUp()
return nil, nil, fmt.Errorf("unable to add node: %v", err)
}

bd := BitcoindBackendConfig{
rpcHost: rpcHost,
rpcUser: rpcUser,
rpcPass: rpcPass,
zmqBlockPath: zmqBlockPath,
zmqTxPath: zmqTxPath,
p2pPort: p2pPort,
rpcClient: client,
minerAddr: miner,
}

return &bd, cleanUp, nil
}
9 changes: 7 additions & 2 deletions lntest/btcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ type BtcdBackendConfig struct {
minerAddr string
}

// A compile time assertion to ensure BtcdBackendConfig meets the BackendConfig
// interface.
var _ BackendConfig = (*BtcdBackendConfig)(nil)

// GenArgs returns the arguments needed to be passed to LND at startup for
// using this node as a chain backend.
func (b BtcdBackendConfig) GenArgs() []string {
Expand Down Expand Up @@ -67,7 +71,9 @@ func (b BtcdBackendConfig) Name() string {
// NewBackend starts a new rpctest.Harness and returns a BtcdBackendConfig for
// that node. miner should be set to the P2P address of the miner to connect
// to.
func NewBackend(miner string) (*BtcdBackendConfig, func(), error) {
func NewBackend(miner string, netParams *chaincfg.Params) (
*BtcdBackendConfig, func(), error) {

args := []string{
"--rejectnonstd",
"--txindex",
Expand All @@ -76,7 +82,6 @@ func NewBackend(miner string) (*BtcdBackendConfig, func(), error) {
"--logdir=" + logDir,
"--connect=" + miner,
}
netParams := &chaincfg.SimNetParams
chainBackend, err := rpctest.New(netParams, nil, args)
if err != nil {
return nil, nil, fmt.Errorf("unable to create btcd node: %v", err)
Expand Down
27 changes: 16 additions & 11 deletions lntest/itest/lnd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import (
)

var (
harnessNetParams = &chaincfg.SimNetParams
harnessNetParams = &chaincfg.RegressionNetParams
)

const (
Expand Down Expand Up @@ -8853,7 +8853,6 @@ func testRejectHTLC(net *lntest.NetworkHarness, t *harnessTest) {
//
const chanAmt = btcutil.Amount(1000000)
ctxb := context.Background()
timeout := time.Duration(time.Second * 5)

// Create Carol with reject htlc flag.
carol, err := net.NewNode("Carol", []string{"--rejecthtlc"})
Expand Down Expand Up @@ -8885,7 +8884,7 @@ func testRejectHTLC(net *lntest.NetworkHarness, t *harnessTest) {
}

// Open a channel between Alice and Carol.
ctxt, _ := context.WithTimeout(ctxb, timeout)
ctxt, _ := context.WithTimeout(ctxb, channelOpenTimeout)
chanPointAlice := openChannelAndAssert(
ctxt, t, net, net.Alice, carol,
lntest.OpenChannelParams{
Expand All @@ -8894,7 +8893,7 @@ func testRejectHTLC(net *lntest.NetworkHarness, t *harnessTest) {
)

// Open a channel between Carol and Bob.
ctxt, _ = context.WithTimeout(ctxb, timeout)
ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout)
chanPointCarol := openChannelAndAssert(
ctxt, t, net, carol, net.Bob,
lntest.OpenChannelParams{
Expand Down Expand Up @@ -8934,7 +8933,7 @@ func testRejectHTLC(net *lntest.NetworkHarness, t *harnessTest) {
}

// Alice pays Carols invoice.
ctxt, _ = context.WithTimeout(ctxb, timeout)
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
err = completePaymentRequests(
ctxt, net.Alice, []string{resp.PaymentRequest}, true,
)
Expand All @@ -8959,7 +8958,7 @@ func testRejectHTLC(net *lntest.NetworkHarness, t *harnessTest) {
}

// Carol pays Bobs invoice.
ctxt, _ = context.WithTimeout(ctxb, timeout)
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
err = completePaymentRequests(
ctxt, carol, []string{resp.PaymentRequest}, true,
)
Expand Down Expand Up @@ -8987,7 +8986,7 @@ func testRejectHTLC(net *lntest.NetworkHarness, t *harnessTest) {
// Alice attempts to pay Bobs invoice. This payment should be rejected since
// we are using Carol as an intermediary hop, Carol is running lnd with
// --rejecthtlc.
ctxt, _ = context.WithTimeout(ctxb, timeout)
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
err = completePaymentRequests(
ctxt, net.Alice, []string{resp.PaymentRequest}, true,
)
Expand All @@ -9001,9 +9000,9 @@ func testRejectHTLC(net *lntest.NetworkHarness, t *harnessTest) {
}

// Close all channels.
ctxt, _ = context.WithTimeout(ctxb, timeout)
ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout)
closeChannelAndAssert(ctxt, t, net, net.Alice, chanPointAlice, false)
ctxt, _ = context.WithTimeout(ctxb, timeout)
ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout)
closeChannelAndAssert(ctxt, t, net, carol, chanPointCarol, false)
}

Expand Down Expand Up @@ -12760,6 +12759,10 @@ func testSendUpdateDisableChannel(net *lntest.NetworkHarness, t *harnessTest) {
},
)
mineBlocks(t, net, 1, 1)

// And finally, clean up the force closed channel by mining the
// sweeping transaction.
cleanupForceClose(t, net, net.Alice, chanPointAliceCarol)
}

// testAbandonChannel abandones a channel and asserts that it is no
Expand Down Expand Up @@ -14415,7 +14418,9 @@ func TestLightningNetworkDaemon(t *testing.T) {
}()

// Start a chain backend.
chainBackend, cleanUp, err := lntest.NewBackend(miner.P2PAddress())
chainBackend, cleanUp, err := lntest.NewBackend(
miner.P2PAddress(), harnessNetParams,
)
if err != nil {
ht.Fatalf("unable to start backend: %v", err)
}
Expand Down Expand Up @@ -14454,7 +14459,7 @@ func TestLightningNetworkDaemon(t *testing.T) {

// Next mine enough blocks in order for segwit and the CSV package
// soft-fork to activate on SimNet.
numBlocks := chaincfg.SimNetParams.MinerConfirmationWindow * 2
numBlocks := harnessNetParams.MinerConfirmationWindow * 2
if _, err := miner.Node.Generate(numBlocks); err != nil {
ht.Fatalf("unable to generate blocks: %v", err)
}
Expand Down
14 changes: 12 additions & 2 deletions lntest/neutrino.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,22 @@

package lntest

import "fmt"
import (
"fmt"

"github.com/btcsuite/btcd/chaincfg"
)

// NeutrinoBackendConfig is an implementation of the BackendConfig interface
// backed by a neutrino node.
type NeutrinoBackendConfig struct {
minerAddr string
}

// A compile time assertion to ensure NeutrinoBackendConfig meets the
// BackendConfig interface.
var _ BackendConfig = (*NeutrinoBackendConfig)(nil)

// GenArgs returns the arguments needed to be passed to LND at startup for
// using this node as a chain backend.
func (b NeutrinoBackendConfig) GenArgs() []string {
Expand All @@ -35,7 +43,9 @@ func (b NeutrinoBackendConfig) Name() string {
}

// NewBackend starts and returns a NeutrinoBackendConfig for the node.
func NewBackend(miner string) (*NeutrinoBackendConfig, func(), error) {
func NewBackend(miner string, _ *chaincfg.Params) (
*NeutrinoBackendConfig, func(), error) {

bd := &NeutrinoBackendConfig{
minerAddr: miner,
}
Expand Down