itest: refactor testGarbageCollectLinkNodes
This commit is contained in:
3 files changed
+52
-169
No files matched your search
@@ -91,4 +91,8 @@ var allTestCasesTemp = []*lntemp.TestCase{
|
|||||||
Name: "max pending channel",
|
Name: "max pending channel",
|
||||||
TestFunc: testMaxPendingChannels,
|
TestFunc: testMaxPendingChannels,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "garbage collect link nodes",
|
||||||
|
TestFunc: testGarbageCollectLinkNodes,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
+48
-165
@@ -7,7 +7,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcutil"
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
"github.com/btcsuite/btcwallet/wallet"
|
"github.com/btcsuite/btcwallet/wallet"
|
||||||
@@ -20,6 +19,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||||
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
|
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
|
||||||
"github.com/lightningnetwork/lnd/lntemp"
|
"github.com/lightningnetwork/lnd/lntemp"
|
||||||
|
"github.com/lightningnetwork/lnd/lntemp/node"
|
||||||
"github.com/lightningnetwork/lnd/lntest"
|
"github.com/lightningnetwork/lnd/lntest"
|
||||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
@@ -416,32 +416,30 @@ func testMaxPendingChannels(ht *lntemp.HarnessTest) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// testGarbageCollectLinkNodes tests that we properly garbage collect link nodes
|
// testGarbageCollectLinkNodes tests that we properly garbage collect link
|
||||||
// from the database and the set of persistent connections within the server.
|
// nodes from the database and the set of persistent connections within the
|
||||||
func testGarbageCollectLinkNodes(net *lntest.NetworkHarness, t *harnessTest) {
|
// server.
|
||||||
ctxb := context.Background()
|
func testGarbageCollectLinkNodes(ht *lntemp.HarnessTest) {
|
||||||
|
const chanAmt = 1000000
|
||||||
|
|
||||||
const (
|
alice, bob := ht.Alice, ht.Bob
|
||||||
chanAmt = 1000000
|
|
||||||
)
|
|
||||||
|
|
||||||
// Open a channel between Alice and Bob which will later be
|
// Open a channel between Alice and Bob which will later be
|
||||||
// cooperatively closed.
|
// cooperatively closed.
|
||||||
coopChanPoint := openChannelAndAssert(
|
coopChanPoint := ht.OpenChannel(
|
||||||
t, net, net.Alice, net.Bob, lntest.OpenChannelParams{
|
alice, bob, lntemp.OpenChannelParams{
|
||||||
Amt: chanAmt,
|
Amt: chanAmt,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create Carol's node and connect Alice to her.
|
// Create Carol's node and connect Alice to her.
|
||||||
carol := net.NewNode(t.t, "Carol", nil)
|
carol := ht.NewNode("Carol", nil)
|
||||||
defer shutdownAndAssert(net, t, carol)
|
ht.ConnectNodes(alice, carol)
|
||||||
net.ConnectNodes(t.t, net.Alice, carol)
|
|
||||||
|
|
||||||
// Open a channel between Alice and Carol which will later be force
|
// Open a channel between Alice and Carol which will later be force
|
||||||
// closed.
|
// closed.
|
||||||
forceCloseChanPoint := openChannelAndAssert(
|
forceCloseChanPoint := ht.OpenChannel(
|
||||||
t, net, net.Alice, carol, lntest.OpenChannelParams{
|
alice, carol, lntemp.OpenChannelParams{
|
||||||
Amt: chanAmt,
|
Amt: chanAmt,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -449,200 +447,85 @@ func testGarbageCollectLinkNodes(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
// Now, create Dave's a node and also open a channel between Alice and
|
// 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
|
// him. This link will serve as the only persistent link throughout
|
||||||
// restarts in this test.
|
// restarts in this test.
|
||||||
dave := net.NewNode(t.t, "Dave", nil)
|
dave := ht.NewNode("Dave", nil)
|
||||||
defer shutdownAndAssert(net, t, dave)
|
|
||||||
|
|
||||||
net.ConnectNodes(t.t, net.Alice, dave)
|
ht.ConnectNodes(alice, dave)
|
||||||
persistentChanPoint := openChannelAndAssert(
|
persistentChanPoint := ht.OpenChannel(
|
||||||
t, net, net.Alice, dave, lntest.OpenChannelParams{
|
alice, dave, lntemp.OpenChannelParams{
|
||||||
Amt: chanAmt,
|
Amt: chanAmt,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
// isConnected is a helper closure that checks if a peer is connected to
|
|
||||||
// Alice.
|
|
||||||
isConnected := func(pubKey string) bool {
|
|
||||||
req := &lnrpc.ListPeersRequest{}
|
|
||||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
resp, err := net.Alice.ListPeers(ctxt, 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
|
// Restart both Bob and Carol to ensure Alice is able to reconnect to
|
||||||
// them.
|
// them.
|
||||||
if err := net.RestartNode(net.Bob, nil); err != nil {
|
ht.RestartNode(bob)
|
||||||
t.Fatalf("unable to restart bob's node: %v", err)
|
ht.RestartNode(carol)
|
||||||
}
|
|
||||||
if err := net.RestartNode(carol, nil); err != nil {
|
|
||||||
t.Fatalf("unable to restart carol's node: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
require.Eventually(t.t, func() bool {
|
ht.AssertConnected(alice, bob)
|
||||||
return isConnected(net.Bob.PubKeyStr)
|
ht.AssertConnected(alice, carol)
|
||||||
}, defaultTimeout, 20*time.Millisecond)
|
|
||||||
require.Eventually(t.t, func() bool {
|
|
||||||
return isConnected(carol.PubKeyStr)
|
|
||||||
}, defaultTimeout, 20*time.Millisecond)
|
|
||||||
|
|
||||||
// We'll also restart Alice to ensure she can reconnect to her peers
|
// We'll also restart Alice to ensure she can reconnect to her peers
|
||||||
// with open channels.
|
// with open channels.
|
||||||
if err := net.RestartNode(net.Alice, nil); err != nil {
|
ht.RestartNode(alice)
|
||||||
t.Fatalf("unable to restart alice's node: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
require.Eventually(t.t, func() bool {
|
ht.AssertConnected(alice, bob)
|
||||||
return isConnected(net.Bob.PubKeyStr)
|
ht.AssertConnected(alice, carol)
|
||||||
}, defaultTimeout, 20*time.Millisecond)
|
ht.AssertConnected(alice, dave)
|
||||||
require.Eventually(t.t, func() bool {
|
|
||||||
return isConnected(carol.PubKeyStr)
|
|
||||||
}, defaultTimeout, 20*time.Millisecond)
|
|
||||||
require.Eventually(t.t, func() bool {
|
|
||||||
return isConnected(dave.PubKeyStr)
|
|
||||||
}, defaultTimeout, 20*time.Millisecond)
|
|
||||||
err := wait.Predicate(func() bool {
|
|
||||||
return isConnected(dave.PubKeyStr)
|
|
||||||
}, defaultTimeout)
|
|
||||||
|
|
||||||
// testReconnection is a helper closure that restarts the nodes at both
|
// testReconnection is a helper closure that restarts the nodes at both
|
||||||
// ends of a channel to ensure they do not reconnect after restarting.
|
// ends of a channel to ensure they do not reconnect after restarting.
|
||||||
// When restarting Alice, we'll first need to ensure she has
|
// When restarting Alice, we'll first need to ensure she has
|
||||||
// reestablished her connection with Dave, as they still have an open
|
// reestablished her connection with Dave, as they still have an open
|
||||||
// channel together.
|
// channel together.
|
||||||
testReconnection := func(node *lntest.HarnessNode) {
|
testReconnection := func(node *node.HarnessNode) {
|
||||||
// Restart both nodes, to trigger the pruning logic.
|
// Restart both nodes, to trigger the pruning logic.
|
||||||
if err := net.RestartNode(node, nil); err != nil {
|
ht.RestartNode(node)
|
||||||
t.Fatalf("unable to restart %v's node: %v",
|
ht.RestartNode(alice)
|
||||||
node.Name(), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := net.RestartNode(net.Alice, nil); err != nil {
|
|
||||||
t.Fatalf("unable to restart alice's node: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now restart both nodes and make sure they don't reconnect.
|
// Now restart both nodes and make sure they don't reconnect.
|
||||||
if err := net.RestartNode(node, nil); err != nil {
|
ht.RestartNode(node)
|
||||||
t.Fatalf("unable to restart %v's node: %v", node.Name(),
|
ht.AssertNotConnected(alice, node)
|
||||||
err)
|
|
||||||
}
|
|
||||||
err = wait.Invariant(func() bool {
|
|
||||||
return !isConnected(node.PubKeyStr)
|
|
||||||
}, 5*time.Second)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("alice reconnected to %v", node.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := net.RestartNode(net.Alice, nil); err != nil {
|
ht.RestartNode(alice)
|
||||||
t.Fatalf("unable to restart alice's node: %v", err)
|
ht.AssertConnected(alice, dave)
|
||||||
}
|
ht.AssertNotConnected(alice, node)
|
||||||
err = wait.Predicate(func() bool {
|
|
||||||
return isConnected(dave.PubKeyStr)
|
|
||||||
}, defaultTimeout)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("alice didn't reconnect to Dave")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = wait.Invariant(func() bool {
|
|
||||||
return !isConnected(node.PubKeyStr)
|
|
||||||
}, 5*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
|
// 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
|
// is no reconnection logic between the both once the channel is fully
|
||||||
// closed.
|
// closed.
|
||||||
closeChannelAndAssert(t, net, net.Alice, coopChanPoint, false)
|
ht.CloseChannel(alice, coopChanPoint)
|
||||||
|
|
||||||
testReconnection(net.Bob)
|
testReconnection(bob)
|
||||||
|
|
||||||
// We'll do the same with Alice and Carol, but this time we'll force
|
// We'll do the same with Alice and Carol, but this time we'll force
|
||||||
// close the channel instead.
|
// close the channel instead.
|
||||||
closeChannelAndAssert(t, net, net.Alice, forceCloseChanPoint, true)
|
ht.ForceCloseChannel(alice, forceCloseChanPoint)
|
||||||
|
|
||||||
// Cleanup by mining the force close and sweep transaction.
|
|
||||||
cleanupForceClose(t, net, net.Alice, forceCloseChanPoint)
|
|
||||||
|
|
||||||
// We'll need to mine some blocks in order to mark the channel fully
|
// We'll need to mine some blocks in order to mark the channel fully
|
||||||
// closed.
|
// closed.
|
||||||
_, err = net.Miner.Client.Generate(chainreg.DefaultBitcoinTimeLockDelta - defaultCSV)
|
ht.MineBlocks(
|
||||||
if err != nil {
|
chainreg.DefaultBitcoinTimeLockDelta - defaultCSV,
|
||||||
t.Fatalf("unable to generate blocks: %v", err)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
// Before we test reconnection, we'll ensure that the channel has been
|
// Before we test reconnection, we'll ensure that the channel has been
|
||||||
// fully cleaned up for both Carol and Alice.
|
// fully cleaned up for both Carol and Alice.
|
||||||
var predErr error
|
ht.AssertNumPendingForceClose(alice, 0)
|
||||||
pendingChansRequest := &lnrpc.PendingChannelsRequest{}
|
ht.AssertNumPendingForceClose(carol, 0)
|
||||||
err = wait.Predicate(func() bool {
|
|
||||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
pendingChanResp, err := net.Alice.PendingChannels(
|
|
||||||
ctxt, pendingChansRequest,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
predErr = fmt.Errorf("unable to query for pending "+
|
|
||||||
"channels: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
predErr = checkNumForceClosedChannels(pendingChanResp, 0)
|
|
||||||
if predErr != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
|
|
||||||
pendingChanResp, err = carol.PendingChannels(
|
|
||||||
ctxt, pendingChansRequest,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
predErr = fmt.Errorf("unable to query for pending "+
|
|
||||||
"channels: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
predErr = checkNumForceClosedChannels(pendingChanResp, 0)
|
|
||||||
|
|
||||||
return predErr == nil
|
|
||||||
}, defaultTimeout)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("channels not marked as fully resolved: %v", predErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
testReconnection(carol)
|
testReconnection(carol)
|
||||||
|
|
||||||
// Finally, we'll ensure that Bob and Carol no longer show in Alice's
|
// Finally, we'll ensure that Bob and Carol no longer show in Alice's
|
||||||
// channel graph.
|
// channel graph.
|
||||||
describeGraphReq := &lnrpc.ChannelGraphRequest{
|
req := &lnrpc.ChannelGraphRequest{IncludeUnannounced: true}
|
||||||
IncludeUnannounced: true,
|
channelGraph := alice.RPC.DescribeGraph(req)
|
||||||
}
|
require.NotContains(ht, channelGraph.Nodes, bob.PubKeyStr,
|
||||||
ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
|
"did not expect to find bob in the channel graph, but did")
|
||||||
channelGraph, err := net.Alice.DescribeGraph(ctxt, describeGraphReq)
|
require.NotContains(ht, channelGraph.Nodes, carol.PubKeyStr,
|
||||||
if err != nil {
|
"did not expect to find carol in the channel graph, but did")
|
||||||
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.
|
// Now that the test is done, we can also close the persistent link.
|
||||||
closeChannelAndAssert(t, net, net.Alice, persistentChanPoint, false)
|
ht.CloseChannel(alice, persistentChanPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
// testRejectHTLC tests that a node can be created with the flag --rejecthtlc.
|
// testRejectHTLC tests that a node can be created with the flag --rejecthtlc.
|
||||||
|
|||||||
@@ -179,10 +179,6 @@ var allTestCases = []*testCase{
|
|||||||
name: "failing link",
|
name: "failing link",
|
||||||
test: testFailingChannel,
|
test: testFailingChannel,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "garbage collect link nodes",
|
|
||||||
test: testGarbageCollectLinkNodes,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "abandonchannel",
|
name: "abandonchannel",
|
||||||
test: testAbandonChannel,
|
test: testAbandonChannel,
|
||||||
|
|||||||
Reference in new issue
Block a user