github.com/decred/dcrlnd@v0.7.6/lntest/itest/lnd_wallet_import_test.go (about)

     1  package itest
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math"
     7  	"testing"
     8  
     9  	"github.com/davecgh/go-spew/spew"
    10  	"github.com/decred/dcrd/txscript/v4/stdaddr"
    11  	"github.com/decred/dcrd/txscript/v4/stdscript"
    12  	"github.com/decred/dcrd/wire"
    13  	"github.com/decred/dcrlnd/lnrpc"
    14  	"github.com/decred/dcrlnd/lnrpc/walletrpc"
    15  	"github.com/decred/dcrlnd/lntest"
    16  	"github.com/decred/dcrlnd/lntest/wait"
    17  	"github.com/decred/dcrlnd/lnwallet"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  const (
    22  	defaultAccount         = lnwallet.DefaultAccountName
    23  	defaultImportedAccount = "imported"
    24  )
    25  
    26  // walletToLNAddrType maps walletrpc.AddressType to lnrpc.AddressType.
    27  func walletToLNAddrType(t *testing.T, addrType walletrpc.AddressType) lnrpc.AddressType {
    28  	switch addrType {
    29  	case walletrpc.AddressType_NESTED_WITNESS_PUBKEY_HASH,
    30  		walletrpc.AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH:
    31  
    32  		return lnrpc.AddressType_NESTED_PUBKEY_HASH
    33  
    34  	case walletrpc.AddressType_WITNESS_PUBKEY_HASH:
    35  		return lnrpc.AddressType_WITNESS_PUBKEY_HASH
    36  
    37  	default:
    38  		t.Fatalf("unhandled addr type %v", addrType)
    39  		return 0
    40  	}
    41  }
    42  
    43  // newExternalAddr generates a new external address of an imported account for a
    44  // pair of nodes, where one acts as the funder and the other as the signer.
    45  func newExternalAddr(t *testing.T, funder, signer *lntest.HarnessNode,
    46  	importedAccount string, addrType walletrpc.AddressType) string {
    47  
    48  	// We'll generate a new address for Carol from Dave's node to receive
    49  	// and fund a new channel.
    50  	ctxb := context.Background()
    51  	ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
    52  	defer cancel()
    53  	funderResp, err := funder.NewAddress(ctxt, &lnrpc.NewAddressRequest{
    54  		Type:    walletToLNAddrType(t, addrType),
    55  		Account: importedAccount,
    56  	})
    57  	require.NoError(t, err)
    58  
    59  	// Carol also needs to generate the address for the sake of this test to
    60  	// be able to sign the channel funding input.
    61  	ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
    62  	defer cancel()
    63  	signerResp, err := signer.NewAddress(ctxt, &lnrpc.NewAddressRequest{
    64  		Type: walletToLNAddrType(t, addrType),
    65  	})
    66  	require.NoError(t, err)
    67  
    68  	// Sanity check that the generated addresses match.
    69  	require.Equal(t, funderResp.Address, signerResp.Address)
    70  	assertExternalAddrType(t, funderResp.Address, addrType)
    71  
    72  	return funderResp.Address
    73  }
    74  
    75  // assertExternalAddrType asserts that an external address generated for an
    76  // imported account is of the expected type.
    77  func assertExternalAddrType(t *testing.T, addrStr string,
    78  	accountAddrType walletrpc.AddressType) {
    79  
    80  	addr, err := stdaddr.DecodeAddress(addrStr, harnessNetParams)
    81  	require.NoError(t, err)
    82  
    83  	switch accountAddrType {
    84  
    85  	/*
    86  		case walletrpc.AddressType_WITNESS_PUBKEY_HASH:
    87  			require.IsType(t, addr, &stdaddr.AddressWitnessPubKeyHash{})
    88  
    89  		case walletrpc.AddressType_NESTED_WITNESS_PUBKEY_HASH,
    90  			walletrpc.AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH:
    91  
    92  			require.IsType(t, addr, &stdaddr.AddressScriptHash{})
    93  	*/
    94  
    95  	default:
    96  		_ = addr
    97  		t.Fatalf("unsupported account addr type %v", accountAddrType)
    98  	}
    99  }
   100  
   101  // assertOutputScriptType asserts that a transaction's output, indicated by the
   102  // output with the given amount, has a script of the expected type. This assumes
   103  // all transaction outputs have unique amounts.
   104  func assertOutputScriptType(t *testing.T, expType stdscript.ScriptType,
   105  	tx *wire.MsgTx, outputAmt int64) {
   106  
   107  	for _, txOut := range tx.TxOut {
   108  		if txOut.Value != outputAmt {
   109  			continue
   110  		}
   111  
   112  		gotTyp := stdscript.DetermineScriptType(txOut.Version, txOut.PkScript)
   113  		require.Equal(t, gotTyp, expType)
   114  		return
   115  	}
   116  
   117  	// No output with the given amount was found.
   118  	t.Fatalf("output with amount %v not found in transaction %v", outputAmt,
   119  		spew.Sdump(tx))
   120  }
   121  
   122  // assertAccountBalance asserts that the unconfirmed and confirmed balance for
   123  // the given account is satisfied by the WalletBalance and ListUnspent RPCs. The
   124  // unconfirmed balance is not checked for neutrino nodes.
   125  func assertAccountBalance(t *testing.T, node *lntest.HarnessNode, account string,
   126  	confirmedBalance, unconfirmedBalance int64) {
   127  
   128  	err := wait.NoError(func() error {
   129  		balanceResp, err := node.WalletBalance(
   130  			context.Background(), &lnrpc.WalletBalanceRequest{},
   131  		)
   132  		if err != nil {
   133  			return err
   134  		}
   135  		require.Contains(t, balanceResp.AccountBalance, account)
   136  		accountBalance := balanceResp.AccountBalance[account]
   137  
   138  		// Check confirmed balance.
   139  		if accountBalance.ConfirmedBalance != confirmedBalance {
   140  			return fmt.Errorf("expected confirmed balance %v, "+
   141  				"got %v", confirmedBalance,
   142  				accountBalance.ConfirmedBalance)
   143  		}
   144  		listUtxosReq := &lnrpc.ListUnspentRequest{
   145  			MinConfs: 1,
   146  			MaxConfs: math.MaxInt32,
   147  			Account:  account,
   148  		}
   149  		confirmedUtxosResp, err := node.ListUnspent(
   150  			context.Background(), listUtxosReq,
   151  		)
   152  		if err != nil {
   153  			return err
   154  		}
   155  		var totalConfirmedVal int64
   156  		for _, utxo := range confirmedUtxosResp.Utxos {
   157  			totalConfirmedVal += utxo.AmountAtoms
   158  		}
   159  		if totalConfirmedVal != confirmedBalance {
   160  			return fmt.Errorf("expected total confirmed utxo "+
   161  				"balance %v, got %v", confirmedBalance,
   162  				totalConfirmedVal)
   163  		}
   164  
   165  		// Skip unconfirmed balance checks for neutrino nodes.
   166  		if node.Cfg.BackendCfg.Name() == "spv" {
   167  			return nil
   168  		}
   169  
   170  		// Check unconfirmed balance.
   171  		if accountBalance.UnconfirmedBalance != unconfirmedBalance {
   172  			return fmt.Errorf("expected unconfirmed balance %v, "+
   173  				"got %v", unconfirmedBalance,
   174  				accountBalance.UnconfirmedBalance)
   175  		}
   176  		listUtxosReq.MinConfs = 0
   177  		listUtxosReq.MaxConfs = 0
   178  		unconfirmedUtxosResp, err := node.ListUnspent(
   179  			context.Background(), listUtxosReq,
   180  		)
   181  		require.NoError(t, err)
   182  		var totalUnconfirmedVal int64
   183  		for _, utxo := range unconfirmedUtxosResp.Utxos {
   184  			totalUnconfirmedVal += utxo.AmountAtoms
   185  		}
   186  		if totalUnconfirmedVal != unconfirmedBalance {
   187  			return fmt.Errorf("expected total unconfirmed utxo "+
   188  				"balance %v, got %v", unconfirmedBalance,
   189  				totalUnconfirmedVal)
   190  		}
   191  
   192  		return nil
   193  	}, defaultTimeout)
   194  	require.NoError(t, err)
   195  }
   196  
   197  /*
   198  // psbtSendFromImportedAccount attempts to fund a PSBT from the given imported
   199  // account, originating from the source node to the destination.
   200  func psbtSendFromImportedAccount(t *harnessTest, srcNode, destNode,
   201  	signer *lntest.HarnessNode, account string,
   202  	accountAddrType walletrpc.AddressType) {
   203  
   204  	ctxb := context.Background()
   205  
   206  	ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
   207  	defer cancel()
   208  	balanceResp, err := srcNode.WalletBalance(ctxt, &lnrpc.WalletBalanceRequest{})
   209  	require.NoError(t.t, err)
   210  	require.Contains(t.t, balanceResp.AccountBalance, account)
   211  	confBalance := balanceResp.AccountBalance[account].ConfirmedBalance
   212  
   213  	destAmt := confBalance - 10000
   214  	ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
   215  	defer cancel()
   216  	destAddrResp, err := destNode.NewAddress(ctxt, &lnrpc.NewAddressRequest{
   217  		Type: lnrpc.AddressType_WITNESS_PUBKEY_HASH,
   218  	})
   219  	require.NoError(t.t, err)
   220  
   221  	ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
   222  	defer cancel()
   223  	fundReq := &walletrpc.FundPsbtRequest{
   224  		Template: &walletrpc.FundPsbtRequest_Raw{
   225  			Raw: &walletrpc.TxTemplate{
   226  				Outputs: map[string]uint64{
   227  					destAddrResp.Address: uint64(destAmt),
   228  				},
   229  			},
   230  		},
   231  		Fees: &walletrpc.FundPsbtRequest_AtomsPerByte{
   232  			AtomsPerByte: 1,
   233  		},
   234  		Account: account,
   235  	}
   236  	fundResp, err := srcNode.WalletKitClient.FundPsbt(ctxt, fundReq)
   237  	require.NoError(t.t, err)
   238  
   239  	// Have Carol sign the PSBT input since Dave doesn't have any private
   240  	// key information.
   241  	ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
   242  	defer cancel()
   243  	finalizeReq := &walletrpc.FinalizePsbtRequest{
   244  		FundedPsbt: fundResp.FundedPsbt,
   245  	}
   246  	finalizeResp, err := signer.WalletKitClient.FinalizePsbt(ctxt, finalizeReq)
   247  	require.NoError(t.t, err)
   248  
   249  	// With the PSBT signed, we can broadcast the resulting transaction.
   250  	ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
   251  	defer cancel()
   252  	publishReq := &walletrpc.Transaction{
   253  		TxHex: finalizeResp.RawFinalTx,
   254  	}
   255  	_, err = srcNode.WalletKitClient.PublishTransaction(ctxt, publishReq)
   256  	require.NoError(t.t, err)
   257  
   258  	// Carol's balance from Dave's perspective should update accordingly.
   259  	var (
   260  		expTxFee            int64
   261  		expChangeScriptType txscript.ScriptClass
   262  	)
   263  	switch accountAddrType {
   264  	case walletrpc.AddressType_WITNESS_PUBKEY_HASH:
   265  		expTxFee = 141
   266  		expChangeScriptType = txscript.WitnessV0PubKeyHashTy
   267  
   268  	case walletrpc.AddressType_NESTED_WITNESS_PUBKEY_HASH:
   269  		if account != defaultImportedAccount {
   270  			expTxFee = 165
   271  			expChangeScriptType = txscript.ScriptHashTy
   272  			break
   273  		}
   274  
   275  		// Spends from the default NP2WKH imported account have the same
   276  		// fee rate as the hybrid address type since a NP2WKH input is
   277  		// spent and a P2WKH change output is created.
   278  		fallthrough
   279  
   280  	case walletrpc.AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH:
   281  		expTxFee = 164
   282  		expChangeScriptType = txscript.WitnessV0PubKeyHashTy
   283  
   284  	default:
   285  		t.Fatalf("unsupported addr type %v", accountAddrType)
   286  	}
   287  	changeUtxoAmt := confBalance - destAmt - expTxFee
   288  
   289  	// If the transaction was created from the default imported account,
   290  	// then any change produced is moved to the default wallet account.
   291  	accountWithBalance := account
   292  	if account == defaultImportedAccount {
   293  		accountWithBalance = defaultAccount
   294  	}
   295  	assertAccountBalance(t.t, srcNode, accountWithBalance, 0, changeUtxoAmt)
   296  	_ = mineBlocks(t, t.lndHarness, 1, 1)
   297  	assertAccountBalance(t.t, srcNode, accountWithBalance, changeUtxoAmt, 0)
   298  
   299  	// Finally, assert that the transaction has the expected change address
   300  	// type based on the account.
   301  	var tx wire.MsgTx
   302  	err = tx.Deserialize(bytes.NewReader(finalizeResp.RawFinalTx))
   303  	require.NoError(t.t, err)
   304  	assertOutputScriptType(t.t, expChangeScriptType, &tx, changeUtxoAmt)
   305  }
   306  
   307  // fundChanAndCloseFromImportedAccount attempts to a fund a channel from the
   308  // given imported account, originating from the source node to the destination
   309  // node. To ensure the channel is operational before closing it, a test payment
   310  // is made. Several balance assertions are made along the way for the sake of
   311  // correctness.
   312  func fundChanAndCloseFromImportedAccount(t *harnessTest, srcNode, destNode,
   313  	signer *lntest.HarnessNode, account string,
   314  	accountAddrType walletrpc.AddressType, utxoAmt, chanSize int64) {
   315  
   316  	ctxb := context.Background()
   317  
   318  	// Retrieve the current confirmed balance to make some assertions later
   319  	// on.
   320  	ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
   321  	defer cancel()
   322  	balanceResp, err := srcNode.WalletBalance(ctxt, &lnrpc.WalletBalanceRequest{})
   323  	require.NoError(t.t, err)
   324  	require.Contains(t.t, balanceResp.AccountBalance, account)
   325  	accountConfBalance := balanceResp.
   326  		AccountBalance[account].ConfirmedBalance
   327  	defaultAccountConfBalance := balanceResp.
   328  		AccountBalance[defaultAccount].ConfirmedBalance
   329  
   330  	// Now, start the channel funding process. We'll need to connect both
   331  	// nodes first.
   332  	t.lndHarness.EnsureConnected(t.t, srcNode, destNode)
   333  
   334  	// The source node will then fund the channel through a PSBT shim.
   335  	var pendingChanID [32]byte
   336  	_, err = rand.Read(pendingChanID[:])
   337  	require.NoError(t.t, err)
   338  
   339  	ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
   340  	defer cancel()
   341  	chanUpdates, rawPsbt, err := openChannelPsbt(
   342  		ctxt, srcNode, destNode, lntest.OpenChannelParams{
   343  			Amt: dcrutil.Amount(chanSize),
   344  			FundingShim: &lnrpc.FundingShim{
   345  				Shim: &lnrpc.FundingShim_PsbtShim{
   346  					PsbtShim: &lnrpc.PsbtShim{
   347  						PendingChanId: pendingChanID[:],
   348  					},
   349  				},
   350  			},
   351  		},
   352  	)
   353  	require.NoError(t.t, err)
   354  
   355  	ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
   356  	defer cancel()
   357  	fundReq := &walletrpc.FundPsbtRequest{
   358  		Template: &walletrpc.FundPsbtRequest_Psbt{
   359  			Psbt: rawPsbt,
   360  		},
   361  		Fees: &walletrpc.FundPsbtRequest_AtomsPerByte{
   362  			AtomsPerByte: 1,
   363  		},
   364  		Account: account,
   365  	}
   366  	fundResp, err := srcNode.WalletKitClient.FundPsbt(ctxt, fundReq)
   367  	require.NoError(t.t, err)
   368  
   369  	_, err = srcNode.FundingStateStep(ctxb, &lnrpc.FundingTransitionMsg{
   370  		Trigger: &lnrpc.FundingTransitionMsg_PsbtVerify{
   371  			PsbtVerify: &lnrpc.FundingPsbtVerify{
   372  				PendingChanId: pendingChanID[:],
   373  				FundedPsbt:    fundResp.FundedPsbt,
   374  			},
   375  		},
   376  	})
   377  	require.NoError(t.t, err)
   378  
   379  	// Now that we have a PSBT to fund the channel, our signer needs to sign
   380  	// it.
   381  	ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
   382  	defer cancel()
   383  	finalizeReq := &walletrpc.FinalizePsbtRequest{
   384  		FundedPsbt: fundResp.FundedPsbt,
   385  	}
   386  	finalizeResp, err := signer.WalletKitClient.FinalizePsbt(ctxt, finalizeReq)
   387  	require.NoError(t.t, err)
   388  
   389  	// The source node can then submit the signed PSBT and complete the
   390  	// channel funding process.
   391  	_, err = srcNode.FundingStateStep(ctxb, &lnrpc.FundingTransitionMsg{
   392  		Trigger: &lnrpc.FundingTransitionMsg_PsbtFinalize{
   393  			PsbtFinalize: &lnrpc.FundingPsbtFinalize{
   394  				PendingChanId: pendingChanID[:],
   395  				SignedPsbt:    finalizeResp.SignedPsbt,
   396  			},
   397  		},
   398  	})
   399  	require.NoError(t.t, err)
   400  
   401  	// We should receive a notification of the channel funding transaction
   402  	// being broadcast.
   403  	ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
   404  	defer cancel()
   405  	updateResp, err := receiveChanUpdate(ctxt, chanUpdates)
   406  	require.NoError(t.t, err)
   407  	upd, ok := updateResp.Update.(*lnrpc.OpenStatusUpdate_ChanPending)
   408  	require.True(t.t, ok)
   409  
   410  	// Mine enough blocks to announce the channel to the network, making
   411  	// balance assertions along the way.
   412  	var (
   413  		expChanTxFee        int64
   414  		expChangeScriptType txscript.ScriptClass
   415  	)
   416  	switch accountAddrType {
   417  	case walletrpc.AddressType_WITNESS_PUBKEY_HASH:
   418  		expChanTxFee = 153
   419  		expChangeScriptType = txscript.WitnessV0PubKeyHashTy
   420  
   421  	case walletrpc.AddressType_NESTED_WITNESS_PUBKEY_HASH:
   422  		if account != defaultImportedAccount {
   423  			expChanTxFee = 177
   424  			expChangeScriptType = txscript.ScriptHashTy
   425  			break
   426  		}
   427  
   428  		// Spends from the default NP2WKH imported account have the same
   429  		// fee rate as the hybrid address type since a NP2WKH input is
   430  		// spent and a P2WKH change output is created.
   431  		fallthrough
   432  
   433  	case walletrpc.AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH:
   434  		expChanTxFee = 176
   435  		expChangeScriptType = txscript.WitnessV0PubKeyHashTy
   436  
   437  	default:
   438  		t.Fatalf("unsupported addr type %v", accountAddrType)
   439  	}
   440  	chanChangeUtxoAmt := utxoAmt - chanSize - expChanTxFee
   441  	txHash, err := chainhash.NewHash(upd.ChanPending.Txid)
   442  	require.NoError(t.t, err)
   443  
   444  	// If we're spending from the default imported account, then any change
   445  	// outputs produced are moved to the default wallet account, so we
   446  	// should expect to see balances there.
   447  	var confBalanceAfterChan int64
   448  	if account == defaultImportedAccount {
   449  		confBalanceAfterChan = defaultAccountConfBalance
   450  		assertAccountBalance(t.t, srcNode, account, 0, 0)
   451  		assertAccountBalance(
   452  			t.t, srcNode, defaultAccount, defaultAccountConfBalance,
   453  			chanChangeUtxoAmt,
   454  		)
   455  
   456  		block := mineBlocks(t, t.lndHarness, 6, 1)[0]
   457  		assertTxInBlock(t, block, txHash)
   458  
   459  		confBalanceAfterChan += chanChangeUtxoAmt
   460  		assertAccountBalance(t.t, srcNode, account, 0, 0)
   461  		assertAccountBalance(
   462  			t.t, srcNode, defaultAccount, confBalanceAfterChan, 0,
   463  		)
   464  	} else {
   465  		// Otherwise, all interactions remain within Carol's imported
   466  		// account.
   467  		confBalanceAfterChan = accountConfBalance - utxoAmt
   468  		assertAccountBalance(
   469  			t.t, srcNode, account, confBalanceAfterChan,
   470  			chanChangeUtxoAmt,
   471  		)
   472  
   473  		block := mineBlocks(t, t.lndHarness, 6, 1)[0]
   474  		assertTxInBlock(t, block, txHash)
   475  
   476  		confBalanceAfterChan += chanChangeUtxoAmt
   477  		assertAccountBalance(
   478  			t.t, srcNode, account, confBalanceAfterChan, 0,
   479  		)
   480  	}
   481  
   482  	// Assert that the transaction has the expected change address type
   483  	// based on the account.
   484  	var tx wire.MsgTx
   485  	err = tx.Deserialize(bytes.NewReader(finalizeResp.RawFinalTx))
   486  	require.NoError(t.t, err)
   487  	assertOutputScriptType(t.t, expChangeScriptType, &tx, chanChangeUtxoAmt)
   488  
   489  	// Wait for the channel to be announced by both parties.
   490  	chanPoint := &lnrpc.ChannelPoint{
   491  		FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
   492  			FundingTxidBytes: upd.ChanPending.Txid,
   493  		},
   494  		OutputIndex: upd.ChanPending.OutputIndex,
   495  	}
   496  	err = srcNode.WaitForNetworkChannelOpen(chanPoint)
   497  	require.NoError(t.t, err)
   498  	err = destNode.WaitForNetworkChannelOpen(chanPoint)
   499  	require.NoError(t.t, err)
   500  
   501  	// Send a test payment to ensure the channel is operating as normal.
   502  	const invoiceAmt = 100000
   503  	ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
   504  	defer cancel()
   505  	resp, err := destNode.AddInvoice(ctxt, &lnrpc.Invoice{
   506  		Memo:  "psbt import chan",
   507  		Value: invoiceAmt,
   508  	})
   509  	require.NoError(t.t, err)
   510  
   511  	err = completePaymentRequests(
   512  		srcNode, srcNode.RouterClient,
   513  		[]string{resp.PaymentRequest}, true,
   514  	)
   515  	require.NoError(t.t, err)
   516  
   517  	// Now that we've confirmed the opened channel works, we'll close it.
   518  	closeChannelAndAssert(t, t.lndHarness, srcNode, chanPoint, false)
   519  
   520  	// Since the channel still had funds left on the source node's side,
   521  	// they must've been redeemed after the close. Without a pre-negotiated
   522  	// close address, the funds will go into the source node's wallet
   523  	// instead of the imported account.
   524  	const chanCloseTxFee = 9050
   525  	balanceFromClosedChan := chanSize - invoiceAmt - chanCloseTxFee
   526  
   527  	if account == defaultImportedAccount {
   528  		assertAccountBalance(t.t, srcNode, account, 0, 0)
   529  		assertAccountBalance(
   530  			t.t, srcNode, defaultAccount,
   531  			confBalanceAfterChan+balanceFromClosedChan, 0,
   532  		)
   533  	} else {
   534  		assertAccountBalance(
   535  			t.t, srcNode, account, confBalanceAfterChan, 0,
   536  		)
   537  		assertAccountBalance(
   538  			t.t, srcNode, defaultAccount, balanceFromClosedChan, 0,
   539  		)
   540  	}
   541  }
   542  */
   543  
   544  // testWalletImportAccount tests that an imported account can fund transactions
   545  // and channels through PSBTs, by having one node (the one with the imported
   546  // account) craft the transactions and another node act as the signer.
   547  func testWalletImportAccount(net *lntest.NetworkHarness, t *harnessTest) {
   548  	t.t.Skip("Disabled due to no support for PSBT")
   549  	/*
   550  		testCases := []struct {
   551  			name     string
   552  			addrType walletrpc.AddressType
   553  		}{
   554  			{
   555  				name:     "standard BIP-0049",
   556  				addrType: walletrpc.AddressType_NESTED_WITNESS_PUBKEY_HASH,
   557  			},
   558  			{
   559  				name:     "lnd BIP-0049 variant",
   560  				addrType: walletrpc.AddressType_HYBRID_NESTED_WITNESS_PUBKEY_HASH,
   561  			},
   562  			{
   563  				name:     "standard BIP-0084",
   564  				addrType: walletrpc.AddressType_WITNESS_PUBKEY_HASH,
   565  			},
   566  		}
   567  
   568  		for _, tc := range testCases {
   569  			tc := tc
   570  			success := t.t.Run(tc.name, func(tt *testing.T) {
   571  				ht := newHarnessTest(tt, net)
   572  				ht.RunTestCase(&testCase{
   573  					name: tc.name,
   574  					test: func(net1 *lntest.NetworkHarness, t1 *harnessTest) {
   575  						testWalletImportAccountScenario(
   576  							net, t, tc.addrType,
   577  						)
   578  					},
   579  				})
   580  			})
   581  			if !success {
   582  				// Log failure time to help relate the lnd logs to the
   583  				// failure.
   584  				t.Logf("Failure time: %v", time.Now().Format(
   585  					"2006-01-02 15:04:05.000",
   586  				))
   587  				break
   588  			}
   589  		}
   590  	*/
   591  }
   592  
   593  /*
   594  func testWalletImportAccountScenario(net *lntest.NetworkHarness, t *harnessTest,
   595  	addrType walletrpc.AddressType) {
   596  
   597  	// We'll start our test by having two nodes, Carol and Dave. Carol's
   598  	// default wallet account will be imported into Dave's node.
   599  	carol := net.NewNode(t.t, "carol", nil)
   600  	defer shutdownAndAssert(net, t, carol)
   601  
   602  	dave := net.NewNode(t.t, "dave", nil)
   603  	defer shutdownAndAssert(net, t, dave)
   604  
   605  	runWalletImportAccountScenario(net, t, addrType, carol, dave)
   606  }
   607  
   608  func runWalletImportAccountScenario(net *lntest.NetworkHarness, t *harnessTest,
   609  	addrType walletrpc.AddressType, carol, dave *lntest.HarnessNode) {
   610  
   611  	ctxb := context.Background()
   612  	const utxoAmt int64 = dcrutil.AtomsPerCoin
   613  
   614  	ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
   615  	defer cancel()
   616  	listReq := &walletrpc.ListAccountsRequest{
   617  		Name:        "default",
   618  		AddressType: addrType,
   619  	}
   620  	listResp, err := carol.WalletKitClient.ListAccounts(ctxt, listReq)
   621  	require.NoError(t.t, err)
   622  	require.Equal(t.t, len(listResp.Accounts), 1)
   623  	carolAccount := listResp.Accounts[0]
   624  
   625  	ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
   626  	defer cancel()
   627  	const importedAccount = "carol"
   628  	importReq := &walletrpc.ImportAccountRequest{
   629  		Name:              importedAccount,
   630  		ExtendedPublicKey: carolAccount.ExtendedPublicKey,
   631  		AddressType:       addrType,
   632  	}
   633  	_, err = dave.WalletKitClient.ImportAccount(ctxt, importReq)
   634  	require.NoError(t.t, err)
   635  
   636  	// We'll generate an address for Carol from Dave's node to receive some
   637  	// funds.
   638  	externalAddr := newExternalAddr(
   639  		t.t, dave, carol, importedAccount, addrType,
   640  	)
   641  
   642  	// Send coins to Carol's address and confirm them, making sure the
   643  	// balance updates accordingly.
   644  	ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
   645  	defer cancel()
   646  	_, err = net.Alice.SendCoins(ctxt, &lnrpc.SendCoinsRequest{
   647  		Addr:         externalAddr,
   648  		Amount:       utxoAmt,
   649  		AtomsPerByte: 1,
   650  	})
   651  	require.NoError(t.t, err)
   652  
   653  	assertAccountBalance(t.t, dave, importedAccount, 0, utxoAmt)
   654  	_ = mineBlocks(t, net, 1, 1)
   655  	assertAccountBalance(t.t, dave, importedAccount, utxoAmt, 0)
   656  
   657  	// To ensure that Dave can use Carol's account as watch-only, we'll
   658  	// construct a PSBT that sends funds to Alice, which we'll then hand
   659  	// over to Carol to sign.
   660  	psbtSendFromImportedAccount(
   661  		t, dave, net.Alice, carol, importedAccount, addrType,
   662  	)
   663  
   664  	// We'll generate a new address for Carol from Dave's node to receive
   665  	// and fund a new channel.
   666  	externalAddr = newExternalAddr(
   667  		t.t, dave, carol, importedAccount, addrType,
   668  	)
   669  
   670  	// Retrieve the current confirmed balance of the imported account for
   671  	// some assertions we'll make later on.
   672  	ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
   673  	defer cancel()
   674  	balanceResp, err := dave.WalletBalance(ctxt, &lnrpc.WalletBalanceRequest{})
   675  	require.NoError(t.t, err)
   676  	require.Contains(t.t, balanceResp.AccountBalance, importedAccount)
   677  	confBalance := balanceResp.AccountBalance[importedAccount].ConfirmedBalance
   678  
   679  	// Send coins to Carol's address and confirm them, making sure the
   680  	// balance updates accordingly.
   681  	ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
   682  	defer cancel()
   683  	_, err = net.Alice.SendCoins(ctxt, &lnrpc.SendCoinsRequest{
   684  		Addr:       externalAddr,
   685  		Amount:     utxoAmt,
   686  		SatPerByte: 1,
   687  	})
   688  	require.NoError(t.t, err)
   689  
   690  	assertAccountBalance(t.t, dave, importedAccount, confBalance, utxoAmt)
   691  	_ = mineBlocks(t, net, 1, 1)
   692  	assertAccountBalance(
   693  		t.t, dave, importedAccount, confBalance+utxoAmt, 0,
   694  	)
   695  
   696  	// Now that we have enough funds, it's time to fund the channel, make a
   697  	// test payment, and close it. This contains several balance assertions
   698  	// along the way.
   699  	fundChanAndCloseFromImportedAccount(
   700  		t, dave, net.Alice, carol, importedAccount, addrType, utxoAmt,
   701  		int64(dcrlnd.MaxFundingAmount),
   702  	)
   703  }
   704  */
   705  
   706  // testWalletImportPubKey tests that an imported public keys can fund
   707  // transactions and channels through PSBTs, by having one node (the one with the
   708  // imported account) craft the transactions and another node act as the signer.
   709  func testWalletImportPubKey(net *lntest.NetworkHarness, t *harnessTest) {
   710  	t.t.Skip("Disabled due to no support for PSBT")
   711  	/*
   712  		testCases := []struct {
   713  			name     string
   714  			addrType walletrpc.AddressType
   715  		}{
   716  			{
   717  				name:     "BIP-0049",
   718  				addrType: walletrpc.AddressType_NESTED_WITNESS_PUBKEY_HASH,
   719  			},
   720  			{
   721  				name:     "BIP-0084",
   722  				addrType: walletrpc.AddressType_WITNESS_PUBKEY_HASH,
   723  			},
   724  		}
   725  
   726  		for _, tc := range testCases {
   727  			tc := tc
   728  			success := t.t.Run(tc.name, func(tt *testing.T) {
   729  				ht := newHarnessTest(tt, net)
   730  				ht.RunTestCase(&testCase{
   731  					name: tc.name,
   732  					test: func(net1 *lntest.NetworkHarness, t1 *harnessTest) {
   733  						testWalletImportPubKeyScenario(
   734  							net, t, tc.addrType,
   735  						)
   736  					},
   737  				})
   738  			})
   739  			if !success {
   740  				// Log failure time to help relate the lnd logs to the
   741  				// failure.
   742  				t.Logf("Failure time: %v", time.Now().Format(
   743  					"2006-01-02 15:04:05.000",
   744  				))
   745  				break
   746  			}
   747  		}
   748  	*/
   749  }
   750  
   751  /*
   752  func testWalletImportPubKeyScenario(net *lntest.NetworkHarness, t *harnessTest,
   753  	addrType walletrpc.AddressType) {
   754  
   755  	ctxb := context.Background()
   756  	const utxoAmt int64 = dcrutil.AtomsPerCoin
   757  
   758  	// We'll start our test by having two nodes, Carol and Dave.
   759  	carol := net.NewNode(t.t, "carol", nil)
   760  	defer shutdownAndAssert(net, t, carol)
   761  
   762  	dave := net.NewNode(t.t, "dave", nil)
   763  	defer shutdownAndAssert(net, t, dave)
   764  
   765  	// We'll define a helper closure that we'll use throughout the test to
   766  	// generate a new address of the given type from Carol's perspective,
   767  	// import it into Dave's wallet, and fund it.
   768  	importPubKey := func(keyIndex uint32, prevConfBalance, prevUnconfBalance int64) {
   769  		// Retrieve Carol's account public key for the corresponding
   770  		// address type.
   771  		ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
   772  		defer cancel()
   773  		listReq := &walletrpc.ListAccountsRequest{
   774  			Name:        "default",
   775  			AddressType: addrType,
   776  		}
   777  		listResp, err := carol.WalletKitClient.ListAccounts(ctxt, listReq)
   778  		require.NoError(t.t, err)
   779  		require.Equal(t.t, len(listResp.Accounts), 1)
   780  		p2wkhAccount := listResp.Accounts[0]
   781  
   782  		// Derive the external address at the given index.
   783  		accountPubKey, err := hdkeychain.NewKeyFromString(
   784  			p2wkhAccount.ExtendedPublicKey,
   785  		)
   786  		require.NoError(t.t, err)
   787  		externalAccountExtKey, err := accountPubKey.Derive(0)
   788  		require.NoError(t.t, err)
   789  		externalAddrExtKey, err := externalAccountExtKey.Derive(keyIndex)
   790  		require.NoError(t.t, err)
   791  		externalAddrPubKey, err := externalAddrExtKey.ECPubKey()
   792  		require.NoError(t.t, err)
   793  
   794  		// Import the public key into Dave.
   795  		ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
   796  		defer cancel()
   797  		importReq := &walletrpc.ImportPublicKeyRequest{
   798  			PublicKey:   externalAddrPubKey.SerializeCompressed(),
   799  			AddressType: addrType,
   800  		}
   801  		_, err = dave.WalletKitClient.ImportPublicKey(ctxt, importReq)
   802  		require.NoError(t.t, err)
   803  
   804  		// We'll also generate the same address for Carol, as it'll be
   805  		// required later when signing.
   806  		ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
   807  		defer cancel()
   808  		carolAddrResp, err := carol.NewAddress(ctxt, &lnrpc.NewAddressRequest{
   809  			Type: walletToLNAddrType(t.t, addrType),
   810  		})
   811  		require.NoError(t.t, err)
   812  
   813  		// Send coins to Carol's address and confirm them, making sure
   814  		// the balance updates accordingly.
   815  		ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
   816  		defer cancel()
   817  		_, err = net.Alice.SendCoins(ctxt, &lnrpc.SendCoinsRequest{
   818  			Addr:       carolAddrResp.Address,
   819  			Amount:     utxoAmt,
   820  			SatPerByte: 1,
   821  		})
   822  		require.NoError(t.t, err)
   823  
   824  		assertAccountBalance(
   825  			t.t, dave, defaultImportedAccount, prevConfBalance,
   826  			prevUnconfBalance+utxoAmt,
   827  		)
   828  		_ = mineBlocks(t, net, 1, 1)
   829  		assertAccountBalance(
   830  			t.t, dave, defaultImportedAccount,
   831  			prevConfBalance+utxoAmt, prevUnconfBalance,
   832  		)
   833  	}
   834  
   835  	// We'll have Carol generate a new external address, which we'll import
   836  	// into Dave.
   837  	importPubKey(0, 0, 0)
   838  
   839  	// To ensure that Dave can use Carol's public key as watch-only, we'll
   840  	// construct a PSBT that sends funds to Alice, which we'll then hand
   841  	// over to Carol to sign.
   842  	psbtSendFromImportedAccount(
   843  		t, dave, net.Alice, carol, defaultImportedAccount, addrType,
   844  	)
   845  
   846  	// We'll now attempt to fund a channel.
   847  	//
   848  	// We'll have Carol generate another external address, which we'll
   849  	// import into Dave again.
   850  	ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
   851  	defer cancel()
   852  	balanceResp, err := dave.WalletBalance(ctxt, &lnrpc.WalletBalanceRequest{})
   853  	require.NoError(t.t, err)
   854  	require.Contains(t.t, balanceResp.AccountBalance, defaultImportedAccount)
   855  	confBalance := balanceResp.
   856  		AccountBalance[defaultImportedAccount].ConfirmedBalance
   857  	importPubKey(1, confBalance, 0)
   858  
   859  	// Now that we have enough funds, it's time to fund the channel, make a
   860  	// test payment, and close it. This contains several balance assertions
   861  	// along the way.
   862  	fundChanAndCloseFromImportedAccount(
   863  		t, dave, net.Alice, carol, defaultImportedAccount, addrType,
   864  		utxoAmt, int64(dcrlnd.MaxFundingAmount),
   865  	)
   866  }
   867  */