github.com/decred/dcrlnd@v0.7.6/lnwallet/test/test_interface.go (about)

     1  package lnwallettest
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"crypto/sha256"
     7  	"encoding/hex"
     8  	"fmt"
     9  	"io/ioutil"
    10  	"math"
    11  	"net"
    12  	"os"
    13  	"path"
    14  	"path/filepath"
    15  	"reflect"
    16  	"runtime"
    17  	"strings"
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/davecgh/go-spew/spew"
    22  	"github.com/decred/dcrlnd/blockcache"
    23  	"github.com/decred/dcrlnd/chainntnfs/dcrdnotify"
    24  	"golang.org/x/exp/slices"
    25  	"matheusd.com/testctx"
    26  
    27  	_ "decred.org/dcrwallet/v4/wallet/drivers/bdb"
    28  
    29  	"github.com/decred/dcrd/chaincfg/chainhash"
    30  	"github.com/decred/dcrd/chaincfg/v3"
    31  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
    32  	"github.com/decred/dcrd/dcrjson/v4"
    33  	"github.com/decred/dcrd/dcrutil/v4"
    34  	"github.com/decred/dcrd/rpcclient/v8"
    35  	"github.com/decred/dcrd/txscript/v4"
    36  	"github.com/decred/dcrd/txscript/v4/stdaddr"
    37  	"github.com/decred/dcrd/txscript/v4/stdscript"
    38  	"github.com/decred/dcrd/wire"
    39  	rpctest "github.com/decred/dcrtest/dcrdtest"
    40  	"github.com/stretchr/testify/require"
    41  
    42  	"github.com/decred/dcrlnd/chainntnfs"
    43  	"github.com/decred/dcrlnd/channeldb"
    44  	"github.com/decred/dcrlnd/input"
    45  	"github.com/decred/dcrlnd/internal/testutils"
    46  	"github.com/decred/dcrlnd/keychain"
    47  	"github.com/decred/dcrlnd/kvdb"
    48  	"github.com/decred/dcrlnd/labels"
    49  	"github.com/decred/dcrlnd/lnwallet"
    50  	"github.com/decred/dcrlnd/lnwallet/chainfee"
    51  	"github.com/decred/dcrlnd/lnwallet/chanfunding"
    52  	"github.com/decred/dcrlnd/lnwallet/dcrwallet"
    53  	"github.com/decred/dcrlnd/lnwallet/remotedcrwallet"
    54  	"github.com/decred/dcrlnd/lnwire"
    55  )
    56  
    57  var (
    58  	bobsPrivKey = []byte{
    59  		0x81, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
    60  		0x63, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
    61  		0xd, 0xe7, 0x95, 0xe4, 0xb7, 0x25, 0xb8, 0x4d,
    62  		0x1e, 0xb, 0x4c, 0xfd, 0x9e, 0xc5, 0x8c, 0xe9,
    63  	}
    64  
    65  	// Use a hard-coded HD seed.
    66  	testHdSeed = chainhash.Hash{
    67  		0xb7, 0x94, 0x38, 0x5f, 0x2d, 0x1e, 0xf7, 0xab,
    68  		0x4d, 0x92, 0x73, 0xd1, 0x90, 0x63, 0x81, 0xb4,
    69  		0x4f, 0x2f, 0x6f, 0x25, 0x88, 0xa3, 0xef, 0xb9,
    70  		0x6a, 0x49, 0x18, 0x83, 0x31, 0x98, 0x47, 0x53,
    71  	}
    72  
    73  	aliceHDSeed = chainhash.Hash{
    74  		0xb7, 0x94, 0x38, 0x5f, 0x2d, 0x1e, 0xf7, 0xab,
    75  		0x4d, 0x92, 0x73, 0xd1, 0x90, 0x63, 0x81, 0xb4,
    76  		0x4f, 0x2f, 0x6f, 0x25, 0x18, 0xa3, 0xef, 0xb9,
    77  		0x64, 0x49, 0x18, 0x83, 0x31, 0x98, 0x47, 0x53,
    78  	}
    79  	bobHDSeed = chainhash.Hash{
    80  		0xb7, 0x94, 0x38, 0x5f, 0x2d, 0x1e, 0xf7, 0xab,
    81  		0x4d, 0x92, 0x73, 0xd1, 0x90, 0x63, 0x81, 0xb4,
    82  		0x4f, 0x2f, 0x6f, 0x25, 0x98, 0xa3, 0xef, 0xb9,
    83  		0x69, 0x49, 0x18, 0x83, 0x31, 0x98, 0x47, 0x53,
    84  	}
    85  
    86  	netParams = chaincfg.SimNetParams()
    87  	chainHash = &netParams.GenesisHash
    88  
    89  	alicePub = secp256k1.PrivKeyFromBytes(testHdSeed[:]).PubKey()
    90  	bobPub   = secp256k1.PrivKeyFromBytes(bobsPrivKey).PubKey()
    91  
    92  	// The number of confirmations required to consider any created channel
    93  	// open.
    94  	numReqConfs uint16 = 1
    95  
    96  	csvDelay uint16 = 4
    97  
    98  	scriptVersion uint16 = 0
    99  
   100  	bobAddr, _   = net.ResolveTCPAddr("tcp", "10.0.0.2:9000")
   101  	aliceAddr, _ = net.ResolveTCPAddr("tcp", "10.0.0.3:9000")
   102  
   103  	defaultFeeRate                 = chainfee.AtomPerKByte(1e4)
   104  	defaultMaxLocalCsvDelay uint16 = 10000
   105  )
   106  
   107  // assertProperBalance asserts than the total value of the unspent outputs
   108  // within the wallet are *exactly* amount. If unable to retrieve the current
   109  // balance, or the assertion fails, the test will halt with a fatal error.
   110  func assertProperBalance(t *testing.T, lw *lnwallet.LightningWallet,
   111  	numConfirms int32, amount float64) {
   112  
   113  	balance, err := lw.ConfirmedBalance(numConfirms, lnwallet.DefaultAccountName)
   114  	if err != nil {
   115  		t.Fatalf("unable to query for balance: %v", err)
   116  	}
   117  	if balance.ToCoin() != amount {
   118  		t.Fatalf("wallet credits not properly loaded, should have %v DCR, "+
   119  			"instead have %v", amount, balance)
   120  	}
   121  }
   122  
   123  func assertReservationDeleted(res *lnwallet.ChannelReservation, t *testing.T) {
   124  	if err := res.Cancel(); err == nil {
   125  		t.Fatalf("reservation wasn't deleted from wallet")
   126  	}
   127  }
   128  
   129  // mineAndAssertTxInBlock asserts that a transaction is included within the next
   130  // block mined.
   131  func mineAndAssertTxInBlock(t *testing.T, miner *rpctest.Harness,
   132  	vw *rpctest.VotingWallet, txid chainhash.Hash) {
   133  
   134  	t.Helper()
   135  
   136  	// First, we'll wait for the transaction to arrive in the mempool.
   137  	if err := waitForMempoolTx(miner, &txid); err != nil {
   138  		t.Fatalf("unable to find %v in the mempool: %v", txid, err)
   139  	}
   140  
   141  	// We'll mined a block to confirm it.
   142  	blockHashes, err := vw.GenerateBlocks(context.TODO(), 1)
   143  	if err != nil {
   144  		t.Fatalf("unable to generate new block: %v", err)
   145  	}
   146  
   147  	// Finally, we'll check it was actually mined in this block.
   148  	block, err := miner.Node.GetBlock(context.TODO(), blockHashes[0])
   149  	if err != nil {
   150  		t.Fatalf("unable to get block %v: %v", blockHashes[0], err)
   151  	}
   152  	if len(block.Transactions) != 2 {
   153  		t.Fatalf("expected 2 transactions in block, found %d",
   154  			len(block.Transactions))
   155  	}
   156  	txHash := block.Transactions[1].TxHash()
   157  	if txHash != txid {
   158  		t.Fatalf("expected transaction %v to be mined, found %v", txid,
   159  			txHash)
   160  	}
   161  }
   162  
   163  // newPkScript generates a new public key script of the given address type.
   164  func newPkScript(t *testing.T, w *lnwallet.LightningWallet,
   165  	addrType lnwallet.AddressType) []byte {
   166  
   167  	t.Helper()
   168  
   169  	addr, err := w.NewAddress(addrType, false, lnwallet.DefaultAccountName)
   170  	if err != nil {
   171  		t.Fatalf("unable to create new address: %v", err)
   172  	}
   173  	pkScript, err := input.PayToAddrScript(addr)
   174  	if err != nil {
   175  		t.Fatalf("unable to create output script: %v", err)
   176  	}
   177  
   178  	// Wait for the wallet's address manager to close (see dcrwallet#1372).
   179  	time.Sleep(time.Millisecond * 50)
   180  
   181  	return pkScript
   182  }
   183  
   184  // sendCoins is a helper function that encompasses all the things needed for two
   185  // parties to send on-chain funds to each other.
   186  func sendCoins(t *testing.T, miner *rpctest.Harness, vw *rpctest.VotingWallet,
   187  	sender, receiver *lnwallet.LightningWallet, output *wire.TxOut,
   188  	feeRate chainfee.AtomPerKByte, mineBlock bool, minConf int32) *wire.MsgTx { //nolint:unparam
   189  
   190  	t.Helper()
   191  
   192  	tx, err := sender.SendOutputs(
   193  		[]*wire.TxOut{output}, feeRate, minConf, labels.External, "",
   194  	)
   195  	if err != nil {
   196  		t.Fatalf("unable to send transaction: %v", err)
   197  	}
   198  
   199  	if mineBlock {
   200  		mineAndAssertTxInBlock(t, miner, vw, tx.TxHash())
   201  	}
   202  
   203  	if err := waitForWalletSync(miner, sender); err != nil {
   204  		t.Fatalf("unable to sync alice: %v", err)
   205  	}
   206  	if err := waitForWalletSync(miner, receiver); err != nil {
   207  		t.Fatalf("unable to sync bob: %v", err)
   208  	}
   209  
   210  	return tx
   211  }
   212  
   213  // assertTxInWallet asserts that a transaction exists in the wallet with the
   214  // expected confirmation status.
   215  func assertTxInWallet(t *testing.T, w *lnwallet.LightningWallet,
   216  	txHash chainhash.Hash, confirmed bool) {
   217  
   218  	t.Helper()
   219  
   220  	// We'll fetch all of our transaction and go through each one until
   221  	// finding the expected transaction with its expected confirmation
   222  	// status.
   223  	txs, err := w.ListTransactionDetails(0, dcrwallet.UnconfirmedHeight, "")
   224  	if err != nil {
   225  		t.Fatalf("unable to retrieve transactions: %v", err)
   226  	}
   227  	for _, tx := range txs {
   228  		if tx.Hash != txHash {
   229  			continue
   230  		}
   231  		if tx.NumConfirmations <= 0 && confirmed {
   232  			t.Fatalf("expected transaction %v to be confirmed",
   233  				txHash)
   234  		}
   235  		if tx.NumConfirmations > 0 && !confirmed {
   236  			t.Fatalf("expected transaction %v to be unconfirmed",
   237  				txHash)
   238  		}
   239  
   240  		// We've found the transaction and it matches the desired
   241  		// confirmation status, so we can exit.
   242  		return
   243  	}
   244  
   245  	t.Fatalf("transaction %v not found", txHash)
   246  }
   247  
   248  func loadTestCredits(miner *rpctest.Harness, w *lnwallet.LightningWallet,
   249  	blockGenerator func(context.Context, uint32) ([]*chainhash.Hash, error),
   250  	numOutputs int, dcrPerOutput float64) error {
   251  
   252  	// Using the mining node, spend from a coinbase output numOutputs to
   253  	// give us dcrPerOutput with each output.
   254  	atomsPerOutput, err := dcrutil.NewAmount(dcrPerOutput)
   255  	if err != nil {
   256  		return fmt.Errorf("unable to create amt: %v", err)
   257  	}
   258  	expectedBalance, err := w.ConfirmedBalance(1, lnwallet.DefaultAccountName)
   259  	if err != nil {
   260  		return err
   261  	}
   262  	expectedBalance += dcrutil.Amount(int64(atomsPerOutput) * int64(numOutputs))
   263  	addrs := make([]stdaddr.Address, numOutputs)
   264  	for i := 0; i < numOutputs; i++ {
   265  		// Grab a fresh address from the wallet to house this output.
   266  		addrs[i], err = w.NewAddress(
   267  			lnwallet.PubKeyHash, false,
   268  			lnwallet.DefaultAccountName,
   269  		)
   270  		if err != nil {
   271  			return err
   272  		}
   273  	}
   274  
   275  	// Sleep for a bit to allow the wallet to unlock the mutexes of the address
   276  	// manager and underlying database. This is needed to prevent a possible
   277  	// deadlock condition in the wallet when generating new addresses while
   278  	// processing a transaction (see
   279  	// https://github.com/dcrwallet/issues/1372). This isn't pretty,
   280  	// but 200ms should be more than enough to prevent triggering this bug
   281  	// on most dev machines.
   282  	time.Sleep(time.Millisecond * 200)
   283  	ctxb := context.Background()
   284  
   285  	for _, walletAddr := range addrs {
   286  		script, err := input.PayToAddrScript(walletAddr)
   287  		if err != nil {
   288  			return err
   289  		}
   290  
   291  		output := &wire.TxOut{
   292  			Value:    int64(atomsPerOutput),
   293  			PkScript: script,
   294  			Version:  scriptVersion,
   295  		}
   296  		if _, err := miner.SendOutputs(ctxb, []*wire.TxOut{output}, 1e5); err != nil {
   297  			return err
   298  		}
   299  	}
   300  
   301  	// TODO(roasbeef): shouldn't hardcode 10, use config param that dictates
   302  	// how many confs we wait before opening a channel.
   303  	// Generate 10 blocks with the mining node, this should mine all
   304  	// numOutputs transactions created above. We generate 10 blocks here
   305  	// in order to give all the outputs a "sufficient" number of confirmations.
   306  	if _, err := blockGenerator(context.TODO(), 10); err != nil {
   307  		return err
   308  	}
   309  
   310  	time.Sleep(time.Millisecond * 200)
   311  
   312  	// Wait until the wallet has finished syncing up to the main chain.
   313  	ticker := time.NewTicker(100 * time.Millisecond)
   314  	timeout := time.After(30 * time.Second)
   315  
   316  	for range ticker.C {
   317  		balance, err := w.ConfirmedBalance(1, lnwallet.DefaultAccountName)
   318  		if err != nil {
   319  			return err
   320  		}
   321  		if balance == expectedBalance {
   322  			break
   323  		}
   324  		select {
   325  		case <-timeout:
   326  			synced, _, err := w.IsSynced()
   327  			if err != nil {
   328  				return err
   329  			}
   330  			return fmt.Errorf("timed out after 30 seconds "+
   331  				"waiting for balance %v, current balance %v, "+
   332  				"synced: %t", expectedBalance, balance, synced)
   333  		default:
   334  		}
   335  	}
   336  	ticker.Stop()
   337  
   338  	return nil
   339  }
   340  
   341  // createTestWallet creates a test LightningWallet will a total of 20DCR
   342  // available for funding channels.
   343  func createTestWallet(fullDb *channeldb.DB, miningNode *rpctest.Harness,
   344  	netParams *chaincfg.Params, notifier chainntnfs.ChainNotifier,
   345  	wc lnwallet.WalletController, keyRing keychain.SecretKeyRing,
   346  	signer input.Signer, bio lnwallet.BlockChainIO,
   347  	vw *rpctest.VotingWallet) (*lnwallet.LightningWallet, error) {
   348  
   349  	cfg := lnwallet.Config{
   350  		Database:         fullDb.ChannelStateDB(),
   351  		Notifier:         notifier,
   352  		SecretKeyRing:    keyRing,
   353  		WalletController: wc,
   354  		Signer:           signer,
   355  		ChainIO:          bio,
   356  		FeeEstimator:     chainfee.NewStaticEstimator(defaultFeeRate, 0),
   357  		DefaultConstraints: channeldb.ChannelConstraints{
   358  			DustLimit:        6030,
   359  			MaxPendingAmount: lnwire.NewMAtomsFromAtoms(dcrutil.AtomsPerCoin) * 100,
   360  			ChanReserve:      100,
   361  			MinHTLC:          400,
   362  			MaxAcceptedHtlcs: 900,
   363  		},
   364  		NetParams: *netParams,
   365  	}
   366  
   367  	wallet, err := lnwallet.NewLightningWallet(cfg)
   368  	if err != nil {
   369  		return nil, err
   370  	}
   371  
   372  	if err := wallet.Startup(); err != nil {
   373  		return nil, err
   374  	}
   375  
   376  	return wallet, nil
   377  }
   378  
   379  func testGetRecoveryInfo(miner *rpctest.Harness, // nolint: unused
   380  	vw *rpctest.VotingWallet, alice, bob *lnwallet.LightningWallet,
   381  	t *testing.T) {
   382  
   383  	// alice's wallet is in recovery mode
   384  	expectedRecoveryMode := true
   385  	expectedProgress := float64(1)
   386  
   387  	isRecoveryMode, progress, err := alice.GetRecoveryInfo()
   388  	require.NoError(t, err, "unable to get alice's recovery info")
   389  
   390  	require.Equal(t,
   391  		expectedRecoveryMode, isRecoveryMode, "recovery mode incorrect",
   392  	)
   393  	require.Equal(t, expectedProgress, progress, "progress incorrect")
   394  
   395  	// Generate 5 blocks and check the recovery process again.
   396  	const numBlocksMined = 5
   397  	_, err = vw.GenerateBlocks(context.TODO(), numBlocksMined)
   398  	require.NoError(t, err, "unable to mine blocks")
   399  
   400  	// Check the recovery process. Once synced, the progress should be 1.
   401  	err = waitForWalletSync(miner, alice)
   402  	require.NoError(t, err, "Couldn't sync Alice's wallet")
   403  
   404  	isRecoveryMode, progress, err = alice.GetRecoveryInfo()
   405  	require.NoError(t, err, "unable to get alice's recovery info")
   406  
   407  	require.Equal(t,
   408  		expectedRecoveryMode, isRecoveryMode, "recovery mode incorrect",
   409  	)
   410  	require.Equal(t, expectedProgress, progress, "progress incorrect")
   411  
   412  	// bob's wallet is not in recovery mode
   413  	expectedRecoveryMode = false
   414  	expectedProgress = float64(0)
   415  
   416  	isRecoveryMode, progress, err = bob.GetRecoveryInfo()
   417  	require.NoError(t, err, "unable to get bob's recovery info")
   418  
   419  	require.Equal(t,
   420  		expectedRecoveryMode, isRecoveryMode, "recovery mode incorrect",
   421  	)
   422  	require.Equal(t, expectedProgress, progress, "progress incorrect")
   423  }
   424  
   425  func testDualFundingReservationWorkflow(miner *rpctest.Harness,
   426  	vw *rpctest.VotingWallet, alice, bob *lnwallet.LightningWallet,
   427  	t *testing.T) {
   428  
   429  	fundingAmount, err := dcrutil.NewAmount(5)
   430  	if err != nil {
   431  		t.Fatalf("unable to create amt: %v", err)
   432  	}
   433  
   434  	// In this scenario, we'll test a dual funder reservation, with each
   435  	// side putting in 10 DCR.
   436  
   437  	// Alice initiates a channel funded with 5 DCR for each side, so 10 DCR
   438  	// total. She also generates 2 DCR in change.
   439  	feePerKB, err := alice.Cfg.FeeEstimator.EstimateFeePerKB(1)
   440  	if err != nil {
   441  		t.Fatalf("unable to query fee estimator: %v", err)
   442  	}
   443  
   444  	aliceReq := &lnwallet.InitFundingReserveMsg{
   445  		ChainHash:        chainHash,
   446  		NodeID:           bobPub,
   447  		NodeAddr:         bobAddr,
   448  		LocalFundingAmt:  fundingAmount,
   449  		RemoteFundingAmt: fundingAmount,
   450  		CommitFeePerKB:   feePerKB,
   451  		FundingFeePerKB:  feePerKB,
   452  		PushMAtoms:       0,
   453  		Flags:            lnwire.FFAnnounceChannel,
   454  	}
   455  	aliceChanReservation, err := alice.InitChannelReservation(aliceReq)
   456  	if err != nil {
   457  		t.Fatalf("unable to initialize funding reservation: %v", err)
   458  	}
   459  	aliceChanReservation.SetNumConfsRequired(numReqConfs)
   460  	channelConstraints := &channeldb.ChannelConstraints{
   461  		DustLimit:        alice.Cfg.DefaultConstraints.DustLimit,
   462  		ChanReserve:      fundingAmount / 100,
   463  		MaxPendingAmount: lnwire.NewMAtomsFromAtoms(fundingAmount),
   464  		MinHTLC:          1,
   465  		MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
   466  		CsvDelay:         csvDelay,
   467  	}
   468  	err = aliceChanReservation.CommitConstraints(
   469  		channelConstraints, defaultMaxLocalCsvDelay, false,
   470  	)
   471  	if err != nil {
   472  		t.Fatalf("unable to verify constraints: %v", err)
   473  	}
   474  
   475  	// The channel reservation should now be populated with a multi-sig key
   476  	// from our HD chain, a change output with 3 DCR, and 2 outputs
   477  	// selected of 4 DCR each. Additionally, the rest of the items needed
   478  	// to fulfill a funding contribution should also have been filled in.
   479  	aliceContribution := aliceChanReservation.OurContribution()
   480  	if len(aliceContribution.Inputs) < 1 {
   481  		t.Fatalf("outputs for funding tx not properly selected, have %v "+
   482  			"outputs should at least 1", len(aliceContribution.Inputs))
   483  	}
   484  	if len(aliceContribution.ChangeOutputs) != 1 {
   485  		t.Fatalf("coin selection failed, should have one change outputs, "+
   486  			"instead have: %v", len(aliceContribution.ChangeOutputs))
   487  	}
   488  	assertContributionInitPopulated(t, aliceContribution)
   489  
   490  	// Bob does the same, generating his own contribution. He then also
   491  	// receives' Alice's contribution, and consumes that so we can continue
   492  	// the funding process.
   493  	bobReq := &lnwallet.InitFundingReserveMsg{
   494  		ChainHash:        chainHash,
   495  		NodeID:           alicePub,
   496  		NodeAddr:         aliceAddr,
   497  		LocalFundingAmt:  fundingAmount,
   498  		RemoteFundingAmt: fundingAmount,
   499  		CommitFeePerKB:   feePerKB,
   500  		FundingFeePerKB:  feePerKB,
   501  		PushMAtoms:       0,
   502  		Flags:            lnwire.FFAnnounceChannel,
   503  	}
   504  	bobChanReservation, err := bob.InitChannelReservation(bobReq)
   505  	if err != nil {
   506  		t.Fatalf("bob unable to init channel reservation: %v", err)
   507  	}
   508  	err = bobChanReservation.CommitConstraints(
   509  		channelConstraints, defaultMaxLocalCsvDelay, true,
   510  	)
   511  	if err != nil {
   512  		t.Fatalf("unable to verify constraints: %v", err)
   513  	}
   514  	bobChanReservation.SetNumConfsRequired(numReqConfs)
   515  
   516  	assertContributionInitPopulated(t, bobChanReservation.OurContribution())
   517  
   518  	err = bobChanReservation.ProcessContribution(aliceContribution)
   519  	if err != nil {
   520  		t.Fatalf("bob unable to process alice's contribution: %v", err)
   521  	}
   522  	assertContributionInitPopulated(t, bobChanReservation.TheirContribution())
   523  
   524  	bobContribution := bobChanReservation.OurContribution()
   525  
   526  	// Bob then sends over his contribution, which will be consumed by
   527  	// Alice. After this phase, Alice should have all the necessary
   528  	// material required to craft the funding transaction and commitment
   529  	// transactions.
   530  	err = aliceChanReservation.ProcessContribution(bobContribution)
   531  	if err != nil {
   532  		t.Fatalf("alice unable to process bob's contribution: %v", err)
   533  	}
   534  	assertContributionInitPopulated(t, aliceChanReservation.TheirContribution())
   535  
   536  	// At this point, all Alice's signatures should be fully populated.
   537  	aliceFundingSigs, aliceCommitSig := aliceChanReservation.OurSignatures()
   538  	if aliceFundingSigs == nil {
   539  		t.Fatalf("alice's funding signatures not populated")
   540  	}
   541  	if aliceCommitSig == nil {
   542  		t.Fatalf("alice's commit signatures not populated")
   543  	}
   544  
   545  	// Additionally, Bob's signatures should also be fully populated.
   546  	bobFundingSigs, bobCommitSig := bobChanReservation.OurSignatures()
   547  	if bobFundingSigs == nil {
   548  		t.Fatalf("bob's funding signatures not populated")
   549  	}
   550  	if bobCommitSig == nil {
   551  		t.Fatalf("bob's commit signatures not populated")
   552  	}
   553  
   554  	// To conclude, we'll consume first Alice's signatures with Bob, and
   555  	// then the other way around.
   556  	_, err = aliceChanReservation.CompleteReservation(
   557  		bobFundingSigs, bobCommitSig,
   558  	)
   559  	if err != nil {
   560  		for _, in := range aliceChanReservation.FinalFundingTx().TxIn {
   561  			fmt.Println(in.PreviousOutPoint.String())
   562  		}
   563  		t.Fatalf("unable to consume alice's sigs: %v", err)
   564  	}
   565  	_, err = bobChanReservation.CompleteReservation(
   566  		aliceFundingSigs, aliceCommitSig,
   567  	)
   568  	if err != nil {
   569  		t.Fatalf("unable to consume bob's sigs: %v", err)
   570  	}
   571  
   572  	// At this point, the funding tx should have been populated.
   573  	fundingTx := aliceChanReservation.FinalFundingTx()
   574  	if fundingTx == nil {
   575  		t.Fatalf("funding transaction never created!")
   576  	}
   577  
   578  	// The resulting active channel state should have been persisted to the
   579  	// DB.
   580  	fundingSha := fundingTx.TxHash()
   581  	aliceChannels, err := alice.Cfg.Database.FetchOpenChannels(bobPub)
   582  	if err != nil {
   583  		t.Fatalf("unable to retrieve channel from DB: %v", err)
   584  	}
   585  	if !bytes.Equal(aliceChannels[0].FundingOutpoint.Hash[:], fundingSha[:]) {
   586  		t.Fatalf("channel state not properly saved")
   587  	}
   588  	if !aliceChannels[0].ChanType.IsDualFunder() {
   589  		t.Fatalf("channel not detected as dual funder")
   590  	}
   591  	bobChannels, err := bob.Cfg.Database.FetchOpenChannels(alicePub)
   592  	if err != nil {
   593  		t.Fatalf("unable to retrieve channel from DB: %v", err)
   594  	}
   595  	if !bytes.Equal(bobChannels[0].FundingOutpoint.Hash[:], fundingSha[:]) {
   596  		t.Fatalf("channel state not properly saved")
   597  	}
   598  	if !bobChannels[0].ChanType.IsDualFunder() {
   599  		t.Fatalf("channel not detected as dual funder")
   600  	}
   601  
   602  	// Let Alice publish the funding transaction.
   603  	err = alice.PublishTransaction(fundingTx, "")
   604  	if err != nil {
   605  		t.Fatalf("unable to publish funding tx: %v", err)
   606  	}
   607  
   608  	// Mine a single block, the funding transaction should be included
   609  	// within this block.
   610  	err = waitForMempoolTx(miner, &fundingSha)
   611  	if err != nil {
   612  		t.Fatalf("tx not relayed to miner: %v", err)
   613  	}
   614  	blockHashes, err := vw.GenerateBlocks(context.TODO(), 1)
   615  	if err != nil {
   616  		t.Fatalf("unable to generate block: %v", err)
   617  	}
   618  	block, err := miner.Node.GetBlock(context.TODO(), blockHashes[0])
   619  	if err != nil {
   620  		t.Fatalf("unable to find block: %v", err)
   621  	}
   622  	if len(block.Transactions) != 2 {
   623  		t.Fatalf("funding transaction wasn't mined: %v", err)
   624  	}
   625  	blockTx := block.Transactions[1]
   626  	if blockTx.TxHash() != fundingSha {
   627  		t.Fatalf("incorrect transaction was mined")
   628  	}
   629  
   630  	assertReservationDeleted(aliceChanReservation, t)
   631  	assertReservationDeleted(bobChanReservation, t)
   632  
   633  	// Wait for wallets to catch up to prevent issues in subsequent tests.
   634  	err = waitForWalletSync(miner, alice)
   635  	if err != nil {
   636  		t.Fatalf("unable to sync alice: %v", err)
   637  	}
   638  	err = waitForWalletSync(miner, bob)
   639  	if err != nil {
   640  		t.Fatalf("unable to sync bob: %v", err)
   641  	}
   642  }
   643  
   644  func testFundingTransactionLockedOutputs(miner *rpctest.Harness,
   645  	vw *rpctest.VotingWallet, alice, _ *lnwallet.LightningWallet,
   646  	t *testing.T) {
   647  
   648  	// Create a single channel asking for 16 DCR total.
   649  	fundingAmount := dcrutil.Amount(8 * 1e8)
   650  
   651  	feePerKB, err := alice.Cfg.FeeEstimator.EstimateFeePerKB(1)
   652  	if err != nil {
   653  		t.Fatalf("unable to query fee estimator: %v", err)
   654  	}
   655  	req := &lnwallet.InitFundingReserveMsg{
   656  		ChainHash:        chainHash,
   657  		NodeID:           bobPub,
   658  		NodeAddr:         bobAddr,
   659  		LocalFundingAmt:  fundingAmount,
   660  		RemoteFundingAmt: 0,
   661  		CommitFeePerKB:   feePerKB,
   662  		FundingFeePerKB:  feePerKB,
   663  		PushMAtoms:       0,
   664  		Flags:            lnwire.FFAnnounceChannel,
   665  		PendingChanID:    [32]byte{0, 1, 2, 3},
   666  	}
   667  	chanReservation, err := alice.InitChannelReservation(req)
   668  	if err != nil {
   669  		t.Fatalf("unable to initialize funding reservation 1: %v", err)
   670  	}
   671  
   672  	// Now attempt to reserve funds for another channel, this time
   673  	// requesting 900 DCR. We only have around 64DCR worth of outpoints
   674  	// that aren't locked, so this should fail.
   675  	amt, err := dcrutil.NewAmount(900)
   676  	if err != nil {
   677  		t.Fatalf("unable to create amt: %v", err)
   678  	}
   679  	failedReq := &lnwallet.InitFundingReserveMsg{
   680  		ChainHash:        chainHash,
   681  		NodeID:           bobPub,
   682  		NodeAddr:         bobAddr,
   683  		LocalFundingAmt:  amt,
   684  		RemoteFundingAmt: 0,
   685  		CommitFeePerKB:   feePerKB,
   686  		FundingFeePerKB:  feePerKB,
   687  		PushMAtoms:       0,
   688  		Flags:            lnwire.FFAnnounceChannel,
   689  		PendingChanID:    [32]byte{1, 2, 3, 4},
   690  	}
   691  	failedReservation, err := alice.InitChannelReservation(failedReq)
   692  	if err == nil {
   693  		t.Fatalf("not error returned, should fail on coin selection")
   694  	}
   695  	if _, ok := err.(*chanfunding.ErrInsufficientFunds); !ok {
   696  		t.Fatalf("error not coinselect error: %v", err)
   697  	}
   698  	if failedReservation != nil {
   699  		t.Fatalf("reservation should be nil")
   700  	}
   701  
   702  	// Cancel the older reservation so it won't affect other tests.
   703  	if err := chanReservation.Cancel(); err != nil {
   704  		t.Fatalf("unable to cancel reservation: %v", err)
   705  	}
   706  }
   707  
   708  func testFundingCancellationNotEnoughFunds(miner *rpctest.Harness,
   709  	vw *rpctest.VotingWallet, alice, _ *lnwallet.LightningWallet,
   710  	t *testing.T) {
   711  
   712  	feePerKB, err := alice.Cfg.FeeEstimator.EstimateFeePerKB(1)
   713  	if err != nil {
   714  		t.Fatalf("unable to query fee estimator: %v", err)
   715  	}
   716  
   717  	totalBalance, err := alice.ConfirmedBalance(0, "")
   718  	if err != nil {
   719  		t.Fatalf("unable to fetch confirmed balance: %v", err)
   720  	}
   721  
   722  	// Create a reservation for almost the entire wallet amount.
   723  	fundingAmount := totalBalance - dcrutil.AtomsPerCoin
   724  	req := &lnwallet.InitFundingReserveMsg{
   725  		ChainHash:        chainHash,
   726  		NodeID:           bobPub,
   727  		NodeAddr:         bobAddr,
   728  		LocalFundingAmt:  fundingAmount,
   729  		RemoteFundingAmt: 0,
   730  		CommitFeePerKB:   feePerKB,
   731  		FundingFeePerKB:  feePerKB,
   732  		PushMAtoms:       0,
   733  		Flags:            lnwire.FFAnnounceChannel,
   734  		PendingChanID:    [32]byte{2, 3, 4, 5},
   735  	}
   736  	chanReservation, err := alice.InitChannelReservation(req)
   737  	if err != nil {
   738  		t.Fatalf("unable to initialize funding reservation: %v", err)
   739  	}
   740  
   741  	// Attempt to create another channel spending the same amount. This
   742  	// should fail.
   743  	req.PendingChanID = [32]byte{3, 4, 5, 6}
   744  	_, err = alice.InitChannelReservation(req)
   745  	if _, ok := err.(*chanfunding.ErrInsufficientFunds); !ok {
   746  		t.Fatalf("coin selection succeeded should have insufficient funds: %v",
   747  			err)
   748  	}
   749  
   750  	// Now cancel that old reservation.
   751  	if err := chanReservation.Cancel(); err != nil {
   752  		t.Fatalf("unable to cancel reservation: %v", err)
   753  	}
   754  
   755  	// Those outpoints should no longer be locked.
   756  	lockedOutPoints := alice.LockedOutpoints()
   757  	if len(lockedOutPoints) != 0 {
   758  		t.Fatalf("outpoints still locked")
   759  	}
   760  
   761  	// Reservation ID should no longer be tracked.
   762  	numReservations := alice.ActiveReservations()
   763  	if len(alice.ActiveReservations()) != 0 {
   764  		t.Fatalf("should have 0 reservations, instead have %v",
   765  			numReservations)
   766  	}
   767  
   768  	// TODO(roasbeef): create method like Balance that ignores locked
   769  	// outpoints, will let us fail early/fast instead of querying and
   770  	// attempting coin selection.
   771  
   772  	// Request to fund a new channel should now succeed.
   773  	req.PendingChanID = [32]byte{4, 5, 6, 7, 8}
   774  	if _, err := alice.InitChannelReservation(req); err != nil {
   775  		t.Fatalf("unable to initialize funding reservation: %v", err)
   776  	}
   777  }
   778  
   779  func testCancelNonExistentReservation(miner *rpctest.Harness,
   780  	vw *rpctest.VotingWallet, alice, _ *lnwallet.LightningWallet,
   781  	t *testing.T) {
   782  
   783  	feePerKB, err := alice.Cfg.FeeEstimator.EstimateFeePerKB(1)
   784  	if err != nil {
   785  		t.Fatalf("unable to query fee estimator: %v", err)
   786  	}
   787  
   788  	// Create our own reservation, give it some ID.
   789  	res, err := lnwallet.NewChannelReservation(
   790  		20000, 20000, feePerKB, alice, 22, 10, &testHdSeed,
   791  		lnwire.FFAnnounceChannel, lnwallet.CommitmentTypeTweakless,
   792  		nil, [32]byte{}, 0,
   793  	)
   794  	if err != nil {
   795  		t.Fatalf("unable to create res: %v", err)
   796  	}
   797  
   798  	// Attempt to cancel this reservation. This should fail, we know
   799  	// nothing of it.
   800  	if err := res.Cancel(); err == nil {
   801  		t.Fatalf("canceled non-existent reservation")
   802  	}
   803  }
   804  
   805  func testReservationInitiatorBalanceBelowDustCancel(miner *rpctest.Harness,
   806  	vw *rpctest.VotingWallet, alice, _ *lnwallet.LightningWallet,
   807  	t *testing.T) {
   808  
   809  	// We'll attempt to create a new reservation with an extremely high
   810  	// commitment fee rate. This should push our balance into the negative
   811  	// and result in a failure to create the reservation.
   812  	const numDCR = 4
   813  	fundingAmount, err := dcrutil.NewAmount(numDCR)
   814  	if err != nil {
   815  		t.Fatalf("unable to create amt: %v", err)
   816  	}
   817  
   818  	FeePerKB := chainfee.AtomPerKByte(
   819  		numDCR * numDCR * dcrutil.AtomsPerCoin,
   820  	)
   821  	req := &lnwallet.InitFundingReserveMsg{
   822  		ChainHash:        chainHash,
   823  		NodeID:           bobPub,
   824  		NodeAddr:         bobAddr,
   825  		LocalFundingAmt:  fundingAmount,
   826  		RemoteFundingAmt: 0,
   827  		CommitFeePerKB:   FeePerKB,
   828  		FundingFeePerKB:  1000,
   829  		PushMAtoms:       0,
   830  		Flags:            lnwire.FFAnnounceChannel,
   831  		CommitType:       lnwallet.CommitmentTypeTweakless,
   832  		PendingChanID:    [32]byte{11, 12, 13, 14},
   833  	}
   834  	_, err = alice.InitChannelReservation(req)
   835  	switch {
   836  	case err == nil:
   837  		t.Fatalf("initialization should have failed due to " +
   838  			"insufficient local amount")
   839  
   840  	case !strings.Contains(err.Error(), "funder balance too small"):
   841  		t.Fatalf("incorrect error: %v", err)
   842  	}
   843  }
   844  
   845  func assertContributionInitPopulated(t *testing.T, c *lnwallet.ChannelContribution) {
   846  	_, _, line, _ := runtime.Caller(1)
   847  
   848  	if c.FirstCommitmentPoint == nil {
   849  		t.Fatalf("line #%v: commitment point not fond", line)
   850  	}
   851  
   852  	if c.CsvDelay == 0 {
   853  		t.Fatalf("line #%v: csv delay not set", line)
   854  	}
   855  
   856  	if c.MultiSigKey.PubKey == nil {
   857  		t.Fatalf("line #%v: multi-sig key not set", line)
   858  	}
   859  	if c.RevocationBasePoint.PubKey == nil {
   860  		t.Fatalf("line #%v: revocation key not set", line)
   861  	}
   862  	if c.PaymentBasePoint.PubKey == nil {
   863  		t.Fatalf("line #%v: payment key not set", line)
   864  	}
   865  	if c.DelayBasePoint.PubKey == nil {
   866  		t.Fatalf("line #%v: delay key not set", line)
   867  	}
   868  
   869  	if c.DustLimit == 0 {
   870  		t.Fatalf("line #%v: dust limit not set", line)
   871  	}
   872  	if c.MaxPendingAmount == 0 {
   873  		t.Fatalf("line #%v: max pending amt not set", line)
   874  	}
   875  	if c.ChanReserve == 0 {
   876  		t.Fatalf("line #%v: chan reserve not set", line)
   877  	}
   878  	if c.MinHTLC == 0 {
   879  		t.Fatalf("line #%v: min htlc not set", line)
   880  	}
   881  	if c.MaxAcceptedHtlcs == 0 {
   882  		t.Fatalf("line #%v: max accepted htlc's not set", line)
   883  	}
   884  }
   885  
   886  func testSingleFunderReservationWorkflow(miner *rpctest.Harness,
   887  	vw *rpctest.VotingWallet,
   888  	alice, bob *lnwallet.LightningWallet, t *testing.T,
   889  	commitType lnwallet.CommitmentType,
   890  	aliceChanFunder chanfunding.Assembler, fetchFundingTx func() *wire.MsgTx,
   891  	pendingChanID [32]byte, thawHeight uint32) {
   892  
   893  	// For this scenario, Alice will be the channel initiator while bob
   894  	// will act as the responder to the workflow.
   895  
   896  	// First, Alice will Initialize a reservation for a channel with 4 DCR
   897  	// funded solely by us. We'll also initially push 1 DCR of the channel
   898  	// towards Bob's side.
   899  	fundingAmt, err := dcrutil.NewAmount(4)
   900  	if err != nil {
   901  		t.Fatalf("unable to create amt: %v", err)
   902  	}
   903  	pushAmt := lnwire.NewMAtomsFromAtoms(dcrutil.AtomsPerCoin)
   904  	feePerKB, err := alice.Cfg.FeeEstimator.EstimateFeePerKB(1)
   905  	if err != nil {
   906  		t.Fatalf("unable to query fee estimator: %v", err)
   907  	}
   908  	aliceReq := &lnwallet.InitFundingReserveMsg{
   909  		ChainHash:        chainHash,
   910  		PendingChanID:    pendingChanID,
   911  		NodeID:           bobPub,
   912  		NodeAddr:         bobAddr,
   913  		LocalFundingAmt:  fundingAmt,
   914  		RemoteFundingAmt: 0,
   915  		CommitFeePerKB:   feePerKB,
   916  		FundingFeePerKB:  feePerKB,
   917  		PushMAtoms:       pushAmt,
   918  		Flags:            lnwire.FFAnnounceChannel,
   919  		CommitType:       commitType,
   920  		ChanFunder:       aliceChanFunder,
   921  	}
   922  	aliceChanReservation, err := alice.InitChannelReservation(aliceReq)
   923  	if err != nil {
   924  		t.Fatalf("unable to init channel reservation: %v", err)
   925  	}
   926  	aliceChanReservation.SetNumConfsRequired(numReqConfs)
   927  	channelConstraints := &channeldb.ChannelConstraints{
   928  		DustLimit:        alice.Cfg.DefaultConstraints.DustLimit,
   929  		ChanReserve:      fundingAmt / 100,
   930  		MaxPendingAmount: lnwire.NewMAtomsFromAtoms(fundingAmt),
   931  		MinHTLC:          1,
   932  		MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
   933  		CsvDelay:         csvDelay,
   934  	}
   935  	err = aliceChanReservation.CommitConstraints(
   936  		channelConstraints, defaultMaxLocalCsvDelay, false,
   937  	)
   938  	if err != nil {
   939  		t.Fatalf("unable to verify constraints: %v", err)
   940  	}
   941  
   942  	// Verify all contribution fields have been set properly, but only if
   943  	// Alice is the funder herself.
   944  	aliceContribution := aliceChanReservation.OurContribution()
   945  	if fetchFundingTx == nil {
   946  		if len(aliceContribution.Inputs) < 1 {
   947  			t.Fatalf("outputs for funding tx not properly "+
   948  				"selected, have %v outputs should at least 1",
   949  				len(aliceContribution.Inputs))
   950  		}
   951  		if len(aliceContribution.ChangeOutputs) != 1 {
   952  			t.Fatalf("coin selection failed, should have one "+
   953  				"change outputs, instead have: %v",
   954  				len(aliceContribution.ChangeOutputs))
   955  		}
   956  	}
   957  	assertContributionInitPopulated(t, aliceContribution)
   958  
   959  	// Next, Bob receives the initial request, generates a corresponding
   960  	// reservation initiation, then consume Alice's contribution.
   961  	bobReq := &lnwallet.InitFundingReserveMsg{
   962  		ChainHash:        chainHash,
   963  		PendingChanID:    pendingChanID,
   964  		NodeID:           alicePub,
   965  		NodeAddr:         aliceAddr,
   966  		LocalFundingAmt:  0,
   967  		RemoteFundingAmt: fundingAmt,
   968  		CommitFeePerKB:   feePerKB,
   969  		FundingFeePerKB:  feePerKB,
   970  		PushMAtoms:       pushAmt,
   971  		Flags:            lnwire.FFAnnounceChannel,
   972  		CommitType:       commitType,
   973  	}
   974  	bobChanReservation, err := bob.InitChannelReservation(bobReq)
   975  	if err != nil {
   976  		t.Fatalf("unable to create bob reservation: %v", err)
   977  	}
   978  	err = bobChanReservation.CommitConstraints(
   979  		channelConstraints, defaultMaxLocalCsvDelay, true,
   980  	)
   981  	if err != nil {
   982  		t.Fatalf("unable to verify constraints: %v", err)
   983  	}
   984  	bobChanReservation.SetNumConfsRequired(numReqConfs)
   985  
   986  	// We'll ensure that Bob's contribution also gets generated properly.
   987  	bobContribution := bobChanReservation.OurContribution()
   988  	assertContributionInitPopulated(t, bobContribution)
   989  
   990  	// With his contribution generated, he can now process Alice's
   991  	// contribution.
   992  	err = bobChanReservation.ProcessSingleContribution(aliceContribution)
   993  	if err != nil {
   994  		t.Fatalf("bob unable to process alice's contribution: %v", err)
   995  	}
   996  	assertContributionInitPopulated(t, bobChanReservation.TheirContribution())
   997  
   998  	// Bob will next send over his contribution to Alice, we simulate this
   999  	// by having Alice immediately process his contribution.
  1000  	err = aliceChanReservation.ProcessContribution(bobContribution)
  1001  	if err != nil {
  1002  		t.Fatalf("alice unable to process bob's contribution: %v", err)
  1003  	}
  1004  	assertContributionInitPopulated(t, bobChanReservation.TheirContribution())
  1005  
  1006  	// At this point, Alice should have generated all the signatures
  1007  	// required for the funding transaction, as well as Alice's commitment
  1008  	// signature to bob, but only if the funding transaction was
  1009  	// constructed internally.
  1010  	aliceRemoteContribution := aliceChanReservation.TheirContribution()
  1011  	aliceFundingSigs, aliceCommitSig := aliceChanReservation.OurSignatures()
  1012  	if fetchFundingTx == nil && aliceFundingSigs == nil {
  1013  		t.Fatalf("funding sigs not found")
  1014  	}
  1015  	if aliceCommitSig == nil {
  1016  		t.Fatalf("commitment sig not found")
  1017  	}
  1018  
  1019  	// Additionally, the funding tx and the funding outpoint should have
  1020  	// been populated.
  1021  	if aliceChanReservation.FinalFundingTx() == nil && fetchFundingTx == nil {
  1022  		t.Fatalf("funding transaction never created!")
  1023  	}
  1024  	if aliceChanReservation.FundingOutpoint() == nil {
  1025  		t.Fatalf("funding outpoint never created!")
  1026  	}
  1027  
  1028  	// Their funds should also be filled in.
  1029  	if len(aliceRemoteContribution.Inputs) != 0 {
  1030  		t.Fatalf("bob shouldn't have any inputs, instead has %v",
  1031  			len(aliceRemoteContribution.Inputs))
  1032  	}
  1033  	if len(aliceRemoteContribution.ChangeOutputs) != 0 {
  1034  		t.Fatalf("bob shouldn't have any change outputs, instead "+
  1035  			"has %v",
  1036  			aliceRemoteContribution.ChangeOutputs[0].Value)
  1037  	}
  1038  
  1039  	// Next, Alice will send over her signature for Bob's commitment
  1040  	// transaction, as well as the funding outpoint.
  1041  	fundingPoint := aliceChanReservation.FundingOutpoint()
  1042  	_, err = bobChanReservation.CompleteReservationSingle(
  1043  		fundingPoint, aliceCommitSig,
  1044  	)
  1045  	if err != nil {
  1046  		t.Fatalf("bob unable to consume single reservation: %v", err)
  1047  	}
  1048  
  1049  	// Finally, we'll conclude the reservation process by sending over
  1050  	// Bob's commitment signature, which is the final thing Alice needs to
  1051  	// be able to safely broadcast the funding transaction.
  1052  	_, bobCommitSig := bobChanReservation.OurSignatures()
  1053  	if bobCommitSig == nil {
  1054  		t.Fatalf("bob failed to generate commitment signature: %v", err)
  1055  	}
  1056  	_, err = aliceChanReservation.CompleteReservation(
  1057  		nil, bobCommitSig,
  1058  	)
  1059  	if err != nil {
  1060  		t.Fatalf("alice unable to complete reservation: %v", err)
  1061  	}
  1062  
  1063  	// If the caller provided an alternative way to obtain the funding tx,
  1064  	// then we'll use that. Otherwise, we'll obtain it directly from Alice.
  1065  	var fundingTx *wire.MsgTx
  1066  	if fetchFundingTx != nil {
  1067  		fundingTx = fetchFundingTx()
  1068  	} else {
  1069  		fundingTx = aliceChanReservation.FinalFundingTx()
  1070  	}
  1071  
  1072  	// The resulting active channel state should have been persisted to the
  1073  	// DB for both Alice and Bob.
  1074  	fundingSha := fundingTx.TxHash()
  1075  	aliceChannels, err := alice.Cfg.Database.FetchOpenChannels(bobPub)
  1076  	if err != nil {
  1077  		t.Fatalf("unable to retrieve channel from DB: %v", err)
  1078  	}
  1079  	if len(aliceChannels) != 1 {
  1080  		t.Fatalf("alice didn't save channel state: %v", err)
  1081  	}
  1082  	if !bytes.Equal(aliceChannels[0].FundingOutpoint.Hash[:], fundingSha[:]) {
  1083  		t.Fatalf("channel state not properly saved: %v vs %v",
  1084  			hex.EncodeToString(aliceChannels[0].FundingOutpoint.Hash[:]),
  1085  			hex.EncodeToString(fundingSha[:]))
  1086  	}
  1087  	if !aliceChannels[0].IsInitiator {
  1088  		t.Fatalf("alice not detected as channel initiator")
  1089  	}
  1090  	if !aliceChannels[0].ChanType.IsSingleFunder() {
  1091  		t.Fatalf("channel type is incorrect, expected %v instead got %v",
  1092  			channeldb.SingleFunderBit, aliceChannels[0].ChanType)
  1093  	}
  1094  
  1095  	bobChannels, err := bob.Cfg.Database.FetchOpenChannels(alicePub)
  1096  	if err != nil {
  1097  		t.Fatalf("unable to retrieve channel from DB: %v", err)
  1098  	}
  1099  	if len(bobChannels) != 1 {
  1100  		t.Fatalf("bob didn't save channel state: %v", err)
  1101  	}
  1102  	if !bytes.Equal(bobChannels[0].FundingOutpoint.Hash[:], fundingSha[:]) {
  1103  		t.Fatalf("channel state not properly saved: %v vs %v",
  1104  			hex.EncodeToString(bobChannels[0].FundingOutpoint.Hash[:]),
  1105  			hex.EncodeToString(fundingSha[:]))
  1106  	}
  1107  	if bobChannels[0].IsInitiator {
  1108  		t.Fatalf("bob not detected as channel responder")
  1109  	}
  1110  	if !bobChannels[0].ChanType.IsSingleFunder() {
  1111  		t.Fatalf("channel type is incorrect, expected %v instead got %v",
  1112  			channeldb.SingleFunderBit, bobChannels[0].ChanType)
  1113  	}
  1114  
  1115  	// Let Alice publish the funding transaction.
  1116  	err = alice.PublishTransaction(fundingTx, "")
  1117  	if err != nil {
  1118  		t.Fatalf("unable to publish funding tx: %v", err)
  1119  	}
  1120  
  1121  	// Mine a single block, the funding transaction should be included
  1122  	// within this block.
  1123  	err = waitForMempoolTx(miner, &fundingSha)
  1124  	if err != nil {
  1125  		t.Fatalf("tx not relayed to miner: %v", err)
  1126  	}
  1127  	blockHashes, err := vw.GenerateBlocks(context.TODO(), 1)
  1128  	if err != nil {
  1129  		t.Fatalf("unable to generate block: %v", err)
  1130  	}
  1131  	block, err := miner.Node.GetBlock(context.TODO(), blockHashes[0])
  1132  	if err != nil {
  1133  		t.Fatalf("unable to find block: %v", err)
  1134  	}
  1135  	if len(block.Transactions) != 2 {
  1136  		t.Fatalf("funding transaction wasn't mined: %d",
  1137  			len(block.Transactions))
  1138  	}
  1139  	blockTx := block.Transactions[1]
  1140  	if blockTx.TxHash() != fundingSha {
  1141  		t.Fatalf("incorrect transaction was mined")
  1142  	}
  1143  
  1144  	// If a frozen channel was requested, then we expect that both channel
  1145  	// types show as being a frozen channel type.
  1146  	aliceChanFrozen := aliceChannels[0].ChanType.IsFrozen()
  1147  	bobChanFrozen := bobChannels[0].ChanType.IsFrozen()
  1148  	if thawHeight != 0 && (!aliceChanFrozen || !bobChanFrozen) {
  1149  		t.Fatalf("expected both alice and bob to have frozen chans: "+
  1150  			"alice_frozen=%v, bob_frozen=%v", aliceChanFrozen,
  1151  			bobChanFrozen)
  1152  	}
  1153  	if thawHeight != bobChannels[0].ThawHeight {
  1154  		t.Fatalf("wrong thaw height: expected %v got %v", thawHeight,
  1155  			bobChannels[0].ThawHeight)
  1156  	}
  1157  	if thawHeight != aliceChannels[0].ThawHeight {
  1158  		t.Fatalf("wrong thaw height: expected %v got %v", thawHeight,
  1159  			aliceChannels[0].ThawHeight)
  1160  	}
  1161  
  1162  	assertReservationDeleted(aliceChanReservation, t)
  1163  	assertReservationDeleted(bobChanReservation, t)
  1164  }
  1165  
  1166  func testListTransactionDetails(miner *rpctest.Harness,
  1167  	vw *rpctest.VotingWallet, alice, _ *lnwallet.LightningWallet,
  1168  	t *testing.T) {
  1169  
  1170  	// Create 5 new outputs spendable by the wallet.
  1171  	const numTxns = 5
  1172  	const outputAmt = dcrutil.AtomsPerCoin
  1173  	var err error
  1174  	addrs := make([]stdaddr.Address, numTxns)
  1175  	for i := 0; i < numTxns; i++ {
  1176  		addrs[i], err = alice.NewAddress(
  1177  			lnwallet.PubKeyHash, false,
  1178  			lnwallet.DefaultAccountName,
  1179  		)
  1180  		if err != nil {
  1181  			t.Fatalf("unable to create new address: %v", err)
  1182  		}
  1183  	}
  1184  
  1185  	// Let the wallet close the address manager (see issue dcrwallet#1372).
  1186  	time.Sleep(time.Millisecond * 50)
  1187  	ctxb := context.Background()
  1188  
  1189  	txids := make(map[chainhash.Hash]struct{})
  1190  	for i := 0; i < numTxns; i++ {
  1191  		script, err := input.PayToAddrScript(addrs[i])
  1192  		if err != nil {
  1193  			t.Fatalf("unable to create output script: %v", err)
  1194  		}
  1195  
  1196  		output := &wire.TxOut{
  1197  			Value:    outputAmt,
  1198  			PkScript: script,
  1199  		}
  1200  		txid, err := miner.SendOutputs(ctxb, []*wire.TxOut{output},
  1201  			dcrutil.Amount(defaultFeeRate))
  1202  		if err != nil {
  1203  			t.Fatalf("unable to send coinbase: %v", err)
  1204  		}
  1205  		txids[*txid] = struct{}{}
  1206  		err = waitForMempoolTx(miner, txid)
  1207  		if err != nil {
  1208  			t.Fatalf("unable to detect mempool tx: %v", err)
  1209  		}
  1210  	}
  1211  
  1212  	// Get the miner's current best block height before we mine blocks.
  1213  	_, startHeight, err := miner.Node.GetBestBlock(context.TODO())
  1214  	if err != nil {
  1215  		t.Fatalf("cannot get best block: %v", err)
  1216  	}
  1217  
  1218  	// Generate 10 blocks to mine all the transactions created above.
  1219  	const numBlocksMined = 10
  1220  	blocks, err := vw.GenerateBlocks(context.TODO(), numBlocksMined)
  1221  	if err != nil {
  1222  		t.Fatalf("unable to mine blocks: %v", err)
  1223  	}
  1224  
  1225  	// Our new best block height should be our start height + the number of
  1226  	// blocks we just mined.
  1227  	chainTip := startHeight + numBlocksMined
  1228  
  1229  	// Next, fetch all the current transaction details. We should find all
  1230  	// of our transactions between our start height before we generated
  1231  	// blocks, and our end height, which is the chain tip. This query does
  1232  	// not include unconfirmed transactions, since all of our transactions
  1233  	// should be confirmed.
  1234  	err = waitForWalletSync(miner, alice)
  1235  	if err != nil {
  1236  		t.Fatalf("Couldn't sync Alice's wallet: %v", err)
  1237  	}
  1238  	txDetails, err := alice.ListTransactionDetails(
  1239  		int32(startHeight), int32(chainTip), "",
  1240  	)
  1241  	if err != nil {
  1242  		t.Fatalf("unable to fetch tx details: %v", err)
  1243  	}
  1244  
  1245  	// This is a mapping from:
  1246  	// blockHash -> transactionHash -> transactionOutputs
  1247  	blockTxOuts := make(map[chainhash.Hash]map[chainhash.Hash][]*wire.TxOut)
  1248  
  1249  	// Each of the transactions created above should be found with the
  1250  	// proper details populated.
  1251  	for _, txDetail := range txDetails {
  1252  		if _, ok := txids[txDetail.Hash]; !ok {
  1253  			continue
  1254  		}
  1255  
  1256  		if txDetail.NumConfirmations != numBlocksMined {
  1257  			t.Fatalf("num confs incorrect, got %v expected %v",
  1258  				txDetail.NumConfirmations, numBlocksMined)
  1259  		}
  1260  		if txDetail.Value != outputAmt {
  1261  			t.Fatalf("tx value incorrect, got %v expected %v",
  1262  				txDetail.Value, outputAmt)
  1263  		}
  1264  
  1265  		if !bytes.Equal(txDetail.BlockHash[:], blocks[0][:]) {
  1266  			t.Fatalf("block hash mismatch, got %v expected %v",
  1267  				txDetail.BlockHash, blocks[0])
  1268  		}
  1269  
  1270  		// This fetches the transactions in a block so that we can compare the
  1271  		// txouts stored in the mined transaction against the ones in the transaction
  1272  		// details
  1273  		if _, ok := blockTxOuts[*txDetail.BlockHash]; !ok {
  1274  			fetchedBlock, err := alice.Cfg.ChainIO.GetBlock(txDetail.BlockHash)
  1275  			if err != nil {
  1276  				t.Fatalf("err fetching block: %s", err)
  1277  			}
  1278  
  1279  			transactions :=
  1280  				make(map[chainhash.Hash][]*wire.TxOut, len(fetchedBlock.Transactions))
  1281  			for _, tx := range fetchedBlock.Transactions {
  1282  				transactions[tx.TxHash()] = tx.TxOut
  1283  			}
  1284  
  1285  			blockTxOuts[fetchedBlock.BlockHash()] = transactions
  1286  		}
  1287  
  1288  		if txOuts, ok := blockTxOuts[*txDetail.BlockHash][txDetail.Hash]; !ok {
  1289  			t.Fatalf("tx (%v) not found in block (%v)",
  1290  				txDetail.Hash, txDetail.BlockHash)
  1291  		} else {
  1292  			var destinationAddresses []stdaddr.Address
  1293  
  1294  			for _, txOut := range txOuts {
  1295  				_, addrs :=
  1296  					stdscript.ExtractAddrs(txOut.Version, txOut.PkScript,
  1297  						&alice.Cfg.NetParams)
  1298  				destinationAddresses = append(destinationAddresses, addrs...)
  1299  			}
  1300  
  1301  			if !reflect.DeepEqual(txDetail.DestAddresses, destinationAddresses) {
  1302  				t.Fatalf("destination addresses mismatch, got %v expected %v",
  1303  					txDetail.DestAddresses, destinationAddresses)
  1304  			}
  1305  		}
  1306  
  1307  		delete(txids, txDetail.Hash)
  1308  	}
  1309  	if len(txids) != 0 {
  1310  		t.Fatalf("all transactions not found in details: left=%v, "+
  1311  			"returned_set=%v", spew.Sdump(txids),
  1312  			spew.Sdump(txDetails))
  1313  	}
  1314  
  1315  	// Next create a transaction paying to an output which isn't under the
  1316  	// wallet's control.
  1317  	b := txscript.NewScriptBuilder()
  1318  	b.AddOp(txscript.OP_0)
  1319  	outputScript, err := b.Script()
  1320  	if err != nil {
  1321  		t.Fatalf("unable to make output script: %v", err)
  1322  	}
  1323  	burnOutput := wire.NewTxOut(outputAmt, outputScript)
  1324  	burnTX, err := alice.SendOutputs(
  1325  		[]*wire.TxOut{burnOutput}, defaultFeeRate, 1, labels.External, "",
  1326  	)
  1327  	if err != nil {
  1328  		t.Fatalf("unable to create burn tx: %v", err)
  1329  	}
  1330  	burnTXID := burnTX.TxHash()
  1331  	err = waitForMempoolTx(miner, &burnTXID)
  1332  	if err != nil {
  1333  		t.Fatalf("tx not relayed to miner: %v", err)
  1334  	}
  1335  
  1336  	// Before we mine the next block, we'll ensure that the above
  1337  	// transaction shows up in the set of unconfirmed transactions returned
  1338  	// by ListTransactionDetails.
  1339  	err = waitForWalletSync(miner, alice)
  1340  	if err != nil {
  1341  		t.Fatalf("Couldn't sync Alice's wallet: %v", err)
  1342  	}
  1343  
  1344  	// Query our wallet for transactions from the chain tip, including
  1345  	// unconfirmed transactions. The transaction above should be included
  1346  	// with a confirmation height of 0, indicating that it has not been
  1347  	// mined yet.
  1348  	txDetails, err = alice.ListTransactionDetails(
  1349  		int32(chainTip), dcrwallet.UnconfirmedHeight, "",
  1350  	)
  1351  	if err != nil {
  1352  		t.Fatalf("unable to fetch tx details: %v", err)
  1353  	}
  1354  	var mempoolTxFound bool
  1355  	for _, txDetail := range txDetails {
  1356  		if !bytes.Equal(txDetail.Hash[:], burnTXID[:]) {
  1357  			continue
  1358  		}
  1359  
  1360  		// Now that we've found the transaction, ensure that it has a
  1361  		// negative number of confirmations to indicate that it's
  1362  		// unconfirmed.
  1363  		mempoolTxFound = true
  1364  		if txDetail.NumConfirmations != 0 {
  1365  			t.Fatalf("num confs incorrect, got %v expected %v",
  1366  				txDetail.NumConfirmations, 0)
  1367  		}
  1368  	}
  1369  	if !mempoolTxFound {
  1370  		t.Fatalf("unable to find mempool tx in tx details!")
  1371  	}
  1372  
  1373  	// Generate one block for our transaction to confirm in.
  1374  	var numBlocks int32 = 1
  1375  	burnBlock, err := vw.GenerateBlocks(context.TODO(), uint32(numBlocks))
  1376  	if err != nil {
  1377  		t.Fatalf("unable to mine block: %v", err)
  1378  	}
  1379  
  1380  	// Progress our chain tip by the number of blocks we have just mined.
  1381  	chainTip += int64(numBlocks)
  1382  
  1383  	// Fetch the transaction details again, the new transaction should be
  1384  	// shown as debiting from the wallet's balance. Start and end height
  1385  	// are inclusive, so we use chainTip for both parameters to get only
  1386  	// transactions from the last block.
  1387  	err = waitForWalletSync(miner, alice)
  1388  	if err != nil {
  1389  		t.Fatalf("Couldn't sync Alice's wallet: %v", err)
  1390  	}
  1391  	txDetails, err = alice.ListTransactionDetails(
  1392  		int32(chainTip), int32(chainTip), "",
  1393  	)
  1394  	if err != nil {
  1395  		t.Fatalf("unable to fetch tx details: %v", err)
  1396  	}
  1397  	var burnTxFound bool
  1398  	for _, txDetail := range txDetails {
  1399  		if !bytes.Equal(txDetail.Hash[:], burnTXID[:]) {
  1400  			continue
  1401  		}
  1402  
  1403  		burnTxFound = true
  1404  		if txDetail.NumConfirmations != 1 {
  1405  			t.Fatalf("num confs incorrect, got %v expected %v",
  1406  				txDetail.NumConfirmations, 1)
  1407  		}
  1408  
  1409  		// We assert that the value is greater than the amount we
  1410  		// attempted to send, as the wallet should have paid some amount
  1411  		// of network fees.
  1412  		if txDetail.Value >= -outputAmt {
  1413  			fmt.Println(spew.Sdump(txDetail))
  1414  			t.Fatalf("tx value incorrect, got %v expected %v",
  1415  				int64(txDetail.Value), -int64(outputAmt))
  1416  		}
  1417  		if !bytes.Equal(txDetail.BlockHash[:], burnBlock[0][:]) {
  1418  			t.Fatalf("block hash mismatch, got %v expected %v",
  1419  				txDetail.BlockHash, burnBlock[0])
  1420  		}
  1421  	}
  1422  	if !burnTxFound {
  1423  		t.Fatal("tx burning dcr not found")
  1424  	}
  1425  
  1426  	// Generate a block which has no wallet transactions in it.
  1427  	chainTip += int64(numBlocks)
  1428  	_, err = miner.Node.Generate(context.TODO(), uint32(numBlocks))
  1429  	if err != nil {
  1430  		t.Fatalf("unable to mine block: %v", err)
  1431  	}
  1432  
  1433  	err = waitForWalletSync(miner, alice)
  1434  	if err != nil {
  1435  		t.Fatalf("Couldn't sync Alice's wallet: %v", err)
  1436  	}
  1437  
  1438  	// Query for transactions only in the latest block. We do not expect
  1439  	// any transactions to be returned.
  1440  	txDetails, err = alice.ListTransactionDetails(
  1441  		int32(chainTip), int32(chainTip), "",
  1442  	)
  1443  	if err != nil {
  1444  		t.Fatalf("unexpected error: %v", err)
  1445  	}
  1446  	if len(txDetails) != 0 {
  1447  		t.Fatalf("expected 0 transactions, got: %v", len(txDetails))
  1448  	}
  1449  }
  1450  
  1451  func testTransactionSubscriptions(miner *rpctest.Harness,
  1452  	vw *rpctest.VotingWallet, alice, _ *lnwallet.LightningWallet,
  1453  	t *testing.T) {
  1454  
  1455  	// Generate a block and wait for wallet sync to ensure any outstanding
  1456  	// txs from previous tests won't interfere with this test.
  1457  	if _, err := vw.GenerateBlocks(context.TODO(), 1); err != nil {
  1458  		t.Fatalf("unable to generate block: %v", err)
  1459  	}
  1460  	err := waitForWalletSync(miner, alice)
  1461  	if err != nil {
  1462  		t.Fatalf("Couldn't sync Alice's wallet: %v", err)
  1463  	}
  1464  
  1465  	// First, check to see if this wallet meets the TransactionNotifier
  1466  	// interface, if not then we'll skip this test for this particular
  1467  	// implementation of the WalletController.
  1468  	txClient, err := alice.SubscribeTransactions()
  1469  	if err != nil {
  1470  		t.Skipf("unable to generate tx subscription: %v", err)
  1471  	}
  1472  	defer txClient.Cancel()
  1473  
  1474  	const (
  1475  		outputAmt = dcrutil.AtomsPerCoin
  1476  		numTxns   = 3
  1477  	)
  1478  	errCh1 := make(chan error, 1)
  1479  	switch alice.BackEnd() {
  1480  	case "neutrino":
  1481  		// Neutrino doesn't listen for unconfirmed transactions.
  1482  	default:
  1483  		go func() {
  1484  			for i := 0; i < numTxns; i++ {
  1485  				txDetail := <-txClient.UnconfirmedTransactions()
  1486  				if txDetail.NumConfirmations != 0 {
  1487  					errCh1 <- fmt.Errorf("incorrect number of confs, "+
  1488  						"expected %v got %v", 0,
  1489  						txDetail.NumConfirmations)
  1490  					return
  1491  				}
  1492  				if txDetail.Value != outputAmt {
  1493  					errCh1 <- fmt.Errorf("incorrect output amt, "+
  1494  						"expected %v got %v", outputAmt,
  1495  						txDetail.Value)
  1496  					return
  1497  				}
  1498  				if txDetail.BlockHash != nil {
  1499  					errCh1 <- fmt.Errorf("block hash should be nil, "+
  1500  						"is instead %v",
  1501  						txDetail.BlockHash)
  1502  					return
  1503  				}
  1504  			}
  1505  			errCh1 <- nil
  1506  		}()
  1507  	}
  1508  
  1509  	// Next, fetch a fresh address from the wallet, create 3 new outputs
  1510  	// with the pkScript.
  1511  	addrs := make([]stdaddr.Address, numTxns)
  1512  	for i := 0; i < numTxns; i++ {
  1513  		addrs[i], err = alice.NewAddress(
  1514  			lnwallet.PubKeyHash, false,
  1515  			lnwallet.DefaultAccountName,
  1516  		)
  1517  		if err != nil {
  1518  			t.Fatalf("unable to create new address: %v", err)
  1519  		}
  1520  	}
  1521  
  1522  	// Sleep to allow the wallet's address manager to close (see issue
  1523  	// dcrwallet#1372).
  1524  	time.Sleep(time.Millisecond * 50)
  1525  	ctxb := context.Background()
  1526  
  1527  	for i := 0; i < numTxns; i++ {
  1528  		script, err := input.PayToAddrScript(addrs[i])
  1529  		if err != nil {
  1530  			t.Fatalf("unable to create output script: %v", err)
  1531  		}
  1532  
  1533  		output := &wire.TxOut{
  1534  			Value:    outputAmt,
  1535  			PkScript: script,
  1536  		}
  1537  		txid, err := miner.SendOutputs(ctxb, []*wire.TxOut{output},
  1538  			dcrutil.Amount(defaultFeeRate))
  1539  		if err != nil {
  1540  			t.Fatalf("unable to send coinbase: %v", err)
  1541  		}
  1542  		err = waitForMempoolTx(miner, txid)
  1543  		if err != nil {
  1544  			t.Fatalf("tx not relayed to miner: %v", err)
  1545  		}
  1546  	}
  1547  
  1548  	switch alice.BackEnd() {
  1549  	case "neutrino":
  1550  		// Neutrino doesn't listen for on unconfirmed transactions.
  1551  	default:
  1552  		// We should receive a notification for all three transactions
  1553  		// generated above.
  1554  		select {
  1555  		case <-time.After(time.Second * 10):
  1556  			t.Fatalf("transactions not received after 10 seconds")
  1557  		case err := <-errCh1:
  1558  			if err != nil {
  1559  				t.Fatal(err)
  1560  			}
  1561  		}
  1562  	}
  1563  
  1564  	errCh2 := make(chan error, 1)
  1565  	go func() {
  1566  		for i := 0; i < numTxns; i++ {
  1567  			txDetail := <-txClient.ConfirmedTransactions()
  1568  			if txDetail.NumConfirmations != 1 {
  1569  				errCh2 <- fmt.Errorf("incorrect number of confs for %s, expected %v got %v",
  1570  					txDetail.Hash, 1, txDetail.NumConfirmations)
  1571  				return
  1572  			}
  1573  			if txDetail.Value != outputAmt {
  1574  				errCh2 <- fmt.Errorf("incorrect output amt, expected %v got %v in txid %s",
  1575  					outputAmt, txDetail.Value, txDetail.Hash)
  1576  				return
  1577  			}
  1578  		}
  1579  		errCh2 <- nil
  1580  	}()
  1581  
  1582  	// Next mine a single block, all the transactions generated above
  1583  	// should be included.
  1584  	if _, err := vw.GenerateBlocks(context.TODO(), 1); err != nil {
  1585  		t.Fatalf("unable to generate block: %v", err)
  1586  	}
  1587  
  1588  	// We should receive a notification for all three transactions
  1589  	// since they should be mined in the next block.
  1590  	select {
  1591  	case <-time.After(time.Second * 5):
  1592  		t.Fatalf("transactions not received after 5 seconds")
  1593  	case err := <-errCh2:
  1594  		if err != nil {
  1595  			t.Fatal(err)
  1596  		}
  1597  	}
  1598  
  1599  	// We'll also ensure that the client is able to send our new
  1600  	// notifications when we _create_ transactions ourselves that spend our
  1601  	// own outputs.
  1602  	b := txscript.NewScriptBuilder()
  1603  	b.AddOp(txscript.OP_RETURN)
  1604  	outputScript, err := b.Script()
  1605  	if err != nil {
  1606  		t.Fatalf("unable to make output script: %v", err)
  1607  	}
  1608  	burnOutput := wire.NewTxOut(outputAmt, outputScript)
  1609  	tx, err := alice.SendOutputs(
  1610  		[]*wire.TxOut{burnOutput}, defaultFeeRate, 1, labels.External, "",
  1611  	)
  1612  	if err != nil {
  1613  		t.Fatalf("unable to create burn tx: %v", err)
  1614  	}
  1615  	txid := tx.TxHash()
  1616  	err = waitForMempoolTx(miner, &txid)
  1617  	if err != nil {
  1618  		t.Fatalf("tx not relayed to miner: %v", err)
  1619  	}
  1620  
  1621  	// Before we mine the next block, we'll ensure that the above
  1622  	// transaction shows up in the set of unconfirmed transactions returned
  1623  	// by ListTransactionDetails.
  1624  	err = waitForWalletSync(miner, alice)
  1625  	if err != nil {
  1626  		t.Fatalf("Couldn't sync Alice's wallet: %v", err)
  1627  	}
  1628  
  1629  	// As we just sent the transaction and it was landed in the mempool, we
  1630  	// should get a notification for a new unconfirmed transactions
  1631  	select {
  1632  	case <-time.After(time.Second * 10):
  1633  		t.Fatalf("transactions not received after 10 seconds")
  1634  	case unConfTx := <-txClient.UnconfirmedTransactions():
  1635  		if unConfTx.Hash != txid {
  1636  			t.Fatalf("wrong txn notified: expected %v got %v",
  1637  				txid, unConfTx.Hash)
  1638  		}
  1639  	}
  1640  }
  1641  
  1642  // scriptFromKey creates a P2WKH script from the given pubkey.
  1643  func scriptFromKey(pubkey *secp256k1.PublicKey) ([]byte, error) {
  1644  	pubkeyHash := dcrutil.Hash160(pubkey.SerializeCompressed())
  1645  	keyAddr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(
  1646  		pubkeyHash, chaincfg.SimNetParams(),
  1647  	)
  1648  	if err != nil {
  1649  		return nil, fmt.Errorf("unable to create addr: %v", err)
  1650  	}
  1651  	keyScript, err := input.PayToAddrScript(keyAddr)
  1652  	if err != nil {
  1653  		return nil, fmt.Errorf("unable to generate script: %v", err)
  1654  	}
  1655  
  1656  	return keyScript, nil
  1657  }
  1658  
  1659  // mineAndAssert mines a block and ensures the passed TX is part of that block.
  1660  func mineAndAssert(r *rpctest.Harness, vw *rpctest.VotingWallet, tx *wire.MsgTx) error {
  1661  	txid := tx.TxHash()
  1662  	err := waitForMempoolTx(r, &txid)
  1663  	if err != nil {
  1664  		return fmt.Errorf("tx not relayed to miner: %v", err)
  1665  	}
  1666  
  1667  	blockHashes, err := vw.GenerateBlocks(context.TODO(), 1)
  1668  	if err != nil {
  1669  		return fmt.Errorf("unable to generate block: %v", err)
  1670  	}
  1671  
  1672  	block, err := r.Node.GetBlock(context.TODO(), blockHashes[0])
  1673  	if err != nil {
  1674  		return fmt.Errorf("unable to find block: %v", err)
  1675  	}
  1676  
  1677  	if len(block.Transactions) != 2 {
  1678  		return fmt.Errorf("expected 2 txs in block, got %d",
  1679  			len(block.Transactions))
  1680  	}
  1681  
  1682  	blockTx := block.Transactions[1]
  1683  	if blockTx.TxHash() != tx.TxHash() {
  1684  		return fmt.Errorf("incorrect transaction was mined")
  1685  	}
  1686  
  1687  	// Sleep for a second before returning, to make sure the block has
  1688  	// propagated.
  1689  	time.Sleep(1 * time.Second)
  1690  	return nil
  1691  }
  1692  
  1693  // txFromOutput takes a tx paying to fromPubKey, and creates a new tx that
  1694  // spends the output from this tx, to an address derived from payToPubKey.
  1695  func txFromOutput(tx *wire.MsgTx, signer input.Signer, fromPubKey,
  1696  	payToPubKey *secp256k1.PublicKey, txFee dcrutil.Amount,
  1697  	rbf bool) (*wire.MsgTx, error) {
  1698  
  1699  	// Generate the script we want to spend from.
  1700  	keyScript, err := scriptFromKey(fromPubKey)
  1701  	if err != nil {
  1702  		return nil, fmt.Errorf("unable to generate script: %v", err)
  1703  	}
  1704  
  1705  	// We assume the output was paid to the keyScript made earlier.
  1706  	var outputIndex uint32
  1707  	if len(tx.TxOut) == 1 || bytes.Equal(tx.TxOut[0].PkScript, keyScript) {
  1708  		outputIndex = 0
  1709  	} else {
  1710  		outputIndex = 1
  1711  	}
  1712  	outputValue := tx.TxOut[outputIndex].Value
  1713  
  1714  	// With the index located, we can create a transaction spending the
  1715  	// referenced output.
  1716  	tx1 := wire.NewMsgTx()
  1717  	tx1.Version = 2
  1718  
  1719  	// If we want to create a tx that signals replacement, set its
  1720  	// sequence number to the max one that signals replacement.
  1721  	// Otherwise we just use the standard max sequence.
  1722  	sequence := wire.MaxTxInSequenceNum
  1723  	if rbf {
  1724  		sequence = 0xfffffffd // mempool.MaxRBFSequence
  1725  	}
  1726  
  1727  	tx1.AddTxIn(&wire.TxIn{
  1728  		PreviousOutPoint: wire.OutPoint{
  1729  			Hash:  tx.TxHash(),
  1730  			Index: outputIndex,
  1731  			Tree:  wire.TxTreeRegular,
  1732  		},
  1733  		Sequence: sequence,
  1734  	})
  1735  
  1736  	// Create a script to pay to.
  1737  	payToScript, err := scriptFromKey(payToPubKey)
  1738  	if err != nil {
  1739  		return nil, fmt.Errorf("unable to generate script: %v", err)
  1740  	}
  1741  	tx1.AddTxOut(&wire.TxOut{
  1742  		Value:    outputValue - int64(txFee),
  1743  		PkScript: payToScript,
  1744  	})
  1745  
  1746  	// Now we can populate the sign descriptor which we'll use to generate
  1747  	// the signature.
  1748  	signDesc := &input.SignDescriptor{
  1749  		KeyDesc: keychain.KeyDescriptor{
  1750  			PubKey: fromPubKey,
  1751  		},
  1752  		WitnessScript: keyScript,
  1753  		Output:        tx.TxOut[outputIndex],
  1754  		HashType:      txscript.SigHashAll,
  1755  		InputIndex:    0, // Has only one input.
  1756  	}
  1757  
  1758  	// With the descriptor created, we use it to generate a signature, then
  1759  	// manually create a valid witness stack we'll use for signing.
  1760  	spendSig, err := signer.SignOutputRaw(tx1, signDesc)
  1761  	if err != nil {
  1762  		return nil, fmt.Errorf("unable to generate signature: %v", err)
  1763  	}
  1764  	witness := make([][]byte, 2)
  1765  	witness[0] = append(spendSig.Serialize(), byte(txscript.SigHashAll))
  1766  	witness[1] = fromPubKey.SerializeCompressed()
  1767  	tx1.TxIn[0].SignatureScript, err = input.WitnessStackToSigScript(witness)
  1768  	if err != nil {
  1769  		return nil, fmt.Errorf("unable to convert witness stack to sigScript: %v", err)
  1770  	}
  1771  
  1772  	// Finally, attempt to validate the completed transaction. This should
  1773  	// succeed if the wallet was able to properly generate the proper
  1774  	// private key.
  1775  	vm, err := txscript.NewEngine(
  1776  		keyScript, tx1, 0, input.ScriptVerifyFlags, tx.TxOut[outputIndex].Version, nil,
  1777  	)
  1778  	if err != nil {
  1779  		return nil, fmt.Errorf("unable to create engine: %v", err)
  1780  	}
  1781  	if err := vm.Execute(); err != nil {
  1782  		return nil, fmt.Errorf("spend is invalid: %v", err)
  1783  	}
  1784  
  1785  	return tx1, nil
  1786  }
  1787  
  1788  // newTx sends coins from Alice's wallet, mines this transaction, and creates a
  1789  // new, unconfirmed tx that spends this output to pubKey.
  1790  func newTx(t *testing.T, r *rpctest.Harness, vw *rpctest.VotingWallet, pubKey *secp256k1.PublicKey,
  1791  	alice *lnwallet.LightningWallet, rbf bool) *wire.MsgTx {
  1792  	t.Helper()
  1793  
  1794  	keyScript, err := scriptFromKey(pubKey)
  1795  	if err != nil {
  1796  		t.Fatalf("unable to generate script: %v", err)
  1797  	}
  1798  
  1799  	// Instruct the wallet to fund the output with a newly created
  1800  	// transaction.
  1801  	newOutput := &wire.TxOut{
  1802  		Value:    dcrutil.AtomsPerCoin,
  1803  		PkScript: keyScript,
  1804  	}
  1805  	tx, err := alice.SendOutputs(
  1806  		[]*wire.TxOut{newOutput}, defaultFeeRate, 1, labels.External, "",
  1807  	)
  1808  	if err != nil {
  1809  		t.Fatalf("unable to create output: %v", err)
  1810  	}
  1811  
  1812  	// Query for the transaction generated above so we can located the
  1813  	// index of our output.
  1814  	if err := mineAndAssert(r, vw, tx); err != nil {
  1815  		t.Fatalf("unable to mine tx: %v", err)
  1816  	}
  1817  
  1818  	// Create a new unconfirmed tx that spends this output.
  1819  	txFee := dcrutil.Amount(defaultFeeRate)
  1820  	tx1, err := txFromOutput(
  1821  		tx, alice.Cfg.Signer, pubKey, pubKey, txFee, rbf,
  1822  	)
  1823  	if err != nil {
  1824  		t.Fatal(err)
  1825  	}
  1826  
  1827  	return tx1
  1828  }
  1829  
  1830  // testPublishTransaction checks that PublishTransaction returns the expected
  1831  // error types in case the transaction being published conflicts with the
  1832  // current mempool or chain.
  1833  func testPublishTransaction(r *rpctest.Harness, vw *rpctest.VotingWallet,
  1834  	alice, _ *lnwallet.LightningWallet, t *testing.T) {
  1835  
  1836  	// Generate a pubkey, and pay-to-addr script.
  1837  	keyDesc, err := alice.DeriveNextKey(keychain.KeyFamilyMultiSig)
  1838  	if err != nil {
  1839  		t.Fatalf("unable to obtain public key: %v", err)
  1840  	}
  1841  
  1842  	// We will first check that publishing a transaction already in the
  1843  	// mempool does NOT return an error. Create the tx.
  1844  	tx1 := newTx(t, r, vw, keyDesc.PubKey, alice, false)
  1845  
  1846  	// Publish the transaction.
  1847  	err = alice.PublishTransaction(tx1, labels.External)
  1848  	if err != nil {
  1849  		t.Fatalf("unable to publish: %v", err)
  1850  	}
  1851  
  1852  	txid1 := tx1.TxHash()
  1853  	err = waitForMempoolTx(r, &txid1)
  1854  	if err != nil {
  1855  		t.Fatalf("tx not relayed to miner: %v", err)
  1856  	}
  1857  
  1858  	// Publish the exact same transaction again. This should not return an
  1859  	// error, even though the transaction is already in the mempool.
  1860  	err = alice.PublishTransaction(tx1, labels.External)
  1861  	if err != nil {
  1862  		t.Fatalf("unable to publish: %v", err)
  1863  	}
  1864  
  1865  	// Mine the transaction.
  1866  	if _, err := vw.GenerateBlocks(context.TODO(), 1); err != nil {
  1867  		t.Fatalf("unable to generate block: %v", err)
  1868  	}
  1869  
  1870  	// We'll now test that we don't get an error if we try to publish a
  1871  	// transaction that is already mined.
  1872  	//
  1873  	// Create a new transaction. We must do this to properly test the
  1874  	// reject messages from our peers. They might only send us a reject
  1875  	// message for a given tx once, so we create a new to make sure it is
  1876  	// not just immediately rejected.
  1877  	tx2 := newTx(t, r, vw, keyDesc.PubKey, alice, false)
  1878  
  1879  	// Publish this tx.
  1880  	err = alice.PublishTransaction(tx2, labels.External)
  1881  	if err != nil {
  1882  		t.Fatalf("unable to publish: %v", err)
  1883  	}
  1884  
  1885  	// Mine the transaction.
  1886  	if err := mineAndAssert(r, vw, tx2); err != nil {
  1887  		t.Fatalf("unable to mine tx: %v", err)
  1888  	}
  1889  
  1890  	// Publish the transaction again. It is already mined, and we don't
  1891  	// expect this to return an error.
  1892  	err = alice.PublishTransaction(tx2, labels.External)
  1893  	if err != nil {
  1894  		t.Fatalf("unable to publish: %v", err)
  1895  	}
  1896  
  1897  	// We'll do the next mempool check on both RBF and non-RBF enabled
  1898  	// transactions.
  1899  	var (
  1900  		txFee         = dcrutil.Amount(defaultFeeRate * 5)
  1901  		tx3, tx3Spend *wire.MsgTx
  1902  	)
  1903  
  1904  	// Note: decred does not support rbf at this time, so test only with
  1905  	// rbf == false.
  1906  	rbfTests := []bool{false}
  1907  	for _, rbf := range rbfTests {
  1908  		// Now we'll try to double spend an output with a different
  1909  		// transaction. Create a new tx and publish it. This is the
  1910  		// output we'll try to double spend.
  1911  		tx3 = newTx(t, r, vw, keyDesc.PubKey, alice, false)
  1912  		err := alice.PublishTransaction(tx3, labels.External)
  1913  		if err != nil {
  1914  			t.Fatalf("unable to publish: %v", err)
  1915  		}
  1916  
  1917  		// Mine the transaction.
  1918  		if err := mineAndAssert(r, vw, tx3); err != nil {
  1919  			t.Fatalf("unable to mine tx: %v", err)
  1920  		}
  1921  
  1922  		// Now we create a transaction that spends the output from the
  1923  		// tx just mined.
  1924  		tx4, err := txFromOutput(
  1925  			tx3, alice.Cfg.Signer, keyDesc.PubKey,
  1926  			keyDesc.PubKey, txFee, rbf,
  1927  		)
  1928  		if err != nil {
  1929  			t.Fatal(err)
  1930  		}
  1931  
  1932  		// This should be accepted into the mempool.
  1933  		err = alice.PublishTransaction(tx4, labels.External)
  1934  		if err != nil {
  1935  			t.Fatalf("unable to publish: %v", err)
  1936  		}
  1937  
  1938  		// Keep track of the last successfully published tx to spend
  1939  		// tx3.
  1940  		tx3Spend = tx4
  1941  
  1942  		txid4 := tx4.TxHash()
  1943  		err = waitForMempoolTx(r, &txid4)
  1944  		if err != nil {
  1945  			t.Fatalf("tx not relayed to miner: %v", err)
  1946  		}
  1947  
  1948  		// Create a new key we'll pay to, to ensure we create a unique
  1949  		// transaction.
  1950  		keyDesc2, err := alice.DeriveNextKey(
  1951  			keychain.KeyFamilyMultiSig,
  1952  		)
  1953  		if err != nil {
  1954  			t.Fatalf("unable to obtain public key: %v", err)
  1955  		}
  1956  
  1957  		// Create a new transaction that spends the output from tx3,
  1958  		// and that pays to a different address. We expect this to be
  1959  		// rejected because it is a double spend.
  1960  		tx5, err := txFromOutput(
  1961  			tx3, alice.Cfg.Signer, keyDesc.PubKey,
  1962  			keyDesc2.PubKey, txFee, rbf,
  1963  		)
  1964  		if err != nil {
  1965  			t.Fatal(err)
  1966  		}
  1967  
  1968  		err = alice.PublishTransaction(tx5, labels.External)
  1969  		if err != lnwallet.ErrDoubleSpend {
  1970  			t.Fatalf("expected ErrDoubleSpend, got: %v", err)
  1971  		}
  1972  
  1973  		// Create another transaction that spends the same output, but
  1974  		// has a higher fee. We expect also this tx to be rejected for
  1975  		// non-RBF enabled transactions, while it should succeed
  1976  		// otherwise.
  1977  		pubKey3, err := alice.DeriveNextKey(keychain.KeyFamilyMultiSig)
  1978  		if err != nil {
  1979  			t.Fatalf("unable to obtain public key: %v", err)
  1980  		}
  1981  		tx6, err := txFromOutput(
  1982  			tx3, alice.Cfg.Signer, keyDesc.PubKey,
  1983  			pubKey3.PubKey, 2*txFee, rbf,
  1984  		)
  1985  		if err != nil {
  1986  			t.Fatal(err)
  1987  		}
  1988  
  1989  		// Expect rejection in non-RBF case.
  1990  		expErr := lnwallet.ErrDoubleSpend
  1991  		if rbf {
  1992  			// Expect success in rbf case.
  1993  			expErr = nil
  1994  			tx3Spend = tx6
  1995  		}
  1996  		err = alice.PublishTransaction(tx6, labels.External)
  1997  		if err != expErr {
  1998  			t.Fatalf("expected ErrDoubleSpend, got: %v", err)
  1999  		}
  2000  
  2001  		// Mine the tx spending tx3.
  2002  		if err := mineAndAssert(r, vw, tx3Spend); err != nil {
  2003  			t.Fatalf("unable to mine tx: %v", err)
  2004  		}
  2005  	}
  2006  
  2007  	// At last we try to spend an output already spent by a confirmed
  2008  	// transaction.
  2009  	//
  2010  	// TODO(halseth): we currently skip this test for neutrino, as the
  2011  	// backing btcd node will consider the tx being an orphan, and will
  2012  	// accept it. Should look into if this is the behavior also for
  2013  	// bitcoind, and update test accordingly.
  2014  	//
  2015  	// TODO(decred) wallet/v3 also changed the semantics to simply ignore
  2016  	// spent output errors and return nil when publishing a double spend
  2017  	// that was already mined, so we ignore this test as well.
  2018  	if alice.BackEnd() == "disabled" {
  2019  		// Create another tx spending tx3.
  2020  		pubKey4, err := alice.DeriveNextKey(
  2021  			keychain.KeyFamilyMultiSig,
  2022  		)
  2023  		if err != nil {
  2024  			t.Fatalf("unable to obtain public key: %v", err)
  2025  		}
  2026  		tx7, err := txFromOutput(
  2027  			tx3, alice.Cfg.Signer, keyDesc.PubKey,
  2028  			pubKey4.PubKey, txFee, false,
  2029  		)
  2030  
  2031  		if err != nil {
  2032  			t.Fatal(err)
  2033  		}
  2034  
  2035  		// Expect rejection.
  2036  		err = alice.PublishTransaction(tx7, labels.External)
  2037  		if err != lnwallet.ErrDoubleSpend {
  2038  			t.Fatalf("expected ErrDoubleSpend, got: %v", err)
  2039  		}
  2040  	}
  2041  }
  2042  
  2043  func testSignOutputUsingTweaks(r *rpctest.Harness,
  2044  	avw *rpctest.VotingWallet, alice, _ *lnwallet.LightningWallet,
  2045  	t *testing.T) {
  2046  
  2047  	// We'd like to test the ability of the wallet's input.Signer implementation
  2048  	// to be able to sign with a private key derived from tweaking the
  2049  	// specific public key. This scenario exercises the case when the
  2050  	// wallet needs to sign for a sweep of a revoked output, or just claim
  2051  	// any output that pays to a tweaked key.
  2052  
  2053  	// First, generate a new public key under the control of the wallet,
  2054  	// then generate a revocation key using it.
  2055  	pubKey, err := alice.DeriveNextKey(
  2056  		keychain.KeyFamilyMultiSig,
  2057  	)
  2058  	if err != nil {
  2059  		t.Fatalf("unable to obtain public key: %v", err)
  2060  	}
  2061  
  2062  	// As we'd like to test both single tweak, and double tweak spends,
  2063  	// we'll generate a commitment pre-image, then derive a revocation key
  2064  	// and single tweak from that.
  2065  	commitPreimage := bytes.Repeat([]byte{2}, 32)
  2066  	commitSecret := secp256k1.PrivKeyFromBytes(commitPreimage)
  2067  	commitPoint := commitSecret.PubKey()
  2068  
  2069  	revocationKey := input.DeriveRevocationPubkey(pubKey.PubKey, commitPoint)
  2070  	commitTweak := input.SingleTweakBytes(commitPoint, pubKey.PubKey)
  2071  
  2072  	tweakedPub := input.TweakPubKey(pubKey.PubKey, commitPoint)
  2073  
  2074  	// As we'd like to test both single and double tweaks, we'll repeat
  2075  	// the same set up twice. The first will use a regular single tweak,
  2076  	// and the second will use a double tweak.
  2077  	baseKey := pubKey
  2078  	for i := 0; i < 2; i++ {
  2079  		var tweakedKey *secp256k1.PublicKey
  2080  		if i == 0 {
  2081  			tweakedKey = tweakedPub
  2082  		} else {
  2083  			tweakedKey = revocationKey
  2084  		}
  2085  
  2086  		// Using the given key for the current iteration, we'll
  2087  		// generate a regular p2wkh from that.
  2088  		pubkeyHash := dcrutil.Hash160(tweakedKey.SerializeCompressed())
  2089  		keyAddr, err := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(pubkeyHash,
  2090  			netParams)
  2091  		if err != nil {
  2092  			t.Fatalf("unable to create addr: %v", err)
  2093  		}
  2094  		keyScript, err := input.PayToAddrScript(keyAddr)
  2095  		if err != nil {
  2096  			t.Fatalf("unable to generate script: %v", err)
  2097  		}
  2098  
  2099  		// With the script fully assembled, instruct the wallet to fund
  2100  		// the output with a newly created transaction.
  2101  		newOutput := &wire.TxOut{
  2102  			Value:    dcrutil.AtomsPerCoin,
  2103  			PkScript: keyScript,
  2104  			Version:  scriptVersion,
  2105  		}
  2106  		tx, err := alice.SendOutputs(
  2107  			[]*wire.TxOut{newOutput}, defaultFeeRate, 1, labels.External, "",
  2108  		)
  2109  		if err != nil {
  2110  			t.Fatalf("unable to create output: %v", err)
  2111  		}
  2112  		txid := tx.TxHash()
  2113  		// Query for the transaction generated above so we can located
  2114  		// the index of our output.
  2115  		err = waitForMempoolTx(r, &txid)
  2116  		if err != nil {
  2117  			t.Fatalf("tx not relayed to miner: %v", err)
  2118  		}
  2119  		var outputIndex uint32
  2120  		if bytes.Equal(tx.TxOut[0].PkScript, keyScript) {
  2121  			outputIndex = 0
  2122  		} else {
  2123  			outputIndex = 1
  2124  		}
  2125  
  2126  		// With the index located, we can create a transaction spending
  2127  		// the referenced output.
  2128  		sweepTx := wire.NewMsgTx()
  2129  		sweepTx.AddTxIn(&wire.TxIn{
  2130  			PreviousOutPoint: wire.OutPoint{
  2131  				Hash:  txid,
  2132  				Index: outputIndex,
  2133  				Tree:  wire.TxTreeRegular,
  2134  			},
  2135  		})
  2136  		sweepTx.AddTxOut(&wire.TxOut{
  2137  			Value:    1000,
  2138  			PkScript: keyScript,
  2139  			Version:  scriptVersion,
  2140  		})
  2141  
  2142  		// Now we can populate the sign descriptor which we'll use to
  2143  		// generate the signature. Within the descriptor we set the
  2144  		// private tweak value as the key in the script is derived
  2145  		// based on this tweak value and the key we originally
  2146  		// generated above.
  2147  		signDesc := &input.SignDescriptor{
  2148  			KeyDesc: keychain.KeyDescriptor{
  2149  				PubKey: baseKey.PubKey,
  2150  			},
  2151  			WitnessScript: keyScript,
  2152  			Output:        newOutput,
  2153  			HashType:      txscript.SigHashAll,
  2154  			InputIndex:    0,
  2155  		}
  2156  
  2157  		// If this is the first, loop, we'll use the generated single
  2158  		// tweak, otherwise, we'll use the double tweak.
  2159  		if i == 0 {
  2160  			signDesc.SingleTweak = commitTweak
  2161  		} else {
  2162  			signDesc.DoubleTweak = commitSecret
  2163  		}
  2164  
  2165  		// With the descriptor created, we use it to generate a
  2166  		// signature, then manually create a valid witness stack we'll
  2167  		// use for signing.
  2168  		spendSig, err := alice.Cfg.Signer.SignOutputRaw(sweepTx, signDesc)
  2169  		if err != nil {
  2170  			t.Fatalf("unable to generate signature: %v", err)
  2171  		}
  2172  		witness := make([][]byte, 2)
  2173  		witness[0] = append(spendSig.Serialize(), byte(txscript.SigHashAll))
  2174  		witness[1] = tweakedKey.SerializeCompressed()
  2175  		sweepTx.TxIn[0].SignatureScript, err = input.WitnessStackToSigScript(witness)
  2176  		if err != nil {
  2177  			t.Fatalf("unable to convert witness stack to sigScript: %v", err)
  2178  		}
  2179  
  2180  		// Finally, attempt to validate the completed transaction. This
  2181  		// should succeed if the wallet was able to properly generate
  2182  		// the proper private key.
  2183  		vm, err := txscript.NewEngine(keyScript,
  2184  			sweepTx, 0, input.ScriptVerifyFlags, newOutput.Version, nil)
  2185  		if err != nil {
  2186  			t.Fatalf("unable to create engine: %v", err)
  2187  		}
  2188  		if err := vm.Execute(); err != nil {
  2189  			t.Fatalf("spend #%v is invalid: %v", i, err)
  2190  		}
  2191  	}
  2192  }
  2193  
  2194  func testReorgWalletBalance(r *rpctest.Harness, vw *rpctest.VotingWallet,
  2195  	w *lnwallet.LightningWallet, _ *lnwallet.LightningWallet,
  2196  	t *testing.T) {
  2197  
  2198  	ctxb := context.Background()
  2199  
  2200  	// Currently disabled due to
  2201  	// https://github.com/decred/dcrwallet/issues/1710. Re-assess after
  2202  	// that is fixed.
  2203  	if w.BackEnd() == "dcrw-spv" {
  2204  		t.Skipf("Skipping for SPV for the moment")
  2205  	}
  2206  
  2207  	// We first mine a few blocks to ensure any transactions still in the
  2208  	// mempool confirm, and then get the original balance, before a
  2209  	// reorganization that doesn't invalidate any existing transactions or
  2210  	// create any new non-coinbase transactions. We'll then check if it's
  2211  	// the same after the empty reorg.
  2212  	_, err := vw.GenerateBlocks(ctxb, 5)
  2213  	if err != nil {
  2214  		t.Fatalf("unable to generate blocks on passed node: %v", err)
  2215  	}
  2216  
  2217  	// Give wallet time to catch up.
  2218  	err = waitForWalletSync(r, w)
  2219  	if err != nil {
  2220  		t.Fatalf("unable to sync wallet: %v", err)
  2221  	}
  2222  
  2223  	// Send some money from the miner to the wallet
  2224  	err = loadTestCredits(r, w, vw.GenerateBlocks, 20, 4)
  2225  	if err != nil {
  2226  		t.Fatalf("unable to send money to lnwallet: %v", err)
  2227  	}
  2228  
  2229  	// Send some money from the wallet back to the miner.
  2230  	// Grab a fresh address from the miner to house this output.
  2231  	minerAddr, err := r.NewAddress(ctxb)
  2232  	if err != nil {
  2233  		t.Fatalf("unable to generate address for miner: %v", err)
  2234  	}
  2235  	script, err := input.PayToAddrScript(minerAddr)
  2236  	if err != nil {
  2237  		t.Fatalf("unable to create pay to addr script: %v", err)
  2238  	}
  2239  	output := &wire.TxOut{
  2240  		Value:    1e8,
  2241  		PkScript: script,
  2242  	}
  2243  	tx, err := w.SendOutputs(
  2244  		[]*wire.TxOut{output}, defaultFeeRate, 1, labels.External, "",
  2245  	)
  2246  	if err != nil {
  2247  		t.Fatalf("unable to send outputs: %v", err)
  2248  	}
  2249  	txid := tx.TxHash()
  2250  	err = waitForMempoolTx(r, &txid)
  2251  	if err != nil {
  2252  		t.Fatalf("tx not relayed to miner: %v", err)
  2253  	}
  2254  	_, err = vw.GenerateBlocks(ctxb, 3)
  2255  	if err != nil {
  2256  		t.Fatalf("unable to generate blocks on passed node: %v", err)
  2257  	}
  2258  
  2259  	// Give wallet time to catch up.
  2260  	err = waitForWalletSync(r, w)
  2261  	if err != nil {
  2262  		t.Fatalf("unable to sync wallet: %v", err)
  2263  	}
  2264  
  2265  	// Get the original balance.
  2266  	origBalance, err := w.ConfirmedBalance(1, lnwallet.DefaultAccountName)
  2267  	if err != nil {
  2268  		t.Fatalf("unable to query for balance: %v", err)
  2269  	}
  2270  
  2271  	// Now we cause a reorganization as follows.
  2272  	// Step 1: create a new miner and start it.
  2273  	r2, err := testutils.NewSetupRPCTest(testctx.New(t), 5, r.ActiveNet, nil, []string{"--txindex"}, false, 0)
  2274  	if err != nil {
  2275  		t.Fatalf("unable to create temp miner: %v", err)
  2276  	}
  2277  	defer r2.TearDown()
  2278  	newBalance, err := w.ConfirmedBalance(1, lnwallet.DefaultAccountName)
  2279  	if err != nil {
  2280  		t.Fatalf("unable to query for balance: %v", err)
  2281  	}
  2282  	if origBalance != newBalance {
  2283  		t.Fatalf("wallet balance incorrect, should have %v, "+
  2284  			"instead have %v", origBalance, newBalance)
  2285  	}
  2286  
  2287  	// Step 2: connect the miner to the passed miner and wait for
  2288  	// synchronization.
  2289  	err = rpctest.ConnectNode(ctxb, r2, r)
  2290  	if err != nil {
  2291  		t.Fatalf("unable to connect mining nodes together: %v", err)
  2292  	}
  2293  	err = rpctest.JoinNodes(ctxb, []*rpctest.Harness{r2, r}, rpctest.Blocks)
  2294  	if err != nil {
  2295  		t.Fatalf("unable to synchronize mining nodes: %v", err)
  2296  	}
  2297  
  2298  	mineFirst := func(nb uint32) ([]*chainhash.Hash, error) {
  2299  		return vw.GenerateBlocks(ctxb, nb)
  2300  	}
  2301  	mineSecond := func(nb uint32) ([]*chainhash.Hash, error) {
  2302  		return rpctest.AdjustedSimnetMiner(context.Background(), r2.Node, nb)
  2303  	}
  2304  
  2305  	// Step 3: Do a set of reorgs by disconnecting the two miners, mining
  2306  	// one block on the passed miner and two on the created miner,
  2307  	// connecting them, and waiting for them to sync.
  2308  	for i := 0; i < 5; i++ {
  2309  		// Wait for disconnection
  2310  		timeout := time.After(30 * time.Second)
  2311  		stillConnected := true
  2312  		for stillConnected {
  2313  			// Allow for timeout
  2314  			time.Sleep(100 * time.Millisecond)
  2315  			select {
  2316  			case <-timeout:
  2317  				t.Fatalf("timeout waiting for miner disconnect")
  2318  			default:
  2319  			}
  2320  			err = rpctest.RemoveNode(ctxb, r2, r)
  2321  			if err != nil {
  2322  				t.Fatalf("unable to disconnect mining nodes: %v",
  2323  					err)
  2324  			}
  2325  			stillConnected, err = rpctest.NodesConnected(ctxb, r2, r, true)
  2326  			if err != nil {
  2327  				t.Fatalf("error checking node connectivity: %v",
  2328  					err)
  2329  			}
  2330  		}
  2331  		_, err = mineFirst(2)
  2332  		if err != nil {
  2333  			t.Fatalf("unable to generate blocks on passed node: %v",
  2334  				err)
  2335  		}
  2336  		_, err = mineSecond(3)
  2337  		if err != nil {
  2338  			t.Fatalf("unable to generate blocks on created node: %v",
  2339  				err)
  2340  		}
  2341  
  2342  		// Give wallet time to catch up so we force a full reorg.
  2343  		err = waitForWalletSync(r, w)
  2344  		if err != nil {
  2345  			t.Fatalf("unable to sync wallet: %v", err)
  2346  		}
  2347  
  2348  		// Step 5: Reconnect the miners and wait for them to synchronize.
  2349  		err = rpctest.ConnectNode(ctxb, r2, r)
  2350  		if err != nil {
  2351  			switch err := err.(type) {
  2352  			case *dcrjson.RPCError:
  2353  				if err.Code != -8 {
  2354  					t.Fatalf("unable to connect mining "+
  2355  						"nodes together: %v", err)
  2356  				}
  2357  			default:
  2358  				t.Fatalf("unable to connect mining nodes "+
  2359  					"together: %v", err)
  2360  			}
  2361  		}
  2362  		err = rpctest.JoinNodes(ctxb, []*rpctest.Harness{r2, r},
  2363  			rpctest.Blocks)
  2364  		if err != nil {
  2365  			t.Fatalf("unable to synchronize mining nodes: %v", err)
  2366  		}
  2367  
  2368  		// Give wallet time to catch up.
  2369  		err = waitForWalletSync(r, w)
  2370  		if err != nil {
  2371  			t.Fatalf("unable to sync wallet: %v", err)
  2372  		}
  2373  	}
  2374  
  2375  	// Now we check that the wallet balance stays the same.
  2376  	newBalance, err = w.ConfirmedBalance(1, lnwallet.DefaultAccountName)
  2377  	if err != nil {
  2378  		t.Fatalf("unable to query for balance: %v", err)
  2379  	}
  2380  	if origBalance != newBalance {
  2381  		t.Fatalf("wallet balance incorrect, should have %v, "+
  2382  			"instead have %v", origBalance, newBalance)
  2383  	}
  2384  }
  2385  
  2386  // testChangeOutputSpendConfirmation ensures that when we attempt to spend a
  2387  // change output created by the wallet, the wallet receives its confirmation
  2388  // once included in the chain.
  2389  func testChangeOutputSpendConfirmation(r *rpctest.Harness,
  2390  	vw *rpctest.VotingWallet, alice, bob *lnwallet.LightningWallet,
  2391  	t *testing.T) {
  2392  
  2393  	// In order to test that we see the confirmation of a transaction that
  2394  	// spends an output created by SendOutputs, we'll start by emptying
  2395  	// Alice's wallet so that no other UTXOs can be picked. To do so, we'll
  2396  	// generate an address for Bob, who will receive all the coins.
  2397  	// Assuming a balance of 80 DCR and a transaction fee of 2500 atom/kB,
  2398  	// we'll craft the following transaction so that Alice doesn't have any
  2399  	// UTXOs left.
  2400  	aliceBalance, err := alice.ConfirmedBalance(0, lnwallet.DefaultAccountName)
  2401  	if err != nil {
  2402  		t.Fatalf("unable to retrieve alice's balance: %v", err)
  2403  	}
  2404  	bobPkScript := newPkScript(t, bob, lnwallet.PubKeyHash)
  2405  
  2406  	// A transaction to sweep all 80 DCR that should be in the wallet will
  2407  	// be estimated to have ~3407 bytes, so calculate what a tx of that size
  2408  	// will pay in fees and remove from the total amount.
  2409  	//
  2410  	// TODO(wilmer): replace this once SendOutputs easily supports sending
  2411  	// all funds in one transaction.
  2412  	txFeeRate := defaultFeeRate
  2413  	txFee := txFeeRate.FeeForSize(3407)
  2414  	output := &wire.TxOut{
  2415  		Value:    int64(aliceBalance - txFee),
  2416  		PkScript: bobPkScript,
  2417  	}
  2418  	tx := sendCoins(t, r, vw, alice, bob, output, txFeeRate, true, 1)
  2419  	txHash := tx.TxHash()
  2420  	assertTxInWallet(t, alice, txHash, true)
  2421  	assertTxInWallet(t, bob, txHash, true)
  2422  
  2423  	// With the transaction sent and confirmed, Alice's balance should now
  2424  	// be 0.
  2425  	aliceBalance, err = alice.ConfirmedBalance(0, lnwallet.DefaultAccountName)
  2426  	if err != nil {
  2427  		t.Fatalf("unable to retrieve alice's balance: %v", err)
  2428  	}
  2429  	if aliceBalance != 0 {
  2430  		t.Fatalf("expected alice's balance to be 0 DCR, found %v",
  2431  			aliceBalance)
  2432  	}
  2433  
  2434  	// Now, we'll send an output back to Alice from Bob of 1 DCR.
  2435  	alicePkScript := newPkScript(t, alice, lnwallet.PubKeyHash)
  2436  	output = &wire.TxOut{
  2437  		Value:    dcrutil.AtomsPerCoin,
  2438  		PkScript: alicePkScript,
  2439  		Version:  scriptVersion,
  2440  	}
  2441  	tx = sendCoins(t, r, vw, bob, alice, output, txFeeRate, true, 1)
  2442  	txHash = tx.TxHash()
  2443  	assertTxInWallet(t, alice, txHash, true)
  2444  	assertTxInWallet(t, bob, txHash, true)
  2445  
  2446  	// Alice now has an available output to spend, but it was not a change
  2447  	// output, which is what the test expects. Therefore, we'll generate one
  2448  	// by sending Bob back some coins.
  2449  	output = &wire.TxOut{
  2450  		Value:    dcrutil.AtomsPerCent,
  2451  		PkScript: bobPkScript,
  2452  	}
  2453  	tx = sendCoins(t, r, vw, alice, bob, output, txFeeRate, true, 1)
  2454  	txHash = tx.TxHash()
  2455  	assertTxInWallet(t, alice, txHash, true)
  2456  	assertTxInWallet(t, bob, txHash, true)
  2457  
  2458  	// Then, we'll spend the change output and ensure we see its
  2459  	// confirmation come in.
  2460  	tx = sendCoins(t, r, vw, alice, bob, output, txFeeRate, true, 1)
  2461  	txHash = tx.TxHash()
  2462  	assertTxInWallet(t, alice, txHash, true)
  2463  	assertTxInWallet(t, bob, txHash, true)
  2464  
  2465  	// Finally, we'll replenish Alice's wallet with some more coins to
  2466  	// ensure she has enough for any following test cases.
  2467  	if err := loadTestCredits(r, alice, vw.GenerateBlocks, 20, 4); err != nil {
  2468  		t.Fatalf("unable to replenish alice's wallet: %v", err)
  2469  	}
  2470  }
  2471  
  2472  // testSpendUnconfirmed ensures that when can spend unconfirmed outputs.
  2473  func testSpendUnconfirmed(miner *rpctest.Harness, vw *rpctest.VotingWallet,
  2474  	alice, bob *lnwallet.LightningWallet, t *testing.T) {
  2475  
  2476  	bobPkScript := newPkScript(t, bob, lnwallet.PubKeyHash)
  2477  	alicePkScript := newPkScript(t, alice, lnwallet.PubKeyHash)
  2478  	txFeeRate := defaultFeeRate
  2479  
  2480  	// First we will empty out bob's wallet, sending the entire balance
  2481  	// to alice. We check the balance by listing the utxos to calculate
  2482  	// the required tx fee.
  2483  	var bobBalance dcrutil.Amount
  2484  	utxos, err := bob.ListUnspentWitness(0, math.MaxInt32, "")
  2485  	require.Nil(t, err)
  2486  	var sz input.TxSizeEstimator
  2487  	for _, u := range utxos {
  2488  		bobBalance += u.Value
  2489  		sz.AddP2PKHInput()
  2490  	}
  2491  	sz.AddP2PKHOutput()
  2492  
  2493  	// The wallet internally adds a possible change output when estimating
  2494  	// the size, therefore we add _another_ p2pkh output to account for that
  2495  	// and avoid an error when spending the full amount. The resulting change
  2496  	// will be dust, and the wallet will not actually add the change output.
  2497  	sz.AddP2PKHOutput()
  2498  
  2499  	txFee := txFeeRate.FeeForSize(sz.Size()) // Fee to spend bob's utxos to 1 output
  2500  	output := &wire.TxOut{
  2501  		Value:    int64(bobBalance - txFee),
  2502  		PkScript: alicePkScript,
  2503  	}
  2504  
  2505  	tx := sendCoins(t, miner, vw, bob, alice, output, txFeeRate, true, 1)
  2506  	txHash := tx.TxHash()
  2507  	assertTxInWallet(t, alice, txHash, true)
  2508  	assertTxInWallet(t, bob, txHash, true)
  2509  
  2510  	// Verify that bob doesn't have enough balance to send coins.
  2511  	output = &wire.TxOut{
  2512  		Value:    dcrutil.AtomsPerCoin * 0.5,
  2513  		PkScript: alicePkScript,
  2514  	}
  2515  	_, err = bob.SendOutputs(
  2516  		[]*wire.TxOut{output}, txFeeRate, 0, labels.External, "",
  2517  	)
  2518  	if err == nil {
  2519  		t.Fatalf("should have not been able to pay due to insufficient balance: %v", err)
  2520  	}
  2521  
  2522  	// Next we will send a transaction to bob but leave it in an
  2523  	// unconfirmed state.
  2524  	output = &wire.TxOut{
  2525  		Value:    dcrutil.AtomsPerCoin,
  2526  		PkScript: bobPkScript,
  2527  	}
  2528  	tx = sendCoins(t, miner, vw, alice, bob, output, txFeeRate, false, 1)
  2529  	txHash = tx.TxHash()
  2530  	assertTxInWallet(t, alice, txHash, false)
  2531  	assertTxInWallet(t, bob, txHash, false)
  2532  
  2533  	// Now, try to spend some of the unconfirmed funds from bob's wallet.
  2534  	output = &wire.TxOut{
  2535  		Value:    dcrutil.AtomsPerCoin * 0.5,
  2536  		PkScript: alicePkScript,
  2537  	}
  2538  
  2539  	// First, verify that we don't have enough balance to send the coins
  2540  	// using confirmed outputs only.
  2541  	_, err = bob.SendOutputs(
  2542  		[]*wire.TxOut{output}, txFeeRate, 1, labels.External, "",
  2543  	)
  2544  	if err == nil {
  2545  		t.Fatalf("should have not been able to pay due to insufficient balance: %v", err)
  2546  	}
  2547  
  2548  	// Now try the send again using unconfirmed outputs.
  2549  	tx = sendCoins(t, miner, vw, bob, alice, output, txFeeRate, false, 0)
  2550  	txHash = tx.TxHash()
  2551  	assertTxInWallet(t, alice, txHash, false)
  2552  	assertTxInWallet(t, bob, txHash, false)
  2553  
  2554  	// Mine the unconfirmed transactions.
  2555  	err = waitForMempoolTx(miner, &txHash)
  2556  	if err != nil {
  2557  		t.Fatalf("tx not relayed to miner: %v", err)
  2558  	}
  2559  	if _, err := vw.GenerateBlocks(context.TODO(), 1); err != nil {
  2560  		t.Fatalf("unable to generate block: %v", err)
  2561  	}
  2562  	if err := waitForWalletSync(miner, alice); err != nil {
  2563  		t.Fatalf("unable to sync alice: %v", err)
  2564  	}
  2565  	if err := waitForWalletSync(miner, bob); err != nil {
  2566  		t.Fatalf("unable to sync bob: %v", err)
  2567  	}
  2568  
  2569  	// Finally, send the remainder of bob's wallet balance back to him so
  2570  	// that these money movements dont mess up later tests.
  2571  	output = &wire.TxOut{
  2572  		Value:    int64(bobBalance) - (dcrutil.AtomsPerCoin * 0.4),
  2573  		PkScript: bobPkScript,
  2574  	}
  2575  	tx = sendCoins(t, miner, vw, alice, bob, output, txFeeRate, true, 1)
  2576  	txHash = tx.TxHash()
  2577  	assertTxInWallet(t, alice, txHash, true)
  2578  	assertTxInWallet(t, bob, txHash, true)
  2579  }
  2580  
  2581  // testLastUnusedAddr tests that the LastUnusedAddress returns the address if
  2582  // it isn't used, and also that once the address becomes used, then it's
  2583  // properly rotated.
  2584  func testLastUnusedAddr(miner *rpctest.Harness,
  2585  	vw *rpctest.VotingWallet,
  2586  	alice, bob *lnwallet.LightningWallet, t *testing.T) {
  2587  
  2588  	// This is unimplemented on remotedcrwallet, but it's a bad
  2589  	// idea to use anyway and isn't currently used anywhere in the
  2590  	// code except the rpcserver, which we don't use anyway.
  2591  	if alice.BackEnd() == "remotedcrwallet" {
  2592  		t.Skip()
  2593  	}
  2594  
  2595  	if _, err := vw.GenerateBlocks(context.TODO(), 1); err != nil {
  2596  		t.Fatalf("unable to generate block: %v", err)
  2597  	}
  2598  
  2599  	// We'll repeat this test for each address type to ensure they're all
  2600  	// rotated properly.
  2601  	addrTypes := []lnwallet.AddressType{
  2602  		lnwallet.PubKeyHash,
  2603  	}
  2604  	for _, addrType := range addrTypes {
  2605  		addr1, err := alice.LastUnusedAddress(
  2606  			addrType, lnwallet.DefaultAccountName,
  2607  		)
  2608  		if err != nil {
  2609  			t.Fatalf("unable to get addr: %v", err)
  2610  		}
  2611  		addr2, err := alice.LastUnusedAddress(
  2612  			addrType, lnwallet.DefaultAccountName,
  2613  		)
  2614  		if err != nil {
  2615  			t.Fatalf("unable to get addr: %v", err)
  2616  		}
  2617  
  2618  		// If we generate two addresses back to back, then we should
  2619  		// get the same addr, as none of them have been used yet.
  2620  		if addr1.String() != addr2.String() {
  2621  			t.Fatalf("addresses changed w/o use: %v vs %v", addr1, addr2)
  2622  		}
  2623  
  2624  		// Next, we'll have Bob pay to Alice's new address. This should
  2625  		// trigger address rotation at the backend wallet.
  2626  		addrScript, err := input.PayToAddrScript(addr1)
  2627  		if err != nil {
  2628  			t.Fatalf("unable to convert addr to script: %v", err)
  2629  		}
  2630  		feeRate := chainfee.AtomPerKByte(1e4)
  2631  		output := &wire.TxOut{
  2632  			Value:    1000000,
  2633  			PkScript: addrScript,
  2634  		}
  2635  		sendCoins(t, miner, vw, bob, alice, output, feeRate, true, 1)
  2636  
  2637  		// If we make a new address, then it should be brand new, as
  2638  		// the prior address has been used.
  2639  		addr3, err := alice.LastUnusedAddress(
  2640  			addrType, lnwallet.DefaultAccountName,
  2641  		)
  2642  		if err != nil {
  2643  			t.Fatalf("unable to get addr: %v", err)
  2644  		}
  2645  		if addr1.String() == addr3.String() {
  2646  			t.Fatalf("address should have changed but didn't")
  2647  		}
  2648  	}
  2649  }
  2650  
  2651  // testManyNewAddresses checks that the underlying wallet driver can generate
  2652  // many new on-chain addresses without erroring. This verifies a bug that
  2653  // could cause the wallet to use the wrong wrapping mode for new addresses.
  2654  func testManyNewAddresses(r *rpctest.Harness, vw *rpctest.VotingWallet,
  2655  	w, _ *lnwallet.LightningWallet, t *testing.T) {
  2656  	const maxAddrs = 40
  2657  	for i := 0; i < maxAddrs; i++ {
  2658  		_, err := w.NewAddress(lnwallet.PubKeyHash, false, lnwallet.DefaultAccountName)
  2659  		if err != nil {
  2660  			t.Fatalf("unable to generate new address %d: %v", i, err)
  2661  		}
  2662  	}
  2663  }
  2664  
  2665  // testCreateSimpleTx checks that a call to CreateSimpleTx will return a
  2666  // transaction that is equal to the one that is being created by SendOutputs in
  2667  // a subsequent call.
  2668  func testCreateSimpleTx(r *rpctest.Harness, // nolint: unused
  2669  	vw *rpctest.VotingWallet,
  2670  	w, _ *lnwallet.LightningWallet, t *testing.T) {
  2671  
  2672  	// Send some money from the miner to the wallet
  2673  	err := loadTestCredits(r, w, vw.GenerateBlocks, 20, 4)
  2674  	if err != nil {
  2675  		t.Fatalf("unable to send money to lnwallet: %v", err)
  2676  	}
  2677  
  2678  	// The test cases we will run through for all backends.
  2679  	testCases := []struct {
  2680  		outVals     []int64
  2681  		feeRate     chainfee.AtomPerKByte
  2682  		valid       bool
  2683  		unconfirmed bool
  2684  	}{
  2685  		{
  2686  			outVals:     []int64{},
  2687  			feeRate:     2500,
  2688  			valid:       false, // No outputs.
  2689  			unconfirmed: false,
  2690  		},
  2691  		{
  2692  			outVals:     []int64{},
  2693  			feeRate:     2500,
  2694  			valid:       false, // No outputs.
  2695  			unconfirmed: true,
  2696  		},
  2697  
  2698  		{
  2699  			outVals:     []int64{1e3},
  2700  			feeRate:     2500,
  2701  			valid:       false, // Dust output.
  2702  			unconfirmed: false,
  2703  		},
  2704  		{
  2705  			outVals:     []int64{1e3},
  2706  			feeRate:     2500,
  2707  			valid:       false, // Dust output.
  2708  			unconfirmed: true,
  2709  		},
  2710  		{
  2711  			outVals:     []int64{1e8},
  2712  			feeRate:     2500,
  2713  			valid:       true,
  2714  			unconfirmed: false,
  2715  		},
  2716  		{
  2717  			outVals:     []int64{1e8},
  2718  			feeRate:     2500,
  2719  			valid:       true,
  2720  			unconfirmed: true,
  2721  		},
  2722  
  2723  		{
  2724  			outVals:     []int64{1e8, 2e8, 1e8, 2e7, 3e5},
  2725  			feeRate:     2500,
  2726  			valid:       true,
  2727  			unconfirmed: false,
  2728  		},
  2729  		{
  2730  			outVals:     []int64{1e8, 2e8, 1e8, 2e7, 3e5},
  2731  			feeRate:     2500,
  2732  			valid:       true,
  2733  			unconfirmed: true,
  2734  		},
  2735  
  2736  		{
  2737  			outVals:     []int64{1e8, 2e8, 1e8, 2e7, 3e5},
  2738  			feeRate:     12500,
  2739  			valid:       true,
  2740  			unconfirmed: false,
  2741  		},
  2742  		{
  2743  			outVals:     []int64{1e8, 2e8, 1e8, 2e7, 3e5},
  2744  			feeRate:     12500,
  2745  			valid:       true,
  2746  			unconfirmed: true,
  2747  		},
  2748  
  2749  		{
  2750  			outVals:     []int64{1e8, 2e8, 1e8, 2e7, 3e5},
  2751  			feeRate:     50000,
  2752  			valid:       true,
  2753  			unconfirmed: false,
  2754  		},
  2755  		{
  2756  			outVals:     []int64{1e8, 2e8, 1e8, 2e7, 3e5},
  2757  			feeRate:     50000,
  2758  			valid:       true,
  2759  			unconfirmed: true,
  2760  		},
  2761  
  2762  		{
  2763  			outVals: []int64{1e8, 2e8, 1e8, 2e7, 3e5, 1e8, 2e8,
  2764  				1e8, 2e7, 3e5},
  2765  			feeRate:     44250,
  2766  			valid:       true,
  2767  			unconfirmed: false,
  2768  		},
  2769  		{
  2770  			outVals: []int64{1e8, 2e8, 1e8, 2e7, 3e5, 1e8, 2e8,
  2771  				1e8, 2e7, 3e5},
  2772  			feeRate:     44250,
  2773  			valid:       true,
  2774  			unconfirmed: true,
  2775  		},
  2776  	}
  2777  
  2778  	ctxb := context.Background()
  2779  	for _, test := range testCases {
  2780  		var minConfs int32 = 1
  2781  		feeRate := test.feeRate
  2782  
  2783  		// Grab some fresh addresses from the miner that we will send
  2784  		// to.
  2785  		outputs := make([]*wire.TxOut, len(test.outVals))
  2786  		for i, outVal := range test.outVals {
  2787  			minerAddr, err := r.NewAddress(ctxb)
  2788  			if err != nil {
  2789  				t.Fatalf("unable to generate address for "+
  2790  					"miner: %v", err)
  2791  			}
  2792  			script, err := input.PayToAddrScript(minerAddr)
  2793  			if err != nil {
  2794  				t.Fatalf("unable to create pay to addr "+
  2795  					"script: %v", err)
  2796  			}
  2797  			output := &wire.TxOut{
  2798  				Value:    outVal,
  2799  				PkScript: script,
  2800  			}
  2801  
  2802  			outputs[i] = output
  2803  		}
  2804  
  2805  		// Now try creating a tx spending to these outputs.
  2806  		createTx, createErr := w.CreateSimpleTx(
  2807  			outputs, feeRate, minConfs, true,
  2808  		)
  2809  		if test.valid == (createErr != nil) {
  2810  			fmt.Println(spew.Sdump(createTx.Tx))
  2811  			t.Fatalf("got unexpected error when creating tx: %v",
  2812  				createErr)
  2813  		}
  2814  
  2815  		// Also send to these outputs. This should result in a tx
  2816  		// _very_ similar to the one we just created being sent. The
  2817  		// only difference is that the dry run tx is not signed, and
  2818  		// that the change output position might be different.
  2819  		tx, sendErr := w.SendOutputs(outputs, feeRate, minConfs, labels.External, "")
  2820  		if test.valid == (sendErr != nil) {
  2821  			t.Fatalf("got unexpected error when sending tx: %v",
  2822  				sendErr)
  2823  		}
  2824  
  2825  		// We expected either both to not fail, or both to fail with
  2826  		// the same error.
  2827  		if createErr != sendErr {
  2828  			t.Fatalf("error creating tx (%v) different "+
  2829  				"from error sending outputs (%v)",
  2830  				createErr, sendErr)
  2831  		}
  2832  
  2833  		// If we expected the creation to fail, then this test is over.
  2834  		if !test.valid {
  2835  			continue
  2836  		}
  2837  
  2838  		txid := tx.TxHash()
  2839  		err = waitForMempoolTx(r, &txid)
  2840  		if err != nil {
  2841  			t.Fatalf("tx not relayed to miner: %v", err)
  2842  		}
  2843  
  2844  		// Helper method to check that the two txs are similar.
  2845  		assertSimilarTx := func(a, b *wire.MsgTx) error {
  2846  			if a.Version != b.Version {
  2847  				return fmt.Errorf("different versions: "+
  2848  					"%v vs %v", a.Version, b.Version)
  2849  			}
  2850  			if a.LockTime != b.LockTime {
  2851  				return fmt.Errorf("different locktimes: "+
  2852  					"%v vs %v", a.LockTime, b.LockTime)
  2853  			}
  2854  			if len(a.TxIn) != len(b.TxIn) {
  2855  				return fmt.Errorf("different number of "+
  2856  					"inputs: %v vs %v", len(a.TxIn),
  2857  					len(b.TxIn))
  2858  			}
  2859  			if len(a.TxOut) != len(b.TxOut) {
  2860  				return fmt.Errorf("different number of "+
  2861  					"outputs: %v vs %v", len(a.TxOut),
  2862  					len(b.TxOut))
  2863  			}
  2864  
  2865  			// They should be spending the same inputs.
  2866  			for i := range a.TxIn {
  2867  				prevA := a.TxIn[i].PreviousOutPoint
  2868  				prevB := b.TxIn[i].PreviousOutPoint
  2869  				if prevA != prevB {
  2870  					return fmt.Errorf("different inputs: "+
  2871  						"%v vs %v", spew.Sdump(prevA),
  2872  						spew.Sdump(prevB))
  2873  				}
  2874  			}
  2875  
  2876  			// They should have the same outputs. Since the change
  2877  			// output position gets randomized, they are not
  2878  			// guaranteed to be in the same order.
  2879  			for _, outA := range a.TxOut {
  2880  				found := false
  2881  				for _, outB := range b.TxOut {
  2882  					if reflect.DeepEqual(outA, outB) {
  2883  						found = true
  2884  						break
  2885  					}
  2886  				}
  2887  				if !found {
  2888  					return fmt.Errorf("did not find "+
  2889  						"output %v", spew.Sdump(outA))
  2890  				}
  2891  			}
  2892  			return nil
  2893  		}
  2894  
  2895  		// Assert that our "template tx" was similar to the one that
  2896  		// ended up being sent.
  2897  		if err := assertSimilarTx(createTx.Tx, tx); err != nil {
  2898  			t.Fatalf("transactions not similar: %v", err)
  2899  		}
  2900  	}
  2901  }
  2902  
  2903  type walletTestCase struct {
  2904  	name string
  2905  	test func(miner *rpctest.Harness, vw *rpctest.VotingWallet,
  2906  		alice, bob *lnwallet.LightningWallet, test *testing.T)
  2907  }
  2908  
  2909  var walletTests = []walletTestCase{
  2910  	{
  2911  		// TODO(wilmer): this test should remain first until the wallet
  2912  		// can properly craft a transaction that spends all of its
  2913  		// on-chain funds.
  2914  		name: "change output spend confirmation",
  2915  		test: testChangeOutputSpendConfirmation,
  2916  	},
  2917  	{
  2918  		// This test also needs to happen at the start of testing, to
  2919  		// prevent a reorg past SVH which could cause the voting wallet
  2920  		// to misbehave.
  2921  		name: "reorg wallet balance",
  2922  		test: testReorgWalletBalance,
  2923  	},
  2924  	{
  2925  		name: "spend unconfirmed outputs",
  2926  		test: testSpendUnconfirmed,
  2927  	},
  2928  	{
  2929  		name: "insane fee reject",
  2930  		test: testReservationInitiatorBalanceBelowDustCancel,
  2931  	},
  2932  	{
  2933  		name: "single funding workflow",
  2934  		test: func(miner *rpctest.Harness, vw *rpctest.VotingWallet,
  2935  			alice, bob *lnwallet.LightningWallet, t *testing.T) {
  2936  
  2937  			testSingleFunderReservationWorkflow(
  2938  				miner, vw, alice, bob, t,
  2939  				lnwallet.CommitmentTypeLegacy, nil, nil,
  2940  				[32]byte{15, 16, 17, 18}, 0,
  2941  			)
  2942  		},
  2943  	},
  2944  	{
  2945  		name: "single funding workflow tweakless",
  2946  		test: func(miner *rpctest.Harness, vw *rpctest.VotingWallet,
  2947  			alice, bob *lnwallet.LightningWallet, t *testing.T) {
  2948  
  2949  			testSingleFunderReservationWorkflow(
  2950  				miner, vw, alice, bob, t,
  2951  				lnwallet.CommitmentTypeTweakless, nil, nil,
  2952  				[32]byte{19, 20, 21, 22}, 0,
  2953  			)
  2954  		},
  2955  	},
  2956  	{
  2957  		name: "single funding workflow external funding tx",
  2958  		test: testSingleFunderExternalFundingTx,
  2959  	},
  2960  	{
  2961  		name: "dual funder workflow",
  2962  		test: testDualFundingReservationWorkflow,
  2963  	},
  2964  	{
  2965  		name: "output locking",
  2966  		test: testFundingTransactionLockedOutputs,
  2967  	},
  2968  	{
  2969  		name: "reservation insufficient funds",
  2970  		test: testFundingCancellationNotEnoughFunds,
  2971  	},
  2972  	{
  2973  		name: "transaction subscriptions",
  2974  		test: testTransactionSubscriptions,
  2975  	},
  2976  	{
  2977  		name: "transaction details",
  2978  		test: testListTransactionDetails,
  2979  	},
  2980  	{
  2981  		name: "publish transaction",
  2982  		test: testPublishTransaction,
  2983  	},
  2984  	{
  2985  		name: "signed with tweaked pubkeys",
  2986  		test: testSignOutputUsingTweaks,
  2987  	},
  2988  	{
  2989  		name: "test cancel non-existent reservation",
  2990  		test: testCancelNonExistentReservation,
  2991  	},
  2992  	{
  2993  		name: "last unused addr",
  2994  		test: testLastUnusedAddr,
  2995  	}, {
  2996  		name: "test many new addresses",
  2997  		test: testManyNewAddresses,
  2998  	},
  2999  	// TODO(decred) re-enable these tests after implementing.
  3000  	// { name: "create simple tx", test: testCreateSimpleTx, },
  3001  	// { name: "test get recovery info", test: testGetRecoveryInfo, },
  3002  }
  3003  
  3004  func clearWalletStates(a, b *lnwallet.LightningWallet) error {
  3005  	a.ResetReservations()
  3006  	b.ResetReservations()
  3007  
  3008  	if err := a.Cfg.Database.GetParentDB().Wipe(); err != nil {
  3009  		return err
  3010  	}
  3011  
  3012  	return b.Cfg.Database.GetParentDB().Wipe()
  3013  }
  3014  
  3015  func waitForMempoolTx(r *rpctest.Harness, txid *chainhash.Hash) error {
  3016  	var found bool
  3017  	var tx *dcrutil.Tx
  3018  	var err error
  3019  	timeout := time.After(30 * time.Second)
  3020  	for !found {
  3021  		// Do a short wait
  3022  		select {
  3023  		case <-timeout:
  3024  			return fmt.Errorf("timeout after 10s")
  3025  		default:
  3026  		}
  3027  		time.Sleep(100 * time.Millisecond)
  3028  
  3029  		// Check for the harness' knowledge of the txid
  3030  		tx, err = r.Node.GetRawTransaction(context.TODO(), txid)
  3031  		if err != nil {
  3032  			switch e := err.(type) {
  3033  			case *dcrjson.RPCError:
  3034  				if e.Code == dcrjson.ErrRPCNoTxInfo {
  3035  					continue
  3036  				}
  3037  			default:
  3038  			}
  3039  			return err
  3040  		}
  3041  		if tx != nil && tx.MsgTx().TxHash() == *txid {
  3042  			found = true
  3043  		}
  3044  	}
  3045  	return nil
  3046  }
  3047  
  3048  func waitForWalletSync(r *rpctest.Harness, w *lnwallet.LightningWallet) error {
  3049  	var (
  3050  		synced      bool
  3051  		err         error
  3052  		predErr     error
  3053  		bestHash    *chainhash.Hash
  3054  		knownHash   chainhash.Hash
  3055  		knownHeight int64
  3056  		bestHeight  int64
  3057  	)
  3058  	timeout := time.After(10 * time.Second)
  3059  	for !synced {
  3060  		// Do a short wait
  3061  		select {
  3062  		case <-timeout:
  3063  			return fmt.Errorf("timeout after 30s. predErr=%v", predErr)
  3064  		case <-time.Tick(100 * time.Millisecond):
  3065  		}
  3066  
  3067  		// Check whether the chain source of the wallet is caught up to
  3068  		// the harness it's supposed to be catching up to.
  3069  		bestHash, bestHeight, err = r.Node.GetBestBlock(context.TODO())
  3070  		if err != nil {
  3071  			return fmt.Errorf("error getting node best block: %v", err)
  3072  		}
  3073  		knownHeight, knownHash, _, err = w.BestBlock()
  3074  		if err != nil {
  3075  			return fmt.Errorf("error getting chainIO bestBlock: %v", err)
  3076  		}
  3077  		if knownHeight != bestHeight {
  3078  			predErr = fmt.Errorf("miner and wallet best heights "+
  3079  				"are not the same (want=%d got=%d)",
  3080  				bestHeight, knownHeight)
  3081  			continue
  3082  		}
  3083  		if knownHash != *bestHash {
  3084  			return fmt.Errorf("hash at height %d doesn't match: "+
  3085  				"expected %s, got %s", bestHeight, bestHash,
  3086  				knownHash)
  3087  		}
  3088  
  3089  		// Check for synchronization.
  3090  		synced, _, err = w.IsSynced()
  3091  		if err != nil {
  3092  			return err
  3093  		}
  3094  		if !synced {
  3095  			predErr = fmt.Errorf("wallet isSynced=false")
  3096  		}
  3097  	}
  3098  	return nil
  3099  }
  3100  
  3101  // testSingleFunderExternalFundingTx tests that the wallet is able to properly
  3102  // carry out a funding flow backed by a channel point that has been crafted
  3103  // outside the wallet.
  3104  func testSingleFunderExternalFundingTx(miner *rpctest.Harness,
  3105  	vw *rpctest.VotingWallet,
  3106  	alice, bob *lnwallet.LightningWallet, t *testing.T) {
  3107  
  3108  	// First, we'll obtain multi-sig keys from both Alice and Bob which
  3109  	// simulates them exchanging keys on a higher level.
  3110  	aliceFundingKey, err := alice.DeriveNextKey(keychain.KeyFamilyMultiSig)
  3111  	if err != nil {
  3112  		t.Fatalf("unable to obtain alice funding key: %v", err)
  3113  	}
  3114  	bobFundingKey, err := bob.DeriveNextKey(keychain.KeyFamilyMultiSig)
  3115  	if err != nil {
  3116  		t.Fatalf("unable to obtain bob funding key: %v", err)
  3117  	}
  3118  
  3119  	// We'll now set up for them to open a 4 BTC channel, with 1 BTC pushed
  3120  	// to Bob's side.
  3121  	chanAmt := 4 * dcrutil.AtomsPerCoin
  3122  
  3123  	// Simulating external funding negotiation, we'll now create the
  3124  	// funding transaction for both parties. Utilizing existing tools,
  3125  	// we'll create a new chanfunding.Assembler hacked by Alice's wallet.
  3126  	aliceChanFunder := chanfunding.NewWalletAssembler(chanfunding.WalletConfig{
  3127  		CoinSource:       lnwallet.NewCoinSource(alice),
  3128  		CoinSelectLocker: alice,
  3129  		CoinLocker:       alice,
  3130  		Signer:           alice.Cfg.Signer,
  3131  		DustLimit:        600,
  3132  	})
  3133  
  3134  	// With the chan funder created, we'll now provision a funding intent,
  3135  	// bind the keys we obtained above, and finally obtain our funding
  3136  	// transaction and outpoint.
  3137  	fundingIntent, err := aliceChanFunder.ProvisionChannel(&chanfunding.Request{
  3138  		LocalAmt: dcrutil.Amount(chanAmt),
  3139  		MinConfs: 1,
  3140  		FeeRate:  1e4,
  3141  		ChangeAddr: func() (stdaddr.Address, error) {
  3142  			return alice.NewAddress(
  3143  				lnwallet.PubKeyHash, true,
  3144  				lnwallet.DefaultAccountName,
  3145  			)
  3146  		},
  3147  	})
  3148  	if err != nil {
  3149  		t.Fatalf("unable to perform coin selection: %v", err)
  3150  	}
  3151  
  3152  	// With our intent created, we'll instruct it to finalize the funding
  3153  	// transaction, and also hand us the outpoint so we can simulate
  3154  	// external crafting of the funding transaction.
  3155  	var (
  3156  		fundingTx *wire.MsgTx
  3157  		chanPoint *wire.OutPoint
  3158  	)
  3159  	if fullIntent, ok := fundingIntent.(*chanfunding.FullIntent); ok {
  3160  		fullIntent.BindKeys(&aliceFundingKey, bobFundingKey.PubKey)
  3161  
  3162  		fundingTx, err = fullIntent.CompileFundingTx(nil, nil)
  3163  		if err != nil {
  3164  			t.Fatalf("unable to compile funding tx: %v", err)
  3165  		}
  3166  		chanPoint, err = fullIntent.ChanPoint()
  3167  		if err != nil {
  3168  			t.Fatalf("unable to obtain chan point: %v", err)
  3169  		}
  3170  	} else {
  3171  		t.Fatalf("expected full intent, instead got: %T", fullIntent)
  3172  	}
  3173  
  3174  	// Now that we have the fully constructed funding transaction, we'll
  3175  	// create a new shim external funder out of it for Alice, and prep a
  3176  	// shim intent for Bob.
  3177  	thawHeight := uint32(200)
  3178  	aliceExternalFunder := chanfunding.NewCannedAssembler(
  3179  		thawHeight, *chanPoint, dcrutil.Amount(chanAmt), &aliceFundingKey,
  3180  		bobFundingKey.PubKey, true,
  3181  	)
  3182  	bobShimIntent, err := chanfunding.NewCannedAssembler(
  3183  		thawHeight, *chanPoint, dcrutil.Amount(chanAmt), &bobFundingKey,
  3184  		aliceFundingKey.PubKey, false,
  3185  	).ProvisionChannel(&chanfunding.Request{
  3186  		LocalAmt: dcrutil.Amount(chanAmt),
  3187  		MinConfs: 1,
  3188  		FeeRate:  1e4,
  3189  		ChangeAddr: func() (stdaddr.Address, error) {
  3190  			return bob.NewAddress(
  3191  				lnwallet.PubKeyHash, true,
  3192  				lnwallet.DefaultAccountName,
  3193  			)
  3194  		},
  3195  	})
  3196  	if err != nil {
  3197  		t.Fatalf("unable to create shim intent for bob: %v", err)
  3198  	}
  3199  
  3200  	// At this point, we have everything we need to carry out our test, so
  3201  	// we'll being the funding flow between Alice and Bob.
  3202  	//
  3203  	// However, before we do so, we'll register a new shim intent for Bob,
  3204  	// so he knows what keys to use when he receives the funding request
  3205  	// from Alice.
  3206  	pendingChanID := testHdSeed
  3207  	err = bob.RegisterFundingIntent(pendingChanID, bobShimIntent)
  3208  	if err != nil {
  3209  		t.Fatalf("unable to register intent: %v", err)
  3210  	}
  3211  
  3212  	// Now we can carry out the single funding flow as normal, we'll
  3213  	// specify our external funder and funding transaction, as well as the
  3214  	// pending channel ID generated above to allow Alice and Bob to track
  3215  	// the funding flow externally.
  3216  	testSingleFunderReservationWorkflow(
  3217  		miner, vw, alice, bob, t, lnwallet.CommitmentTypeTweakless,
  3218  		aliceExternalFunder, func() *wire.MsgTx {
  3219  			return fundingTx
  3220  		}, pendingChanID, thawHeight,
  3221  	)
  3222  }
  3223  
  3224  // TestInterfaces tests all registered interfaces with a unified set of tests
  3225  // which exercise each of the required methods found within the WalletController
  3226  // interface.
  3227  //
  3228  // NOTE: In the future, when additional implementations of the WalletController
  3229  // interface have been implemented, in order to ensure the new concrete
  3230  // implementation is automatically tested, two steps must be undertaken. First,
  3231  // one needs add a "non-captured" (_) import from the new sub-package. This
  3232  // import should trigger an init() method within the package which registers
  3233  // the interface. Second, an additional case in the switch within the main loop
  3234  // below needs to be added which properly initializes the interface.
  3235  //
  3236  // TODO(roasbeef): purge bobNode in favor of dual lnwallet's
  3237  func TestLightningWallet(t *testing.T, driverName, backEnd string) {
  3238  	t.Parallel()
  3239  
  3240  	walletDriver := lnwallet.WalletDriverForName(driverName)
  3241  	if walletDriver == nil {
  3242  		t.Fatalf("wallet driver %s does not exist", driverName)
  3243  	}
  3244  
  3245  	if !slices.Contains(walletDriver.BackEnds(), backEnd) {
  3246  		t.Fatalf("wallet driver %s does not support backend %s",
  3247  			walletDriver.WalletType, backEnd)
  3248  	}
  3249  
  3250  	var miningNode *rpctest.Harness
  3251  
  3252  	// Initialize the harness around a dcrd node which will
  3253  	// serve as our dedicated miner to generate blocks,
  3254  	// cause re-orgs, etc. We'll set up this node with a
  3255  	// chain length of 125, so we have plenty of DCR to
  3256  	// play around with.
  3257  	minerLogDir := fmt.Sprintf(".miner-logs-%s-%s",
  3258  		walletDriver.WalletType, backEnd)
  3259  	minerArgs := []string{"--txindex", "--debuglevel=debug",
  3260  		"--logdir=" + minerLogDir}
  3261  	miningNode, err := testutils.NewSetupRPCTest(
  3262  		testctx.New(t), 5, netParams, nil, minerArgs, true, 0,
  3263  	)
  3264  	require.NoError(t, err)
  3265  
  3266  	defer func() {
  3267  		err := miningNode.TearDown()
  3268  		if err != nil {
  3269  			t.Errorf("unable to teardown rpc test harness: %v", err)
  3270  		}
  3271  
  3272  		// Copy the node logs from the original log dir.
  3273  		oldFileName := path.Join(minerLogDir, netParams.Name,
  3274  			"dcrd.log")
  3275  		newFileName := fmt.Sprintf("output-miner-%s-%s.log",
  3276  			walletDriver.WalletType, backEnd)
  3277  		err = os.Rename(oldFileName, newFileName)
  3278  		if err != nil {
  3279  			t.Logf("could not rename %s to %s: %v\n",
  3280  				oldFileName, newFileName, err)
  3281  		}
  3282  	}()
  3283  
  3284  	// Generate the premine block.
  3285  	_, err = miningNode.Node.Generate(context.TODO(), 1)
  3286  	require.NoError(t, err)
  3287  
  3288  	// Generate enough blocks for the initial load of test and voting
  3289  	// wallet but not so many that it would trigger a reorg after SVH
  3290  	// during the testReorgWalletBalance test.
  3291  	_, err = rpctest.AdjustedSimnetMiner(context.Background(), miningNode.Node, 40)
  3292  	require.NoError(t, err)
  3293  
  3294  	// Setup a voting wallet for when the chain passes SVH.
  3295  	vwCtx, vwCancel := context.WithCancel(context.Background())
  3296  	defer vwCancel()
  3297  	votingWallet, err := rpctest.NewVotingWallet(vwCtx, miningNode)
  3298  	require.NoError(t, err)
  3299  	votingWallet.SetErrorReporting(func(err error) {
  3300  		t.Logf("Voting wallet error: %v", err)
  3301  	})
  3302  	votingWallet.SetMiner(func(ctx context.Context, nb uint32) ([]*chainhash.Hash, error) {
  3303  		return rpctest.AdjustedSimnetMiner(ctx, miningNode.Node, nb)
  3304  	})
  3305  	if err = votingWallet.Start(vwCtx); err != nil {
  3306  		t.Fatalf("unable to start voting wallet: %v", err)
  3307  	}
  3308  
  3309  	rpcConfig := miningNode.RPCConfig()
  3310  
  3311  	tempDir, err := ioutil.TempDir("", "channeldb")
  3312  	require.NoError(t, err)
  3313  	db, err := channeldb.Open(tempDir)
  3314  	require.NoError(t, err)
  3315  	hintCacheCfg := chainntnfs.CacheConfig{
  3316  		QueryDisable: false,
  3317  	}
  3318  	hintCache, err := chainntnfs.NewHeightHintCache(hintCacheCfg, db.Backend)
  3319  	require.NoError(t, err)
  3320  	chainNotifier, err := dcrdnotify.New(
  3321  		&rpcConfig, netParams, hintCache, hintCache, nil,
  3322  	)
  3323  	require.NoError(t, err)
  3324  	if err := chainNotifier.Start(); err != nil {
  3325  		t.Fatalf("unable to start notifier: %v", err)
  3326  	}
  3327  
  3328  	runTests(t, walletDriver, backEnd, miningNode, rpcConfig, chainNotifier,
  3329  		votingWallet)
  3330  }
  3331  
  3332  // runTests runs all of the tests for a single interface implementation and
  3333  // chain back-end combination. This makes it easier to use `defer` as well as
  3334  // factoring out the test logic from the loop which cycles through the
  3335  // interface implementations.
  3336  func runTests(t *testing.T, walletDriver *lnwallet.WalletDriver,
  3337  	backEnd string, miningNode *rpctest.Harness,
  3338  	rpcConfig rpcclient.ConnConfig,
  3339  	chainNotifier *dcrdnotify.DcrdNotifier,
  3340  	votingWallet *rpctest.VotingWallet) bool {
  3341  	var (
  3342  		aliceBio lnwallet.BlockChainIO
  3343  		bobBio   lnwallet.BlockChainIO
  3344  
  3345  		aliceSigner input.Signer
  3346  		bobSigner   input.Signer
  3347  
  3348  		aliceKeyRing keychain.SecretKeyRing
  3349  		bobKeyRing   keychain.SecretKeyRing
  3350  
  3351  		aliceWalletController lnwallet.WalletController
  3352  		bobWalletController   lnwallet.WalletController
  3353  	)
  3354  
  3355  	tempTestDirAlice, err := ioutil.TempDir("", "lnwallet")
  3356  	if err != nil {
  3357  		t.Fatalf("unable to create temp directory: %v", err)
  3358  	}
  3359  	t.Logf("Alice Dir: %s", tempTestDirAlice)
  3360  	//defer os.RemoveAll(tempTestDirAlice)
  3361  
  3362  	tempTestDirBob, err := ioutil.TempDir("", "lnwallet")
  3363  	if err != nil {
  3364  		t.Fatalf("unable to create temp directory: %v", err)
  3365  	}
  3366  	t.Logf("Bob Dir: %s", tempTestDirBob)
  3367  	//defer os.RemoveAll(tempTestDirBob)
  3368  
  3369  	aliceDBDir := filepath.Join(tempTestDirAlice, "cdb")
  3370  	aliceCDB, err := channeldb.Open(aliceDBDir)
  3371  	if err != nil {
  3372  		t.Fatalf("unable to open alice cdb: %v", err)
  3373  	}
  3374  	defer aliceCDB.Close()
  3375  
  3376  	bobDBDir := filepath.Join(tempTestDirBob, "cdb")
  3377  	bobCDB, err := channeldb.Open(bobDBDir)
  3378  	if err != nil {
  3379  		t.Fatalf("unable to open bob cdb: %v", err)
  3380  	}
  3381  	defer bobCDB.Close()
  3382  
  3383  	aliceSeed := sha256.New()
  3384  	aliceSeed.Write([]byte(backEnd))
  3385  	aliceSeed.Write([]byte(walletDriver.WalletType))
  3386  	aliceSeed.Write(aliceHDSeed[:])
  3387  	aliceSeedBytes := aliceSeed.Sum(nil)
  3388  	alicePrivatePass := []byte("alice-pass")
  3389  
  3390  	bobSeed := sha256.New()
  3391  	bobSeed.Write([]byte(backEnd))
  3392  	bobSeed.Write([]byte(walletDriver.WalletType))
  3393  	bobSeed.Write(bobHDSeed[:])
  3394  	bobSeedBytes := bobSeed.Sum(nil)
  3395  	bobPrivatePass := []byte("bob-pass")
  3396  
  3397  	blockCache := blockcache.NewBlockCache(10000)
  3398  
  3399  	walletType := walletDriver.WalletType
  3400  	switch walletType {
  3401  	case "dcrwallet":
  3402  		var aliceSyncer, bobSyncer dcrwallet.WalletSyncer
  3403  		switch backEnd {
  3404  		case "dcrd":
  3405  			aliceSyncer, err = dcrwallet.NewRPCSyncer(rpcConfig,
  3406  				netParams)
  3407  			if err != nil {
  3408  				t.Fatalf("unable to make chain rpc: %v", err)
  3409  			}
  3410  			bobSyncer, err = dcrwallet.NewRPCSyncer(rpcConfig,
  3411  				netParams)
  3412  			if err != nil {
  3413  				t.Fatalf("unable to make chain rpc: %v", err)
  3414  			}
  3415  
  3416  			aliceBio, err = dcrwallet.NewRPCChainIO(rpcConfig, netParams, blockCache)
  3417  			if err != nil {
  3418  				t.Fatalf("unable to make alice chain IO: %v", err)
  3419  			}
  3420  
  3421  			bobBio, err = dcrwallet.NewRPCChainIO(rpcConfig, netParams, blockCache)
  3422  			if err != nil {
  3423  				t.Fatalf("unable to make bob chain IO: %v", err)
  3424  			}
  3425  		case "spv":
  3426  			spvCfg := &dcrwallet.SPVSyncerConfig{
  3427  				Net:        netParams,
  3428  				Peers:      []string{miningNode.P2PAddress()},
  3429  				AppDataDir: tempTestDirAlice, // Safe to reuse since we use a fixed addr.
  3430  			}
  3431  
  3432  			aliceSyncer, err = dcrwallet.NewSPVSyncer(spvCfg)
  3433  			if err != nil {
  3434  				t.Fatalf("unable to make alice spv syncer: %v", err)
  3435  			}
  3436  			bobSyncer, err = dcrwallet.NewSPVSyncer(spvCfg)
  3437  			if err != nil {
  3438  				t.Fatalf("unable to make bob spv syncer: %v", err)
  3439  			}
  3440  		default:
  3441  			t.Fatalf("unknown chain driver: %v", backEnd)
  3442  		}
  3443  
  3444  		aliceWalletConfig := &dcrwallet.Config{
  3445  			PrivatePass: alicePrivatePass,
  3446  			HdSeed:      aliceSeedBytes,
  3447  			NetParams:   netParams,
  3448  			DataDir:     tempTestDirAlice,
  3449  			Syncer:      aliceSyncer,
  3450  			ChainIO:     aliceBio,
  3451  			DB:          aliceCDB,
  3452  		}
  3453  		aliceWalletController, err = walletDriver.New(
  3454  			aliceWalletConfig, blockCache,
  3455  		)
  3456  		if err != nil {
  3457  			t.Fatalf("unable to create alice wallet: %v", err)
  3458  		}
  3459  		aliceSigner = aliceWalletController.(*dcrwallet.DcrWallet)
  3460  		aliceKeyRing = aliceWalletController.(*dcrwallet.DcrWallet)
  3461  
  3462  		bobWalletConfig := &dcrwallet.Config{
  3463  			PrivatePass: bobPrivatePass,
  3464  			HdSeed:      bobSeedBytes,
  3465  			NetParams:   netParams,
  3466  			DataDir:     tempTestDirBob,
  3467  			Syncer:      bobSyncer,
  3468  			ChainIO:     bobBio,
  3469  			DB:          bobCDB,
  3470  		}
  3471  		bobWalletController, err = walletDriver.New(
  3472  			bobWalletConfig, blockCache,
  3473  		)
  3474  		if err != nil {
  3475  			t.Fatalf("unable to create bob wallet: %v", err)
  3476  		}
  3477  		bobSigner = bobWalletController.(*dcrwallet.DcrWallet)
  3478  		bobKeyRing = bobWalletController.(*dcrwallet.DcrWallet)
  3479  
  3480  		if backEnd == "spv" {
  3481  			aliceBio = aliceWalletController.(*dcrwallet.DcrWallet)
  3482  			bobBio = bobWalletController.(*dcrwallet.DcrWallet)
  3483  		}
  3484  	case "remotedcrwallet":
  3485  		var rpcSyncCfg *rpcclient.ConnConfig
  3486  		var spvSyncCfg *testutils.SPVConfig
  3487  
  3488  		switch backEnd {
  3489  		case "dcrd":
  3490  			aliceBio, err = dcrwallet.NewRPCChainIO(rpcConfig,
  3491  				netParams, blockCache)
  3492  			if err != nil {
  3493  				t.Fatalf("unable to make chain rpc: %v", err)
  3494  			}
  3495  			bobBio, err = dcrwallet.NewRPCChainIO(rpcConfig,
  3496  				netParams, blockCache)
  3497  			if err != nil {
  3498  				t.Fatalf("unable to make chain rpc: %v", err)
  3499  			}
  3500  
  3501  			rpcSyncCfg = &rpcConfig
  3502  
  3503  		case "spv":
  3504  			spvSyncCfg = &testutils.SPVConfig{
  3505  				Address: miningNode.P2PAddress(),
  3506  			}
  3507  
  3508  		default:
  3509  			t.Fatalf("unknown chain driver: %v", backEnd)
  3510  		}
  3511  		aliceConn, aliceCleanup := testutils.NewCustomTestRemoteDcrwallet(
  3512  			t, "Alice", tempTestDirAlice, aliceSeedBytes,
  3513  			alicePrivatePass, rpcSyncCfg, spvSyncCfg,
  3514  		)
  3515  		defer aliceCleanup()
  3516  		if err := testutils.SetPerAccountPassphrase(aliceConn, alicePrivatePass); err != nil {
  3517  			t.Fatalf("unable to set alice wallet to account pwd: %v", err)
  3518  		}
  3519  		aliceWalletConfig := &remotedcrwallet.Config{
  3520  			Conn:        aliceConn,
  3521  			ChainIO:     aliceBio,
  3522  			PrivatePass: alicePrivatePass,
  3523  			NetParams:   netParams,
  3524  			DB:          aliceCDB,
  3525  		}
  3526  		aliceWalletController, err = walletDriver.New(aliceWalletConfig)
  3527  		if err != nil {
  3528  			t.Fatalf("unable to create alice wallet: %v", err)
  3529  		}
  3530  		aliceSigner = aliceWalletController.(*remotedcrwallet.DcrWallet)
  3531  		aliceKeyRing = aliceWalletController.(*remotedcrwallet.DcrWallet)
  3532  
  3533  		bobConn, bobCleanup := testutils.NewCustomTestRemoteDcrwallet(
  3534  			t, "Bob", tempTestDirBob, bobSeedBytes, bobPrivatePass,
  3535  			rpcSyncCfg, spvSyncCfg,
  3536  		)
  3537  		defer bobCleanup()
  3538  		if err := testutils.SetPerAccountPassphrase(bobConn, bobPrivatePass); err != nil {
  3539  			t.Fatalf("unable to set bob wallet to account pwd: %v", err)
  3540  		}
  3541  		bobWalletConfig := &remotedcrwallet.Config{
  3542  			Conn:        bobConn,
  3543  			ChainIO:     bobBio,
  3544  			PrivatePass: bobPrivatePass,
  3545  			NetParams:   netParams,
  3546  			DB:          bobCDB,
  3547  		}
  3548  		bobWalletController, err = walletDriver.New(bobWalletConfig)
  3549  		if err != nil {
  3550  			t.Fatalf("unable to create bob wallet: %v", err)
  3551  		}
  3552  		bobSigner = bobWalletController.(*remotedcrwallet.DcrWallet)
  3553  		bobKeyRing = bobWalletController.(*remotedcrwallet.DcrWallet)
  3554  
  3555  		if backEnd == "spv" {
  3556  			aliceBio = aliceWalletController.(*remotedcrwallet.DcrWallet)
  3557  			bobBio = bobWalletController.(*remotedcrwallet.DcrWallet)
  3558  		}
  3559  	default:
  3560  		t.Fatalf("unknown wallet driver: %v", walletType)
  3561  	}
  3562  
  3563  	// Funding via 20 outputs with 4DCR each.
  3564  	alice, err := createTestWallet(
  3565  		aliceCDB, miningNode, netParams,
  3566  		chainNotifier, aliceWalletController, aliceKeyRing,
  3567  		aliceSigner, aliceBio, votingWallet,
  3568  	)
  3569  	if err != nil {
  3570  		t.Fatalf("unable to create test ln wallet: %v", err)
  3571  	}
  3572  	defer alice.Shutdown()
  3573  
  3574  	bob, err := createTestWallet(
  3575  		bobCDB, miningNode, netParams,
  3576  		chainNotifier, bobWalletController, bobKeyRing,
  3577  		bobSigner, bobBio, votingWallet,
  3578  	)
  3579  	if err != nil {
  3580  		t.Fatalf("unable to create test ln wallet: %v", err)
  3581  	}
  3582  	defer bob.Shutdown()
  3583  
  3584  	// Wait for both wallets to be synced.
  3585  	timeout := time.After(time.Second * 120)
  3586  	aliceSync := aliceWalletController.InitialSyncChannel()
  3587  	bobSync := bobWalletController.InitialSyncChannel()
  3588  	for aliceSync != nil || bobSync != nil {
  3589  		select {
  3590  		case <-timeout:
  3591  			t.Fatalf("timeout while waiting for wallets to sync")
  3592  		case <-aliceSync:
  3593  			t.Logf("Alice synced")
  3594  			aliceSync = nil
  3595  		case <-bobSync:
  3596  			t.Logf("Bob synced")
  3597  			bobSync = nil
  3598  		}
  3599  	}
  3600  
  3601  	// Load our test wallets with 20 outputs each holding 1DCR.
  3602  	if err := loadTestCredits(miningNode, alice, votingWallet.GenerateBlocks, 20, 1); err != nil {
  3603  		t.Fatalf("unable to send initial funds to alice: %v", err)
  3604  	}
  3605  	if err := loadTestCredits(miningNode, bob, votingWallet.GenerateBlocks, 20, 1); err != nil {
  3606  		t.Fatalf("unable to send initial funds to bob: %v", err)
  3607  	}
  3608  
  3609  	t.Logf("Loaded test credits")
  3610  
  3611  	// Both wallets should now have 20DCR available for
  3612  	// spending.
  3613  	assertProperBalance(t, alice, 1, 20)
  3614  	assertProperBalance(t, bob, 1, 20)
  3615  
  3616  	// Execute every test, clearing possibly mutated
  3617  	// wallet state after each step.
  3618  	for _, walletTest := range walletTests {
  3619  
  3620  		walletTest := walletTest
  3621  
  3622  		testName := fmt.Sprintf("%v/%v:%v", walletType, backEnd,
  3623  			walletTest.name)
  3624  		success := t.Run(testName, func(t *testing.T) {
  3625  			if backEnd == "spv" &&
  3626  				strings.Contains(walletTest.name, "dual funder") {
  3627  				t.Skip("skipping dual funder tests for spv")
  3628  			}
  3629  			if backEnd == "spv" &&
  3630  				strings.Contains(walletTest.name, "spend unconfirmed") {
  3631  				t.Skip("skipping spend unconfirmed tests for spv")
  3632  			}
  3633  			if backEnd == "spv" &&
  3634  				strings.Contains(walletTest.name, "reorg ") {
  3635  				t.Skip("skipping reorg tests for spv")
  3636  			}
  3637  
  3638  			walletTest.test(miningNode, votingWallet, alice, bob, t)
  3639  		})
  3640  		if !success {
  3641  			return false
  3642  		}
  3643  
  3644  		// TODO(roasbeef): possible reset mining
  3645  		// node's chainstate to initial level, cleanly
  3646  		// wipe buckets
  3647  		if err := clearWalletStates(alice, bob); err !=
  3648  			nil && err != kvdb.ErrBucketNotFound {
  3649  			t.Fatalf("unable to wipe wallet state: %v", err)
  3650  		}
  3651  	}
  3652  
  3653  	return true
  3654  }