From f590a96372d84ccf9304255e44662e6b0f6ab60d Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Mon, 8 Aug 2022 20:50:03 +0800 Subject: [PATCH] itest: refactor `testRevokedCloseRetributionZeroValueRemoteOutput` --- lntest/itest/list_on_test.go | 5 + lntest/itest/lnd_revocation_test.go | 147 ++++++-------------------- lntest/itest/lnd_test_list_on_test.go | 4 - 3 files changed, 38 insertions(+), 118 deletions(-) diff --git a/lntest/itest/list_on_test.go b/lntest/itest/list_on_test.go index bba41fcb4..744090442 100644 --- a/lntest/itest/list_on_test.go +++ b/lntest/itest/list_on_test.go @@ -295,4 +295,9 @@ var allTestCasesTemp = []*lntemp.TestCase{ Name: "revoked uncooperative close retribution", TestFunc: testRevokedCloseRetribution, }, + { + Name: "revoked uncooperative close retribution zero value " + + "remote output", + TestFunc: testRevokedCloseRetributionZeroValueRemoteOutput, + }, } diff --git a/lntest/itest/lnd_revocation_test.go b/lntest/itest/lnd_revocation_test.go index 8850c10c3..03193f032 100644 --- a/lntest/itest/lnd_revocation_test.go +++ b/lntest/itest/lnd_revocation_test.go @@ -169,9 +169,7 @@ func testRevokedCloseRetribution(ht *lntemp.HarnessTest) { // testRevokedCloseRetributionZeroValueRemoteOutput tests that Dave is able // carry out retribution in the event that he fails in state where the remote // commitment output has zero-value. -func testRevokedCloseRetributionZeroValueRemoteOutput(net *lntest.NetworkHarness, - t *harnessTest) { - +func testRevokedCloseRetributionZeroValueRemoteOutput(ht *lntemp.HarnessTest) { const ( chanAmt = funding.MaxBtcFundingAmount paymentAmt = 10000 @@ -180,177 +178,103 @@ func testRevokedCloseRetributionZeroValueRemoteOutput(net *lntest.NetworkHarness // Since we'd like to test some multi-hop failure scenarios, we'll // introduce another node into our test network: Carol. - carol := net.NewNode(t.t, "Carol", []string{"--hodl.exit-settle"}) - defer shutdownAndAssert(net, t, carol) + carol := ht.NewNode("Carol", []string{"--hodl.exit-settle"}) // Dave will be the breached party. We set --nolisten to ensure Carol // won't be able to connect to him and trigger the channel data // protection logic automatically. We also can't have Dave automatically // re-connect too early, otherwise DLP would be initiated instead of the // breach we want to provoke. - dave := net.NewNode( - t.t, "Dave", + dave := ht.NewNode( + "Dave", []string{"--hodl.exit-settle", "--nolisten", "--minbackoff=1h"}, ) - defer shutdownAndAssert(net, t, dave) // We must let Dave have an open channel before he can send a node // announcement, so we open a channel with Carol, - net.ConnectNodes(t.t, dave, carol) + ht.ConnectNodes(dave, carol) // Before we make a channel, we'll load up Dave with some coins sent // directly from the miner. - net.SendCoins(t.t, btcutil.SatoshiPerBitcoin, dave) + ht.FundCoins(btcutil.SatoshiPerBitcoin, dave) // In order to test Dave's response to an uncooperative channel // closure by Carol, we'll first open up a channel between them with a // 0.5 BTC value. - chanPoint := openChannelAndAssert( - t, net, dave, carol, - lntest.OpenChannelParams{ - Amt: chanAmt, - }, + chanPoint := ht.OpenChannel( + dave, carol, lntemp.OpenChannelParams{Amt: chanAmt}, ) // With the channel open, we'll create a few invoices for Carol that // Dave will pay to in order to advance the state of the channel. - carolPayReqs, _, _, err := createPayReqs( - carol, paymentAmt, numInvoices, - ) - if err != nil { - t.Fatalf("unable to create pay reqs: %v", err) - } - - // Wait for Dave to receive the channel edge from the funding manager. - err = dave.WaitForNetworkChannelOpen(chanPoint) - if err != nil { - t.Fatalf("dave didn't see the dave->carol channel before "+ - "timeout: %v", err) - } + carolPayReqs, _, _ := ht.CreatePayReqs(carol, paymentAmt, numInvoices) // Next query for Carol's channel state, as we sent 0 payments, Carol // should now see her balance as being 0 satoshis. - carolChan, err := getChanInfo(carol) - if err != nil { - t.Fatalf("unable to get carol's channel info: %v", err) - } - if carolChan.LocalBalance != 0 { - t.Fatalf("carol's balance is incorrect, got %v, expected %v", - carolChan.LocalBalance, 0) - } + carolChan := ht.AssertChannelLocalBalance(carol, chanPoint, 0) // Grab Carol's current commitment height (update number), we'll later // revert her to this state after additional updates to force her to // broadcast this soon to be revoked state. - carolStateNumPreCopy := carolChan.NumUpdates + carolStateNumPreCopy := int(carolChan.NumUpdates) // With the temporary file created, copy Carol's current state into the // temporary file we created above. Later after more updates, we'll // restore this state. - if err := net.BackupDb(carol); err != nil { - t.Fatalf("unable to copy database files: %v", err) - } + ht.BackupDB(carol) // Reconnect the peers after the restart that was needed for the db // backup. - net.EnsureConnected(t.t, dave, carol) + ht.EnsureConnected(dave, carol) // Finally, send payments from Dave to Carol, consuming Carol's // remaining payment hashes. - err = completePaymentRequests( - dave, dave.RouterClient, carolPayReqs, false, - ) - if err != nil { - t.Fatalf("unable to send payments: %v", err) - } - - _, err = getChanInfo(carol) - if err != nil { - t.Fatalf("unable to get carol chan info: %v", err) - } + ht.CompletePaymentRequestsNoWait(dave, carolPayReqs, chanPoint) // Now we shutdown Carol, copying over the her temporary database state // which has the *prior* channel state over her current most up to date // state. With this, we essentially force Carol to travel back in time // within the channel's history. - if err = net.RestartNode(carol, func() error { - return net.RestoreDb(carol) - }); err != nil { - t.Fatalf("unable to restart node: %v", err) - } + ht.RestartNodeAndRestoreDB(carol) // Now query for Carol's channel state, it should show that she's at a // state number in the past, not the *latest* state. - carolChan, err = getChanInfo(carol) - if err != nil { - t.Fatalf("unable to get carol chan info: %v", err) - } - if carolChan.NumUpdates != carolStateNumPreCopy { - t.Fatalf("db copy failed: %v", carolChan.NumUpdates) - } + ht.AssertChannelCommitHeight(carol, chanPoint, carolStateNumPreCopy) // Now force Carol to execute a *force* channel closure by unilaterally // broadcasting her current channel state. This is actually the // commitment transaction of a prior *revoked* state, so she'll soon // feel the wrath of Dave's retribution. - force := true - closeUpdates, closeTxID, closeErr := net.CloseChannel( - carol, chanPoint, force, + stream, closeTxID := ht.CloseChannelAssertPending( + carol, chanPoint, true, ) - require.NoError(t.t, closeErr, "unable to close channel") - - // Query the mempool for the breaching closing transaction, this should - // be broadcast by Carol when she force closes the channel above. - txid, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout) - if err != nil { - t.Fatalf("unable to find Carol's force close tx in mempool: %v", - err) - } - if *txid != *closeTxID { - t.Fatalf("expected closeTx(%v) in mempool, instead found %v", - closeTxID, txid) - } // Finally, generate a single block, wait for the final close status // update, then ensure that the closing transaction was included in the // block. - block := mineBlocks(t, net, 1, 1)[0] + ht.MineBlocksAndAssertNumTxes(1, 1) // Here, Dave receives a confirmation of Carol's breach transaction. // We restart Dave to ensure that he is persisting his retribution // state and continues exacting justice after his node restarts. - if err := net.RestartNode(dave, nil); err != nil { - t.Fatalf("unable to stop Dave's node: %v", err) - } + ht.RestartNode(dave) - breachTXID, err := net.WaitForChannelClose(closeUpdates) - if err != nil { - t.Fatalf("error while waiting for channel close: %v", err) - } - assertTxInBlock(t, block, breachTXID) + // The breachTXID should match the above closeTxID. + breachTXID := ht.WaitForChannelCloseEvent(stream) + require.EqualValues(ht, breachTXID, closeTxID) // Query the mempool for Dave's justice transaction, this should be // broadcast as Carol's contract breaching transaction gets confirmed // above. - justiceTXID, err := waitForTxInMempool(net.Miner.Client, minerMempoolTimeout) - if err != nil { - t.Fatalf("unable to find Dave's justice tx in mempool: %v", - err) - } - time.Sleep(100 * time.Millisecond) + justiceTXID := ht.Miner.AssertNumTxsInMempool(1)[0] // Query for the mempool transaction found above. Then assert that all // the inputs of this transaction are spending outputs generated by // Carol's breach transaction above. - justiceTx, err := net.Miner.Client.GetRawTransaction(justiceTXID) - if err != nil { - t.Fatalf("unable to query for justice tx: %v", err) - } + justiceTx := ht.Miner.GetRawTransaction(justiceTXID) for _, txIn := range justiceTx.MsgTx().TxIn { - if !bytes.Equal(txIn.PreviousOutPoint.Hash[:], breachTXID[:]) { - t.Fatalf("justice tx not spending commitment utxo "+ - "instead is: %v", txIn.PreviousOutPoint) - } + require.Equal(ht, breachTXID[:], txIn.PreviousOutPoint.Hash[:], + "justice tx not spending commitment utxo ") } // We restart Dave here to ensure that he persists his retribution state @@ -358,25 +282,20 @@ func testRevokedCloseRetributionZeroValueRemoteOutput(net *lntest.NetworkHarness // this point, Dave has broadcast the justice transaction, but it hasn't // been confirmed yet; when Dave restarts, he should start waiting for // the justice transaction to confirm again. - if err := net.RestartNode(dave, nil); err != nil { - t.Fatalf("unable to restart Dave's node: %v", err) - } + ht.RestartNode(dave) // Now mine a block, this transaction should include Dave's justice // transaction which was just accepted into the mempool. - block = mineBlocks(t, net, 1, 1)[0] + block := ht.MineBlocksAndAssertNumTxes(1, 1)[0] // The block should have exactly *two* transactions, one of which is // the justice transaction. - if len(block.Transactions) != 2 { - t.Fatalf("transaction wasn't mined") - } + require.Len(ht, block.Transactions, 2, "transaction wasn't mined") justiceSha := block.Transactions[1].TxHash() - if !bytes.Equal(justiceTx.Hash()[:], justiceSha[:]) { - t.Fatalf("justice tx wasn't mined") - } + require.Equal(ht, justiceTx.Hash()[:], justiceSha[:], + "justice tx wasn't mined") - assertNodeNumChannels(t, dave, 0) + ht.AssertNodeNumChannels(dave, 0) } // testRevokedCloseRetributionRemoteHodl tests that Dave properly responds to a diff --git a/lntest/itest/lnd_test_list_on_test.go b/lntest/itest/lnd_test_list_on_test.go index 479d15831..ca7ef2172 100644 --- a/lntest/itest/lnd_test_list_on_test.go +++ b/lntest/itest/lnd_test_list_on_test.go @@ -72,10 +72,6 @@ var allTestCases = []*testCase{ name: "switch offline delivery outgoing offline", test: testSwitchOfflineDeliveryOutgoingOffline, }, - { - name: "revoked uncooperative close retribution zero value remote output", - test: testRevokedCloseRetributionZeroValueRemoteOutput, - }, { name: "revoked uncooperative close retribution remote hodl", test: testRevokedCloseRetributionRemoteHodl,