diff --git a/lnd_test.go b/lnd_test.go index cb78e648..ab4e2c83 100644 --- a/lnd_test.go +++ b/lnd_test.go @@ -12970,9 +12970,14 @@ func TestLightningNetworkDaemon(t *testing.T) { } }() + chainBackend := lntest.BtcdBackendConfig{ + RPCConfig: btcdHarness.RPCConfig(), + P2PAddress: btcdHarness.P2PAddress(), + } + // First create the network harness to gain access to its // 'OnTxAccepted' call back. - lndHarness, err = lntest.NewNetworkHarness(btcdHarness) + lndHarness, err = lntest.NewNetworkHarness(btcdHarness, chainBackend) if err != nil { ht.Fatalf("unable to create lightning network harness: %v", err) } diff --git a/lntest/btcd.go b/lntest/btcd.go new file mode 100644 index 00000000..7cbe9f28 --- /dev/null +++ b/lntest/btcd.go @@ -0,0 +1,87 @@ +package lntest + +import ( + "encoding/hex" + "fmt" + "os" + + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/integration/rpctest" + "github.com/btcsuite/btcd/rpcclient" +) + +// logDir is the name of the temporary log directory. +const logDir = "./.backendlogs" + +// BtcdBackendConfig is an implementation of the BackendConfig interface +// backed by a btcd node. +type BtcdBackendConfig struct { + // RPCConfig houses the connection config to the backing btcd instance. + RPCConfig rpcclient.ConnConfig + + // P2PAddress is the p2p address of the btcd instance. + P2PAddress string +} + +// 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 { + var args []string + encodedCert := hex.EncodeToString(b.RPCConfig.Certificates) + args = append(args, "--bitcoin.node=btcd") + args = append(args, fmt.Sprintf("--btcd.rpchost=%v", b.RPCConfig.Host)) + args = append(args, fmt.Sprintf("--btcd.rpcuser=%v", b.RPCConfig.User)) + args = append(args, fmt.Sprintf("--btcd.rpcpass=%v", b.RPCConfig.Pass)) + args = append(args, fmt.Sprintf("--btcd.rawrpccert=%v", encodedCert)) + + return args +} + +// P2PAddr returns the address of this node to be used when connection over the +// Bitcoin P2P network. +func (b BtcdBackendConfig) P2PAddr() string { + return b.P2PAddress +} + +// NewBtcdBackend starts a new rpctest.Harness and returns a BtcdBackendConfig +// for that node. +func NewBtcdBackend() (*BtcdBackendConfig, func(), error) { + args := []string{ + "--rejectnonstd", + "--txindex", + "--trickleinterval=100ms", + "--debuglevel=debug", + "--logdir=" + logDir, + } + 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) + } + + if err := chainBackend.SetUp(false, 0); err != nil { + return nil, nil, fmt.Errorf("unable to set up btcd backend: %v", err) + } + + bd := &BtcdBackendConfig{ + RPCConfig: chainBackend.RPCConfig(), + P2PAddress: chainBackend.P2PAddress(), + } + + cleanUp := func() { + chainBackend.TearDown() + + // After shutting down the chain backend, we'll make a copy of + // the log file before deleting the temporary log dir. + logFile := logDir + "/" + netParams.Name + "/btcd.log" + err := CopyFile("./output_btcd_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) + } + } + + return bd, cleanUp, nil +} diff --git a/lntest/harness.go b/lntest/harness.go index 0a3a9d2e..70ab825c 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -16,7 +16,6 @@ import ( "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/integration/rpctest" - "github.com/btcsuite/btcd/rpcclient" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" @@ -50,13 +49,16 @@ const ( // The harness by default is created with two active nodes on the network: // Alice and Bob. type NetworkHarness struct { - rpcConfig rpcclient.ConnConfig netParams *chaincfg.Params // Miner is a reference to a running full node that can be used to create // new blocks on the network. Miner *rpctest.Harness + // BackendCfg houses the information necessary to use a node as LND + // chain backend, such as rpc configuration, P2P information etc. + BackendCfg BackendConfig + activeNodes map[int]*HarnessNode nodesByPub map[string]*HarnessNode @@ -82,7 +84,7 @@ type NetworkHarness struct { // TODO(roasbeef): add option to use golang's build library to a binary of the // current repo. This will save developers from having to manually `go install` // within the repo each time before changes -func NewNetworkHarness(r *rpctest.Harness) (*NetworkHarness, error) { +func NewNetworkHarness(r *rpctest.Harness, b BackendConfig) (*NetworkHarness, error) { n := NetworkHarness{ activeNodes: make(map[int]*HarnessNode), nodesByPub: make(map[string]*HarnessNode), @@ -91,7 +93,7 @@ func NewNetworkHarness(r *rpctest.Harness) (*NetworkHarness, error) { lndErrorChan: make(chan error), netParams: r.ActiveNet, Miner: r, - rpcConfig: r.RPCConfig(), + BackendCfg: b, quit: make(chan struct{}), } go n.networkWatcher() @@ -355,11 +357,11 @@ func (n *NetworkHarness) RestoreNodeWithSeed(name string, extraArgs []string, func (n *NetworkHarness) newNode(name string, extraArgs []string, hasSeed bool) (*HarnessNode, error) { node, err := newNode(nodeConfig{ - Name: name, - HasSeed: hasSeed, - RPCConfig: &n.rpcConfig, - NetParams: n.netParams, - ExtraArgs: extraArgs, + Name: name, + HasSeed: hasSeed, + BackendCfg: n.BackendCfg, + NetParams: n.netParams, + ExtraArgs: extraArgs, }) if err != nil { return nil, err diff --git a/lntest/node.go b/lntest/node.go index d518dd95..55581367 100644 --- a/lntest/node.go +++ b/lntest/node.go @@ -22,7 +22,6 @@ import ( "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" - "github.com/btcsuite/btcd/rpcclient" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" "github.com/go-errors/errors" @@ -91,12 +90,24 @@ func generateListeningPorts() (int, int, int) { return p2p, rpc, rest } +// BackendConfig is an interface that abstracts away the specific chain backend +// node implementation. +type BackendConfig interface { + // GenArgs returns the arguments needed to be passed to LND at startup + // for using this node as a chain backend. + GenArgs() []string + + // P2PAddr returns the address of this node to be used when connection + // over the Bitcoin P2P network. + P2PAddr() string +} + type nodeConfig struct { - Name string - RPCConfig *rpcclient.ConnConfig - NetParams *chaincfg.Params - BaseDir string - ExtraArgs []string + Name string + BackendCfg BackendConfig + NetParams *chaincfg.Params + BaseDir string + ExtraArgs []string DataDir string LogDir string @@ -144,16 +155,13 @@ func (cfg nodeConfig) genArgs() []string { args = append(args, "--bitcoin.regtest") } - encodedCert := hex.EncodeToString(cfg.RPCConfig.Certificates) + backendArgs := cfg.BackendCfg.GenArgs() + args = append(args, backendArgs...) args = append(args, "--bitcoin.active") args = append(args, "--nobootstrap") args = append(args, "--debuglevel=debug") args = append(args, "--bitcoin.defaultchanconfs=1") args = append(args, fmt.Sprintf("--bitcoin.defaultremotedelay=%v", DefaultCSV)) - args = append(args, fmt.Sprintf("--btcd.rpchost=%v", cfg.RPCConfig.Host)) - args = append(args, fmt.Sprintf("--btcd.rpcuser=%v", cfg.RPCConfig.User)) - args = append(args, fmt.Sprintf("--btcd.rpcpass=%v", cfg.RPCConfig.Pass)) - args = append(args, fmt.Sprintf("--btcd.rawrpccert=%v", encodedCert)) args = append(args, fmt.Sprintf("--rpclisten=%v", cfg.RPCAddr())) args = append(args, fmt.Sprintf("--restlisten=%v", cfg.RESTAddr())) args = append(args, fmt.Sprintf("--listen=%v", cfg.P2PAddr()))