Merge pull request #1621 from halseth/integration-tests-split-backend-miner
[Integration tests] Split chain backend and miner
This commit is contained in:
commit
32a5f6821a
1
.gitignore
vendored
1
.gitignore
vendored
@ -34,6 +34,7 @@ _testmain.go
|
|||||||
# Integration test log files
|
# Integration test log files
|
||||||
output*.log
|
output*.log
|
||||||
/.backendlogs
|
/.backendlogs
|
||||||
|
/.minerlogs
|
||||||
|
|
||||||
cmd/cmd
|
cmd/cmd
|
||||||
*.key
|
*.key
|
||||||
|
301
lnd_test.go
301
lnd_test.go
@ -21,6 +21,7 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
|
||||||
|
"github.com/btcsuite/btcd/btcjson"
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/integration/rpctest"
|
"github.com/btcsuite/btcd/integration/rpctest"
|
||||||
@ -1542,57 +1543,110 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint3, false)
|
closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint3, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// waitForNodeBlockHeight queries the node for its current block height until
|
||||||
|
// it reaches the passed height.
|
||||||
|
func waitForNodeBlockHeight(ctx context.Context, node *lntest.HarnessNode,
|
||||||
|
height int32) error {
|
||||||
|
var predErr error
|
||||||
|
err := lntest.WaitPredicate(func() bool {
|
||||||
|
ctxt, _ := context.WithTimeout(ctx, 10*time.Second)
|
||||||
|
info, err := node.GetInfo(ctxt, &lnrpc.GetInfoRequest{})
|
||||||
|
if err != nil {
|
||||||
|
predErr = err
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if int32(info.BlockHeight) != height {
|
||||||
|
predErr = fmt.Errorf("expected block height to "+
|
||||||
|
"be %v, was %v", height, info.BlockHeight)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}, 15*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
return predErr
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// assertMinerBlockHeightDelta ensures that tempMiner is 'delta' blocks ahead
|
||||||
|
// of miner.
|
||||||
|
func assertMinerBlockHeightDelta(t *harnessTest,
|
||||||
|
miner, tempMiner *rpctest.Harness, delta int32) {
|
||||||
|
|
||||||
|
// Ensure the chain lengths are what we expect.
|
||||||
|
var predErr error
|
||||||
|
err := lntest.WaitPredicate(func() bool {
|
||||||
|
_, tempMinerHeight, err := tempMiner.Node.GetBestBlock()
|
||||||
|
if err != nil {
|
||||||
|
predErr = fmt.Errorf("unable to get current "+
|
||||||
|
"blockheight %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
_, minerHeight, err := miner.Node.GetBestBlock()
|
||||||
|
if err != nil {
|
||||||
|
predErr = fmt.Errorf("unable to get current "+
|
||||||
|
"blockheight %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if tempMinerHeight != minerHeight+delta {
|
||||||
|
predErr = fmt.Errorf("expected new miner(%d) to be %d "+
|
||||||
|
"blocks ahead of original miner(%d)",
|
||||||
|
tempMinerHeight, delta, minerHeight)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}, time.Second*15)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf(predErr.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// testOpenChannelAfterReorg tests that in the case where we have an open
|
// testOpenChannelAfterReorg tests that in the case where we have an open
|
||||||
// channel where the funding tx gets reorged out, the channel will no
|
// channel where the funding tx gets reorged out, the channel will no
|
||||||
// longer be present in the node's routing table.
|
// longer be present in the node's routing table.
|
||||||
func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) {
|
func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
ctxb := context.Background()
|
var (
|
||||||
|
ctxb = context.Background()
|
||||||
|
temp = "temp"
|
||||||
|
perm = "perm"
|
||||||
|
)
|
||||||
|
|
||||||
// Set up a new miner that we can use to cause a reorg.
|
// Set up a new miner that we can use to cause a reorg.
|
||||||
args := []string{"--rejectnonstd", "--txindex"}
|
args := []string{"--rejectnonstd", "--txindex"}
|
||||||
miner, err := rpctest.New(harnessNetParams,
|
tempMiner, err := rpctest.New(harnessNetParams,
|
||||||
&rpcclient.NotificationHandlers{}, args)
|
&rpcclient.NotificationHandlers{}, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create mining node: %v", err)
|
t.Fatalf("unable to create mining node: %v", err)
|
||||||
}
|
}
|
||||||
if err := miner.SetUp(true, 50); err != nil {
|
if err := tempMiner.SetUp(false, 0); err != nil {
|
||||||
t.Fatalf("unable to set up mining node: %v", err)
|
t.Fatalf("unable to set up mining node: %v", err)
|
||||||
}
|
}
|
||||||
defer miner.TearDown()
|
defer tempMiner.TearDown()
|
||||||
|
|
||||||
if err := miner.Node.NotifyNewTransactions(false); err != nil {
|
|
||||||
t.Fatalf("unable to request transaction notifications: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We start by connecting the new miner to our original miner,
|
// We start by connecting the new miner to our original miner,
|
||||||
// such that it will sync to our original chain.
|
// such that it will sync to our original chain.
|
||||||
if err := rpctest.ConnectNode(net.Miner, miner); err != nil {
|
err = net.Miner.Node.Node(
|
||||||
t.Fatalf("unable to connect harnesses: %v", err)
|
btcjson.NConnect, tempMiner.P2PAddress(), &temp,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to remove node: %v", err)
|
||||||
}
|
}
|
||||||
nodeSlice := []*rpctest.Harness{net.Miner, miner}
|
nodeSlice := []*rpctest.Harness{net.Miner, tempMiner}
|
||||||
if err := rpctest.JoinNodes(nodeSlice, rpctest.Blocks); err != nil {
|
if err := rpctest.JoinNodes(nodeSlice, rpctest.Blocks); err != nil {
|
||||||
t.Fatalf("unable to join node on blocks: %v", err)
|
t.Fatalf("unable to join node on blocks: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The two should be on the same blockheight.
|
// The two miners should be on the same blockheight.
|
||||||
_, newNodeHeight, err := miner.Node.GetBestBlock()
|
assertMinerBlockHeightDelta(t, net.Miner, tempMiner, 0)
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to get current blockheight %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, orgNodeHeight, err := net.Miner.Node.GetBestBlock()
|
// We disconnect the two miners, such that we can mine two different
|
||||||
if err != nil {
|
// chains and can cause a reorg later.
|
||||||
t.Fatalf("unable to get current blockheight %v", err)
|
err = net.Miner.Node.Node(
|
||||||
}
|
btcjson.NDisconnect, tempMiner.P2PAddress(), &temp,
|
||||||
|
)
|
||||||
if newNodeHeight != orgNodeHeight {
|
|
||||||
t.Fatalf("expected new miner(%d) and original miner(%d) to "+
|
|
||||||
"be on the same height", newNodeHeight, orgNodeHeight)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We disconnect the two nodes, such that we can start mining on them
|
|
||||||
// individually without the other one learning about the new blocks.
|
|
||||||
err = net.Miner.Node.AddNode(miner.P2PAddress(), rpcclient.ANRemove)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to remove node: %v", err)
|
t.Fatalf("unable to remove node: %v", err)
|
||||||
}
|
}
|
||||||
@ -1608,7 +1662,8 @@ func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
t.Fatalf("unable to open channel: %v", err)
|
t.Fatalf("unable to open channel: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for miner to have seen the funding tx.
|
// Wait for miner to have seen the funding tx. The temporary miner is
|
||||||
|
// disconnected, and won't see the transaction.
|
||||||
_, err = waitForTxInMempool(net.Miner.Node, minerMempoolTimeout)
|
_, err = waitForTxInMempool(net.Miner.Node, minerMempoolTimeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to find funding tx in mempool: %v", err)
|
t.Fatalf("failed to find funding tx in mempool: %v", err)
|
||||||
@ -1627,25 +1682,27 @@ func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
|
|
||||||
// We now cause a fork, by letting our original miner mine 10 blocks,
|
// We now cause a fork, by letting our original miner mine 10 blocks,
|
||||||
// and our new miner mine 15. This will also confirm our pending
|
// and our new miner mine 15. This will also confirm our pending
|
||||||
// channel, which should be considered open.
|
// channel on the original miner's chain, which should be considered
|
||||||
|
// open.
|
||||||
block := mineBlocks(t, net, 10, 1)[0]
|
block := mineBlocks(t, net, 10, 1)[0]
|
||||||
assertTxInBlock(t, block, fundingTxID)
|
assertTxInBlock(t, block, fundingTxID)
|
||||||
miner.Node.Generate(15)
|
if _, err := tempMiner.Node.Generate(15); err != nil {
|
||||||
|
t.Fatalf("unable to generate blocks: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure the chain lengths are what we expect.
|
// Ensure the chain lengths are what we expect, with the temp miner
|
||||||
_, newNodeHeight, err = miner.Node.GetBestBlock()
|
// being 5 blocks ahead.
|
||||||
|
assertMinerBlockHeightDelta(t, net.Miner, tempMiner, 5)
|
||||||
|
|
||||||
|
// Wait for Alice to sync to the original miner's chain.
|
||||||
|
_, minerHeight, err := net.Miner.Node.GetBestBlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to get current blockheight %v", err)
|
t.Fatalf("unable to get current blockheight %v", err)
|
||||||
}
|
}
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
||||||
_, orgNodeHeight, err = net.Miner.Node.GetBestBlock()
|
err = waitForNodeBlockHeight(ctxt, net.Alice, minerHeight)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to get current blockheight %v", err)
|
t.Fatalf("unable to sync to chain: %v", err)
|
||||||
}
|
|
||||||
|
|
||||||
if newNodeHeight != orgNodeHeight+5 {
|
|
||||||
t.Fatalf("expected new miner(%d) to be 5 blocks ahead of "+
|
|
||||||
"original miner(%d)", newNodeHeight, orgNodeHeight)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chanPoint := &lnrpc.ChannelPoint{
|
chanPoint := &lnrpc.ChannelPoint{
|
||||||
@ -1689,49 +1746,86 @@ func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
numEdges)
|
numEdges)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connecting the two miners should now cause our original one to sync
|
// Now we disconnect Alice's chain backend from the original miner, and
|
||||||
// to the new, and longer chain.
|
// connect the two miners together. Since the temporary miner knows
|
||||||
if err := rpctest.ConnectNode(net.Miner, miner); err != nil {
|
// about a longer chain, both miners should sync to that chain.
|
||||||
t.Fatalf("unable to connect harnesses: %v", err)
|
err = net.Miner.Node.Node(
|
||||||
|
btcjson.NRemove, net.BackendCfg.P2PAddr(), &perm,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to remove node: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := rpctest.JoinNodes(nodeSlice, rpctest.Blocks); err != nil {
|
// Connecting to the temporary miner should now cause our original
|
||||||
|
// chain to be re-orged out.
|
||||||
|
err = net.Miner.Node.Node(
|
||||||
|
btcjson.NConnect, tempMiner.P2PAddress(), &temp,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to remove node: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes := []*rpctest.Harness{tempMiner, net.Miner}
|
||||||
|
if err := rpctest.JoinNodes(nodes, rpctest.Blocks); err != nil {
|
||||||
t.Fatalf("unable to join node on blocks: %v", err)
|
t.Fatalf("unable to join node on blocks: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Once again they should be on the same chain.
|
// Once again they should be on the same chain.
|
||||||
_, newNodeHeight, err = miner.Node.GetBestBlock()
|
assertMinerBlockHeightDelta(t, net.Miner, tempMiner, 0)
|
||||||
|
|
||||||
|
// Now we disconnect the two miners, and connect our original miner to
|
||||||
|
// our chain backend once again.
|
||||||
|
err = net.Miner.Node.Node(
|
||||||
|
btcjson.NDisconnect, tempMiner.P2PAddress(), &temp,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to remove node: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = net.Miner.Node.Node(
|
||||||
|
btcjson.NConnect, net.BackendCfg.P2PAddr(), &perm,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to remove node: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This should have caused a reorg, and Alice should sync to the longer
|
||||||
|
// chain, where the funding transaction is not confirmed.
|
||||||
|
_, tempMinerHeight, err := tempMiner.Node.GetBestBlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to get current blockheight %v", err)
|
t.Fatalf("unable to get current blockheight %v", err)
|
||||||
}
|
}
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
||||||
_, orgNodeHeight, err = net.Miner.Node.GetBestBlock()
|
err = waitForNodeBlockHeight(ctxt, net.Alice, tempMinerHeight)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to get current blockheight %v", err)
|
t.Fatalf("unable to sync to chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if newNodeHeight != orgNodeHeight {
|
|
||||||
t.Fatalf("expected new miner(%d) and original miner(%d) to "+
|
|
||||||
"be on the same height", newNodeHeight, orgNodeHeight)
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(time.Second * 2)
|
|
||||||
|
|
||||||
// Since the fundingtx was reorged out, Alice should now have no edges
|
// Since the fundingtx was reorged out, Alice should now have no edges
|
||||||
// in her graph.
|
// in her graph.
|
||||||
req = &lnrpc.ChannelGraphRequest{
|
req = &lnrpc.ChannelGraphRequest{
|
||||||
IncludeUnannounced: true,
|
IncludeUnannounced: true,
|
||||||
}
|
}
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
chanGraph, err = net.Alice.DescribeGraph(ctxt, req)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to query for alice's routing table: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
numEdges = len(chanGraph.Edges)
|
var predErr error
|
||||||
if numEdges != 0 {
|
err = lntest.WaitPredicate(func() bool {
|
||||||
t.Fatalf("expected to find no edge in the graph, found %d",
|
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
||||||
numEdges)
|
chanGraph, err = net.Alice.DescribeGraph(ctxt, req)
|
||||||
|
if err != nil {
|
||||||
|
predErr = fmt.Errorf("unable to query for alice's routing table: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
numEdges = len(chanGraph.Edges)
|
||||||
|
if numEdges != 0 {
|
||||||
|
predErr = fmt.Errorf("expected to find no edge in the graph, found %d",
|
||||||
|
numEdges)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}, time.Second*15)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf(predErr.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup by mining the funding tx again, then closing the channel.
|
// Cleanup by mining the funding tx again, then closing the channel.
|
||||||
@ -12930,49 +13024,73 @@ var testsCases = []*testCase{
|
|||||||
func TestLightningNetworkDaemon(t *testing.T) {
|
func TestLightningNetworkDaemon(t *testing.T) {
|
||||||
ht := newHarnessTest(t)
|
ht := newHarnessTest(t)
|
||||||
|
|
||||||
|
// Start a btcd chain backend.
|
||||||
|
chainBackend, cleanUp, err := lntest.NewBtcdBackend()
|
||||||
|
if err != nil {
|
||||||
|
ht.Fatalf("unable to start btcd: %v", err)
|
||||||
|
}
|
||||||
|
defer cleanUp()
|
||||||
|
|
||||||
|
// Declare the network harness here to gain access to its
|
||||||
|
// 'OnTxAccepted' call back.
|
||||||
var lndHarness *lntest.NetworkHarness
|
var lndHarness *lntest.NetworkHarness
|
||||||
|
|
||||||
// First create an instance of the btcd's rpctest.Harness. This will be
|
// Create an instance of the btcd's rpctest.Harness that will act as
|
||||||
// used to fund the wallets of the nodes within the test network and to
|
// the miner for all tests. This will be used to fund the wallets of
|
||||||
// drive blockchain related events within the network. Revert the default
|
// the nodes within the test network and to drive blockchain related
|
||||||
// setting of accepting non-standard transactions on simnet to reject them.
|
// events within the network. Revert the default setting of accepting
|
||||||
// Transactions on the lightning network should always be standard to get
|
// non-standard transactions on simnet to reject them. Transactions on
|
||||||
// better guarantees of getting included in to blocks.
|
// the lightning network should always be standard to get better
|
||||||
logDir := "./.backendlogs"
|
// guarantees of getting included in to blocks.
|
||||||
|
//
|
||||||
|
// We will also connect it to our chain backend.
|
||||||
|
minerLogDir := "./.minerlogs"
|
||||||
args := []string{
|
args := []string{
|
||||||
"--rejectnonstd",
|
"--rejectnonstd",
|
||||||
"--txindex",
|
"--txindex",
|
||||||
"--debuglevel=debug",
|
"--debuglevel=debug",
|
||||||
"--logdir=" + logDir,
|
"--logdir=" + minerLogDir,
|
||||||
|
"--trickleinterval=100ms",
|
||||||
|
"--connect=" + chainBackend.P2PAddr(),
|
||||||
}
|
}
|
||||||
handlers := &rpcclient.NotificationHandlers{
|
handlers := &rpcclient.NotificationHandlers{
|
||||||
OnTxAccepted: func(hash *chainhash.Hash, amt btcutil.Amount) {
|
OnTxAccepted: func(hash *chainhash.Hash, amt btcutil.Amount) {
|
||||||
lndHarness.OnTxAccepted(hash)
|
lndHarness.OnTxAccepted(hash)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
btcdHarness, err := rpctest.New(harnessNetParams, handlers, args)
|
|
||||||
|
miner, err := rpctest.New(harnessNetParams, handlers, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ht.Fatalf("unable to create mining node: %v", err)
|
ht.Fatalf("unable to create mining node: %v", err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
btcdHarness.TearDown()
|
miner.TearDown()
|
||||||
|
|
||||||
// After shutting down the chain backend, we'll make a copy of
|
// After shutting down the miner, we'll make a copy of the log
|
||||||
// the log file before deleting the temporary log dir.
|
// file before deleting the temporary log dir.
|
||||||
logFile := logDir + "/" + harnessNetParams.Name + "/btcd.log"
|
logFile := fmt.Sprintf(
|
||||||
err := lntest.CopyFile("./output_btcd_chainbackend.log",
|
"%s/%s/btcd.log", minerLogDir, harnessNetParams.Name,
|
||||||
logFile)
|
)
|
||||||
|
err := lntest.CopyFile("./output_btcd_miner.log", logFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("unable to copy file: %v\n", err)
|
fmt.Printf("unable to copy file: %v\n", err)
|
||||||
}
|
}
|
||||||
if err = os.RemoveAll(logDir); err != nil {
|
if err = os.RemoveAll(minerLogDir); err != nil {
|
||||||
fmt.Printf("Cannot remove dir %s: %v\n", logDir, err)
|
fmt.Printf("Cannot remove dir %s: %v\n",
|
||||||
|
minerLogDir, err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// First create the network harness to gain access to its
|
if err := miner.SetUp(true, 50); err != nil {
|
||||||
// 'OnTxAccepted' call back.
|
ht.Fatalf("unable to set up mining node: %v", err)
|
||||||
lndHarness, err = lntest.NewNetworkHarness(btcdHarness)
|
}
|
||||||
|
if err := miner.Node.NotifyNewTransactions(false); err != nil {
|
||||||
|
ht.Fatalf("unable to request transaction notifications: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we can set up our test harness (LND instance), with the chain
|
||||||
|
// backend we just created.
|
||||||
|
lndHarness, err = lntest.NewNetworkHarness(miner, chainBackend)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ht.Fatalf("unable to create lightning network harness: %v", err)
|
ht.Fatalf("unable to create lightning network harness: %v", err)
|
||||||
}
|
}
|
||||||
@ -12994,17 +13112,10 @@ func TestLightningNetworkDaemon(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err := btcdHarness.SetUp(true, 50); err != nil {
|
|
||||||
ht.Fatalf("unable to set up mining node: %v", err)
|
|
||||||
}
|
|
||||||
if err := btcdHarness.Node.NotifyNewTransactions(false); err != nil {
|
|
||||||
ht.Fatalf("unable to request transaction notifications: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next mine enough blocks in order for segwit and the CSV package
|
// Next mine enough blocks in order for segwit and the CSV package
|
||||||
// soft-fork to activate on SimNet.
|
// soft-fork to activate on SimNet.
|
||||||
numBlocks := chaincfg.SimNetParams.MinerConfirmationWindow * 2
|
numBlocks := chaincfg.SimNetParams.MinerConfirmationWindow * 2
|
||||||
if _, err := btcdHarness.Node.Generate(numBlocks); err != nil {
|
if _, err := miner.Node.Generate(numBlocks); err != nil {
|
||||||
ht.Fatalf("unable to generate blocks: %v", err)
|
ht.Fatalf("unable to generate blocks: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
87
lntest/btcd.go
Normal file
87
lntest/btcd.go
Normal file
@ -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
|
||||||
|
}
|
@ -16,7 +16,6 @@ import (
|
|||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/integration/rpctest"
|
"github.com/btcsuite/btcd/integration/rpctest"
|
||||||
"github.com/btcsuite/btcd/rpcclient"
|
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/btcsuite/btcd/txscript"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
@ -50,13 +49,16 @@ const (
|
|||||||
// The harness by default is created with two active nodes on the network:
|
// The harness by default is created with two active nodes on the network:
|
||||||
// Alice and Bob.
|
// Alice and Bob.
|
||||||
type NetworkHarness struct {
|
type NetworkHarness struct {
|
||||||
rpcConfig rpcclient.ConnConfig
|
|
||||||
netParams *chaincfg.Params
|
netParams *chaincfg.Params
|
||||||
|
|
||||||
// Miner is a reference to a running full node that can be used to create
|
// Miner is a reference to a running full node that can be used to create
|
||||||
// new blocks on the network.
|
// new blocks on the network.
|
||||||
Miner *rpctest.Harness
|
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
|
activeNodes map[int]*HarnessNode
|
||||||
|
|
||||||
nodesByPub map[string]*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
|
// 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`
|
// current repo. This will save developers from having to manually `go install`
|
||||||
// within the repo each time before changes
|
// 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{
|
n := NetworkHarness{
|
||||||
activeNodes: make(map[int]*HarnessNode),
|
activeNodes: make(map[int]*HarnessNode),
|
||||||
nodesByPub: make(map[string]*HarnessNode),
|
nodesByPub: make(map[string]*HarnessNode),
|
||||||
@ -91,7 +93,7 @@ func NewNetworkHarness(r *rpctest.Harness) (*NetworkHarness, error) {
|
|||||||
lndErrorChan: make(chan error),
|
lndErrorChan: make(chan error),
|
||||||
netParams: r.ActiveNet,
|
netParams: r.ActiveNet,
|
||||||
Miner: r,
|
Miner: r,
|
||||||
rpcConfig: r.RPCConfig(),
|
BackendCfg: b,
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
}
|
}
|
||||||
go n.networkWatcher()
|
go n.networkWatcher()
|
||||||
@ -355,11 +357,11 @@ func (n *NetworkHarness) RestoreNodeWithSeed(name string, extraArgs []string,
|
|||||||
func (n *NetworkHarness) newNode(name string, extraArgs []string,
|
func (n *NetworkHarness) newNode(name string, extraArgs []string,
|
||||||
hasSeed bool) (*HarnessNode, error) {
|
hasSeed bool) (*HarnessNode, error) {
|
||||||
node, err := newNode(nodeConfig{
|
node, err := newNode(nodeConfig{
|
||||||
Name: name,
|
Name: name,
|
||||||
HasSeed: hasSeed,
|
HasSeed: hasSeed,
|
||||||
RPCConfig: &n.rpcConfig,
|
BackendCfg: n.BackendCfg,
|
||||||
NetParams: n.netParams,
|
NetParams: n.netParams,
|
||||||
ExtraArgs: extraArgs,
|
ExtraArgs: extraArgs,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -22,7 +22,6 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/rpcclient"
|
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
@ -91,12 +90,24 @@ func generateListeningPorts() (int, int, int) {
|
|||||||
return p2p, rpc, rest
|
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 {
|
type nodeConfig struct {
|
||||||
Name string
|
Name string
|
||||||
RPCConfig *rpcclient.ConnConfig
|
BackendCfg BackendConfig
|
||||||
NetParams *chaincfg.Params
|
NetParams *chaincfg.Params
|
||||||
BaseDir string
|
BaseDir string
|
||||||
ExtraArgs []string
|
ExtraArgs []string
|
||||||
|
|
||||||
DataDir string
|
DataDir string
|
||||||
LogDir string
|
LogDir string
|
||||||
@ -144,16 +155,13 @@ func (cfg nodeConfig) genArgs() []string {
|
|||||||
args = append(args, "--bitcoin.regtest")
|
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, "--bitcoin.active")
|
||||||
args = append(args, "--nobootstrap")
|
args = append(args, "--nobootstrap")
|
||||||
args = append(args, "--debuglevel=debug")
|
args = append(args, "--debuglevel=debug")
|
||||||
args = append(args, "--bitcoin.defaultchanconfs=1")
|
args = append(args, "--bitcoin.defaultchanconfs=1")
|
||||||
args = append(args, fmt.Sprintf("--bitcoin.defaultremotedelay=%v", DefaultCSV))
|
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("--rpclisten=%v", cfg.RPCAddr()))
|
||||||
args = append(args, fmt.Sprintf("--restlisten=%v", cfg.RESTAddr()))
|
args = append(args, fmt.Sprintf("--restlisten=%v", cfg.RESTAddr()))
|
||||||
args = append(args, fmt.Sprintf("--listen=%v", cfg.P2PAddr()))
|
args = append(args, fmt.Sprintf("--listen=%v", cfg.P2PAddr()))
|
||||||
|
Loading…
Reference in New Issue
Block a user