lnd/lntest/bitcoind.go

186 lines
4.9 KiB
Go
Raw Normal View History

2019-07-11 13:51:22 +02:00
// +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"
// 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")
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",
2019-07-11 13:51:22 +02:00
"-regtest",
"-txindex",
"-whitelist=127.0.0.1", // whitelist localhost to speed up relay
"-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
}