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"
"os"
"path/filepath"
"runtime"
"testing"
"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
// MaxPendingChannels, and it is usually set in lndMain().
cfg = &config{
MaxPendingChannels: defaultMaxPendingChannels,
MaxPendingChannels: maxPendingChannels,
}
aliceTestDir, err := ioutil.TempDir("", "alicelnwallet")
@ -673,6 +674,8 @@ func assertFundingMsgSent(t *testing.T, msgChan chan lnwire.Message,
sentMsg, ok = msg.(*lnwire.FundingSigned)
case "FundingLocked":
sentMsg, ok = msg.(*lnwire.FundingLocked)
case "Error":
sentMsg, ok = msg.(*lnwire.Error)
default:
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",
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
@ -950,7 +955,7 @@ func assertHandleFundingLocked(t *testing.T, alice, bob *testNode) {
}
func TestFundingManagerNormalWorkflow(t *testing.T) {
alice, bob := setupFundingManagers(t)
alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob)
// 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) {
alice, bob := setupFundingManagers(t)
alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob)
// 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
// fundingLocked message fails the first time.
func TestFundingManagerOfflinePeer(t *testing.T) {
alice, bob := setupFundingManagers(t)
alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob)
// 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
// initFundingMsg has been handled.
func TestFundingManagerPeerTimeoutAfterInitFunding(t *testing.T) {
alice, bob := setupFundingManagers(t)
alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob)
// 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
// fundingOpenMsg has been handled.
func TestFundingManagerPeerTimeoutAfterFundingOpen(t *testing.T) {
alice, bob := setupFundingManagers(t)
alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob)
// 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
// fundingAcceptMsg has been handled.
func TestFundingManagerPeerTimeoutAfterFundingAccept(t *testing.T) {
alice, bob := setupFundingManagers(t)
alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob)
// 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) {
alice, bob := setupFundingManagers(t)
alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob)
// 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.
func TestFundingManagerFundingNotTimeoutInitiator(t *testing.T) {
alice, bob := setupFundingManagers(t)
alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob)
// 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
// message.
func TestFundingManagerReceiveFundingLockedTwice(t *testing.T) {
alice, bob := setupFundingManagers(t)
alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob)
// 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
// announcement is sent and gets restarted.
func TestFundingManagerRestartAfterChanAnn(t *testing.T) {
alice, bob := setupFundingManagers(t)
alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob)
// 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
// fundingLocked and then gets restarted.
func TestFundingManagerRestartAfterReceivingFundingLocked(t *testing.T) {
alice, bob := setupFundingManagers(t)
alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob)
// 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),
// the announcementSignatures nor the nodeAnnouncement messages are sent.
func TestFundingManagerPrivateChannel(t *testing.T) {
alice, bob := setupFundingManagers(t)
alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob)
// 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
// restart.
func TestFundingManagerPrivateRestart(t *testing.T) {
alice, bob := setupFundingManagers(t)
alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob)
// 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
// specify during the channel funding flow is preserved correcly on both sides.
func TestFundingManagerCustomChannelParameters(t *testing.T) {
alice, bob := setupFundingManagers(t)
alice, bob := setupFundingManagers(t, defaultMaxPendingChannels)
defer tearDownFundingManagers(t, alice, bob)
// 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")
}
}
// 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)
}