lntest: Rename structs with proper visibility so lnd_test runs.
This commit is contained in:
parent
3cb0705b8e
commit
43e501feb9
108
lnd_test.go
108
lnd_test.go
@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
|
"github.com/lightningnetwork/lnd/lntest"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/roasbeef/btcd/chaincfg"
|
"github.com/roasbeef/btcd/chaincfg"
|
||||||
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
||||||
@ -36,6 +37,10 @@ import (
|
|||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
harnessNetParams = &chaincfg.SimNetParams
|
||||||
|
)
|
||||||
|
|
||||||
// harnessTest wraps a regular testing.T providing enhanced error detection
|
// harnessTest wraps a regular testing.T providing enhanced error detection
|
||||||
// and propagation. All error will be augmented with a full stack-trace in
|
// and propagation. All error will be augmented with a full stack-trace in
|
||||||
// order to aid in debugging. Additionally, any panics caused by active
|
// order to aid in debugging. Additionally, any panics caused by active
|
||||||
@ -70,7 +75,9 @@ func (h *harnessTest) Fatalf(format string, a ...interface{}) {
|
|||||||
|
|
||||||
// RunTestCase executes a harness test case. Any errors or panics will be
|
// RunTestCase executes a harness test case. Any errors or panics will be
|
||||||
// represented as fatal.
|
// represented as fatal.
|
||||||
func (h *harnessTest) RunTestCase(testCase *testCase, net *networkHarness) {
|
func (h *harnessTest) RunTestCase(testCase *testCase,
|
||||||
|
net *lntest.NetworkHarness) {
|
||||||
|
|
||||||
h.testCase = testCase
|
h.testCase = testCase
|
||||||
defer func() {
|
defer func() {
|
||||||
h.testCase = nil
|
h.testCase = nil
|
||||||
@ -110,7 +117,9 @@ func assertTxInBlock(t *harnessTest, block *wire.MsgBlock, txid *chainhash.Hash)
|
|||||||
|
|
||||||
// mineBlocks mine 'num' of blocks and check that blocks are present in
|
// mineBlocks mine 'num' of blocks and check that blocks are present in
|
||||||
// node blockchain.
|
// node blockchain.
|
||||||
func mineBlocks(t *harnessTest, net *networkHarness, num uint32) []*wire.MsgBlock {
|
func mineBlocks(t *harnessTest, net *lntest.NetworkHarness, num uint32,
|
||||||
|
) []*wire.MsgBlock {
|
||||||
|
|
||||||
blocks := make([]*wire.MsgBlock, num)
|
blocks := make([]*wire.MsgBlock, num)
|
||||||
|
|
||||||
blockHashes, err := net.Miner.Node.Generate(num)
|
blockHashes, err := net.Miner.Node.Generate(num)
|
||||||
@ -135,9 +144,9 @@ func mineBlocks(t *harnessTest, net *networkHarness, num uint32) []*wire.MsgBloc
|
|||||||
// after the channel is considered open: the funding transaction should be
|
// after the channel is considered open: the funding transaction should be
|
||||||
// found within a block, and that Alice can report the status of the new
|
// found within a block, and that Alice can report the status of the new
|
||||||
// channel.
|
// channel.
|
||||||
func openChannelAndAssert(ctx context.Context, t *harnessTest, net *networkHarness,
|
func openChannelAndAssert(ctx context.Context, t *harnessTest,
|
||||||
alice, bob *lightningNode, fundingAmt btcutil.Amount,
|
net *lntest.NetworkHarness, alice, bob *lntest.HarnessNode,
|
||||||
pushAmt btcutil.Amount) *lnrpc.ChannelPoint {
|
fundingAmt btcutil.Amount, pushAmt btcutil.Amount) *lnrpc.ChannelPoint {
|
||||||
|
|
||||||
chanOpenUpdate, err := net.OpenChannel(ctx, alice, bob, fundingAmt,
|
chanOpenUpdate, err := net.OpenChannel(ctx, alice, bob, fundingAmt,
|
||||||
pushAmt)
|
pushAmt)
|
||||||
@ -182,8 +191,9 @@ func openChannelAndAssert(ctx context.Context, t *harnessTest, net *networkHarne
|
|||||||
// via timeout from a base parent. Additionally, once the channel has been
|
// via timeout from a base parent. Additionally, once the channel has been
|
||||||
// detected as closed, an assertion checks that the transaction is found within
|
// detected as closed, an assertion checks that the transaction is found within
|
||||||
// a block.
|
// a block.
|
||||||
func closeChannelAndAssert(ctx context.Context, t *harnessTest, net *networkHarness,
|
func closeChannelAndAssert(ctx context.Context, t *harnessTest,
|
||||||
node *lightningNode, fundingChanPoint *lnrpc.ChannelPoint, force bool) *chainhash.Hash {
|
net *lntest.NetworkHarness, node *lntest.HarnessNode,
|
||||||
|
fundingChanPoint *lnrpc.ChannelPoint, force bool) *chainhash.Hash {
|
||||||
|
|
||||||
closeUpdates, _, err := net.CloseChannel(ctx, node, fundingChanPoint, force)
|
closeUpdates, _, err := net.CloseChannel(ctx, node, fundingChanPoint, force)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -234,7 +244,7 @@ func closeChannelAndAssert(ctx context.Context, t *harnessTest, net *networkHarn
|
|||||||
// numOpenChannelsPending sends an RPC request to a node to get a count of the
|
// numOpenChannelsPending sends an RPC request to a node to get a count of the
|
||||||
// node's channels that are currently in a pending state (with a broadcast, but
|
// node's channels that are currently in a pending state (with a broadcast, but
|
||||||
// not confirmed funding transaction).
|
// not confirmed funding transaction).
|
||||||
func numOpenChannelsPending(ctxt context.Context, node *lightningNode) (int, error) {
|
func numOpenChannelsPending(ctxt context.Context, node *lntest.HarnessNode) (int, error) {
|
||||||
pendingChansRequest := &lnrpc.PendingChannelRequest{}
|
pendingChansRequest := &lnrpc.PendingChannelRequest{}
|
||||||
resp, err := node.PendingChannels(ctxt, pendingChansRequest)
|
resp, err := node.PendingChannels(ctxt, pendingChansRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -246,7 +256,7 @@ func numOpenChannelsPending(ctxt context.Context, node *lightningNode) (int, err
|
|||||||
// assertNumOpenChannelsPending asserts that a pair of nodes have the expected
|
// assertNumOpenChannelsPending asserts that a pair of nodes have the expected
|
||||||
// number of pending channels between them.
|
// number of pending channels between them.
|
||||||
func assertNumOpenChannelsPending(ctxt context.Context, t *harnessTest,
|
func assertNumOpenChannelsPending(ctxt context.Context, t *harnessTest,
|
||||||
alice, bob *lightningNode, expected int) {
|
alice, bob *lntest.HarnessNode, expected int) {
|
||||||
|
|
||||||
const nPolls = 10
|
const nPolls = 10
|
||||||
|
|
||||||
@ -257,12 +267,12 @@ func assertNumOpenChannelsPending(ctxt context.Context, t *harnessTest,
|
|||||||
aliceNumChans, err := numOpenChannelsPending(ctxt, alice)
|
aliceNumChans, err := numOpenChannelsPending(ctxt, alice)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error fetching alice's node (%v) pending channels %v",
|
t.Fatalf("error fetching alice's node (%v) pending channels %v",
|
||||||
alice.nodeID, err)
|
alice.NodeID, err)
|
||||||
}
|
}
|
||||||
bobNumChans, err := numOpenChannelsPending(ctxt, bob)
|
bobNumChans, err := numOpenChannelsPending(ctxt, bob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error fetching bob's node (%v) pending channels %v",
|
t.Fatalf("error fetching bob's node (%v) pending channels %v",
|
||||||
bob.nodeID, err)
|
bob.NodeID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
isLastIteration := i == nPolls-1
|
isLastIteration := i == nPolls-1
|
||||||
@ -290,7 +300,7 @@ func assertNumOpenChannelsPending(ctxt context.Context, t *harnessTest,
|
|||||||
|
|
||||||
// assertNumConnections asserts number current connections between two peers.
|
// assertNumConnections asserts number current connections between two peers.
|
||||||
func assertNumConnections(ctxt context.Context, t *harnessTest,
|
func assertNumConnections(ctxt context.Context, t *harnessTest,
|
||||||
alice, bob *lightningNode, expected int) {
|
alice, bob *lntest.HarnessNode, expected int) {
|
||||||
|
|
||||||
const nPolls = 10
|
const nPolls = 10
|
||||||
|
|
||||||
@ -303,12 +313,12 @@ func assertNumConnections(ctxt context.Context, t *harnessTest,
|
|||||||
aNumPeers, err := alice.ListPeers(ctxt, &lnrpc.ListPeersRequest{})
|
aNumPeers, err := alice.ListPeers(ctxt, &lnrpc.ListPeersRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to fetch alice's node (%v) list peers %v",
|
t.Fatalf("unable to fetch alice's node (%v) list peers %v",
|
||||||
alice.nodeID, err)
|
alice.NodeID, err)
|
||||||
}
|
}
|
||||||
bNumPeers, err := bob.ListPeers(ctxt, &lnrpc.ListPeersRequest{})
|
bNumPeers, err := bob.ListPeers(ctxt, &lnrpc.ListPeersRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to fetch bob's node (%v) list peers %v",
|
t.Fatalf("unable to fetch bob's node (%v) list peers %v",
|
||||||
bob.nodeID, err)
|
bob.NodeID, err)
|
||||||
}
|
}
|
||||||
if len(aNumPeers.Peers) != expected {
|
if len(aNumPeers.Peers) != expected {
|
||||||
// Continue polling if this is not the final
|
// Continue polling if this is not the final
|
||||||
@ -401,7 +411,7 @@ func completePaymentRequests(ctx context.Context, client lnrpc.LightningClient,
|
|||||||
// Bob, then immediately closes the channel after asserting some expected post
|
// Bob, then immediately closes the channel after asserting some expected post
|
||||||
// conditions. Finally, the chain itself is checked to ensure the closing
|
// conditions. Finally, the chain itself is checked to ensure the closing
|
||||||
// transaction was mined.
|
// transaction was mined.
|
||||||
func testBasicChannelFunding(net *networkHarness, t *harnessTest) {
|
func testBasicChannelFunding(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
timeout := time.Duration(time.Second * 5)
|
timeout := time.Duration(time.Second * 5)
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
|
|
||||||
@ -458,7 +468,7 @@ func testBasicChannelFunding(net *networkHarness, t *harnessTest) {
|
|||||||
// 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 *networkHarness, t *harnessTest) {
|
func testOpenChannelAfterReorg(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
timeout := time.Duration(time.Second * 5)
|
timeout := time.Duration(time.Second * 5)
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
|
|
||||||
@ -639,7 +649,7 @@ func testOpenChannelAfterReorg(net *networkHarness, t *harnessTest) {
|
|||||||
|
|
||||||
// testDisconnectingTargetPeer performs a test which
|
// testDisconnectingTargetPeer performs a test which
|
||||||
// disconnects Alice-peer from Bob-peer and then re-connects them again
|
// disconnects Alice-peer from Bob-peer and then re-connects them again
|
||||||
func testDisconnectingTargetPeer(net *networkHarness, t *harnessTest) {
|
func testDisconnectingTargetPeer(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
|
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
|
|
||||||
@ -768,7 +778,7 @@ func testDisconnectingTargetPeer(net *networkHarness, t *harnessTest) {
|
|||||||
// representation of channels if the system is restarted or disconnected.
|
// representation of channels if the system is restarted or disconnected.
|
||||||
// testFundingPersistence mirrors testBasicChannelFunding, but adds restarts
|
// testFundingPersistence mirrors testBasicChannelFunding, but adds restarts
|
||||||
// and checks for the state of channels with unconfirmed funding transactions.
|
// and checks for the state of channels with unconfirmed funding transactions.
|
||||||
func testChannelFundingPersistence(net *networkHarness, t *harnessTest) {
|
func testChannelFundingPersistence(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
|
|
||||||
chanAmt := maxFundingAmount
|
chanAmt := maxFundingAmount
|
||||||
@ -914,7 +924,7 @@ peersPoll:
|
|||||||
|
|
||||||
// testChannelBalance creates a new channel between Alice and Bob, then
|
// testChannelBalance creates a new channel between Alice and Bob, then
|
||||||
// checks channel balance to be equal amount specified while creation of channel.
|
// checks channel balance to be equal amount specified while creation of channel.
|
||||||
func testChannelBalance(net *networkHarness, t *harnessTest) {
|
func testChannelBalance(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
timeout := time.Duration(time.Second * 5)
|
timeout := time.Duration(time.Second * 5)
|
||||||
|
|
||||||
// Open a channel with 0.16 BTC between Alice and Bob, ensuring the
|
// Open a channel with 0.16 BTC between Alice and Bob, ensuring the
|
||||||
@ -1069,8 +1079,7 @@ func assertPendingHtlcStageAndMaturity(t *harnessTest,
|
|||||||
// process.
|
// process.
|
||||||
//
|
//
|
||||||
// TODO(roasbeef): also add an unsettled HTLC before force closing.
|
// TODO(roasbeef): also add an unsettled HTLC before force closing.
|
||||||
func testChannelForceClosure(net *networkHarness, t *harnessTest) {
|
func testChannelForceClosure(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
|
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
const (
|
const (
|
||||||
timeout = time.Duration(time.Second * 10)
|
timeout = time.Duration(time.Second * 10)
|
||||||
@ -1714,7 +1723,7 @@ func testChannelForceClosure(net *networkHarness, t *harnessTest) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSingleHopInvoice(net *networkHarness, t *harnessTest) {
|
func testSingleHopInvoice(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
timeout := time.Duration(time.Second * 5)
|
timeout := time.Duration(time.Second * 5)
|
||||||
|
|
||||||
@ -1851,7 +1860,7 @@ func testSingleHopInvoice(net *networkHarness, t *harnessTest) {
|
|||||||
closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint, false)
|
closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testListPayments(net *networkHarness, t *harnessTest) {
|
func testListPayments(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
timeout := time.Duration(time.Second * 5)
|
timeout := time.Duration(time.Second * 5)
|
||||||
|
|
||||||
@ -1986,7 +1995,7 @@ func testListPayments(net *networkHarness, t *harnessTest) {
|
|||||||
closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint, false)
|
closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testMultiHopPayments(net *networkHarness, t *harnessTest) {
|
func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
const chanAmt = btcutil.Amount(100000)
|
const chanAmt = btcutil.Amount(100000)
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
timeout := time.Duration(time.Second * 5)
|
timeout := time.Duration(time.Second * 5)
|
||||||
@ -2115,7 +2124,7 @@ func testMultiHopPayments(net *networkHarness, t *harnessTest) {
|
|||||||
// creating the seed nodes in the network.
|
// creating the seed nodes in the network.
|
||||||
const baseFee = 1
|
const baseFee = 1
|
||||||
|
|
||||||
assertAmountPaid := func(node *lightningNode, chanPoint wire.OutPoint,
|
assertAmountPaid := func(node *lntest.HarnessNode, chanPoint wire.OutPoint,
|
||||||
amountSent, amountReceived int64) {
|
amountSent, amountReceived int64) {
|
||||||
|
|
||||||
channelName := ""
|
channelName := ""
|
||||||
@ -2220,7 +2229,7 @@ func testMultiHopPayments(net *networkHarness, t *harnessTest) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testInvoiceSubscriptions(net *networkHarness, t *harnessTest) {
|
func testInvoiceSubscriptions(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
const chanAmt = btcutil.Amount(500000)
|
const chanAmt = btcutil.Amount(500000)
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
timeout := time.Duration(time.Second * 5)
|
timeout := time.Duration(time.Second * 5)
|
||||||
@ -2313,7 +2322,7 @@ func testInvoiceSubscriptions(net *networkHarness, t *harnessTest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// testBasicChannelCreation test multiple channel opening and closing.
|
// testBasicChannelCreation test multiple channel opening and closing.
|
||||||
func testBasicChannelCreation(net *networkHarness, t *harnessTest) {
|
func testBasicChannelCreation(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
const (
|
const (
|
||||||
numChannels = 2
|
numChannels = 2
|
||||||
timeout = time.Duration(time.Second * 5)
|
timeout = time.Duration(time.Second * 5)
|
||||||
@ -2340,7 +2349,7 @@ func testBasicChannelCreation(net *networkHarness, t *harnessTest) {
|
|||||||
// testMaxPendingChannels checks that error is returned from remote peer if
|
// testMaxPendingChannels checks that error is returned from remote peer if
|
||||||
// max pending channel number was exceeded and that '--maxpendingchannels' flag
|
// max pending channel number was exceeded and that '--maxpendingchannels' flag
|
||||||
// exists and works properly.
|
// exists and works properly.
|
||||||
func testMaxPendingChannels(net *networkHarness, t *harnessTest) {
|
func testMaxPendingChannels(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
maxPendingChannels := defaultMaxPendingChannels + 1
|
maxPendingChannels := defaultMaxPendingChannels + 1
|
||||||
amount := maxFundingAmount
|
amount := maxFundingAmount
|
||||||
|
|
||||||
@ -2534,7 +2543,7 @@ func waitForNTxsInMempool(miner *rpcclient.Client, n int,
|
|||||||
// testRevokedCloseRetributinPostBreachConf tests that Alice is able carry out
|
// testRevokedCloseRetributinPostBreachConf tests that Alice is able carry out
|
||||||
// retribution in the event that she fails immediately after detecting Bob's
|
// retribution in the event that she fails immediately after detecting Bob's
|
||||||
// breach txn in the mempool.
|
// breach txn in the mempool.
|
||||||
func testRevokedCloseRetribution(net *networkHarness, t *harnessTest) {
|
func testRevokedCloseRetribution(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
const (
|
const (
|
||||||
timeout = time.Duration(time.Second * 10)
|
timeout = time.Duration(time.Second * 10)
|
||||||
@ -2630,8 +2639,7 @@ func testRevokedCloseRetribution(net *networkHarness, t *harnessTest) {
|
|||||||
// With the temporary file created, copy Bob's current state into the
|
// With the temporary file created, copy Bob's current state into the
|
||||||
// temporary file we created above. Later after more updates, we'll
|
// temporary file we created above. Later after more updates, we'll
|
||||||
// restore this state.
|
// restore this state.
|
||||||
bobDbPath := filepath.Join(net.Bob.cfg.DataDir, "simnet/bitcoin/channel.db")
|
if err := copyFile(bobTempDbFile, net.Bob.DBPath()); err != nil {
|
||||||
if err := copyFile(bobTempDbFile, bobDbPath); err != nil {
|
|
||||||
t.Fatalf("unable to copy database files: %v", err)
|
t.Fatalf("unable to copy database files: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2654,7 +2662,7 @@ func testRevokedCloseRetribution(net *networkHarness, t *harnessTest) {
|
|||||||
// state. With this, we essentially force Bob to travel back in time
|
// state. With this, we essentially force Bob to travel back in time
|
||||||
// within the channel's history.
|
// within the channel's history.
|
||||||
if err = net.RestartNode(net.Bob, func() error {
|
if err = net.RestartNode(net.Bob, func() error {
|
||||||
return os.Rename(bobTempDbFile, bobDbPath)
|
return os.Rename(bobTempDbFile, net.Bob.DBPath())
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
t.Fatalf("unable to restart node: %v", err)
|
t.Fatalf("unable to restart node: %v", err)
|
||||||
}
|
}
|
||||||
@ -2769,8 +2777,7 @@ func testRevokedCloseRetribution(net *networkHarness, t *harnessTest) {
|
|||||||
// testRevokedCloseRetributionZeroValueRemoteOutput tests that Alice is able
|
// testRevokedCloseRetributionZeroValueRemoteOutput tests that Alice is able
|
||||||
// carry out retribution in the event that she fails in state where the remote
|
// carry out retribution in the event that she fails in state where the remote
|
||||||
// commitment output has zero-value.
|
// commitment output has zero-value.
|
||||||
func testRevokedCloseRetributionZeroValueRemoteOutput(
|
func testRevokedCloseRetributionZeroValueRemoteOutput(net *lntest.NetworkHarness,
|
||||||
net *networkHarness,
|
|
||||||
t *harnessTest) {
|
t *harnessTest) {
|
||||||
|
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
@ -2871,8 +2878,7 @@ func testRevokedCloseRetributionZeroValueRemoteOutput(
|
|||||||
// With the temporary file created, copy Carol's current state into the
|
// With the temporary file created, copy Carol's current state into the
|
||||||
// temporary file we created above. Later after more updates, we'll
|
// temporary file we created above. Later after more updates, we'll
|
||||||
// restore this state.
|
// restore this state.
|
||||||
carolDbPath := filepath.Join(carol.cfg.DataDir, "simnet/bitcoin/channel.db")
|
if err := copyFile(carolTempDbFile, carol.DBPath()); err != nil {
|
||||||
if err := copyFile(carolTempDbFile, carolDbPath); err != nil {
|
|
||||||
t.Fatalf("unable to copy database files: %v", err)
|
t.Fatalf("unable to copy database files: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2893,7 +2899,7 @@ func testRevokedCloseRetributionZeroValueRemoteOutput(
|
|||||||
// state. With this, we essentially force Carol to travel back in time
|
// state. With this, we essentially force Carol to travel back in time
|
||||||
// within the channel's history.
|
// within the channel's history.
|
||||||
if err = net.RestartNode(carol, func() error {
|
if err = net.RestartNode(carol, func() error {
|
||||||
return os.Rename(carolTempDbFile, carolDbPath)
|
return os.Rename(carolTempDbFile, carol.DBPath())
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
t.Fatalf("unable to restart node: %v", err)
|
t.Fatalf("unable to restart node: %v", err)
|
||||||
}
|
}
|
||||||
@ -3000,8 +3006,7 @@ func testRevokedCloseRetributionZeroValueRemoteOutput(
|
|||||||
// testRevokedCloseRetributionRemoteHodl tests that Alice properly responds to a
|
// testRevokedCloseRetributionRemoteHodl tests that Alice properly responds to a
|
||||||
// channel breach made by the remote party, specifically in the case that the
|
// channel breach made by the remote party, specifically in the case that the
|
||||||
// remote party breaches before settling extended HTLCs.
|
// remote party breaches before settling extended HTLCs.
|
||||||
func testRevokedCloseRetributionRemoteHodl(
|
func testRevokedCloseRetributionRemoteHodl(net *lntest.NetworkHarness,
|
||||||
net *networkHarness,
|
|
||||||
t *harnessTest) {
|
t *harnessTest) {
|
||||||
|
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
@ -3144,8 +3149,7 @@ func testRevokedCloseRetributionRemoteHodl(
|
|||||||
// With the temporary file created, copy Carol's current state into the
|
// With the temporary file created, copy Carol's current state into the
|
||||||
// temporary file we created above. Later after more updates, we'll
|
// temporary file we created above. Later after more updates, we'll
|
||||||
// restore this state.
|
// restore this state.
|
||||||
carolDbPath := filepath.Join(carol.cfg.DataDir, "simnet/bitcoin/channel.db")
|
if err := copyFile(carolTempDbFile, carol.DBPath()); err != nil {
|
||||||
if err := copyFile(carolTempDbFile, carolDbPath); err != nil {
|
|
||||||
t.Fatalf("unable to copy database files: %v", err)
|
t.Fatalf("unable to copy database files: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3167,7 +3171,7 @@ func testRevokedCloseRetributionRemoteHodl(
|
|||||||
// state. With this, we essentially force Carol to travel back in time
|
// state. With this, we essentially force Carol to travel back in time
|
||||||
// within the channel's history.
|
// within the channel's history.
|
||||||
if err = net.RestartNode(carol, func() error {
|
if err = net.RestartNode(carol, func() error {
|
||||||
return os.Rename(carolTempDbFile, carolDbPath)
|
return os.Rename(carolTempDbFile, carol.DBPath())
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
t.Fatalf("unable to restart node: %v", err)
|
t.Fatalf("unable to restart node: %v", err)
|
||||||
}
|
}
|
||||||
@ -3296,7 +3300,7 @@ func testRevokedCloseRetributionRemoteHodl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testHtlcErrorPropagation(net *networkHarness, t *harnessTest) {
|
func testHtlcErrorPropagation(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
// In this test we wish to exercise the daemon's correct parsing,
|
// In this test we wish to exercise the daemon's correct parsing,
|
||||||
// handling, and propagation of errors that occur while processing a
|
// handling, and propagation of errors that occur while processing a
|
||||||
// multi-hop payment.
|
// multi-hop payment.
|
||||||
@ -3582,7 +3586,7 @@ out:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGraphTopologyNotifications(net *networkHarness, t *harnessTest) {
|
func testGraphTopologyNotifications(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
const chanAmt = maxFundingAmount
|
const chanAmt = maxFundingAmount
|
||||||
timeout := time.Duration(time.Second * 5)
|
timeout := time.Duration(time.Second * 5)
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
@ -3808,7 +3812,7 @@ func testGraphTopologyNotifications(net *networkHarness, t *harnessTest) {
|
|||||||
// testNodeAnnouncement ensures that when a node is started with one or more
|
// testNodeAnnouncement ensures that when a node is started with one or more
|
||||||
// external IP addresses specified on the command line, that those addresses
|
// external IP addresses specified on the command line, that those addresses
|
||||||
// announced to the network and reported in the network graph.
|
// announced to the network and reported in the network graph.
|
||||||
func testNodeAnnouncement(net *networkHarness, t *harnessTest) {
|
func testNodeAnnouncement(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
|
|
||||||
ipAddresses := map[string]bool{
|
ipAddresses := map[string]bool{
|
||||||
@ -3883,7 +3887,7 @@ func testNodeAnnouncement(net *networkHarness, t *harnessTest) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNodeSignVerify(net *networkHarness, t *harnessTest) {
|
func testNodeSignVerify(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
timeout := time.Duration(time.Second * 5)
|
timeout := time.Duration(time.Second * 5)
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
|
|
||||||
@ -3961,12 +3965,12 @@ func testNodeSignVerify(net *networkHarness, t *harnessTest) {
|
|||||||
// testAsyncPayments tests the performance of the async payments, and also
|
// testAsyncPayments tests the performance of the async payments, and also
|
||||||
// checks that balances of both sides can't be become negative under stress
|
// checks that balances of both sides can't be become negative under stress
|
||||||
// payment strikes.
|
// payment strikes.
|
||||||
func testAsyncPayments(net *networkHarness, t *harnessTest) {
|
func testAsyncPayments(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
|
|
||||||
// As we'll be querying the channels state frequently we'll
|
// As we'll be querying the channels state frequently we'll
|
||||||
// create a closure helper function for the purpose.
|
// create a closure helper function for the purpose.
|
||||||
getChanInfo := func(node *lightningNode) (*lnrpc.ActiveChannel, error) {
|
getChanInfo := func(node *lntest.HarnessNode) (*lnrpc.ActiveChannel, error) {
|
||||||
req := &lnrpc.ListChannelsRequest{}
|
req := &lnrpc.ListChannelsRequest{}
|
||||||
channelInfo, err := node.ListChannels(ctxb, req)
|
channelInfo, err := node.ListChannels(ctxb, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -4139,12 +4143,12 @@ func testAsyncPayments(net *networkHarness, t *harnessTest) {
|
|||||||
|
|
||||||
// testBidirectionalAsyncPayments tests that nodes are able to send the
|
// testBidirectionalAsyncPayments tests that nodes are able to send the
|
||||||
// payments to each other in async manner without blocking.
|
// payments to each other in async manner without blocking.
|
||||||
func testBidirectionalAsyncPayments(net *networkHarness, t *harnessTest) {
|
func testBidirectionalAsyncPayments(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
|
|
||||||
// As we'll be querying the channels state frequently we'll
|
// As we'll be querying the channels state frequently we'll
|
||||||
// create a closure helper function for the purpose.
|
// create a closure helper function for the purpose.
|
||||||
getChanInfo := func(node *lightningNode) (*lnrpc.ActiveChannel, error) {
|
getChanInfo := func(node *lntest.HarnessNode) (*lnrpc.ActiveChannel, error) {
|
||||||
req := &lnrpc.ListChannelsRequest{}
|
req := &lnrpc.ListChannelsRequest{}
|
||||||
channelInfo, err := node.ListChannels(ctxb, req)
|
channelInfo, err := node.ListChannels(ctxb, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -4376,7 +4380,7 @@ func testBidirectionalAsyncPayments(net *networkHarness, t *harnessTest) {
|
|||||||
|
|
||||||
type testCase struct {
|
type testCase struct {
|
||||||
name string
|
name string
|
||||||
test func(net *networkHarness, t *harnessTest)
|
test func(net *lntest.NetworkHarness, t *harnessTest)
|
||||||
}
|
}
|
||||||
|
|
||||||
var testsCases = []*testCase{
|
var testsCases = []*testCase{
|
||||||
@ -4476,7 +4480,7 @@ func TestLightningNetworkDaemon(t *testing.T) {
|
|||||||
|
|
||||||
// First create the network harness to gain access to its
|
// First create the network harness to gain access to its
|
||||||
// 'OnTxAccepted' call back.
|
// 'OnTxAccepted' call back.
|
||||||
lndHarness, err := newNetworkHarness()
|
lndHarness, err := lntest.NewNetworkHarness()
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,41 @@
|
|||||||
package lntest
|
package lntest
|
||||||
|
|
||||||
// networkHarness is an integration testing harness for the lightning network.
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"google.golang.org/grpc/grpclog"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
|
"github.com/roasbeef/btcd/chaincfg"
|
||||||
|
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
||||||
|
"github.com/roasbeef/btcd/integration/rpctest"
|
||||||
|
"github.com/roasbeef/btcd/rpcclient"
|
||||||
|
"github.com/roasbeef/btcd/txscript"
|
||||||
|
"github.com/roasbeef/btcd/wire"
|
||||||
|
"github.com/roasbeef/btcutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NetworkHarness is an integration testing harness for the lightning network.
|
||||||
// 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
|
rpcConfig rpcclient.ConnConfig
|
||||||
netParams *chaincfg.Params
|
netParams *chaincfg.Params
|
||||||
Miner *rpctest.Harness
|
|
||||||
|
|
||||||
activeNodes map[int]*lightningNode
|
// Miner is a reference to a running full node that can be used to create
|
||||||
|
// new blocks on the network.
|
||||||
|
Miner *rpctest.Harness
|
||||||
|
|
||||||
|
activeNodes map[int]*HarnessNode
|
||||||
|
|
||||||
// Alice and Bob are the initial seeder nodes that are automatically
|
// Alice and Bob are the initial seeder nodes that are automatically
|
||||||
// created to be the initial participants of the test network.
|
// created to be the initial participants of the test network.
|
||||||
Alice *lightningNode
|
Alice *HarnessNode
|
||||||
Bob *lightningNode
|
Bob *HarnessNode
|
||||||
|
|
||||||
seenTxns chan chainhash.Hash
|
seenTxns chan chainhash.Hash
|
||||||
bitcoinWatchRequests chan *txWatchRequest
|
bitcoinWatchRequests chan *txWatchRequest
|
||||||
@ -27,13 +49,13 @@ type networkHarness struct {
|
|||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// newNetworkHarness creates a new network test harness.
|
// NewNetworkHarness creates a new network test harness.
|
||||||
// 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'll save developers from having to manually `go install`
|
// current repo. This'll save developers from having to manually `go install`
|
||||||
// within the repo each time before changes
|
// within the repo each time before changes
|
||||||
func newNetworkHarness() (*networkHarness, error) {
|
func NewNetworkHarness() (*NetworkHarness, error) {
|
||||||
return &networkHarness{
|
return &NetworkHarness{
|
||||||
activeNodes: make(map[int]*lightningNode),
|
activeNodes: make(map[int]*HarnessNode),
|
||||||
seenTxns: make(chan chainhash.Hash),
|
seenTxns: make(chan chainhash.Hash),
|
||||||
bitcoinWatchRequests: make(chan *txWatchRequest),
|
bitcoinWatchRequests: make(chan *txWatchRequest),
|
||||||
lndErrorChan: make(chan error),
|
lndErrorChan: make(chan error),
|
||||||
@ -44,10 +66,10 @@ func newNetworkHarness() (*networkHarness, error) {
|
|||||||
// InitializeSeedNodes initializes alice and bob nodes given an already
|
// InitializeSeedNodes initializes alice and bob nodes given an already
|
||||||
// running instance of btcd's rpctest harness and extra command line flags,
|
// running instance of btcd's rpctest harness and extra command line flags,
|
||||||
// which should be formatted properly - "--arg=value".
|
// which should be formatted properly - "--arg=value".
|
||||||
func (n *networkHarness) InitializeSeedNodes(r *rpctest.Harness, lndArgs []string) error {
|
func (n *NetworkHarness) InitializeSeedNodes(r *rpctest.Harness, lndArgs []string) error {
|
||||||
n.netParams = r.ActiveNet
|
n.netParams = r.ActiveNet
|
||||||
n.Miner = r
|
n.Miner = r
|
||||||
n.rpcConfig = nodeConfig
|
n.rpcConfig = r.RPCConfig()
|
||||||
|
|
||||||
config := nodeConfig{
|
config := nodeConfig{
|
||||||
RPCConfig: &n.rpcConfig,
|
RPCConfig: &n.rpcConfig,
|
||||||
@ -56,17 +78,17 @@ func (n *networkHarness) InitializeSeedNodes(r *rpctest.Harness, lndArgs []strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
n.Alice, err = newLightningNode(config)
|
n.Alice, err = newNode(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
n.Bob, err = newLightningNode(config)
|
n.Bob, err = newNode(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
n.activeNodes[n.Alice.nodeID] = n.Alice
|
n.activeNodes[n.Alice.NodeID] = n.Alice
|
||||||
n.activeNodes[n.Bob.nodeID] = n.Bob
|
n.activeNodes[n.Bob.NodeID] = n.Bob
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -74,7 +96,7 @@ func (n *networkHarness) InitializeSeedNodes(r *rpctest.Harness, lndArgs []strin
|
|||||||
// ProcessErrors returns a channel used for reporting any fatal process errors.
|
// ProcessErrors returns a channel used for reporting any fatal process errors.
|
||||||
// If any of the active nodes within the harness' test network incur a fatal
|
// If any of the active nodes within the harness' test network incur a fatal
|
||||||
// error, that error is sent over this channel.
|
// error, that error is sent over this channel.
|
||||||
func (n *networkHarness) ProcessErrors() <-chan error {
|
func (n *NetworkHarness) ProcessErrors() <-chan error {
|
||||||
return n.lndErrorChan
|
return n.lndErrorChan
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +115,7 @@ func (f *fakeLogger) Println(args ...interface{}) {}
|
|||||||
// node's wallets will be funded wallets with ten 1 BTC outputs each. Finally
|
// node's wallets will be funded wallets with ten 1 BTC outputs each. Finally
|
||||||
// rpc clients capable of communicating with the initial seeder nodes are
|
// rpc clients capable of communicating with the initial seeder nodes are
|
||||||
// created.
|
// created.
|
||||||
func (n *networkHarness) SetUp() error {
|
func (n *NetworkHarness) SetUp() error {
|
||||||
// Swap out grpc's default logger with out fake logger which drops the
|
// Swap out grpc's default logger with out fake logger which drops the
|
||||||
// statements on the floor.
|
// statements on the floor.
|
||||||
grpclog.SetLogger(&fakeLogger{})
|
grpclog.SetLogger(&fakeLogger{})
|
||||||
@ -105,13 +127,13 @@ func (n *networkHarness) SetUp() error {
|
|||||||
wg.Add(2)
|
wg.Add(2)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
if err := n.Alice.Start(n.lndErrorChan); err != nil {
|
if err := n.Alice.start(n.lndErrorChan); err != nil {
|
||||||
errChan <- err
|
errChan <- err
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
if err := n.Bob.Start(n.lndErrorChan); err != nil {
|
if err := n.Bob.start(n.lndErrorChan); err != nil {
|
||||||
errChan <- err
|
errChan <- err
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -200,7 +222,7 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TearDownAll tears down all active nodes within the test lightning network.
|
// TearDownAll tears down all active nodes within the test lightning network.
|
||||||
func (n *networkHarness) TearDownAll() error {
|
func (n *NetworkHarness) TearDownAll() error {
|
||||||
for _, node := range n.activeNodes {
|
for _, node := range n.activeNodes {
|
||||||
if err := node.Shutdown(); err != nil {
|
if err := node.Shutdown(); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -213,14 +235,14 @@ func (n *networkHarness) TearDownAll() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNode fully initializes a returns a new lightningNode binded to the
|
// NewNode fully initializes a returns a new HarnessNode binded to the
|
||||||
// current instance of the network harness. The created node is running, but
|
// current instance of the network harness. The created node is running, but
|
||||||
// not yet connected to other nodes within the network.
|
// not yet connected to other nodes within the network.
|
||||||
func (n *networkHarness) NewNode(extraArgs []string) (*lightningNode, error) {
|
func (n *NetworkHarness) NewNode(extraArgs []string) (*HarnessNode, error) {
|
||||||
n.Lock()
|
n.Lock()
|
||||||
defer n.Unlock()
|
defer n.Unlock()
|
||||||
|
|
||||||
node, err := newLightningNode(nodeConfig{
|
node, err := newNode(nodeConfig{
|
||||||
RPCConfig: &n.rpcConfig,
|
RPCConfig: &n.rpcConfig,
|
||||||
NetParams: n.netParams,
|
NetParams: n.netParams,
|
||||||
ExtraArgs: extraArgs,
|
ExtraArgs: extraArgs,
|
||||||
@ -231,9 +253,9 @@ func (n *networkHarness) NewNode(extraArgs []string) (*lightningNode, error) {
|
|||||||
|
|
||||||
// Put node in activeNodes to ensure Shutdown is called even if Start
|
// Put node in activeNodes to ensure Shutdown is called even if Start
|
||||||
// returns an error.
|
// returns an error.
|
||||||
n.activeNodes[node.nodeID] = node
|
n.activeNodes[node.NodeID] = node
|
||||||
|
|
||||||
if err := node.Start(n.lndErrorChan); err != nil {
|
if err := node.start(n.lndErrorChan); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,7 +268,7 @@ func (n *networkHarness) NewNode(extraArgs []string) (*lightningNode, error) {
|
|||||||
//
|
//
|
||||||
// NOTE: This function may block for up to 15-seconds as it will not return
|
// NOTE: This function may block for up to 15-seconds as it will not return
|
||||||
// until the new connection is detected as being known to both nodes.
|
// until the new connection is detected as being known to both nodes.
|
||||||
func (n *networkHarness) ConnectNodes(ctx context.Context, a, b *lightningNode) error {
|
func (n *NetworkHarness) ConnectNodes(ctx context.Context, a, b *HarnessNode) error {
|
||||||
bobInfo, err := b.GetInfo(ctx, &lnrpc.GetInfoRequest{})
|
bobInfo, err := b.GetInfo(ctx, &lnrpc.GetInfoRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -288,7 +310,7 @@ func (n *networkHarness) ConnectNodes(ctx context.Context, a, b *lightningNode)
|
|||||||
|
|
||||||
// DisconnectNodes disconnects node a from node b by sending RPC message
|
// DisconnectNodes disconnects node a from node b by sending RPC message
|
||||||
// from a node to b node
|
// from a node to b node
|
||||||
func (n *networkHarness) DisconnectNodes(ctx context.Context, a, b *lightningNode) error {
|
func (n *NetworkHarness) DisconnectNodes(ctx context.Context, a, b *HarnessNode) error {
|
||||||
bobInfo, err := b.GetInfo(ctx, &lnrpc.GetInfoRequest{})
|
bobInfo, err := b.GetInfo(ctx, &lnrpc.GetInfoRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -315,8 +337,8 @@ func (n *networkHarness) DisconnectNodes(ctx context.Context, a, b *lightningNod
|
|||||||
// This method can be useful when testing edge cases such as a node broadcast
|
// This method can be useful when testing edge cases such as a node broadcast
|
||||||
// and invalidated prior state, or persistent state recovery, simulating node
|
// and invalidated prior state, or persistent state recovery, simulating node
|
||||||
// crashes, etc.
|
// crashes, etc.
|
||||||
func (n *networkHarness) RestartNode(node *lightningNode, callback func() error) error {
|
func (n *NetworkHarness) RestartNode(node *HarnessNode, callback func() error) error {
|
||||||
return node.Restart(n.lndErrorChan, callback)
|
return node.restart(n.lndErrorChan, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(roasbeef): add a WithChannel higher-order function?
|
// TODO(roasbeef): add a WithChannel higher-order function?
|
||||||
@ -335,7 +357,7 @@ type txWatchRequest struct {
|
|||||||
// bitcoinNetworkWatcher is a goroutine which accepts async notification
|
// bitcoinNetworkWatcher is a goroutine which accepts async notification
|
||||||
// requests for the broadcast of a target transaction, and then dispatches the
|
// requests for the broadcast of a target transaction, and then dispatches the
|
||||||
// transaction once its seen on the Bitcoin network.
|
// transaction once its seen on the Bitcoin network.
|
||||||
func (n *networkHarness) networkWatcher() {
|
func (n *NetworkHarness) networkWatcher() {
|
||||||
seenTxns := make(map[chainhash.Hash]struct{})
|
seenTxns := make(map[chainhash.Hash]struct{})
|
||||||
clients := make(map[chainhash.Hash][]chan struct{})
|
clients := make(map[chainhash.Hash][]chan struct{})
|
||||||
|
|
||||||
@ -381,7 +403,7 @@ func (n *networkHarness) networkWatcher() {
|
|||||||
|
|
||||||
// OnTxAccepted is a callback to be called each time a new transaction has been
|
// OnTxAccepted is a callback to be called each time a new transaction has been
|
||||||
// broadcast on the network.
|
// broadcast on the network.
|
||||||
func (n *networkHarness) OnTxAccepted(hash *chainhash.Hash, amt btcutil.Amount) {
|
func (n *NetworkHarness) OnTxAccepted(hash *chainhash.Hash, amt btcutil.Amount) {
|
||||||
// Return immediately if harness has been torn down.
|
// Return immediately if harness has been torn down.
|
||||||
select {
|
select {
|
||||||
case <-n.quit:
|
case <-n.quit:
|
||||||
@ -398,11 +420,11 @@ func (n *networkHarness) OnTxAccepted(hash *chainhash.Hash, amt btcutil.Amount)
|
|||||||
// the transaction isn't seen within the network before the passed timeout,
|
// the transaction isn't seen within the network before the passed timeout,
|
||||||
// then an error is returned.
|
// then an error is returned.
|
||||||
// TODO(roasbeef): add another method which creates queue of all seen transactions
|
// TODO(roasbeef): add another method which creates queue of all seen transactions
|
||||||
func (n *networkHarness) WaitForTxBroadcast(ctx context.Context, txid chainhash.Hash) error {
|
func (n *NetworkHarness) WaitForTxBroadcast(ctx context.Context, txid chainhash.Hash) error {
|
||||||
// Return immediately if harness has been torn down.
|
// Return immediately if harness has been torn down.
|
||||||
select {
|
select {
|
||||||
case <-n.quit:
|
case <-n.quit:
|
||||||
return fmt.Errorf("networkHarness has been torn down")
|
return fmt.Errorf("NetworkHarness has been torn down")
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,7 +439,7 @@ func (n *networkHarness) WaitForTxBroadcast(ctx context.Context, txid chainhash.
|
|||||||
case <-eventChan:
|
case <-eventChan:
|
||||||
return nil
|
return nil
|
||||||
case <-n.quit:
|
case <-n.quit:
|
||||||
return fmt.Errorf("networkHarness has been torn down")
|
return fmt.Errorf("NetworkHarness has been torn down")
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return fmt.Errorf("tx not seen before context timeout")
|
return fmt.Errorf("tx not seen before context timeout")
|
||||||
}
|
}
|
||||||
@ -427,8 +449,8 @@ func (n *networkHarness) WaitForTxBroadcast(ctx context.Context, txid chainhash.
|
|||||||
// passed channel funding parameters. If the passed context has a timeout, then
|
// passed channel funding parameters. If the passed context has a timeout, then
|
||||||
// if the timeout is reached before the channel pending notification is
|
// if the timeout is reached before the channel pending notification is
|
||||||
// received, an error is returned.
|
// received, an error is returned.
|
||||||
func (n *networkHarness) OpenChannel(ctx context.Context,
|
func (n *NetworkHarness) OpenChannel(ctx context.Context,
|
||||||
srcNode, destNode *lightningNode, amt btcutil.Amount,
|
srcNode, destNode *HarnessNode, amt btcutil.Amount,
|
||||||
pushAmt btcutil.Amount) (lnrpc.Lightning_OpenChannelClient, error) {
|
pushAmt btcutil.Amount) (lnrpc.Lightning_OpenChannelClient, error) {
|
||||||
|
|
||||||
// Wait until srcNode and destNode have the latest chain synced.
|
// Wait until srcNode and destNode have the latest chain synced.
|
||||||
@ -489,8 +511,8 @@ func (n *networkHarness) OpenChannel(ctx context.Context,
|
|||||||
// passed channel funding parameters. If the passed context has a timeout, then
|
// passed channel funding parameters. If the passed context has a timeout, then
|
||||||
// if the timeout is reached before the channel pending notification is
|
// if the timeout is reached before the channel pending notification is
|
||||||
// received, an error is returned.
|
// received, an error is returned.
|
||||||
func (n *networkHarness) OpenPendingChannel(ctx context.Context,
|
func (n *NetworkHarness) OpenPendingChannel(ctx context.Context,
|
||||||
srcNode, destNode *lightningNode, amt btcutil.Amount,
|
srcNode, destNode *HarnessNode, amt btcutil.Amount,
|
||||||
pushAmt btcutil.Amount) (*lnrpc.PendingUpdate, error) {
|
pushAmt btcutil.Amount) (*lnrpc.PendingUpdate, error) {
|
||||||
|
|
||||||
// Wait until srcNode and destNode have blockchain synced
|
// Wait until srcNode and destNode have blockchain synced
|
||||||
@ -549,7 +571,7 @@ func (n *networkHarness) OpenPendingChannel(ctx context.Context,
|
|||||||
// consuming a message from the past open channel stream. If the passed context
|
// consuming a message from the past open channel stream. If the passed context
|
||||||
// has a timeout, then if the timeout is reached before the channel has been
|
// has a timeout, then if the timeout is reached before the channel has been
|
||||||
// opened, then an error is returned.
|
// opened, then an error is returned.
|
||||||
func (n *networkHarness) WaitForChannelOpen(ctx context.Context,
|
func (n *NetworkHarness) WaitForChannelOpen(ctx context.Context,
|
||||||
openChanStream lnrpc.Lightning_OpenChannelClient) (*lnrpc.ChannelPoint, error) {
|
openChanStream lnrpc.Lightning_OpenChannelClient) (*lnrpc.ChannelPoint, error) {
|
||||||
|
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
@ -585,8 +607,8 @@ func (n *networkHarness) WaitForChannelOpen(ctx context.Context,
|
|||||||
// passed channel point, initiated by the passed lnNode. If the passed context
|
// passed channel point, initiated by the passed lnNode. If the passed context
|
||||||
// has a timeout, then if the timeout is reached before the channel close is
|
// has a timeout, then if the timeout is reached before the channel close is
|
||||||
// pending, then an error is returned.
|
// pending, then an error is returned.
|
||||||
func (n *networkHarness) CloseChannel(ctx context.Context,
|
func (n *NetworkHarness) CloseChannel(ctx context.Context,
|
||||||
lnNode *lightningNode, cp *lnrpc.ChannelPoint,
|
lnNode *HarnessNode, cp *lnrpc.ChannelPoint,
|
||||||
force bool) (lnrpc.Lightning_CloseChannelClient, *chainhash.Hash, error) {
|
force bool) (lnrpc.Lightning_CloseChannelClient, *chainhash.Hash, error) {
|
||||||
|
|
||||||
// Create a channel outpoint that we can use to compare to channels
|
// Create a channel outpoint that we can use to compare to channels
|
||||||
@ -684,7 +706,7 @@ CheckActive:
|
|||||||
// stream that the node has deemed the channel has been fully closed. If the
|
// stream that the node has deemed the channel has been fully closed. If the
|
||||||
// passed context has a timeout, then if the timeout is reached before the
|
// passed context has a timeout, then if the timeout is reached before the
|
||||||
// notification is received then an error is returned.
|
// notification is received then an error is returned.
|
||||||
func (n *networkHarness) WaitForChannelClose(ctx context.Context,
|
func (n *NetworkHarness) WaitForChannelClose(ctx context.Context,
|
||||||
closeChanStream lnrpc.Lightning_CloseChannelClient) (*chainhash.Hash, error) {
|
closeChanStream lnrpc.Lightning_CloseChannelClient) (*chainhash.Hash, error) {
|
||||||
|
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
@ -720,8 +742,8 @@ func (n *networkHarness) WaitForChannelClose(ctx context.Context,
|
|||||||
|
|
||||||
// AssertChannelExists asserts that an active channel identified by
|
// AssertChannelExists asserts that an active channel identified by
|
||||||
// channelPoint is known to exist from the point-of-view of node..
|
// channelPoint is known to exist from the point-of-view of node..
|
||||||
func (n *networkHarness) AssertChannelExists(ctx context.Context,
|
func (n *NetworkHarness) AssertChannelExists(ctx context.Context,
|
||||||
node *lightningNode, chanPoint *wire.OutPoint) error {
|
node *HarnessNode, chanPoint *wire.OutPoint) error {
|
||||||
|
|
||||||
req := &lnrpc.ListChannelsRequest{}
|
req := &lnrpc.ListChannelsRequest{}
|
||||||
resp, err := node.ListChannels(ctx, req)
|
resp, err := node.ListChannels(ctx, req)
|
||||||
@ -743,7 +765,7 @@ func (n *networkHarness) AssertChannelExists(ctx context.Context,
|
|||||||
// of a particular node in the case of a test failure.
|
// of a particular node in the case of a test failure.
|
||||||
// Logs from lightning node being generated with delay - you should
|
// Logs from lightning node being generated with delay - you should
|
||||||
// add time.Sleep() in order to get all logs.
|
// add time.Sleep() in order to get all logs.
|
||||||
func (n *networkHarness) DumpLogs(node *lightningNode) (string, error) {
|
func (n *NetworkHarness) DumpLogs(node *HarnessNode) (string, error) {
|
||||||
logFile := fmt.Sprintf("%v/simnet/lnd.log", node.cfg.LogDir)
|
logFile := fmt.Sprintf("%v/simnet/lnd.log", node.cfg.LogDir)
|
||||||
|
|
||||||
buf, err := ioutil.ReadFile(logFile)
|
buf, err := ioutil.ReadFile(logFile)
|
||||||
@ -756,8 +778,8 @@ func (n *networkHarness) DumpLogs(node *lightningNode) (string, error) {
|
|||||||
|
|
||||||
// SendCoins attempts to send amt satoshis from the internal mining node to the
|
// SendCoins attempts to send amt satoshis from the internal mining node to the
|
||||||
// targeted lightning node.
|
// targeted lightning node.
|
||||||
func (n *networkHarness) SendCoins(ctx context.Context, amt btcutil.Amount,
|
func (n *NetworkHarness) SendCoins(ctx context.Context, amt btcutil.Amount,
|
||||||
target *lightningNode) error {
|
target *HarnessNode) error {
|
||||||
|
|
||||||
balReq := &lnrpc.WalletBalanceRequest{}
|
balReq := &lnrpc.WalletBalanceRequest{}
|
||||||
initialBalance, err := target.WalletBalance(ctx, balReq)
|
initialBalance, err := target.WalletBalance(ctx, balReq)
|
||||||
|
201
lntest/node.go
201
lntest/node.go
@ -1,5 +1,34 @@
|
|||||||
package lntest
|
package lntest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/credentials"
|
||||||
|
macaroon "gopkg.in/macaroon.v1"
|
||||||
|
|
||||||
|
"github.com/go-errors/errors"
|
||||||
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
|
"github.com/lightningnetwork/lnd/macaroons"
|
||||||
|
"github.com/roasbeef/btcd/chaincfg"
|
||||||
|
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
||||||
|
"github.com/roasbeef/btcd/rpcclient"
|
||||||
|
"github.com/roasbeef/btcd/wire"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// numActiveNodes is the number of active nodes within the test network.
|
// numActiveNodes is the number of active nodes within the test network.
|
||||||
numActiveNodes = 0
|
numActiveNodes = 0
|
||||||
@ -18,8 +47,6 @@ var (
|
|||||||
// as such: defaultP2pPort + (2 * harness.nodeNum).
|
// as such: defaultP2pPort + (2 * harness.nodeNum).
|
||||||
defaultClientPort = 19556
|
defaultClientPort = 19556
|
||||||
|
|
||||||
harnessNetParams = &chaincfg.SimNetParams
|
|
||||||
|
|
||||||
// logOutput is a flag that can be set to append the output from the
|
// logOutput is a flag that can be set to append the output from the
|
||||||
// seed nodes to log files.
|
// seed nodes to log files.
|
||||||
logOutput = flag.Bool("logoutput", false,
|
logOutput = flag.Bool("logoutput", false,
|
||||||
@ -119,13 +146,14 @@ func (cfg nodeConfig) genArgs() []string {
|
|||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
// lightningNode represents an instance of lnd running within our test network
|
// HarnessNode represents an instance of lnd running within our test network
|
||||||
// harness. Each lightningNode instance also fully embedds an RPC client in
|
// harness. Each HarnessNode instance also fully embedds an RPC client in
|
||||||
// order to pragmatically drive the node.
|
// order to pragmatically drive the node.
|
||||||
type lightningNode struct {
|
type HarnessNode struct {
|
||||||
cfg *nodeConfig
|
cfg *nodeConfig
|
||||||
|
|
||||||
nodeID int
|
// NodeID is a unique identifier for the node within a NetworkHarness.
|
||||||
|
NodeID int
|
||||||
|
|
||||||
// PubKey is the serialized compressed identity public key of the node.
|
// PubKey is the serialized compressed identity public key of the node.
|
||||||
// This field will only be populated once the node itself has been
|
// This field will only be populated once the node itself has been
|
||||||
@ -137,7 +165,7 @@ type lightningNode struct {
|
|||||||
pidFile string
|
pidFile string
|
||||||
|
|
||||||
// processExit is a channel that's closed once it's detected that the
|
// processExit is a channel that's closed once it's detected that the
|
||||||
// process this instance of lightningNode is bound to has exited.
|
// process this instance of HarnessNode is bound to has exited.
|
||||||
processExit chan struct{}
|
processExit chan struct{}
|
||||||
|
|
||||||
chanWatchRequests chan *chanWatchRequest
|
chanWatchRequests chan *chanWatchRequest
|
||||||
@ -148,9 +176,11 @@ type lightningNode struct {
|
|||||||
lnrpc.LightningClient
|
lnrpc.LightningClient
|
||||||
}
|
}
|
||||||
|
|
||||||
// newLightningNode creates a new test lightning node instance from the passed
|
// Assert *HarnessNode implements the lnrpc.LightningClient interface.
|
||||||
// rpc config and slice of extra arguments.
|
var _ lnrpc.LightningClient = (*HarnessNode)(nil)
|
||||||
func newLightningNode(cfg nodeConfig) (*lightningNode, error) {
|
|
||||||
|
// newNode creates a new test lightning node instance from the passed config.
|
||||||
|
func newNode(cfg nodeConfig) (*HarnessNode, error) {
|
||||||
if cfg.BaseDir == "" {
|
if cfg.BaseDir == "" {
|
||||||
var err error
|
var err error
|
||||||
cfg.BaseDir, err = ioutil.TempDir("", "lndtest-node")
|
cfg.BaseDir, err = ioutil.TempDir("", "lndtest-node")
|
||||||
@ -170,30 +200,35 @@ func newLightningNode(cfg nodeConfig) (*lightningNode, error) {
|
|||||||
nodeNum := numActiveNodes
|
nodeNum := numActiveNodes
|
||||||
numActiveNodes++
|
numActiveNodes++
|
||||||
|
|
||||||
return &lightningNode{
|
return &HarnessNode{
|
||||||
cfg: &cfg,
|
cfg: &cfg,
|
||||||
nodeID: nodeNum,
|
NodeID: nodeNum,
|
||||||
chanWatchRequests: make(chan *chanWatchRequest),
|
chanWatchRequests: make(chan *chanWatchRequest),
|
||||||
processExit: make(chan struct{}),
|
processExit: make(chan struct{}),
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DBPath returns the filepath to the channeldb database file for this node.
|
||||||
|
func (hn *HarnessNode) DBPath() string {
|
||||||
|
return hn.cfg.DBPath()
|
||||||
|
}
|
||||||
|
|
||||||
// Start launches a new process running lnd. Additionally, the PID of the
|
// Start launches a new process running lnd. Additionally, the PID of the
|
||||||
// launched process is saved in order to possibly kill the process forcibly
|
// launched process is saved in order to possibly kill the process forcibly
|
||||||
// later.
|
// later.
|
||||||
func (l *lightningNode) Start(lndError chan<- error) error {
|
func (hn *HarnessNode) start(lndError chan<- error) error {
|
||||||
args := l.cfg.genArgs()
|
args := hn.cfg.genArgs()
|
||||||
l.cmd = exec.Command("lnd", args...)
|
hn.cmd = exec.Command("lnd", args...)
|
||||||
|
|
||||||
// Redirect stderr output to buffer
|
// Redirect stderr output to buffer
|
||||||
var errb bytes.Buffer
|
var errb bytes.Buffer
|
||||||
l.cmd.Stderr = &errb
|
hn.cmd.Stderr = &errb
|
||||||
|
|
||||||
// If the logoutput flag is passed, redirect output from the nodes to
|
// If the logoutput flag is passed, redirect output from the nodes to
|
||||||
// log files.
|
// log files.
|
||||||
if *logOutput {
|
if *logOutput {
|
||||||
logFile := fmt.Sprintf("output%d.log", l.nodeID)
|
logFile := fmt.Sprintf("output%d.log", hn.NodeID)
|
||||||
|
|
||||||
// Create file if not exists, otherwise append.
|
// Create file if not exists, otherwise append.
|
||||||
file, err := os.OpenFile(logFile,
|
file, err := os.OpenFile(logFile,
|
||||||
@ -204,69 +239,70 @@ func (l *lightningNode) Start(lndError chan<- error) error {
|
|||||||
|
|
||||||
// Pass node's stderr to both errb and the file.
|
// Pass node's stderr to both errb and the file.
|
||||||
w := io.MultiWriter(&errb, file)
|
w := io.MultiWriter(&errb, file)
|
||||||
l.cmd.Stderr = w
|
hn.cmd.Stderr = w
|
||||||
|
|
||||||
// Pass the node's stdout only to the file.
|
// Pass the node's stdout only to the file.
|
||||||
l.cmd.Stdout = file
|
hn.cmd.Stdout = file
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := l.cmd.Start(); err != nil {
|
if err := hn.cmd.Start(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Launch a new goroutine which that bubbles up any potential fatal
|
// Launch a new goroutine which that bubbles up any potential fatal
|
||||||
// process errors to the goroutine running the tests.
|
// process errors to the goroutine running the tests.
|
||||||
go func() {
|
go func() {
|
||||||
err := l.cmd.Wait()
|
err := hn.cmd.Wait()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lndError <- errors.Errorf("%v\n%v\n", err, errb.String())
|
lndError <- errors.Errorf("%v\n%v\n", err, errb.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signal any onlookers that this process has exited.
|
// Signal any onlookers that this process has exited.
|
||||||
close(l.processExit)
|
close(hn.processExit)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Write process ID to a file.
|
// Write process ID to a file.
|
||||||
if err := l.writePidFile(); err != nil {
|
if err := hn.writePidFile(); err != nil {
|
||||||
l.cmd.Process.Kill()
|
hn.cmd.Process.Kill()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since Stop uses the LightningClient to stop the node, if we fail to get a
|
// Since Stop uses the LightningClient to stop the node, if we fail to get a
|
||||||
// connected client, we have to kill the process.
|
// connected client, we have to kill the process.
|
||||||
conn, err := l.connectRPC()
|
conn, err := hn.connectRPC()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.cmd.Process.Kill()
|
hn.cmd.Process.Kill()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
l.LightningClient = lnrpc.NewLightningClient(conn)
|
hn.LightningClient = lnrpc.NewLightningClient(conn)
|
||||||
|
|
||||||
// Obtain the lnid of this node for quick identification purposes.
|
// Obtain the lnid of this node for quick identification purposes.
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
info, err := l.GetInfo(ctxb, &lnrpc.GetInfoRequest{})
|
info, err := hn.GetInfo(ctxb, &lnrpc.GetInfoRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
l.PubKeyStr = info.IdentityPubkey
|
hn.PubKeyStr = info.IdentityPubkey
|
||||||
|
|
||||||
pubkey, err := hex.DecodeString(info.IdentityPubkey)
|
pubkey, err := hex.DecodeString(info.IdentityPubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
copy(l.PubKey[:], pubkey)
|
copy(hn.PubKey[:], pubkey)
|
||||||
|
|
||||||
// Launch the watcher that'll hook into graph related topology change
|
// Launch the watcher that'll hook into graph related topology change
|
||||||
// from the PoV of this node.
|
// from the PoV of this node.
|
||||||
l.wg.Add(1)
|
hn.wg.Add(1)
|
||||||
go l.lightningNetworkWatcher()
|
go hn.lightningNetworkWatcher()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// writePidFile writes the process ID of the running lnd process to a .pid file.
|
// writePidFile writes the process ID of the running lnd process to a .pid file.
|
||||||
func (l *lightningNode) writePidFile() error {
|
func (hn *HarnessNode) writePidFile() error {
|
||||||
filePath := filepath.Join(l.cfg.BaseDir, fmt.Sprintf("%v.pid", l.nodeID))
|
filePath := filepath.Join(hn.cfg.BaseDir, fmt.Sprintf("%v.pid", hn.NodeID))
|
||||||
|
|
||||||
pid, err := os.Create(filePath)
|
pid, err := os.Create(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -274,22 +310,22 @@ func (l *lightningNode) writePidFile() error {
|
|||||||
}
|
}
|
||||||
defer pid.Close()
|
defer pid.Close()
|
||||||
|
|
||||||
_, err = fmt.Fprintf(pid, "%v\n", l.cmd.Process.Pid)
|
_, err = fmt.Fprintf(pid, "%v\n", hn.cmd.Process.Pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
l.pidFile = filePath
|
hn.pidFile = filePath
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// connectRPC uses the TLS certificate and admin macaroon files written by the
|
// connectRPC uses the TLS certificate and admin macaroon files written by the
|
||||||
// lnd node to create a gRPC client connection.
|
// lnd node to create a gRPC client connection.
|
||||||
func (l *lightningNode) connectRPC() (*grpc.ClientConn, error) {
|
func (hn *HarnessNode) connectRPC() (*grpc.ClientConn, error) {
|
||||||
// Wait until TLS certificate and admin macaroon are created before
|
// Wait until TLS certificate and admin macaroon are created before
|
||||||
// using them, up to 20 sec.
|
// using them, up to 20 sec.
|
||||||
tlsTimeout := time.After(30 * time.Second)
|
tlsTimeout := time.After(30 * time.Second)
|
||||||
for !fileExists(l.cfg.TLSCertPath) || !fileExists(l.cfg.AdminMacPath) {
|
for !fileExists(hn.cfg.TLSCertPath) || !fileExists(hn.cfg.AdminMacPath) {
|
||||||
select {
|
select {
|
||||||
case <-tlsTimeout:
|
case <-tlsTimeout:
|
||||||
return nil, fmt.Errorf("timeout waiting for TLS cert file " +
|
return nil, fmt.Errorf("timeout waiting for TLS cert file " +
|
||||||
@ -299,11 +335,11 @@ func (l *lightningNode) connectRPC() (*grpc.ClientConn, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsCreds, err := credentials.NewClientTLSFromFile(l.cfg.TLSCertPath, "")
|
tlsCreds, err := credentials.NewClientTLSFromFile(hn.cfg.TLSCertPath, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
macBytes, err := ioutil.ReadFile(l.cfg.AdminMacPath)
|
macBytes, err := ioutil.ReadFile(hn.cfg.AdminMacPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -317,26 +353,26 @@ func (l *lightningNode) connectRPC() (*grpc.ClientConn, error) {
|
|||||||
grpc.WithBlock(),
|
grpc.WithBlock(),
|
||||||
grpc.WithTimeout(time.Second * 20),
|
grpc.WithTimeout(time.Second * 20),
|
||||||
}
|
}
|
||||||
return grpc.Dial(l.rpcAddr, opts...)
|
return grpc.Dial(hn.cfg.RPCAddr(), opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanup cleans up all the temporary files created by the node's process.
|
// cleanup cleans up all the temporary files created by the node's process.
|
||||||
func (l *lightningNode) cleanup() error {
|
func (hn *HarnessNode) cleanup() error {
|
||||||
return os.RemoveAll(l.cfg.BaseDir)
|
return os.RemoveAll(hn.cfg.BaseDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop attempts to stop the active lnd process.
|
// Stop attempts to stop the active lnd process.
|
||||||
func (l *lightningNode) Stop() error {
|
func (hn *HarnessNode) stop() error {
|
||||||
// Do nothing if the process never started successfully.
|
// Do nothing if the process never started successfully.
|
||||||
if l.LightningClient == nil {
|
if hn.LightningClient == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do nothing if the process already finished.
|
// Do nothing if the process already finished.
|
||||||
select {
|
select {
|
||||||
case <-l.quit:
|
case <-hn.quit:
|
||||||
return nil
|
return nil
|
||||||
case <-l.processExit:
|
case <-hn.processExit:
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
@ -345,10 +381,10 @@ func (l *lightningNode) Stop() error {
|
|||||||
// closed before a response is returned.
|
// closed before a response is returned.
|
||||||
req := lnrpc.StopRequest{}
|
req := lnrpc.StopRequest{}
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
l.LightningClient.StopDaemon(ctx, &req)
|
hn.LightningClient.StopDaemon(ctx, &req)
|
||||||
|
|
||||||
close(l.quit)
|
close(hn.quit)
|
||||||
l.wg.Wait()
|
hn.wg.Wait()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,17 +394,17 @@ func (l *lightningNode) Stop() error {
|
|||||||
// connection attempt is successful. Additionally, if a callback is passed, the
|
// connection attempt is successful. Additionally, if a callback is passed, the
|
||||||
// closure will be executed after the node has been shutdown, but before the
|
// closure will be executed after the node has been shutdown, but before the
|
||||||
// process has been started up again.
|
// process has been started up again.
|
||||||
func (l *lightningNode) Restart(errChan chan error, callback func() error) error {
|
func (hn *HarnessNode) restart(errChan chan error, callback func() error) error {
|
||||||
if err := l.Stop(); err != nil {
|
if err := hn.stop(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
<-l.processExit
|
<-hn.processExit
|
||||||
|
|
||||||
l.LightningClient = nil
|
hn.LightningClient = nil
|
||||||
l.processExit = make(chan struct{})
|
hn.processExit = make(chan struct{})
|
||||||
l.quit = make(chan struct{})
|
hn.quit = make(chan struct{})
|
||||||
l.wg = sync.WaitGroup{}
|
hn.wg = sync.WaitGroup{}
|
||||||
|
|
||||||
if callback != nil {
|
if callback != nil {
|
||||||
if err := callback(); err != nil {
|
if err := callback(); err != nil {
|
||||||
@ -376,16 +412,16 @@ func (l *lightningNode) Restart(errChan chan error, callback func() error) error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return l.Start(errChan)
|
return hn.start(errChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shutdown stops the active lnd process and clean up any temporary directories
|
// Shutdown stops the active lnd process and clean up any temporary directories
|
||||||
// created along the way.
|
// created along the way.
|
||||||
func (l *lightningNode) Shutdown() error {
|
func (hn *HarnessNode) Shutdown() error {
|
||||||
if err := l.Stop(); err != nil {
|
if err := hn.stop(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := l.cleanup(); err != nil {
|
if err := hn.cleanup(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -407,17 +443,17 @@ type chanWatchRequest struct {
|
|||||||
// closed or opened within the network. In order to dispatch these
|
// closed or opened within the network. In order to dispatch these
|
||||||
// notifications, the GraphTopologySubscription client exposed as part of the
|
// notifications, the GraphTopologySubscription client exposed as part of the
|
||||||
// gRPC interface is used.
|
// gRPC interface is used.
|
||||||
func (l *lightningNode) lightningNetworkWatcher() {
|
func (hn *HarnessNode) lightningNetworkWatcher() {
|
||||||
defer l.wg.Done()
|
defer hn.wg.Done()
|
||||||
|
|
||||||
graphUpdates := make(chan *lnrpc.GraphTopologyUpdate)
|
graphUpdates := make(chan *lnrpc.GraphTopologyUpdate)
|
||||||
l.wg.Add(1)
|
hn.wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer l.wg.Done()
|
defer hn.wg.Done()
|
||||||
|
|
||||||
ctxb := context.Background()
|
ctxb := context.Background()
|
||||||
req := &lnrpc.GraphTopologySubscription{}
|
req := &lnrpc.GraphTopologySubscription{}
|
||||||
topologyClient, err := l.SubscribeChannelGraph(ctxb, req)
|
topologyClient, err := hn.SubscribeChannelGraph(ctxb, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// We panic here in case of an error as failure to
|
// We panic here in case of an error as failure to
|
||||||
// create the topology client will cause all subsequent
|
// create the topology client will cause all subsequent
|
||||||
@ -436,7 +472,7 @@ func (l *lightningNode) lightningNetworkWatcher() {
|
|||||||
|
|
||||||
select {
|
select {
|
||||||
case graphUpdates <- update:
|
case graphUpdates <- update:
|
||||||
case <-l.quit:
|
case <-hn.quit:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -506,7 +542,7 @@ func (l *lightningNode) lightningNetworkWatcher() {
|
|||||||
// A new watch request, has just arrived. We'll either be able
|
// A new watch request, has just arrived. We'll either be able
|
||||||
// to dispatch immediately, or need to add the client for
|
// to dispatch immediately, or need to add the client for
|
||||||
// processing later.
|
// processing later.
|
||||||
case watchRequest := <-l.chanWatchRequests:
|
case watchRequest := <-hn.chanWatchRequests:
|
||||||
targetChan := watchRequest.chanPoint
|
targetChan := watchRequest.chanPoint
|
||||||
|
|
||||||
// TODO(roasbeef): add update type also, checks for
|
// TODO(roasbeef): add update type also, checks for
|
||||||
@ -540,7 +576,7 @@ func (l *lightningNode) lightningNetworkWatcher() {
|
|||||||
closeClients[targetChan] = append(closeClients[targetChan],
|
closeClients[targetChan] = append(closeClients[targetChan],
|
||||||
watchRequest.eventChan)
|
watchRequest.eventChan)
|
||||||
|
|
||||||
case <-l.quit:
|
case <-hn.quit:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -550,7 +586,7 @@ func (l *lightningNode) lightningNetworkWatcher() {
|
|||||||
// outpoint is seen as being fully advertised within the network. A channel is
|
// outpoint is seen as being fully advertised within the network. A channel is
|
||||||
// considered "fully advertised" once both of its directional edges has been
|
// considered "fully advertised" once both of its directional edges has been
|
||||||
// advertised within the test Lightning Network.
|
// advertised within the test Lightning Network.
|
||||||
func (l *lightningNode) WaitForNetworkChannelOpen(ctx context.Context,
|
func (hn *HarnessNode) WaitForNetworkChannelOpen(ctx context.Context,
|
||||||
op *lnrpc.ChannelPoint) error {
|
op *lnrpc.ChannelPoint) error {
|
||||||
|
|
||||||
eventChan := make(chan struct{})
|
eventChan := make(chan struct{})
|
||||||
@ -560,7 +596,7 @@ func (l *lightningNode) WaitForNetworkChannelOpen(ctx context.Context,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
l.chanWatchRequests <- &chanWatchRequest{
|
hn.chanWatchRequests <- &chanWatchRequest{
|
||||||
chanPoint: wire.OutPoint{
|
chanPoint: wire.OutPoint{
|
||||||
Hash: *txid,
|
Hash: *txid,
|
||||||
Index: op.OutputIndex,
|
Index: op.OutputIndex,
|
||||||
@ -581,7 +617,7 @@ func (l *lightningNode) WaitForNetworkChannelOpen(ctx context.Context,
|
|||||||
// outpoint is seen as closed within the network. A channel is considered
|
// outpoint is seen as closed within the network. A channel is considered
|
||||||
// closed once a transaction spending the funding outpoint is seen within a
|
// closed once a transaction spending the funding outpoint is seen within a
|
||||||
// confirmed block.
|
// confirmed block.
|
||||||
func (l *lightningNode) WaitForNetworkChannelClose(ctx context.Context,
|
func (hn *HarnessNode) WaitForNetworkChannelClose(ctx context.Context,
|
||||||
op *lnrpc.ChannelPoint) error {
|
op *lnrpc.ChannelPoint) error {
|
||||||
|
|
||||||
eventChan := make(chan struct{})
|
eventChan := make(chan struct{})
|
||||||
@ -591,7 +627,7 @@ func (l *lightningNode) WaitForNetworkChannelClose(ctx context.Context,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
l.chanWatchRequests <- &chanWatchRequest{
|
hn.chanWatchRequests <- &chanWatchRequest{
|
||||||
chanPoint: wire.OutPoint{
|
chanPoint: wire.OutPoint{
|
||||||
Hash: *txid,
|
Hash: *txid,
|
||||||
Index: op.OutputIndex,
|
Index: op.OutputIndex,
|
||||||
@ -613,7 +649,7 @@ func (l *lightningNode) WaitForNetworkChannelClose(ctx context.Context,
|
|||||||
// timeout, then the goroutine will continually poll until the timeout has
|
// timeout, then the goroutine will continually poll until the timeout has
|
||||||
// elapsed. In the case that the chain isn't synced before the timeout is up,
|
// elapsed. In the case that the chain isn't synced before the timeout is up,
|
||||||
// then this function will return an error.
|
// then this function will return an error.
|
||||||
func (l *lightningNode) WaitForBlockchainSync(ctx context.Context) error {
|
func (hn *HarnessNode) WaitForBlockchainSync(ctx context.Context) error {
|
||||||
errChan := make(chan error, 1)
|
errChan := make(chan error, 1)
|
||||||
retryDelay := time.Millisecond * 100
|
retryDelay := time.Millisecond * 100
|
||||||
|
|
||||||
@ -621,13 +657,13 @@ func (l *lightningNode) WaitForBlockchainSync(ctx context.Context) error {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
case <-l.quit:
|
case <-hn.quit:
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
getInfoReq := &lnrpc.GetInfoRequest{}
|
getInfoReq := &lnrpc.GetInfoRequest{}
|
||||||
getInfoResp, err := l.GetInfo(ctx, getInfoReq)
|
getInfoResp, err := hn.GetInfo(ctx, getInfoReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errChan <- err
|
errChan <- err
|
||||||
return
|
return
|
||||||
@ -646,7 +682,7 @@ func (l *lightningNode) WaitForBlockchainSync(ctx context.Context) error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-l.quit:
|
case <-hn.quit:
|
||||||
return nil
|
return nil
|
||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
return err
|
return err
|
||||||
@ -654,3 +690,14 @@ func (l *lightningNode) WaitForBlockchainSync(ctx context.Context) error {
|
|||||||
return fmt.Errorf("Timeout while waiting for blockchain sync")
|
return fmt.Errorf("Timeout while waiting for blockchain sync")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fileExists reports whether the named file or directory exists.
|
||||||
|
// This function is taken from https://github.com/btcsuite/btcd
|
||||||
|
func fileExists(name string) bool {
|
||||||
|
if _, err := os.Stat(name); err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user