lntemp+itest: refactor testResHandoff

This commit is contained in:
yyforyongyu 2022-08-08 12:19:48 +08:00
parent 83ecc6285c
commit 89727ed1d7
No known key found for this signature in database
GPG key ID: 9BCD95C4FF296868
5 changed files with 62 additions and 136 deletions

View file

@ -480,7 +480,12 @@ func (h *HarnessTest) SuspendNode(node *node.HarnessNode) func() error {
return func() error { return func() error {
h.manager.registerNode(node) h.manager.registerNode(node)
return node.Start(h.runCtx) if err := node.Start(h.runCtx); err != nil {
return err
}
h.WaitForBlockchainSync(node)
return nil
} }
} }

View file

@ -1992,3 +1992,25 @@ func (h *HarnessTest) WaitForNodeBlockHeight(hn *node.HarnessNode,
require.NoErrorf(h, err, "%s: timeout while waiting for height", require.NoErrorf(h, err, "%s: timeout while waiting for height",
hn.Name()) hn.Name())
} }
// AssertChannelCommitHeight asserts the given channel for the node has the
// expected commit height(`NumUpdates`).
func (h *HarnessTest) AssertChannelCommitHeight(hn *node.HarnessNode,
cp *lnrpc.ChannelPoint, height int) {
err := wait.NoError(func() error {
c, err := h.findChannel(hn, cp)
if err != nil {
return err
}
if int(c.NumUpdates) == height {
return nil
}
return fmt.Errorf("expected commit height to be %v, was %v",
height, c.NumUpdates)
}, DefaultTimeout)
require.NoError(h, err, "timeout while waiting for commit height")
}

View file

@ -283,4 +283,8 @@ var allTestCasesTemp = []*lntemp.TestCase{
Name: "psbt channel funding single step", Name: "psbt channel funding single step",
TestFunc: testPsbtChanFundingSingleStep, TestFunc: testPsbtChanFundingSingleStep,
}, },
{
Name: "resolution handoff",
TestFunc: testResHandoff,
},
} }

View file

@ -5,131 +5,69 @@ import (
"github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntemp"
"github.com/lightningnetwork/lnd/lntest/wait"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"golang.org/x/net/context"
) )
// testResHandoff tests that the contractcourt is able to properly hand-off // testResHandoff tests that the contractcourt is able to properly hand-off
// resolution messages to the switch. // resolution messages to the switch.
func testResHandoff(net *lntest.NetworkHarness, t *harnessTest) { func testResHandoff(ht *lntemp.HarnessTest) {
const ( const (
chanAmt = btcutil.Amount(1000000) chanAmt = btcutil.Amount(1000000)
paymentAmt = 50000 paymentAmt = 50000
) )
ctxb := context.Background() alice, bob := ht.Alice, ht.Bob
// First we'll create a channel between Alice and Bob. // First we'll create a channel between Alice and Bob.
net.EnsureConnected(t.t, net.Alice, net.Bob) ht.EnsureConnected(alice, bob)
chanPointAlice := openChannelAndAssert( params := lntemp.OpenChannelParams{Amt: chanAmt}
t, net, net.Alice, net.Bob, chanPointAlice := ht.OpenChannel(alice, bob, params)
lntest.OpenChannelParams{
Amt: chanAmt,
},
)
defer closeChannelAndAssert(t, net, net.Alice, chanPointAlice, false)
// Wait for Alice and Bob to receive the channel edge from the funding
// manager.
err := net.Alice.WaitForNetworkChannelOpen(chanPointAlice)
require.NoError(t.t, err)
err = net.Bob.WaitForNetworkChannelOpen(chanPointAlice)
require.NoError(t.t, err)
// Create a new node Carol that will be in hodl mode. This is used to // Create a new node Carol that will be in hodl mode. This is used to
// trigger the behavior of checkRemoteDanglingActions in the // trigger the behavior of checkRemoteDanglingActions in the
// contractcourt. This will cause Bob to fail the HTLC back to Alice. // contractcourt. This will cause Bob to fail the HTLC back to Alice.
carol := net.NewNode(t.t, "Carol", []string{"--hodl.commit"}) carol := ht.NewNode("Carol", []string{"--hodl.commit"})
defer shutdownAndAssert(net, t, carol) defer ht.Shutdown(carol)
// Connect Bob to Carol. // Connect Bob to Carol.
net.ConnectNodes(t.t, net.Bob, carol) ht.ConnectNodes(bob, carol)
// Open a channel between Bob and Carol. // Open a channel between Bob and Carol.
chanPointCarol := openChannelAndAssert( chanPointCarol := ht.OpenChannel(bob, carol, params)
t, net, net.Bob, carol,
lntest.OpenChannelParams{
Amt: chanAmt,
},
)
// Wait for Bob and Carol to receive the channel edge from the funding
// manager.
err = net.Bob.WaitForNetworkChannelOpen(chanPointCarol)
require.NoError(t.t, err)
err = carol.WaitForNetworkChannelOpen(chanPointCarol)
require.NoError(t.t, err)
// Wait for Alice to see the channel edge in the graph. // Wait for Alice to see the channel edge in the graph.
err = net.Alice.WaitForNetworkChannelOpen(chanPointCarol) ht.AssertTopologyChannelOpen(alice, chanPointCarol)
require.NoError(t.t, err)
// We'll create an invoice for Carol that Alice will attempt to pay. // We'll create an invoice for Carol that Alice will attempt to pay.
// Since Carol is in hodl.commit mode, she won't send back any commit // Since Carol is in hodl.commit mode, she won't send back any commit
// sigs. // sigs.
carolPayReqs, _, _, err := createPayReqs( carolPayReqs, _, _ := ht.CreatePayReqs(carol, paymentAmt, 1)
carol, paymentAmt, 1,
)
require.NoError(t.t, err)
// Alice will now attempt to fulfill the invoice. // Alice will now attempt to fulfill the invoice.
err = completePaymentRequests( ht.CompletePaymentRequestsNoWait(alice, carolPayReqs, chanPointAlice)
net.Alice, net.Alice.RouterClient, carolPayReqs, false,
)
require.NoError(t.t, err)
// Wait until Carol has received the Add, CommitSig from Bob, and has // Wait until Carol has received the Add, CommitSig from Bob, and has
// responded with a RevokeAndAck. We expect NumUpdates to be 1 meaning // responded with a RevokeAndAck. We expect NumUpdates to be 1 meaning
// Carol's CommitHeight is 1. // Carol's CommitHeight is 1.
err = wait.Predicate(func() bool { ht.AssertChannelCommitHeight(carol, chanPointCarol, 1)
carolInfo, err := getChanInfo(carol)
if err != nil {
return false
}
return carolInfo.NumUpdates == 1
}, defaultTimeout)
require.NoError(t.t, err)
// Before we shutdown Alice, we'll assert that she only has 1 update. // Before we shutdown Alice, we'll assert that she only has 1 update.
err = wait.Predicate(func() bool { ht.AssertChannelCommitHeight(alice, chanPointAlice, 1)
aliceInfo, err := getChanInfo(net.Alice)
if err != nil {
return false
}
return aliceInfo.NumUpdates == 1
}, defaultTimeout)
require.NoError(t.t, err)
// We'll shutdown Alice so that Bob can't connect to her. // We'll shutdown Alice so that Bob can't connect to her.
restartAlice, err := net.SuspendNode(net.Alice) restartAlice := ht.SuspendNode(alice)
require.NoError(t.t, err)
// Bob will now force close his channel with Carol such that resolution // Bob will now force close his channel with Carol such that resolution
// messages are created and forwarded backwards to Alice. // messages are created and forwarded backwards to Alice.
_, _, err = net.CloseChannel(net.Bob, chanPointCarol, true) ht.CloseChannelAssertPending(bob, chanPointCarol, true)
require.NoError(t.t, err)
// The channel should be listed in the PendingChannels result. // The channel should be listed in the PendingChannels result.
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) ht.AssertNumWaitingClose(bob, 1)
defer cancel()
pendingChansRequest := &lnrpc.PendingChannelsRequest{} // Mine a block to confirm the closing tx.
pendingChanResp, err := net.Bob.PendingChannels( ht.MineBlocks(1)
ctxt, pendingChansRequest,
)
require.NoError(t.t, err)
require.NoError(t.t, checkNumWaitingCloseChannels(pendingChanResp, 1))
// We'll mine a block to confirm the force close transaction and to
// advance Bob's contract state with Carol to StateContractClosed.
mineBlocks(t, net, 1, 1)
// We sleep here so we can be sure that the hand-off has occurred from // We sleep here so we can be sure that the hand-off has occurred from
// Bob's contractcourt to Bob's htlcswitch. This sleep could be removed // Bob's contractcourt to Bob's htlcswitch. This sleep could be removed
@ -137,64 +75,25 @@ func testResHandoff(net *lntest.NetworkHarness, t *harnessTest) {
// querying the state of resolution messages. // querying the state of resolution messages.
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
// Mine blocks until Bob has no waiting close channels. This tests // Mine blocks until Bob has no waiting close channels. This tests that
// that the circuit-deletion logic is skipped if a resolution message // the circuit-deletion logic is skipped if a resolution message
// exists. // exists.
for { ht.CleanupForceClose(bob, chanPointCarol)
_, err = net.Miner.Client.Generate(1)
require.NoError(t.t, err)
pendingChanResp, err = net.Bob.PendingChannels(
ctxt, pendingChansRequest,
)
require.NoError(t.t, err)
isErr := checkNumForceClosedChannels(pendingChanResp, 0)
if isErr == nil {
break
}
time.Sleep(150 * time.Millisecond)
}
// We will now restart Bob so that we can test whether the resolution // We will now restart Bob so that we can test whether the resolution
// messages are re-forwarded on start-up. // messages are re-forwarded on start-up.
restartBob, err := net.SuspendNode(net.Bob) ht.RestartNode(bob)
require.NoError(t.t, err)
err = restartBob()
require.NoError(t.t, err)
// We'll now also restart Alice and connect her with Bob. // We'll now also restart Alice and connect her with Bob.
err = restartAlice() require.NoError(ht, restartAlice())
require.NoError(t.t, err)
net.EnsureConnected(t.t, net.Alice, net.Bob) ht.EnsureConnected(alice, bob)
// We'll assert that Alice has received the failure resolution // We'll assert that Alice has received the failure resolution message.
// message. ht.AssertChannelCommitHeight(alice, chanPointAlice, 2)
err = wait.Predicate(func() bool {
aliceInfo, err := getChanInfo(net.Alice)
if err != nil {
return false
}
return aliceInfo.NumUpdates == 2
}, defaultTimeout)
require.NoError(t.t, err)
// Assert that Alice's payment failed. // Assert that Alice's payment failed.
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) ht.AssertFirstHTLCError(alice, lnrpc.Failure_PERMANENT_CHANNEL_FAILURE)
paymentsResp, err := net.Alice.ListPayments(
ctxt, &lnrpc.ListPaymentsRequest{
IncludeIncomplete: true,
},
)
require.NoError(t.t, err)
require.Equal(t.t, 1, len(paymentsResp.Payments))
htlcs := paymentsResp.Payments[0].Htlcs ht.CloseChannel(alice, chanPointAlice)
require.Equal(t.t, 1, len(htlcs))
require.Equal(t.t, lnrpc.HTLCAttempt_FAILED, htlcs[0].Status)
} }

View file

@ -186,10 +186,6 @@ var allTestCases = []*testCase{
name: "taproot", name: "taproot",
test: testTaproot, test: testTaproot,
}, },
{
name: "resolution handoff",
test: testResHandoff,
},
{ {
name: "zero conf channel open", name: "zero conf channel open",
test: testZeroConfChannelOpen, test: testZeroConfChannelOpen,