fundingmanager test: add TestFundingManagerMaxPendingChannels

This commit is contained in:
Johan T. Halseth 2018-07-26 19:23:18 +02:00
parent 8b6e7b24aa
commit b437d03174
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26

@ -10,6 +10,7 @@ import (
"net" "net"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"testing" "testing"
"time" "time"
@ -447,11 +448,11 @@ func recreateAliceFundingManager(t *testing.T, alice *testNode) {
} }
} }
func setupFundingManagers(t *testing.T) (*testNode, *testNode) { func setupFundingManagers(t *testing.T, maxPendingChannels int) (*testNode, *testNode) {
// We need to set the global config, as fundingManager uses // We need to set the global config, as fundingManager uses
// MaxPendingChannels, and it is usually set in lndMain(). // MaxPendingChannels, and it is usually set in lndMain().
cfg = &config{ cfg = &config{
MaxPendingChannels: defaultMaxPendingChannels, MaxPendingChannels: maxPendingChannels,
} }
aliceTestDir, err := ioutil.TempDir("", "alicelnwallet") aliceTestDir, err := ioutil.TempDir("", "alicelnwallet")
@ -673,6 +674,8 @@ func assertFundingMsgSent(t *testing.T, msgChan chan lnwire.Message,
sentMsg, ok = msg.(*lnwire.FundingSigned) sentMsg, ok = msg.(*lnwire.FundingSigned)
case "FundingLocked": case "FundingLocked":
sentMsg, ok = msg.(*lnwire.FundingLocked) sentMsg, ok = msg.(*lnwire.FundingLocked)
case "Error":
sentMsg, ok = msg.(*lnwire.Error)
default: default:
t.Fatalf("unknown message type: %s", msgType) t.Fatalf("unknown message type: %s", msgType)
} }
@ -683,8 +686,10 @@ func assertFundingMsgSent(t *testing.T, msgChan chan lnwire.Message,
t.Fatalf("expected %s to be sent, instead got error: %v", t.Fatalf("expected %s to be sent, instead got error: %v",
msgType, lnwire.ErrorCode(errorMsg.Data[0])) msgType, lnwire.ErrorCode(errorMsg.Data[0]))
} }
t.Fatalf("expected %s to be sent, instead got %T",
msgType, msg) _, _, line, _ := runtime.Caller(1)
t.Fatalf("expected %s to be sent, instead got %T at %v",
msgType, msg, line)
} }
return sentMsg return sentMsg
@ -950,7 +955,7 @@ func assertHandleFundingLocked(t *testing.T, alice, bob *testNode) {
} }
func TestFundingManagerNormalWorkflow(t *testing.T) { func TestFundingManagerNormalWorkflow(t *testing.T) {
alice, bob := setupFundingManagers(t) alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob) defer tearDownFundingManagers(t, alice, bob)
// We will consume the channel updates as we go, so no buffering is needed. // We will consume the channel updates as we go, so no buffering is needed.
@ -1020,7 +1025,7 @@ func TestFundingManagerNormalWorkflow(t *testing.T) {
} }
func TestFundingManagerRestartBehavior(t *testing.T) { func TestFundingManagerRestartBehavior(t *testing.T) {
alice, bob := setupFundingManagers(t) alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob) defer tearDownFundingManagers(t, alice, bob)
// Run through the process of opening the channel, up until the funding // Run through the process of opening the channel, up until the funding
@ -1151,7 +1156,7 @@ func TestFundingManagerRestartBehavior(t *testing.T) {
// server to notify when the peer comes online, in case sending the // server to notify when the peer comes online, in case sending the
// fundingLocked message fails the first time. // fundingLocked message fails the first time.
func TestFundingManagerOfflinePeer(t *testing.T) { func TestFundingManagerOfflinePeer(t *testing.T) {
alice, bob := setupFundingManagers(t) alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob) defer tearDownFundingManagers(t, alice, bob)
// Run through the process of opening the channel, up until the funding // Run through the process of opening the channel, up until the funding
@ -1282,7 +1287,7 @@ func TestFundingManagerOfflinePeer(t *testing.T) {
// will properly clean up a zombie reservation that times out after the // will properly clean up a zombie reservation that times out after the
// initFundingMsg has been handled. // initFundingMsg has been handled.
func TestFundingManagerPeerTimeoutAfterInitFunding(t *testing.T) { func TestFundingManagerPeerTimeoutAfterInitFunding(t *testing.T) {
alice, bob := setupFundingManagers(t) alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob) defer tearDownFundingManagers(t, alice, bob)
// We will consume the channel updates as we go, so no buffering is needed. // We will consume the channel updates as we go, so no buffering is needed.
@ -1342,7 +1347,7 @@ func TestFundingManagerPeerTimeoutAfterInitFunding(t *testing.T) {
// will properly clean up a zombie reservation that times out after the // will properly clean up a zombie reservation that times out after the
// fundingOpenMsg has been handled. // fundingOpenMsg has been handled.
func TestFundingManagerPeerTimeoutAfterFundingOpen(t *testing.T) { func TestFundingManagerPeerTimeoutAfterFundingOpen(t *testing.T) {
alice, bob := setupFundingManagers(t) alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob) defer tearDownFundingManagers(t, alice, bob)
// We will consume the channel updates as we go, so no buffering is needed. // We will consume the channel updates as we go, so no buffering is needed.
@ -1411,7 +1416,7 @@ func TestFundingManagerPeerTimeoutAfterFundingOpen(t *testing.T) {
// will properly clean up a zombie reservation that times out after the // will properly clean up a zombie reservation that times out after the
// fundingAcceptMsg has been handled. // fundingAcceptMsg has been handled.
func TestFundingManagerPeerTimeoutAfterFundingAccept(t *testing.T) { func TestFundingManagerPeerTimeoutAfterFundingAccept(t *testing.T) {
alice, bob := setupFundingManagers(t) alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob) defer tearDownFundingManagers(t, alice, bob)
// We will consume the channel updates as we go, so no buffering is needed. // We will consume the channel updates as we go, so no buffering is needed.
@ -1485,7 +1490,7 @@ func TestFundingManagerPeerTimeoutAfterFundingAccept(t *testing.T) {
} }
func TestFundingManagerFundingTimeout(t *testing.T) { func TestFundingManagerFundingTimeout(t *testing.T) {
alice, bob := setupFundingManagers(t) alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob) defer tearDownFundingManagers(t, alice, bob)
// We will consume the channel updates as we go, so no buffering is needed. // We will consume the channel updates as we go, so no buffering is needed.
@ -1530,7 +1535,7 @@ func TestFundingManagerFundingTimeout(t *testing.T) {
// the channel initiator, that it does not timeout when the lnd restarts. // the channel initiator, that it does not timeout when the lnd restarts.
func TestFundingManagerFundingNotTimeoutInitiator(t *testing.T) { func TestFundingManagerFundingNotTimeoutInitiator(t *testing.T) {
alice, bob := setupFundingManagers(t) alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob) defer tearDownFundingManagers(t, alice, bob)
// We will consume the channel updates as we go, so no buffering is needed. // We will consume the channel updates as we go, so no buffering is needed.
@ -1597,7 +1602,7 @@ func TestFundingManagerFundingNotTimeoutInitiator(t *testing.T) {
// continues to operate as expected in case we receive a duplicate fundingLocked // continues to operate as expected in case we receive a duplicate fundingLocked
// message. // message.
func TestFundingManagerReceiveFundingLockedTwice(t *testing.T) { func TestFundingManagerReceiveFundingLockedTwice(t *testing.T) {
alice, bob := setupFundingManagers(t) alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob) defer tearDownFundingManagers(t, alice, bob)
// We will consume the channel updates as we go, so no buffering is needed. // We will consume the channel updates as we go, so no buffering is needed.
@ -1686,7 +1691,7 @@ func TestFundingManagerReceiveFundingLockedTwice(t *testing.T) {
// handles receiving a fundingLocked after the its own fundingLocked and channel // handles receiving a fundingLocked after the its own fundingLocked and channel
// announcement is sent and gets restarted. // announcement is sent and gets restarted.
func TestFundingManagerRestartAfterChanAnn(t *testing.T) { func TestFundingManagerRestartAfterChanAnn(t *testing.T) {
alice, bob := setupFundingManagers(t) alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob) defer tearDownFundingManagers(t, alice, bob)
// We will consume the channel updates as we go, so no buffering is needed. // We will consume the channel updates as we go, so no buffering is needed.
@ -1760,7 +1765,7 @@ func TestFundingManagerRestartAfterChanAnn(t *testing.T) {
// fundingManager continues to operate as expected after it has received // fundingManager continues to operate as expected after it has received
// fundingLocked and then gets restarted. // fundingLocked and then gets restarted.
func TestFundingManagerRestartAfterReceivingFundingLocked(t *testing.T) { func TestFundingManagerRestartAfterReceivingFundingLocked(t *testing.T) {
alice, bob := setupFundingManagers(t) alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob) defer tearDownFundingManagers(t, alice, bob)
// We will consume the channel updates as we go, so no buffering is needed. // We will consume the channel updates as we go, so no buffering is needed.
@ -1830,7 +1835,7 @@ func TestFundingManagerRestartAfterReceivingFundingLocked(t *testing.T) {
// (a channel not supposed to be announced to the rest of the network), // (a channel not supposed to be announced to the rest of the network),
// the announcementSignatures nor the nodeAnnouncement messages are sent. // the announcementSignatures nor the nodeAnnouncement messages are sent.
func TestFundingManagerPrivateChannel(t *testing.T) { func TestFundingManagerPrivateChannel(t *testing.T) {
alice, bob := setupFundingManagers(t) alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob) defer tearDownFundingManagers(t, alice, bob)
// We will consume the channel updates as we go, so no buffering is needed. // We will consume the channel updates as we go, so no buffering is needed.
@ -1910,7 +1915,7 @@ func TestFundingManagerPrivateChannel(t *testing.T) {
// announcement signatures nor the node announcement messages are sent upon // announcement signatures nor the node announcement messages are sent upon
// restart. // restart.
func TestFundingManagerPrivateRestart(t *testing.T) { func TestFundingManagerPrivateRestart(t *testing.T) {
alice, bob := setupFundingManagers(t) alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob) defer tearDownFundingManagers(t, alice, bob)
// We will consume the channel updates as we go, so no buffering is needed. // We will consume the channel updates as we go, so no buffering is needed.
@ -2000,7 +2005,7 @@ func TestFundingManagerPrivateRestart(t *testing.T) {
// TestFundingManagerCustomChannelParameters checks that custom requirements we // TestFundingManagerCustomChannelParameters checks that custom requirements we
// specify during the channel funding flow is preserved correcly on both sides. // specify during the channel funding flow is preserved correcly on both sides.
func TestFundingManagerCustomChannelParameters(t *testing.T) { func TestFundingManagerCustomChannelParameters(t *testing.T) {
alice, bob := setupFundingManagers(t) alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob) defer tearDownFundingManagers(t, alice, bob)
// This is the custom parameters we'll use. // This is the custom parameters we'll use.
@ -2195,3 +2200,164 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
t.Fatalf("alice did not publish funding tx") t.Fatalf("alice did not publish funding tx")
} }
} }
// TestFundingManagerMaxPendingChannels checks that trying to open another
// channel with the same peer when MaxPending channels are pending fails.
func TestFundingManagerMaxPendingChannels(t *testing.T) {
const maxPending = 4
alice, bob := setupFundingManagers(t, maxPending)
defer tearDownFundingManagers(t, alice, bob)
// Create openChanReqs for maxPending+1 channels.
var initReqs []*openChanReq
for i := 0; i < maxPending+1; i++ {
updateChan := make(chan *lnrpc.OpenStatusUpdate)
errChan := make(chan error, 1)
initReq := &openChanReq{
targetPubkey: bob.privKey.PubKey(),
chainHash: *activeNetParams.GenesisHash,
localFundingAmt: 5000000,
pushAmt: lnwire.NewMSatFromSatoshis(0),
private: false,
updates: updateChan,
err: errChan,
}
initReqs = append(initReqs, initReq)
}
// Kick of maxPending+1 funding workflows.
var accepts []*lnwire.AcceptChannel
var lastOpen *lnwire.OpenChannel
for i, initReq := range initReqs {
alice.fundingMgr.initFundingWorkflow(bob, initReq)
// Alice should have sent the OpenChannel message to Bob.
var aliceMsg lnwire.Message
select {
case aliceMsg = <-alice.msgChan:
case err := <-initReq.err:
t.Fatalf("error init funding workflow: %v", err)
case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenChannel message")
}
openChannelReq, ok := aliceMsg.(*lnwire.OpenChannel)
if !ok {
errorMsg, gotError := aliceMsg.(*lnwire.Error)
if gotError {
t.Fatalf("expected OpenChannel to be sent "+
"from bob, instead got error: %v",
lnwire.ErrorCode(errorMsg.Data[0]))
}
t.Fatalf("expected OpenChannel to be sent from "+
"alice, instead got %T", aliceMsg)
}
// Let Bob handle the init message.
bob.fundingMgr.processFundingOpen(openChannelReq, alice)
// Bob should answer with an AcceptChannel message for the
// first maxPending channels.
if i < maxPending {
acceptChannelResponse := assertFundingMsgSent(
t, bob.msgChan, "AcceptChannel",
).(*lnwire.AcceptChannel)
accepts = append(accepts, acceptChannelResponse)
continue
}
// For the last channel, Bob should answer with an error.
lastOpen = openChannelReq
_ = assertFundingMsgSent(
t, bob.msgChan, "Error",
).(*lnwire.Error)
}
// Forward the responses to Alice.
var signs []*lnwire.FundingSigned
for _, accept := range accepts {
alice.fundingMgr.processFundingAccept(accept, bob)
// Alice responds with a FundingCreated message.
fundingCreated := assertFundingMsgSent(
t, alice.msgChan, "FundingCreated",
).(*lnwire.FundingCreated)
// Give the message to Bob.
bob.fundingMgr.processFundingCreated(fundingCreated, alice)
// Finally, Bob should send the FundingSigned message.
fundingSigned := assertFundingMsgSent(
t, bob.msgChan, "FundingSigned",
).(*lnwire.FundingSigned)
signs = append(signs, fundingSigned)
}
// Sending another init request from Alice should still make Bob
// respond with an error.
bob.fundingMgr.processFundingOpen(lastOpen, alice)
_ = assertFundingMsgSent(
t, bob.msgChan, "Error",
).(*lnwire.Error)
// Give the FundingSigned messages to Alice.
for i, sign := range signs {
alice.fundingMgr.processFundingSigned(sign, bob)
// Alice should send a status update for each channel, and
// publish a funding tx to the network.
var pendingUpdate *lnrpc.OpenStatusUpdate
select {
case pendingUpdate = <-initReqs[i].updates:
case <-time.After(time.Second * 5):
t.Fatalf("alice did not send OpenStatusUpdate_ChanPending")
}
_, ok := pendingUpdate.Update.(*lnrpc.OpenStatusUpdate_ChanPending)
if !ok {
t.Fatal("OpenStatusUpdate was not OpenStatusUpdate_ChanPending")
}
select {
case <-alice.publTxChan:
case <-time.After(time.Second * 5):
t.Fatalf("alice did not publish funding tx")
}
}
// Sending another init request from Alice should still make Bob
// respond with an error, since the funding transactions are not
// confirmed yet,
bob.fundingMgr.processFundingOpen(lastOpen, alice)
_ = assertFundingMsgSent(
t, bob.msgChan, "Error",
).(*lnwire.Error)
// Notify that the transactions were mined.
for i := 0; i < maxPending; i++ {
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{}
bob.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{}
// Expect both to be sending FundingLocked.
_ = assertFundingMsgSent(
t, alice.msgChan, "FundingLocked",
).(*lnwire.FundingLocked)
_ = assertFundingMsgSent(
t, bob.msgChan, "FundingLocked",
).(*lnwire.FundingLocked)
}
// Now opening another channel should work.
bob.fundingMgr.processFundingOpen(lastOpen, alice)
// Bob should answer with an AcceptChannel message.
_ = assertFundingMsgSent(
t, bob.msgChan, "AcceptChannel",
).(*lnwire.AcceptChannel)
}