mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-08-25 13:12:11 +02:00
342 lines
11 KiB
Go
342 lines
11 KiB
Go
package itest
|
|
|
|
import (
|
|
"github.com/lightningnetwork/lnd/lntest"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
var peerConnTestCases = []*lntest.TestCase{
|
|
{
|
|
Name: "restricted on inbound",
|
|
TestFunc: testPeerConnRestrictedOnInbound,
|
|
},
|
|
{
|
|
Name: "already connected",
|
|
TestFunc: testPeerConnAlreadyConnected,
|
|
},
|
|
{
|
|
Name: "unlimited outbound",
|
|
TestFunc: testPeerConnUnlimitedOutbound,
|
|
},
|
|
{
|
|
Name: "upgrade access perm",
|
|
TestFunc: testPeerConnUpgradeAccessPerm,
|
|
},
|
|
{
|
|
Name: "node restart",
|
|
TestFunc: testPeerConnNodeRestart,
|
|
},
|
|
{
|
|
Name: "peer reconnect",
|
|
TestFunc: testPeerConnPeerReconnect,
|
|
},
|
|
}
|
|
|
|
// testPeerConnRestrictedOnInbound checks that when the `num-restricted-slots`
|
|
// is reached, no more inbound connection is allowed. In addition, when a slot
|
|
// becomes available, new inbound connection should be allowed.
|
|
func testPeerConnRestrictedOnInbound(ht *lntest.HarnessTest) {
|
|
args := []string{"--num-restricted-slots=1"}
|
|
|
|
// Create a new node with only one slot available.
|
|
alice := ht.NewNode("Alice", args)
|
|
|
|
// Create two nodes Bob and Carol. Bob will connect to Alice first,
|
|
// taking up Alice's only slot, and we expect the connection from Carol
|
|
// to Alice to be failed.
|
|
bob := ht.NewNode("Bob", nil)
|
|
carol := ht.NewNode("Carol", nil)
|
|
|
|
// Bob now connects to Alice - from Alice's PoV, this is her inbound
|
|
// connection from Bob. We expect Bob to connect to Alice successfully.
|
|
_, err := ht.ConnectNodesNoAssert(bob, alice)
|
|
require.NoError(ht, err)
|
|
ht.AssertConnected(alice, bob)
|
|
|
|
// Carol now connects to Alice - from Alice's PoV, this is her inbound
|
|
// connection from Carol. Carol's connection should be failed.
|
|
_, err = ht.ConnectNodesNoAssert(carol, alice)
|
|
require.NoError(ht, err)
|
|
ht.AssertNotConnected(alice, carol)
|
|
|
|
// Bob now disconnects, which will free up Alice's slot.
|
|
ht.DisconnectNodes(bob, alice)
|
|
|
|
// Carol connects again - since Alice's slot is freed, this connection
|
|
// should succeed.
|
|
_, err = ht.ConnectNodesNoAssert(carol, alice)
|
|
require.NoError(ht, err)
|
|
|
|
ht.AssertConnected(alice, carol)
|
|
ht.AssertNotConnected(alice, bob)
|
|
}
|
|
|
|
// testPeerConnAlreadyConnected checks that when there's already a connection
|
|
// alive, another attempt to connect doesn't take up the slot or kill the
|
|
// existing connection, in specific,
|
|
// - When Alice has an inbound connection from Bob, another inbound connection
|
|
// from Bob will be noop.
|
|
// - When Bob has an outbound connection to Alice, another outbound connection
|
|
// to Alice will be noop.
|
|
//
|
|
// In this test we will create nodes using the dev flag `unsafeconnect` to mimic
|
|
// the behaviour of persistent/permanent peer connections, where it's likely
|
|
// inbound and outbound connections are happening at the same time.
|
|
func testPeerConnAlreadyConnected(ht *lntest.HarnessTest) {
|
|
args := []string{
|
|
"--num-restricted-slots=1",
|
|
}
|
|
|
|
// Create a new node with two slots available.
|
|
alice := ht.NewNode("Alice", args)
|
|
bob := ht.NewNode("Bob", []string{"--dev.unsafeconnect"})
|
|
carol := ht.NewNode("Carol", nil)
|
|
|
|
// Bob now connects to Alice - from Alice's PoV, this is her inbound
|
|
// connection from Bob. We expect Bob to connect to Alice successfully.
|
|
_, err := ht.ConnectNodesNoAssert(bob, alice)
|
|
require.NoError(ht, err)
|
|
ht.AssertConnected(alice, bob)
|
|
|
|
// Assert Alice's slot has been filled up by connecting Carol to Alice.
|
|
_, err = ht.ConnectNodesNoAssert(carol, alice)
|
|
require.NoError(ht, err)
|
|
ht.AssertNotConnected(alice, carol)
|
|
|
|
// Bob connects to Alice again - from Alice's PoV, she already has an
|
|
// inbound connection from Bob so this connection attempt should be
|
|
// noop. We expect Alice and Bob to stay connected.
|
|
//
|
|
// TODO(yy): There's no way to assert the connection stays the same atm,
|
|
// need to update the RPC to return the socket port. As for now we need
|
|
// to visit the logs to check the connection is the same or not.
|
|
_, err = ht.ConnectNodesNoAssert(bob, alice)
|
|
require.NoError(ht, err)
|
|
ht.AssertConnected(alice, bob)
|
|
}
|
|
|
|
// testPeerConnUnlimitedOutbound checks that for outbound connections, they are
|
|
// not restricted by the `num-restricted-slots` config.
|
|
func testPeerConnUnlimitedOutbound(ht *lntest.HarnessTest) {
|
|
args := []string{"--num-restricted-slots=1"}
|
|
|
|
// Create a new node with one slot available.
|
|
alice := ht.NewNode("Alice", args)
|
|
|
|
// Create three nodes. Alice will have an inbound connection with Bob
|
|
// and outbound connections with Carol and Dave.
|
|
bob := ht.NewNode("Bob", args)
|
|
carol := ht.NewNode("Carol", args)
|
|
dave := ht.NewNode("Dave", args)
|
|
|
|
// Bob now connects to Alice - from Alice's PoV, this is her inbound
|
|
// connection from Bob. We expect Bob to connect to Alice successfully.
|
|
_, err := ht.ConnectNodesNoAssert(bob, alice)
|
|
require.NoError(ht, err)
|
|
ht.AssertConnected(alice, bob)
|
|
|
|
// Assert Alice's slot has been filled up by connecting Carol to Alice.
|
|
_, err = ht.ConnectNodesNoAssert(carol, alice)
|
|
require.NoError(ht, err)
|
|
ht.AssertNotConnected(alice, carol)
|
|
|
|
// Now let Alice make an outbound connection to Carol and assert it's
|
|
// succeeded.
|
|
_, err = ht.ConnectNodesNoAssert(alice, carol)
|
|
require.NoError(ht, err)
|
|
ht.AssertConnected(alice, carol)
|
|
|
|
// Alice can also make an outbound connection to Dave and assert it's
|
|
// succeeded since outbound connection is not restricted.
|
|
_, err = ht.ConnectNodesNoAssert(alice, dave)
|
|
require.NoError(ht, err)
|
|
ht.AssertConnected(alice, dave)
|
|
}
|
|
|
|
// testPeerConnUpgradeAccessPerm checks that when a peer has, or used to have a
|
|
// channel with Alice, it won't use her restricted slots.
|
|
func testPeerConnUpgradeAccessPerm(ht *lntest.HarnessTest) {
|
|
args := []string{"--num-restricted-slots=1"}
|
|
|
|
// Create a new node with one slot available.
|
|
alice := ht.NewNodeWithCoins("Alice", args)
|
|
bob := ht.NewNode("Bob", nil)
|
|
carol := ht.NewNodeWithCoins("Carol", nil)
|
|
dave := ht.NewNode("Dave", nil)
|
|
eve := ht.NewNode("Eve", nil)
|
|
|
|
// Connect Bob to Alice, which will use Alice's available slot.
|
|
ht.ConnectNodes(bob, alice)
|
|
|
|
// Assert Alice's slot has been filled up by connecting Carol to Alice.
|
|
_, err := ht.ConnectNodesNoAssert(carol, alice)
|
|
require.NoError(ht, err)
|
|
ht.AssertNotConnected(alice, carol)
|
|
|
|
// Open a channel from Alice to Bob and let it stay pending.
|
|
p := lntest.OpenChannelParams{
|
|
Amt: chanAmt,
|
|
}
|
|
pendingUpdate := ht.OpenChannelAssertPending(alice, bob, p)
|
|
cpAB := lntest.ChanPointFromPendingUpdate(pendingUpdate)
|
|
|
|
// Connect Carol to Alice - since Bob now has a pending channel with
|
|
// Alice, there's a slot available for Carol to connect.
|
|
ht.ConnectNodes(carol, alice)
|
|
|
|
// Open a channel from Carol to Alice and let it stay pending.
|
|
pendingUpdate = ht.OpenChannelAssertPending(carol, alice, p)
|
|
cpCA := lntest.ChanPointFromPendingUpdate(pendingUpdate)
|
|
|
|
// Mine the funding txns.
|
|
ht.MineBlocksAndAssertNumTxes(1, 2)
|
|
|
|
// Dave should be able to connect to Alice.
|
|
ht.ConnectNodes(dave, alice)
|
|
|
|
// Open a channel from Alice to Dave, which will free up Alice's slot.
|
|
cpAD := ht.OpenChannel(alice, dave, p)
|
|
|
|
// Close the channels.
|
|
ht.CloseChannel(bob, cpAB)
|
|
ht.CloseChannel(carol, cpCA)
|
|
ht.CloseChannel(dave, cpAD)
|
|
|
|
// Alice should have one slot available, connect Eve to Alice now.
|
|
ht.ConnectNodes(eve, alice)
|
|
}
|
|
|
|
// testPeerConnNodeRestart checks that when a peer has or used to have a channel
|
|
// with Alice, when Alice restarts, she should still have the available slot for
|
|
// more inbound connections.
|
|
func testPeerConnNodeRestart(ht *lntest.HarnessTest) {
|
|
args := []string{"--num-restricted-slots=1"}
|
|
|
|
// Create a new node with one slot available.
|
|
alice := ht.NewNodeWithCoins("Alice", args)
|
|
bob := ht.NewNode("Bob", []string{"--dev.unsafeconnect"})
|
|
carol := ht.NewNode("Carol", nil)
|
|
|
|
// Connect Bob to Alice, which will use Alice's available slot.
|
|
ht.ConnectNodes(bob, alice)
|
|
|
|
// Assert Alice's slot has been filled up by connecting Carol to Alice.
|
|
_, err := ht.ConnectNodesNoAssert(carol, alice)
|
|
require.NoError(ht, err)
|
|
ht.AssertNotConnected(alice, carol)
|
|
|
|
// Restart Alice, which will reset her current slots, allowing Bob to
|
|
// connect to her again.
|
|
ht.RestartNode(alice)
|
|
ht.ConnectNodes(bob, alice)
|
|
|
|
// Open a channel from Alice to Bob and let it stay pending.
|
|
p := lntest.OpenChannelParams{
|
|
Amt: chanAmt,
|
|
}
|
|
pendingUpdate := ht.OpenChannelAssertPending(alice, bob, p)
|
|
cp := lntest.ChanPointFromPendingUpdate(pendingUpdate)
|
|
|
|
// Restart Alice and let Bob connect to her - since Bob has a pending
|
|
// channel, it shouldn't take any slot.
|
|
ht.RestartNode(alice)
|
|
ht.ConnectNodes(bob, alice)
|
|
|
|
// Connect Carol to Alice since Alice has a free slot.
|
|
ht.ConnectNodes(carol, alice)
|
|
|
|
// Mine the funding tx.
|
|
ht.MineBlocksAndAssertNumTxes(1, 1)
|
|
|
|
// Restart Alice and let Bob connect to her - since Bob has an open
|
|
// channel, it shouldn't take any slot.
|
|
ht.RestartNode(alice)
|
|
ht.ConnectNodes(bob, alice)
|
|
|
|
// Connect Carol to Alice since Alice has a free slot.
|
|
ht.ConnectNodes(carol, alice)
|
|
|
|
// Close the channel.
|
|
ht.CloseChannel(alice, cp)
|
|
|
|
// Restart Alice and let Bob connect to her - since Bob has a closed
|
|
// channel, it shouldn't take any slot.
|
|
ht.RestartNode(alice)
|
|
ht.ConnectNodes(bob, alice)
|
|
|
|
// Connect Carol to Alice since Alice has a free slot.
|
|
ht.ConnectNodes(carol, alice)
|
|
}
|
|
|
|
// testPeerConnPeerReconnect checks that when a peer has or used to have a
|
|
// channel with Alice, it will not account for the restricted slot during
|
|
// reconnection.
|
|
func testPeerConnPeerReconnect(ht *lntest.HarnessTest) {
|
|
args := []string{"--num-restricted-slots=1"}
|
|
|
|
// Create a new node with one slot available.
|
|
alice := ht.NewNodeWithCoins("Alice", args)
|
|
bob := ht.NewNode("Bob", []string{"--dev.unsafeconnect"})
|
|
carol := ht.NewNode("Carol", nil)
|
|
|
|
// Connect Bob to Alice, which will use Alice's available slot.
|
|
ht.ConnectNodes(bob, alice)
|
|
|
|
// Let Bob connect to Alice again, which put Bob in Alice's
|
|
// `scheduledPeerConnection` map.
|
|
ht.ConnectNodes(bob, alice)
|
|
|
|
// Assert Alice's slot has been filled up by connecting Carol to Alice.
|
|
_, err := ht.ConnectNodesNoAssert(carol, alice)
|
|
require.NoError(ht, err)
|
|
ht.AssertNotConnected(alice, carol)
|
|
|
|
// Open a channel from Alice to Bob and let it stay pending.
|
|
p := lntest.OpenChannelParams{
|
|
Amt: chanAmt,
|
|
}
|
|
pendingUpdate := ht.OpenChannelAssertPending(alice, bob, p)
|
|
cp := lntest.ChanPointFromPendingUpdate(pendingUpdate)
|
|
|
|
// Bob now perform a reconnection - since Bob has a pending channel, it
|
|
// shouldn't take any slot.
|
|
ht.DisconnectNodes(bob, alice)
|
|
ht.AssertNotConnected(alice, bob)
|
|
ht.ConnectNodes(bob, alice)
|
|
|
|
// Connect Carol to Alice since Alice has a free slot.
|
|
ht.ConnectNodes(carol, alice)
|
|
|
|
// Once the above connection succeeded we let Carol disconnect to free
|
|
// the slot.
|
|
ht.DisconnectNodes(carol, alice)
|
|
|
|
// Mine the funding tx.
|
|
ht.MineBlocksAndAssertNumTxes(1, 1)
|
|
|
|
// Bob now perform a reconnection - since Bob has a pending channel, it
|
|
// shouldn't take any slot.
|
|
ht.DisconnectNodes(bob, alice)
|
|
ht.AssertNotConnected(alice, bob)
|
|
ht.ConnectNodes(bob, alice)
|
|
|
|
// Connect Carol to Alice since Alice has a free slot.
|
|
ht.ConnectNodes(carol, alice)
|
|
|
|
// Once the above connection succeeded we let Carol disconnect to free
|
|
// the slot.
|
|
ht.DisconnectNodes(carol, alice)
|
|
|
|
// Close the channel.
|
|
ht.CloseChannel(alice, cp)
|
|
|
|
// Bob now perform a reconnection - since Bob has a pending channel, it
|
|
// shouldn't take any slot.
|
|
ht.DisconnectNodes(bob, alice)
|
|
ht.AssertNotConnected(alice, bob)
|
|
ht.ConnectNodes(bob, alice)
|
|
|
|
// Connect Carol to Alice since Alice has a free slot.
|
|
ht.ConnectNodes(carol, alice)
|
|
}
|