From 9000994b7b542560bb3938ac27f3cd0cbb36f9d9 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 11 Aug 2022 14:01:08 +0800 Subject: [PATCH] lntemp+itest: refactor wallet import tests --- lntest/itest/list_on_test.go | 8 + lntest/itest/lnd_test_list_on_test.go | 8 - lntest/itest/lnd_wallet_import_test.go | 517 +++++++++---------------- 3 files changed, 188 insertions(+), 345 deletions(-) diff --git a/lntest/itest/list_on_test.go b/lntest/itest/list_on_test.go index d9e002344..51d4d558b 100644 --- a/lntest/itest/list_on_test.go +++ b/lntest/itest/list_on_test.go @@ -469,4 +469,12 @@ var allTestCasesTemp = []*lntemp.TestCase{ Name: "taproot", TestFunc: testTaproot, }, + { + Name: "wallet import account", + TestFunc: testWalletImportAccount, + }, + { + Name: "wallet import pubkey", + TestFunc: testWalletImportPubKey, + }, } diff --git a/lntest/itest/lnd_test_list_on_test.go b/lntest/itest/lnd_test_list_on_test.go index eac437576..05d78ffd1 100644 --- a/lntest/itest/lnd_test_list_on_test.go +++ b/lntest/itest/lnd_test_list_on_test.go @@ -12,14 +12,6 @@ var allTestCases = []*testCase{ name: "async bidirectional payments", test: testBidirectionalAsyncPayments, }, - { - name: "wallet import account", - test: testWalletImportAccount, - }, - { - name: "wallet import pubkey", - test: testWalletImportPubKey, - }, { name: "remote signer", test: testRemoteSigner, diff --git a/lntest/itest/lnd_wallet_import_test.go b/lntest/itest/lnd_wallet_import_test.go index ad8ad1b6b..5f97f74b8 100644 --- a/lntest/itest/lnd_wallet_import_test.go +++ b/lntest/itest/lnd_wallet_import_test.go @@ -2,10 +2,6 @@ package itest import ( "bytes" - "context" - "crypto/rand" - "fmt" - "math" "testing" "time" @@ -20,8 +16,8 @@ import ( "github.com/lightningnetwork/lnd/funding" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc" - "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/lnwallet" "github.com/stretchr/testify/require" ) @@ -55,30 +51,27 @@ func walletToLNAddrType(t *testing.T, // newExternalAddr generates a new external address of an imported account for a // pair of nodes, where one acts as the funder and the other as the signer. -func newExternalAddr(t *testing.T, funder, signer *lntest.HarnessNode, +func newExternalAddr(ht *lntemp.HarnessTest, funder, signer *node.HarnessNode, importedAccount string, addrType walletrpc.AddressType) string { // We'll generate a new address for Carol from Dave's node to receive // and fund a new channel. - ctxb := context.Background() - ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) - defer cancel() - funderResp, err := funder.NewAddress(ctxt, &lnrpc.NewAddressRequest{ - Type: walletToLNAddrType(t, addrType), + req := &lnrpc.NewAddressRequest{ + Type: walletToLNAddrType(ht.T, addrType), Account: importedAccount, - }) - require.NoError(t, err) + } + funderResp := funder.RPC.NewAddress(req) - // Carol also needs to generate the address for the sake of this test to - // be able to sign the channel funding input. - signerResp, err := signer.NewAddress(ctxt, &lnrpc.NewAddressRequest{ - Type: walletToLNAddrType(t, addrType), - }) - require.NoError(t, err) + // Carol also needs to generate the address for the sake of this test + // to be able to sign the channel funding input. + req = &lnrpc.NewAddressRequest{ + Type: walletToLNAddrType(ht.T, addrType), + } + signerResp := signer.RPC.NewAddress(req) // Sanity check that the generated addresses match. - require.Equal(t, funderResp.Address, signerResp.Address) - assertExternalAddrType(t, funderResp.Address, addrType) + require.Equal(ht, funderResp.Address, signerResp.Address) + assertExternalAddrType(ht.T, funderResp.Address, addrType) return funderResp.Address } @@ -130,108 +123,21 @@ func assertOutputScriptType(t *testing.T, expType txscript.ScriptClass, spew.Sdump(tx)) } -// assertAccountBalance asserts that the unconfirmed and confirmed balance for -// the given account is satisfied by the WalletBalance and ListUnspent RPCs. The -// unconfirmed balance is not checked for neutrino nodes. -func assertAccountBalance(t *testing.T, node *lntest.HarnessNode, account string, - confirmedBalance, unconfirmedBalance int64) { - - err := wait.NoError(func() error { - balanceResp, err := node.WalletBalance( - context.Background(), &lnrpc.WalletBalanceRequest{}, - ) - if err != nil { - return err - } - require.Contains(t, balanceResp.AccountBalance, account) - accountBalance := balanceResp.AccountBalance[account] - - // Check confirmed balance. - if accountBalance.ConfirmedBalance != confirmedBalance { - return fmt.Errorf("expected confirmed balance %v, "+ - "got %v", confirmedBalance, - accountBalance.ConfirmedBalance) - } - listUtxosReq := &lnrpc.ListUnspentRequest{ - MinConfs: 1, - MaxConfs: math.MaxInt32, - Account: account, - } - confirmedUtxosResp, err := node.ListUnspent( - context.Background(), listUtxosReq, - ) - if err != nil { - return err - } - var totalConfirmedVal int64 - for _, utxo := range confirmedUtxosResp.Utxos { - totalConfirmedVal += utxo.AmountSat - } - if totalConfirmedVal != confirmedBalance { - return fmt.Errorf("expected total confirmed utxo "+ - "balance %v, got %v", confirmedBalance, - totalConfirmedVal) - } - - // Skip unconfirmed balance checks for neutrino nodes. - if node.Cfg.BackendCfg.Name() == lntest.NeutrinoBackendName { - return nil - } - - // Check unconfirmed balance. - if accountBalance.UnconfirmedBalance != unconfirmedBalance { - return fmt.Errorf("expected unconfirmed balance %v, "+ - "got %v", unconfirmedBalance, - accountBalance.UnconfirmedBalance) - } - listUtxosReq.MinConfs = 0 - listUtxosReq.MaxConfs = 0 - unconfirmedUtxosResp, err := node.ListUnspent( - context.Background(), listUtxosReq, - ) - require.NoError(t, err) - var totalUnconfirmedVal int64 - for _, utxo := range unconfirmedUtxosResp.Utxos { - totalUnconfirmedVal += utxo.AmountSat - } - if totalUnconfirmedVal != unconfirmedBalance { - return fmt.Errorf("expected total unconfirmed utxo "+ - "balance %v, got %v", unconfirmedBalance, - totalUnconfirmedVal) - } - - return nil - }, defaultTimeout) - require.NoError(t, err) -} - // psbtSendFromImportedAccount attempts to fund a PSBT from the given imported // account, originating from the source node to the destination. -func psbtSendFromImportedAccount(t *harnessTest, srcNode, destNode, - signer *lntest.HarnessNode, account string, +func psbtSendFromImportedAccount(ht *lntemp.HarnessTest, srcNode, destNode, + signer *node.HarnessNode, account string, accountAddrType walletrpc.AddressType) { - ctxb := context.Background() - - ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) - defer cancel() - balanceResp, err := srcNode.WalletBalance( - ctxt, &lnrpc.WalletBalanceRequest{}, - ) - require.NoError(t.t, err) - require.Contains(t.t, balanceResp.AccountBalance, account) + balanceResp := srcNode.RPC.WalletBalance() + require.Contains(ht, balanceResp.AccountBalance, account) confBalance := balanceResp.AccountBalance[account].ConfirmedBalance destAmt := confBalance - 10000 - ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout) - defer cancel() - destAddrResp, err := destNode.NewAddress(ctxt, &lnrpc.NewAddressRequest{ + destAddrResp := destNode.RPC.NewAddress(&lnrpc.NewAddressRequest{ Type: lnrpc.AddressType_WITNESS_PUBKEY_HASH, }) - require.NoError(t.t, err) - ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout) - defer cancel() fundReq := &walletrpc.FundPsbtRequest{ Template: &walletrpc.FundPsbtRequest_Raw{ Raw: &walletrpc.TxTemplate{ @@ -245,29 +151,20 @@ func psbtSendFromImportedAccount(t *harnessTest, srcNode, destNode, }, Account: account, } - fundResp, err := srcNode.WalletKitClient.FundPsbt(ctxt, fundReq) - require.NoError(t.t, err) + fundResp := srcNode.RPC.FundPsbt(fundReq) // Have Carol sign the PSBT input since Dave doesn't have any private // key information. - ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout) - defer cancel() finalizeReq := &walletrpc.FinalizePsbtRequest{ FundedPsbt: fundResp.FundedPsbt, } - finalizeResp, err := signer.WalletKitClient.FinalizePsbt( - ctxt, finalizeReq, - ) - require.NoError(t.t, err) + finalizeResp := signer.RPC.FinalizePsbt(finalizeReq) // With the PSBT signed, we can broadcast the resulting transaction. - ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout) - defer cancel() publishReq := &walletrpc.Transaction{ TxHex: finalizeResp.RawFinalTx, } - _, err = srcNode.WalletKitClient.PublishTransaction(ctxt, publishReq) - require.NoError(t.t, err) + srcNode.RPC.PublishTransaction(publishReq) // Carol's balance from Dave's perspective should update accordingly. var ( @@ -304,7 +201,7 @@ func psbtSendFromImportedAccount(t *harnessTest, srcNode, destNode, expChangeScriptType = txscript.WitnessV1TaprootTy default: - t.Fatalf("unsupported addr type %v", accountAddrType) + ht.Fatalf("unsupported addr type %v", accountAddrType) } changeUtxoAmt := confBalance - destAmt - expTxFee @@ -314,16 +211,20 @@ func psbtSendFromImportedAccount(t *harnessTest, srcNode, destNode, if account == defaultImportedAccount { accountWithBalance = defaultAccount } - assertAccountBalance(t.t, srcNode, accountWithBalance, 0, changeUtxoAmt) - _ = mineBlocks(t, t.lndHarness, 1, 1) - assertAccountBalance(t.t, srcNode, accountWithBalance, changeUtxoAmt, 0) + ht.AssertWalletAccountBalance( + srcNode, accountWithBalance, 0, changeUtxoAmt, + ) + ht.MineBlocksAndAssertNumTxes(1, 1) + ht.AssertWalletAccountBalance( + srcNode, accountWithBalance, changeUtxoAmt, 0, + ) // Finally, assert that the transaction has the expected change address // type based on the account. var tx wire.MsgTx - err = tx.Deserialize(bytes.NewReader(finalizeResp.RawFinalTx)) - require.NoError(t.t, err) - assertOutputScriptType(t.t, expChangeScriptType, &tx, changeUtxoAmt) + err := tx.Deserialize(bytes.NewReader(finalizeResp.RawFinalTx)) + require.NoError(ht, err) + assertOutputScriptType(ht.T, expChangeScriptType, &tx, changeUtxoAmt) } // fundChanAndCloseFromImportedAccount attempts to a fund a channel from the @@ -331,21 +232,14 @@ func psbtSendFromImportedAccount(t *harnessTest, srcNode, destNode, // node. To ensure the channel is operational before closing it, a test payment // is made. Several balance assertions are made along the way for the sake of // correctness. -func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode, - signer *lntest.HarnessNode, account string, +func fundChanAndCloseFromImportedAccount(ht *lntemp.HarnessTest, srcNode, + destNode, signer *node.HarnessNode, account string, accountAddrType walletrpc.AddressType, utxoAmt, chanSize int64) { - ctxb := context.Background() - // Retrieve the current confirmed balance to make some assertions later // on. - ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) - defer cancel() - balanceResp, err := srcNode.WalletBalance( - ctxt, &lnrpc.WalletBalanceRequest{}, - ) - require.NoError(t.t, err) - require.Contains(t.t, balanceResp.AccountBalance, account) + balanceResp := srcNode.RPC.WalletBalance() + require.Contains(ht, balanceResp.AccountBalance, account) accountConfBalance := balanceResp. AccountBalance[account].ConfirmedBalance defaultAccountConfBalance := balanceResp. @@ -353,31 +247,23 @@ func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode, // Now, start the channel funding process. We'll need to connect both // nodes first. - t.lndHarness.EnsureConnected(t.t, srcNode, destNode) + ht.EnsureConnected(srcNode, destNode) // The source node will then fund the channel through a PSBT shim. - var pendingChanID [32]byte - _, err = rand.Read(pendingChanID[:]) - require.NoError(t.t, err) - - ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout) - defer cancel() - chanUpdates, rawPsbt, err := openChannelPsbt( - ctxt, srcNode, destNode, lntest.OpenChannelParams{ + pendingChanID := ht.Random32Bytes() + chanUpdates, rawPsbt := ht.OpenChannelPsbt( + srcNode, destNode, lntemp.OpenChannelParams{ Amt: btcutil.Amount(chanSize), FundingShim: &lnrpc.FundingShim{ Shim: &lnrpc.FundingShim_PsbtShim{ PsbtShim: &lnrpc.PsbtShim{ - PendingChanId: pendingChanID[:], + PendingChanId: pendingChanID, }, }, }, }, ) - require.NoError(t.t, err) - ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout) - defer cancel() fundReq := &walletrpc.FundPsbtRequest{ Template: &walletrpc.FundPsbtRequest_Psbt{ Psbt: rawPsbt, @@ -387,49 +273,40 @@ func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode, }, Account: account, } - fundResp, err := srcNode.WalletKitClient.FundPsbt(ctxt, fundReq) - require.NoError(t.t, err) + fundResp := srcNode.RPC.FundPsbt(fundReq) - _, err = srcNode.FundingStateStep(ctxb, &lnrpc.FundingTransitionMsg{ + srcNode.RPC.FundingStateStep(&lnrpc.FundingTransitionMsg{ Trigger: &lnrpc.FundingTransitionMsg_PsbtVerify{ PsbtVerify: &lnrpc.FundingPsbtVerify{ - PendingChanId: pendingChanID[:], + PendingChanId: pendingChanID, FundedPsbt: fundResp.FundedPsbt, }, }, }) - require.NoError(t.t, err) // Now that we have a PSBT to fund the channel, our signer needs to sign // it. - ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout) - defer cancel() finalizeReq := &walletrpc.FinalizePsbtRequest{ FundedPsbt: fundResp.FundedPsbt, } - finalizeResp, err := signer.WalletKitClient.FinalizePsbt(ctxt, finalizeReq) - require.NoError(t.t, err) + finalizeResp := signer.RPC.FinalizePsbt(finalizeReq) // The source node can then submit the signed PSBT and complete the // channel funding process. - _, err = srcNode.FundingStateStep(ctxb, &lnrpc.FundingTransitionMsg{ + srcNode.RPC.FundingStateStep(&lnrpc.FundingTransitionMsg{ Trigger: &lnrpc.FundingTransitionMsg_PsbtFinalize{ PsbtFinalize: &lnrpc.FundingPsbtFinalize{ - PendingChanId: pendingChanID[:], + PendingChanId: pendingChanID, SignedPsbt: finalizeResp.SignedPsbt, }, }, }) - require.NoError(t.t, err) // We should receive a notification of the channel funding transaction // being broadcast. - ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout) - defer cancel() - updateResp, err := receiveChanUpdate(ctxt, chanUpdates) - require.NoError(t.t, err) + updateResp := ht.ReceiveOpenChannelUpdate(chanUpdates) upd, ok := updateResp.Update.(*lnrpc.OpenStatusUpdate_ChanPending) - require.True(t.t, ok) + require.True(ht, ok) // Mine enough blocks to announce the channel to the network, making // balance assertions along the way. @@ -467,11 +344,11 @@ func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode, expChangeScriptType = txscript.WitnessV1TaprootTy default: - t.Fatalf("unsupported addr type %v", accountAddrType) + ht.Fatalf("unsupported addr type %v", accountAddrType) } chanChangeUtxoAmt := utxoAmt - chanSize - expChanTxFee txHash, err := chainhash.NewHash(upd.ChanPending.Txid) - require.NoError(t.t, err) + require.NoError(ht, err) // If we're spending from the default imported account, then any change // outputs produced are moved to the default wallet account, so we @@ -479,35 +356,35 @@ func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode, var confBalanceAfterChan int64 if account == defaultImportedAccount { confBalanceAfterChan = defaultAccountConfBalance - assertAccountBalance(t.t, srcNode, account, 0, 0) - assertAccountBalance( - t.t, srcNode, defaultAccount, defaultAccountConfBalance, + ht.AssertWalletAccountBalance(srcNode, account, 0, 0) + ht.AssertWalletAccountBalance( + srcNode, defaultAccount, defaultAccountConfBalance, chanChangeUtxoAmt, ) - block := mineBlocks(t, t.lndHarness, 6, 1)[0] - assertTxInBlock(t, block, txHash) + block := ht.MineBlocksAndAssertNumTxes(6, 1)[0] + ht.Miner.AssertTxInBlock(block, txHash) confBalanceAfterChan += chanChangeUtxoAmt - assertAccountBalance(t.t, srcNode, account, 0, 0) - assertAccountBalance( - t.t, srcNode, defaultAccount, confBalanceAfterChan, 0, + ht.AssertWalletAccountBalance(srcNode, account, 0, 0) + ht.AssertWalletAccountBalance( + srcNode, defaultAccount, confBalanceAfterChan, 0, ) } else { // Otherwise, all interactions remain within Carol's imported // account. confBalanceAfterChan = accountConfBalance - utxoAmt - assertAccountBalance( - t.t, srcNode, account, confBalanceAfterChan, + ht.AssertWalletAccountBalance( + srcNode, account, confBalanceAfterChan, chanChangeUtxoAmt, ) - block := mineBlocks(t, t.lndHarness, 6, 1)[0] - assertTxInBlock(t, block, txHash) + block := ht.MineBlocksAndAssertNumTxes(6, 1)[0] + ht.Miner.AssertTxInBlock(block, txHash) confBalanceAfterChan += chanChangeUtxoAmt - assertAccountBalance( - t.t, srcNode, account, confBalanceAfterChan, 0, + ht.AssertWalletAccountBalance( + srcNode, account, confBalanceAfterChan, 0, ) } @@ -515,8 +392,10 @@ func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode, // based on the account. var tx wire.MsgTx err = tx.Deserialize(bytes.NewReader(finalizeResp.RawFinalTx)) - require.NoError(t.t, err) - assertOutputScriptType(t.t, expChangeScriptType, &tx, chanChangeUtxoAmt) + require.NoError(ht, err) + assertOutputScriptType( + ht.T, expChangeScriptType, &tx, chanChangeUtxoAmt, + ) // Wait for the channel to be announced by both parties. chanPoint := &lnrpc.ChannelPoint{ @@ -525,29 +404,30 @@ func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode, }, OutputIndex: upd.ChanPending.OutputIndex, } - err = srcNode.WaitForNetworkChannelOpen(chanPoint) - require.NoError(t.t, err) - err = destNode.WaitForNetworkChannelOpen(chanPoint) - require.NoError(t.t, err) + ht.AssertTopologyChannelOpen(srcNode, chanPoint) + ht.AssertTopologyChannelOpen(destNode, chanPoint) // Send a test payment to ensure the channel is operating as normal. const invoiceAmt = 100000 - ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout) - defer cancel() - resp, err := destNode.AddInvoice(ctxt, &lnrpc.Invoice{ + invoice := &lnrpc.Invoice{ Memo: "psbt import chan", Value: invoiceAmt, - }) - require.NoError(t.t, err) + } + resp := destNode.RPC.AddInvoice(invoice) - err = completePaymentRequests( - srcNode, srcNode.RouterClient, - []string{resp.PaymentRequest}, true, - ) - require.NoError(t.t, err) + ht.CompletePaymentRequests(srcNode, []string{resp.PaymentRequest}) + + // TODO(yy): remove the sleep once the following bug is fixed. When the + // payment is reported as settled by srcNode, it's expected the + // commitment dance is finished and all subsequent states have been + // updated. Yet we'd receive the error `cannot co-op close channel with + // active htlcs` or `link failed to shutdown` if we close the channel. + // We need to investigate the order of settling the payments and + // updating commitments to understand and fix . + time.Sleep(2 * time.Second) // Now that we've confirmed the opened channel works, we'll close it. - closeChannelAndAssert(t, t.lndHarness, srcNode, chanPoint, false) + ht.CloseChannel(srcNode, chanPoint) // Since the channel still had funds left on the source node's side, // they must've been redeemed after the close. Without a pre-negotiated @@ -557,17 +437,17 @@ func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode, balanceFromClosedChan := chanSize - invoiceAmt - chanCloseTxFee if account == defaultImportedAccount { - assertAccountBalance(t.t, srcNode, account, 0, 0) - assertAccountBalance( - t.t, srcNode, defaultAccount, + ht.AssertWalletAccountBalance(srcNode, account, 0, 0) + ht.AssertWalletAccountBalance( + srcNode, defaultAccount, confBalanceAfterChan+balanceFromClosedChan, 0, ) } else { - assertAccountBalance( - t.t, srcNode, account, confBalanceAfterChan, 0, + ht.AssertWalletAccountBalance( + srcNode, account, confBalanceAfterChan, 0, ) - assertAccountBalance( - t.t, srcNode, defaultAccount, balanceFromClosedChan, 0, + ht.AssertWalletAccountBalance( + srcNode, defaultAccount, balanceFromClosedChan, 0, ) } } @@ -575,7 +455,7 @@ func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode, // testWalletImportAccount tests that an imported account can fund transactions // and channels through PSBTs, by having one node (the one with the imported // account) craft the transactions and another node act as the signer. -func testWalletImportAccount(net *lntest.NetworkHarness, t *harnessTest) { +func testWalletImportAccount(ht *lntemp.HarnessTest) { testCases := []struct { name string addrType walletrpc.AddressType @@ -600,23 +480,24 @@ func testWalletImportAccount(net *lntest.NetworkHarness, t *harnessTest) { for _, tc := range testCases { tc := tc - success := t.t.Run(tc.name, func(tt *testing.T) { - ht := newHarnessTest(tt, net) - ht.RunTestCase(&testCase{ - name: tc.name, - test: func(net1 *lntest.NetworkHarness, - t1 *harnessTest) { + success := ht.Run(tc.name, func(tt *testing.T) { + testFunc := func(ht *lntemp.HarnessTest) { + testWalletImportAccountScenario( + ht, tc.addrType, + ) + } - testWalletImportAccountScenario( - net, t, tc.addrType, - ) - }, + st := ht.Subtest(tt) + + st.RunTestCase(&lntemp.TestCase{ + Name: tc.name, + TestFunc: testFunc, }) }) if !success { // Log failure time to help relate the lnd logs to the // failure. - t.Logf("Failure time: %v", time.Now().Format( + ht.Logf("Failure time: %v", time.Now().Format( "2006-01-02 15:04:05.000", )) break @@ -624,115 +505,98 @@ func testWalletImportAccount(net *lntest.NetworkHarness, t *harnessTest) { } } -func testWalletImportAccountScenario(net *lntest.NetworkHarness, t *harnessTest, +func testWalletImportAccountScenario(ht *lntemp.HarnessTest, addrType walletrpc.AddressType) { // We'll start our test by having two nodes, Carol and Dave. Carol's // default wallet account will be imported into Dave's node. - carol := net.NewNode(t.t, "carol", nil) - defer shutdownAndAssert(net, t, carol) + // + // NOTE: we won't use standby nodes here since the test will change + // each of the node's wallet state. + carol := ht.NewNode("carol", nil) + dave := ht.NewNode("dave", nil) - dave := net.NewNode(t.t, "dave", nil) - defer shutdownAndAssert(net, t, dave) - - runWalletImportAccountScenario(net, t, addrType, carol, dave) + runWalletImportAccountScenario(ht, addrType, carol, dave) } -func runWalletImportAccountScenario(net *lntest.NetworkHarness, t *harnessTest, - addrType walletrpc.AddressType, carol, dave *lntest.HarnessNode) { +func runWalletImportAccountScenario(ht *lntemp.HarnessTest, + addrType walletrpc.AddressType, carol, dave *node.HarnessNode) { - ctxb := context.Background() const utxoAmt int64 = btcutil.SatoshiPerBitcoin - ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) - defer cancel() listReq := &walletrpc.ListAccountsRequest{ Name: "default", AddressType: addrType, } - listResp, err := carol.WalletKitClient.ListAccounts(ctxt, listReq) - require.NoError(t.t, err) - require.Equal(t.t, len(listResp.Accounts), 1) + listResp := carol.RPC.ListAccounts(listReq) + require.Len(ht, listResp.Accounts, 1) carolAccount := listResp.Accounts[0] - ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout) - defer cancel() const importedAccount = "carol" importReq := &walletrpc.ImportAccountRequest{ Name: importedAccount, ExtendedPublicKey: carolAccount.ExtendedPublicKey, AddressType: addrType, } - _, err = dave.WalletKitClient.ImportAccount(ctxt, importReq) - require.NoError(t.t, err) + dave.RPC.ImportAccount(importReq) // We'll generate an address for Carol from Dave's node to receive some // funds. externalAddr := newExternalAddr( - t.t, dave, carol, importedAccount, addrType, + ht, dave, carol, importedAccount, addrType, ) // Send coins to Carol's address and confirm them, making sure the // balance updates accordingly. - ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout) - defer cancel() - _, err = net.Alice.SendCoins(ctxt, &lnrpc.SendCoinsRequest{ + alice := ht.Alice + req := &lnrpc.SendCoinsRequest{ Addr: externalAddr, Amount: utxoAmt, SatPerByte: 1, - }) - require.NoError(t.t, err) + } + alice.RPC.SendCoins(req) - assertAccountBalance(t.t, dave, importedAccount, 0, utxoAmt) - _ = mineBlocks(t, net, 1, 1) - assertAccountBalance(t.t, dave, importedAccount, utxoAmt, 0) + ht.AssertWalletAccountBalance(dave, importedAccount, 0, utxoAmt) + ht.MineBlocksAndAssertNumTxes(1, 1) + ht.AssertWalletAccountBalance(dave, importedAccount, utxoAmt, 0) // To ensure that Dave can use Carol's account as watch-only, we'll // construct a PSBT that sends funds to Alice, which we'll then hand // over to Carol to sign. psbtSendFromImportedAccount( - t, dave, net.Alice, carol, importedAccount, addrType, + ht, dave, alice, carol, importedAccount, addrType, ) // We'll generate a new address for Carol from Dave's node to receive // and fund a new channel. externalAddr = newExternalAddr( - t.t, dave, carol, importedAccount, addrType, + ht, dave, carol, importedAccount, addrType, ) // Retrieve the current confirmed balance of the imported account for // some assertions we'll make later on. - ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout) - defer cancel() - balanceResp, err := dave.WalletBalance( - ctxt, &lnrpc.WalletBalanceRequest{}, - ) - require.NoError(t.t, err) - require.Contains(t.t, balanceResp.AccountBalance, importedAccount) + balanceResp := dave.RPC.WalletBalance() + require.Contains(ht, balanceResp.AccountBalance, importedAccount) confBalance := balanceResp.AccountBalance[importedAccount].ConfirmedBalance // Send coins to Carol's address and confirm them, making sure the // balance updates accordingly. - ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout) - defer cancel() - _, err = net.Alice.SendCoins(ctxt, &lnrpc.SendCoinsRequest{ + req = &lnrpc.SendCoinsRequest{ Addr: externalAddr, Amount: utxoAmt, SatPerByte: 1, - }) - require.NoError(t.t, err) + } + alice.RPC.SendCoins(req) - assertAccountBalance(t.t, dave, importedAccount, confBalance, utxoAmt) - _ = mineBlocks(t, net, 1, 1) - assertAccountBalance( - t.t, dave, importedAccount, confBalance+utxoAmt, 0, - ) + ht.AssertWalletAccountBalance(dave, importedAccount, confBalance, utxoAmt) + ht.MineBlocksAndAssertNumTxes(1, 1) + ht.AssertWalletAccountBalance(dave, importedAccount, confBalance+utxoAmt, 0) // Now that we have enough funds, it's time to fund the channel, make a // test payment, and close it. This contains several balance assertions // along the way. fundChanAndCloseFromImportedAccount( - t, dave, net.Alice, carol, importedAccount, addrType, utxoAmt, + ht, dave, alice, carol, importedAccount, addrType, utxoAmt, int64(funding.MaxBtcFundingAmount), ) } @@ -740,7 +604,7 @@ func runWalletImportAccountScenario(net *lntest.NetworkHarness, t *harnessTest, // testWalletImportPubKey tests that an imported public keys can fund // transactions and channels through PSBTs, by having one node (the one with the // imported account) craft the transactions and another node act as the signer. -func testWalletImportPubKey(net *lntest.NetworkHarness, t *harnessTest) { +func testWalletImportPubKey(ht *lntemp.HarnessTest) { testCases := []struct { name string addrType walletrpc.AddressType @@ -761,23 +625,24 @@ func testWalletImportPubKey(net *lntest.NetworkHarness, t *harnessTest) { for _, tc := range testCases { tc := tc - success := t.t.Run(tc.name, func(tt *testing.T) { - ht := newHarnessTest(tt, net) - ht.RunTestCase(&testCase{ - name: tc.name, - test: func(net1 *lntest.NetworkHarness, - t1 *harnessTest) { + success := ht.Run(tc.name, func(tt *testing.T) { + testFunc := func(ht *lntemp.HarnessTest) { + testWalletImportPubKeyScenario( + ht, tc.addrType, + ) + } - testWalletImportPubKeyScenario( - net, t, tc.addrType, - ) - }, + st := ht.Subtest(tt) + + st.RunTestCase(&lntemp.TestCase{ + Name: tc.name, + TestFunc: testFunc, }) }) if !success { // Log failure time to help relate the lnd logs to the // failure. - t.Logf("Failure time: %v", time.Now().Format( + ht.Logf("Failure time: %v", time.Now().Format( "2006-01-02 15:04:05.000", )) break @@ -785,18 +650,18 @@ func testWalletImportPubKey(net *lntest.NetworkHarness, t *harnessTest) { } } -func testWalletImportPubKeyScenario(net *lntest.NetworkHarness, t *harnessTest, +func testWalletImportPubKeyScenario(ht *lntemp.HarnessTest, addrType walletrpc.AddressType) { - ctxb := context.Background() const utxoAmt int64 = btcutil.SatoshiPerBitcoin + alice := ht.Alice // We'll start our test by having two nodes, Carol and Dave. - carol := net.NewNode(t.t, "carol", nil) - defer shutdownAndAssert(net, t, carol) - - dave := net.NewNode(t.t, "dave", nil) - defer shutdownAndAssert(net, t, dave) + // + // NOTE: we won't use standby nodes here since the test will change + // each of the node's wallet state. + carol := ht.NewNode("carol", nil) + dave := ht.NewNode("dave", nil) // We'll define a helper closure that we'll use throughout the test to // generate a new address of the given type from Carol's perspective, @@ -806,30 +671,25 @@ func testWalletImportPubKeyScenario(net *lntest.NetworkHarness, t *harnessTest, // Retrieve Carol's account public key for the corresponding // address type. - ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) - defer cancel() listReq := &walletrpc.ListAccountsRequest{ Name: "default", AddressType: addrType, } - listResp, err := carol.WalletKitClient.ListAccounts( - ctxt, listReq, - ) - require.NoError(t.t, err) - require.Equal(t.t, len(listResp.Accounts), 1) + listResp := carol.RPC.ListAccounts(listReq) + require.Len(ht, listResp.Accounts, 1) p2wkhAccount := listResp.Accounts[0] // Derive the external address at the given index. accountPubKey, err := hdkeychain.NewKeyFromString( p2wkhAccount.ExtendedPublicKey, ) - require.NoError(t.t, err) + require.NoError(ht, err) externalAccountExtKey, err := accountPubKey.Derive(0) - require.NoError(t.t, err) + require.NoError(ht, err) externalAddrExtKey, err := externalAccountExtKey.Derive(keyIndex) - require.NoError(t.t, err) + require.NoError(ht, err) externalAddrPubKey, err := externalAddrExtKey.ECPubKey() - require.NoError(t.t, err) + require.NoError(ht, err) // Serialize as 32-byte x-only pubkey for Taproot addresses. serializedPubKey := externalAddrPubKey.SerializeCompressed() @@ -840,44 +700,34 @@ func testWalletImportPubKeyScenario(net *lntest.NetworkHarness, t *harnessTest, } // Import the public key into Dave. - ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout) - defer cancel() importReq := &walletrpc.ImportPublicKeyRequest{ PublicKey: serializedPubKey, AddressType: addrType, } - _, err = dave.WalletKitClient.ImportPublicKey(ctxt, importReq) - require.NoError(t.t, err) + dave.RPC.ImportPublicKey(importReq) // We'll also generate the same address for Carol, as it'll be // required later when signing. - ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout) - defer cancel() - carolAddrResp, err := carol.NewAddress( - ctxt, &lnrpc.NewAddressRequest{ - Type: walletToLNAddrType(t.t, addrType), - }, - ) - require.NoError(t.t, err) + carolAddrResp := carol.RPC.NewAddress(&lnrpc.NewAddressRequest{ + Type: walletToLNAddrType(ht.T, addrType), + }) // Send coins to Carol's address and confirm them, making sure // the balance updates accordingly. - ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout) - defer cancel() - _, err = net.Alice.SendCoins(ctxt, &lnrpc.SendCoinsRequest{ + req := &lnrpc.SendCoinsRequest{ Addr: carolAddrResp.Address, Amount: utxoAmt, SatPerByte: 1, - }) - require.NoError(t.t, err) + } + alice.RPC.SendCoins(req) - assertAccountBalance( - t.t, dave, defaultImportedAccount, prevConfBalance, + ht.AssertWalletAccountBalance( + dave, defaultImportedAccount, prevConfBalance, prevUnconfBalance+utxoAmt, ) - _ = mineBlocks(t, net, 1, 1) - assertAccountBalance( - t.t, dave, defaultImportedAccount, + ht.MineBlocksAndAssertNumTxes(1, 1) + ht.AssertWalletAccountBalance( + dave, defaultImportedAccount, prevConfBalance+utxoAmt, prevUnconfBalance, ) } @@ -890,22 +740,15 @@ func testWalletImportPubKeyScenario(net *lntest.NetworkHarness, t *harnessTest, // construct a PSBT that sends funds to Alice, which we'll then hand // over to Carol to sign. psbtSendFromImportedAccount( - t, dave, net.Alice, carol, defaultImportedAccount, addrType, + ht, dave, alice, carol, defaultImportedAccount, addrType, ) // We'll now attempt to fund a channel. // // We'll have Carol generate another external address, which we'll // import into Dave again. - ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout) - defer cancel() - balanceResp, err := dave.WalletBalance( - ctxt, &lnrpc.WalletBalanceRequest{}, - ) - require.NoError(t.t, err) - require.Contains( - t.t, balanceResp.AccountBalance, defaultImportedAccount, - ) + balanceResp := dave.RPC.WalletBalance() + require.Contains(ht, balanceResp.AccountBalance, defaultImportedAccount) confBalance := balanceResp. AccountBalance[defaultImportedAccount].ConfirmedBalance importPubKey(1, confBalance, 0) @@ -914,7 +757,7 @@ func testWalletImportPubKeyScenario(net *lntest.NetworkHarness, t *harnessTest, // test payment, and close it. This contains several balance assertions // along the way. fundChanAndCloseFromImportedAccount( - t, dave, net.Alice, carol, defaultImportedAccount, addrType, + ht, dave, alice, carol, defaultImportedAccount, addrType, utxoAmt, int64(funding.MaxBtcFundingAmount), ) }