From 0115ec87193dcbfc2f212d2804fb34b240c06142 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Fri, 29 Jul 2022 12:40:41 +0800 Subject: [PATCH] itest: refactor `testMultiHopHtlcRemoteChainClaim` --- ..._multi-hop_htlc_remote_chain_claim_test.go | 221 ++++++------------ lntest/itest/lnd_multi-hop_test.go | 16 +- 2 files changed, 85 insertions(+), 152 deletions(-) diff --git a/lntest/itest/lnd_multi-hop_htlc_remote_chain_claim_test.go b/lntest/itest/lnd_multi-hop_htlc_remote_chain_claim_test.go index 7e69502b2..7433493f6 100644 --- a/lntest/itest/lnd_multi-hop_htlc_remote_chain_claim_test.go +++ b/lntest/itest/lnd_multi-hop_htlc_remote_chain_claim_test.go @@ -1,15 +1,13 @@ package itest import ( - "context" - "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc" - "github.com/lightningnetwork/lnd/lntest" - "github.com/lightningnetwork/lnd/lntest/wait" + "github.com/lightningnetwork/lnd/lntemp" + "github.com/lightningnetwork/lnd/lntemp/node" "github.com/lightningnetwork/lnd/lntypes" "github.com/stretchr/testify/require" ) @@ -19,90 +17,77 @@ import ( // we found out the preimage via the witness beacon, we properly settle the // HTLC directly on-chain using the preimage in order to ensure that we don't // lose any funds. -func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest, - alice, bob *lntest.HarnessNode, c lnrpc.CommitmentType, - zeroConf bool) { - - ctxb := context.Background() +func testMultiHopHtlcRemoteChainClaim(ht *lntemp.HarnessTest, + alice, bob *node.HarnessNode, c lnrpc.CommitmentType, zeroConf bool) { // First, we'll create a three hop network: Alice -> Bob -> Carol, with // Carol refusing to actually settle or directly cancel any HTLC's // self. - aliceChanPoint, bobChanPoint, carol := createThreeHopNetworkOld( - t, net, alice, bob, false, c, zeroConf, + aliceChanPoint, bobChanPoint, carol := createThreeHopNetwork( + ht, alice, bob, false, c, zeroConf, ) - // Clean up carol's node when the test finishes. - defer shutdownAndAssert(net, t, carol) - // With the network active, we'll now add a new hodl invoice at Carol's // end. Make sure the cltv expiry delta is large enough, otherwise Bob // won't send out the outgoing htlc. const invoiceAmt = 100000 - preimage := lntypes.Preimage{1, 2, 5} + var preimage lntypes.Preimage + copy(preimage[:], ht.Random32Bytes()) payHash := preimage.Hash() invoiceReq := &invoicesrpc.AddHoldInvoiceRequest{ Value: invoiceAmt, CltvExpiry: 40, Hash: payHash[:], } - ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) - defer cancel() - carolInvoice, err := carol.AddHoldInvoice(ctxt, invoiceReq) - require.NoError(t.t, err) + carolInvoice := carol.RPC.AddHoldInvoice(invoiceReq) + + // Subscribe the invoice. + stream := carol.RPC.SubscribeSingleInvoice(payHash[:]) // Now that we've created the invoice, we'll send a single payment from // Alice to Carol. We won't wait for the response however, as Carol // will not immediately settle the payment. - ctx, cancel := context.WithCancel(ctxb) - defer cancel() - - _, err = alice.RouterClient.SendPaymentV2( - ctx, &routerrpc.SendPaymentRequest{ - PaymentRequest: carolInvoice.PaymentRequest, - TimeoutSeconds: 60, - FeeLimitMsat: noFeeLimitMsat, - }, - ) - require.NoError(t.t, err) + req := &routerrpc.SendPaymentRequest{ + PaymentRequest: carolInvoice.PaymentRequest, + TimeoutSeconds: 60, + FeeLimitMsat: noFeeLimitMsat, + } + alice.RPC.SendPayment(req) // At this point, all 3 nodes should now have an active channel with // the created HTLC pending on all of them. - nodes := []*lntest.HarnessNode{alice, bob, carol} - err = wait.NoError(func() error { - return assertActiveHtlcs(nodes, payHash[:]) - }, defaultTimeout) - require.NoError(t.t, err) + ht.AssertActiveHtlcs(alice, payHash[:]) + ht.AssertActiveHtlcs(bob, payHash[:]) + ht.AssertActiveHtlcs(carol, payHash[:]) // Wait for carol to mark invoice as accepted. There is a small gap to // bridge between adding the htlc to the channel and executing the exit // hop logic. - waitForInvoiceAccepted(t, carol, payHash) + ht.AssertInvoiceState(stream, lnrpc.Invoice_ACCEPTED) // Increase the fee estimate so that the following force close tx will // be cpfp'ed. - net.SetFeeEstimate(30000) + ht.SetFeeEstimate(30000) // Next, Alice decides that she wants to exit the channel, so she'll // immediately force close the channel by broadcast her commitment // transaction. hasAnchors := commitTypeHasAnchors(c) - aliceForceClose := closeChannelAndAssertType( - t, net, alice, aliceChanPoint, hasAnchors, true, + closeStream, _ := ht.CloseChannelAssertPending( + alice, aliceChanPoint, true, + ) + aliceForceClose := ht.AssertStreamChannelForceClosed( + alice, aliceChanPoint, hasAnchors, closeStream, ) // Wait for the channel to be marked pending force close. - err = waitForChannelPendingForceClose(alice, aliceChanPoint) - require.NoError(t.t, err) + ht.AssertChannelPendingForceClose(alice, aliceChanPoint) // After closeChannelAndAssertType returns, it has mined a block so now // bob will attempt to redeem his anchor commitment (if the channel // type is of that type). if hasAnchors { - _, err = waitForNTxsInMempool( - net.Miner.Client, 1, minerMempoolTimeout, - ) - require.NoError(t.t, err) + ht.Miner.AssertNumTxsInMempool(1) } if c != lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { @@ -112,31 +97,21 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest // sweep tx will be broadcast immediately before it can be // included in a block, so mine one less than defaultCSV in // order to perform mempool assertions. - _, err = net.Miner.Client.Generate(defaultCSV - 1) - require.NoError(t.t, err) + ht.MineBlocksAssertNodesSync(defaultCSV - 1) // Alice should now sweep her funds. - _, err = waitForNTxsInMempool( - net.Miner.Client, 1, minerMempoolTimeout, - ) - require.NoError(t.t, err) + ht.Miner.AssertNumTxsInMempool(1) } // Suspend bob, so Carol is forced to go on chain. - restartBob, err := net.SuspendNode(bob) - require.NoError(t.t, err) + restartBob := ht.SuspendNode(bob) // Settle invoice. This will just mark the invoice as settled, as there // is no link anymore to remove the htlc from the commitment tx. For // this test, it is important to actually settle and not leave the // invoice in the accepted state, because without a known preimage, the // channel arbitrator won't go to chain. - ctx, cancel = context.WithTimeout(ctxb, defaultTimeout) - defer cancel() - _, err = carol.SettleInvoice(ctx, &invoicesrpc.SettleInvoiceMsg{ - Preimage: preimage[:], - }) - require.NoError(t.t, err) + carol.RPC.SettleInvoice(preimage[:]) // We'll now mine enough blocks so Carol decides that she needs to go // on-chain to claim the HTLC as Bob has been inactive. @@ -146,9 +121,7 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest if c != lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { numBlocks -= defaultCSV } - - _, err = net.Miner.Client.Generate(numBlocks) - require.NoError(t.t, err) + ht.MineBlocksAssertNodesSync(numBlocks) expectedTxes := 1 if hasAnchors { @@ -157,33 +130,22 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest // Carol's commitment transaction should now be in the mempool. If // there are anchors, Carol also sweeps her anchor. - _, err = waitForNTxsInMempool( - net.Miner.Client, expectedTxes, minerMempoolTimeout, - ) - require.NoError(t.t, err) - bobFundingTxid, err := lnrpc.GetChanPointFundingTxid(bobChanPoint) - require.NoError(t.t, err) - carolFundingPoint := wire.OutPoint{ - Hash: *bobFundingTxid, - Index: bobChanPoint.OutputIndex, - } + ht.Miner.AssertNumTxsInMempool(expectedTxes) // The closing transaction should be spending from the funding // transaction. - closingTx := getSpendingTxInMempool( - t, net.Miner.Client, minerMempoolTimeout, carolFundingPoint, + closingTx := ht.Miner.AssertOutpointInMempool( + ht.OutPointFromChannelPoint(bobChanPoint), ) closingTxid := closingTx.TxHash() // Mine a block, which should contain: the commitment, possibly an // anchor sweep and the coinbase tx. - block := mineBlocks(t, net, 1, expectedTxes)[0] - require.Len(t.t, block.Transactions, expectedTxes+1) - assertTxInBlock(t, block, &closingTxid) + block := ht.Miner.MineBlocksAndAssertNumTxes(1, expectedTxes)[0] + ht.Miner.AssertTxInBlock(block, &closingTxid) // Restart bob again. - err = restartBob() - require.NoError(t.t, err) + require.NoError(ht, restartBob()) // After the force close transaction is mined, we should expect Bob and // Carol to broadcast some transactions depending on the channel @@ -209,19 +171,15 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest expectedTxes = 2 default: - t.Fatalf("unhandled commitment type %v", c) + ht.Fatalf("unhandled commitment type %v", c) } - txes, err := getNTxsFromMempool( - net.Miner.Client, expectedTxes, minerMempoolTimeout, - ) - require.NoError(t.t, err) + txes := ht.Miner.GetNumTxsFromMempool(expectedTxes) // All transactions should be pending from the commitment transaction. - assertAllTxesSpendFrom(t, txes, closingTxid) + ht.AssertAllTxesSpendFrom(txes, closingTxid) // Mine a block to confirm the two transactions (+ coinbase). - block = mineBlocks(t, net, 1, expectedTxes)[0] - require.Len(t.t, block.Transactions, expectedTxes+1) + ht.Miner.MineBlocksAndAssertNumTxes(1, expectedTxes) // Keep track of the second level tx maturity. carolSecondLevelCSV := uint32(defaultCSV) @@ -229,23 +187,16 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest // When Bob notices Carol's second level transaction in the block, he // will extract the preimage and broadcast a sweep tx to directly claim // the HTLC in his (already closed) channel with Alice. - bobHtlcSweep, err := waitForTxInMempool( - net.Miner.Client, minerMempoolTimeout, - ) - require.NoError(t.t, err) + bobHtlcSweep := ht.Miner.GetNumTxsFromMempool(1)[0] + bobHtlcSweepTxid := bobHtlcSweep.TxHash() // It should spend from the commitment in the channel with Alice. - tx, err := net.Miner.Client.GetRawTransaction(bobHtlcSweep) - require.NoError(t.t, err) - require.Equal( - t.t, *aliceForceClose, tx.MsgTx().TxIn[0].PreviousOutPoint.Hash, - ) + ht.AssertTxSpendFrom(bobHtlcSweep, *aliceForceClose) // We'll now mine a block which should confirm Bob's HTLC sweep // transaction. - block = mineBlocks(t, net, 1, 1)[0] - require.Len(t.t, block.Transactions, 2) - assertTxInBlock(t, block, bobHtlcSweep) + block = ht.Miner.MineBlocksAndAssertNumTxes(1, 1)[0] + ht.Miner.AssertTxInBlock(block, &bobHtlcSweepTxid) carolSecondLevelCSV-- // Now that the sweeping transaction has been confirmed, Bob should now @@ -255,30 +206,22 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { aliceBobPendingChansLeft = 1 } - for _, node := range []*lntest.HarnessNode{alice, bob} { - err = waitForNumChannelPendingForceClose( - node, aliceBobPendingChansLeft, nil, + for _, node := range []*node.HarnessNode{alice, bob} { + ht.AssertNumPendingForceClose( + node, aliceBobPendingChansLeft, ) - require.NoError(t.t, err) } // If we then mine 3 additional blocks, Carol's second level tx will // mature, and she should pull the funds. - _, err = net.Miner.Client.Generate(carolSecondLevelCSV) - require.NoError(t.t, err) - - carolSweep, err := waitForTxInMempool( - net.Miner.Client, minerMempoolTimeout, - ) - require.NoError(t.t, err) + ht.MineBlocksAssertNodesSync(carolSecondLevelCSV) + carolSweep := ht.Miner.AssertNumTxsInMempool(1)[0] // When Carol's sweep gets confirmed, she should have no more pending // channels. - block = mineBlocks(t, net, 1, 1)[0] - assertTxInBlock(t, block, carolSweep) - - err = waitForNumChannelPendingForceClose(carol, 0, nil) - require.NoError(t.t, err) + block = ht.Miner.MineBlocksAndAssertNumTxes(1, 1)[0] + ht.Miner.AssertTxInBlock(block, carolSweep) + ht.AssertNumPendingForceClose(carol, 0) // With the script-enforced lease commitment type, Alice and Bob still // haven't been able to sweep their respective commit outputs due to the @@ -288,57 +231,47 @@ func testMultiHopHtlcRemoteChainClaim(net *lntest.NetworkHarness, t *harnessTest // Due to the way the test is set up, Alice and Bob share the // same CLTV for their commit outputs even though it's enforced // on different channels (Alice-Bob and Bob-Carol). - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - resp, err := alice.PendingChannels( - ctxt, &lnrpc.PendingChannelsRequest{}, - ) - require.NoError(t.t, err) - require.Len(t.t, resp.PendingForceClosingChannels, 1) + resp := alice.RPC.PendingChannels() + require.Len(ht, resp.PendingForceClosingChannels, 1) forceCloseChan := resp.PendingForceClosingChannels[0] - require.Positive(t.t, forceCloseChan.BlocksTilMaturity) + require.Positive(ht, forceCloseChan.BlocksTilMaturity) // Mine enough blocks for the timelock to expire. numBlocks := uint32(forceCloseChan.BlocksTilMaturity) - _, err = net.Miner.Client.Generate(numBlocks) - require.NoError(t.t, err) + ht.MineBlocksAssertNodesSync(numBlocks) // Both Alice and Bob show broadcast their commit sweeps. - aliceCommitOutpoint := wire.OutPoint{Hash: *aliceForceClose, Index: 3} - aliceCommitSweep := assertSpendingTxInMempool( - t, net.Miner.Client, minerMempoolTimeout, + aliceCommitOutpoint := wire.OutPoint{ + Hash: *aliceForceClose, Index: 3, + } + aliceCommitSweep := ht.Miner.AssertOutpointInMempool( aliceCommitOutpoint, ) + aliceCommitSweepTxid := aliceCommitSweep.TxHash() bobCommitOutpoint := wire.OutPoint{Hash: closingTxid, Index: 3} - bobCommitSweep := assertSpendingTxInMempool( - t, net.Miner.Client, minerMempoolTimeout, + bobCommitSweep := ht.Miner.AssertOutpointInMempool( bobCommitOutpoint, ) + bobCommitSweepTxid := bobCommitSweep.TxHash() // Confirm their sweeps. - block := mineBlocks(t, net, 1, 2)[0] - assertTxInBlock(t, block, &aliceCommitSweep) - assertTxInBlock(t, block, &bobCommitSweep) + block := ht.Miner.MineBlocksAndAssertNumTxes(1, 2)[0] + ht.Miner.AssertTxInBlock(block, &aliceCommitSweepTxid) + ht.Miner.AssertTxInBlock(block, &bobCommitSweepTxid) // Alice and Bob should not show any pending channels anymore as // they have been fully resolved. - for _, node := range []*lntest.HarnessNode{alice, bob} { - err = waitForNumChannelPendingForceClose(node, 0, nil) - require.NoError(t.t, err) + for _, node := range []*node.HarnessNode{alice, bob} { + ht.AssertNumPendingForceClose(node, 0) } } // The invoice should show as settled for Carol, indicating that it was // swept on-chain. - invoicesReq := &lnrpc.ListInvoiceRequest{} - invoicesResp, err := carol.ListInvoices(ctxb, invoicesReq) - require.NoError(t.t, err) - require.Len(t.t, invoicesResp.Invoices, 1) - invoice := invoicesResp.Invoices[0] - require.Equal(t.t, lnrpc.Invoice_SETTLED, invoice.State) - require.Equal(t.t, int64(invoiceAmt), invoice.AmtPaidSat) + invoice := ht.AssertInvoiceState(stream, lnrpc.Invoice_SETTLED) + require.Equal(ht, int64(invoiceAmt), invoice.AmtPaidSat) // Finally, check that the Alice's payment is correctly marked // succeeded. - err = checkPaymentStatus(alice, preimage, lnrpc.Payment_SUCCEEDED) - require.NoError(t.t, err) + ht.AssertPaymentStatus(alice, preimage, lnrpc.Payment_SUCCEEDED) } diff --git a/lntest/itest/lnd_multi-hop_test.go b/lntest/itest/lnd_multi-hop_test.go index 15efb9491..1e9bb7561 100644 --- a/lntest/itest/lnd_multi-hop_test.go +++ b/lntest/itest/lnd_multi-hop_test.go @@ -59,14 +59,14 @@ func testMultiHopHtlcClaims(ht *lntemp.HarnessTest) { name: "local chain claim", test: testMultiHopHtlcLocalChainClaim, }, - // { - // // bob: outgoing their commit watch and see, they sweep - // // on chain - // // bob: incoming their commit watch and learn preimage - // // carol: incoming our commit know preimage - // name: "remote chain claim", - // test: testMultiHopHtlcRemoteChainClaim, - // }, + { + // bob: outgoing their commit watch and see, they sweep + // on chain + // bob: incoming their commit watch and learn preimage + // carol: incoming our commit know preimage + name: "remote chain claim", + test: testMultiHopHtlcRemoteChainClaim, + }, // { // // bob: outgoing and incoming, sweep all on chain // name: "local htlc aggregation",