test: add test to garbage collect link nodes
This commit is contained in:
parent
0aa1f39af8
commit
e3162605be
201
lnd_test.go
201
lnd_test.go
@ -22,18 +22,18 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
prand "math/rand"
|
prand "math/rand"
|
||||||
|
|
||||||
"github.com/btcsuite/btclog"
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
|
||||||
"github.com/go-errors/errors"
|
|
||||||
"github.com/lightningnetwork/lnd/lnrpc"
|
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
|
||||||
"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/rpcclient"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
|
"github.com/btcsuite/btclog"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/go-errors/errors"
|
||||||
|
"github.com/lightningnetwork/lnd/lnrpc"
|
||||||
|
"github.com/lightningnetwork/lnd/lntest"
|
||||||
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
@ -4900,6 +4900,191 @@ func testFailingChannel(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// testGarbageCollectLinkNodes tests that we properly garbase collect link nodes
|
||||||
|
// from the database and the set of persistent connections within the server.
|
||||||
|
func testGarbageCollectLinkNodes(net *lntest.NetworkHarness, t *harnessTest) {
|
||||||
|
const (
|
||||||
|
timeout = time.Second * 10
|
||||||
|
chanAmt = 1000000
|
||||||
|
)
|
||||||
|
|
||||||
|
// Open a channel between Alice and Bob which will later be
|
||||||
|
// cooperatively closed.
|
||||||
|
ctxb := context.Background()
|
||||||
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
|
coopChanPoint := openChannelAndAssert(
|
||||||
|
ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create Carol's node and connect Alice to her.
|
||||||
|
carol, err := net.NewNode("Carol", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create carol's node: %v", err)
|
||||||
|
}
|
||||||
|
defer shutdownAndAssert(net, t, carol)
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
if err := net.ConnectNodes(ctxt, net.Alice, carol); err != nil {
|
||||||
|
t.Fatalf("unable to connect alice and carol: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a channel between Alice and Carol which will later be force
|
||||||
|
// closed.
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
forceCloseChanPoint := openChannelAndAssert(
|
||||||
|
ctxt, t, net, net.Alice, carol, chanAmt, 0, false,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Now, create Dave's a node and also open a channel between Alice and
|
||||||
|
// him. This link will serve as the only persistent link throughout
|
||||||
|
// restarts in this test.
|
||||||
|
dave, err := net.NewNode("Dave", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create dave's node: %v", err)
|
||||||
|
}
|
||||||
|
defer shutdownAndAssert(net, t, dave)
|
||||||
|
if err := net.ConnectNodes(ctxt, net.Alice, dave); err != nil {
|
||||||
|
t.Fatalf("unable to connect alice to dave: %v", err)
|
||||||
|
}
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
persistentChanPoint := openChannelAndAssert(
|
||||||
|
ctxt, t, net, net.Alice, dave, chanAmt, 0, false,
|
||||||
|
)
|
||||||
|
|
||||||
|
// isConnected is a helper closure that checks if a peer is connected to
|
||||||
|
// Alice.
|
||||||
|
isConnected := func(pubKey string) bool {
|
||||||
|
req := &lnrpc.ListPeersRequest{}
|
||||||
|
resp, err := net.Alice.ListPeers(ctxb, req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to retrieve alice's peers: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, peer := range resp.Peers {
|
||||||
|
if peer.PubKey == pubKey {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restart both Bob and Carol to ensure Alice is able to reconnect to
|
||||||
|
// them.
|
||||||
|
if err := net.RestartNode(net.Bob, nil); err != nil {
|
||||||
|
t.Fatalf("unable to restart bob's node: %v", err)
|
||||||
|
}
|
||||||
|
if err := net.RestartNode(carol, nil); err != nil {
|
||||||
|
t.Fatalf("unable to restart carol's node: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = lntest.WaitPredicate(func() bool {
|
||||||
|
return isConnected(net.Bob.PubKeyStr)
|
||||||
|
}, 15*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("alice did not reconnect to bob")
|
||||||
|
}
|
||||||
|
err = lntest.WaitPredicate(func() bool {
|
||||||
|
return isConnected(carol.PubKeyStr)
|
||||||
|
}, 15*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("alice did not reconnect to carol")
|
||||||
|
}
|
||||||
|
|
||||||
|
// We'll also restart Alice to ensure she can reconnect to her peers
|
||||||
|
// with open channels.
|
||||||
|
if err := net.RestartNode(net.Alice, nil); err != nil {
|
||||||
|
t.Fatalf("unable to restart alice's node: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = lntest.WaitPredicate(func() bool {
|
||||||
|
return isConnected(net.Bob.PubKeyStr)
|
||||||
|
}, 15*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("alice did not reconnect to bob")
|
||||||
|
}
|
||||||
|
err = lntest.WaitPredicate(func() bool {
|
||||||
|
return isConnected(carol.PubKeyStr)
|
||||||
|
}, 15*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("alice did not reconnect to carol")
|
||||||
|
}
|
||||||
|
|
||||||
|
// testReconnection is a helper closure that restarts the nodes at both
|
||||||
|
// ends of a channel to ensure they do not reconnect after restarting.
|
||||||
|
// When restarting Alice, we'll first need to ensure she has
|
||||||
|
// reestablished her connection with Dave, as they still have an open
|
||||||
|
// channel together.
|
||||||
|
testReconnection := func(node *lntest.HarnessNode) {
|
||||||
|
if err := net.RestartNode(node, nil); err != nil {
|
||||||
|
t.Fatalf("unable to restart %v's node: %v", node.Name(),
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
err = lntest.WaitPredicate(func() bool {
|
||||||
|
return !isConnected(node.PubKeyStr)
|
||||||
|
}, 20*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("alice reconnected to %v", node.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := net.RestartNode(net.Alice, nil); err != nil {
|
||||||
|
t.Fatalf("unable to restart alice's node: %v", err)
|
||||||
|
}
|
||||||
|
err = lntest.WaitPredicate(func() bool {
|
||||||
|
if !isConnected(dave.PubKeyStr) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return !isConnected(node.PubKeyStr)
|
||||||
|
}, 20*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("alice reconnected to %v", node.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, we'll close the channel between Alice and Bob and ensure there
|
||||||
|
// is no reconnection logic between the both once the channel is fully
|
||||||
|
// closed.
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
closeChannelAndAssert(ctxt, t, net, net.Alice, coopChanPoint, false)
|
||||||
|
|
||||||
|
testReconnection(net.Bob)
|
||||||
|
|
||||||
|
// We'll do the same with Alice and Carol, but this time we'll force
|
||||||
|
// close the channel instead.
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
closeChannelAndAssert(ctxt, t, net, net.Alice, forceCloseChanPoint, true)
|
||||||
|
|
||||||
|
// We'll need to mine some blocks in order to mark the channel fully
|
||||||
|
// closed.
|
||||||
|
_, err = net.Miner.Node.Generate(defaultBitcoinTimeLockDelta)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to generate blocks: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testReconnection(carol)
|
||||||
|
|
||||||
|
// Finally, we'll ensure that Bob and Carol no longer show in Alice's
|
||||||
|
// channel graph.
|
||||||
|
describeGraphReq := &lnrpc.ChannelGraphRequest{}
|
||||||
|
channelGraph, err := net.Alice.DescribeGraph(ctxb, describeGraphReq)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to query for alice's channel graph: %v", err)
|
||||||
|
}
|
||||||
|
for _, node := range channelGraph.Nodes {
|
||||||
|
if node.PubKey == net.Bob.PubKeyStr {
|
||||||
|
t.Fatalf("did not expect to find bob in the channel " +
|
||||||
|
"graph, but did")
|
||||||
|
}
|
||||||
|
if node.PubKey == carol.PubKeyStr {
|
||||||
|
t.Fatalf("did not expect to find carol in the channel " +
|
||||||
|
"graph, but did")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that the test is done, we can also close the persistent link.
|
||||||
|
ctxt, _ = context.WithTimeout(ctxb, timeout)
|
||||||
|
closeChannelAndAssert(ctxt, t, net, net.Alice, persistentChanPoint, false)
|
||||||
|
}
|
||||||
|
|
||||||
// testRevokedCloseRetribution tests that Alice is able carry out
|
// testRevokedCloseRetribution 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.
|
||||||
@ -10324,6 +10509,10 @@ var testsCases = []*testCase{
|
|||||||
name: "failing link",
|
name: "failing link",
|
||||||
test: testFailingChannel,
|
test: testFailingChannel,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "garbage collect link nodes",
|
||||||
|
test: testGarbageCollectLinkNodes,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "revoked uncooperative close retribution zero value remote output",
|
name: "revoked uncooperative close retribution zero value remote output",
|
||||||
test: testRevokedCloseRetributionZeroValueRemoteOutput,
|
test: testRevokedCloseRetributionZeroValueRemoteOutput,
|
||||||
|
Loading…
Reference in New Issue
Block a user