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

     1  package itest
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math"
     7  	"time"
     8  
     9  	"github.com/decred/dcrd/dcrutil/v4"
    10  	"github.com/decred/dcrlnd/input"
    11  	"github.com/decred/dcrlnd/lnrpc"
    12  	"github.com/decred/dcrlnd/lnrpc/walletrpc"
    13  	"github.com/decred/dcrlnd/lntest"
    14  	"github.com/decred/dcrlnd/lntest/wait"
    15  	"github.com/decred/dcrlnd/lnwallet/chainfee"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  func testExtraAccountsFeatures(net *lntest.NetworkHarness, t *harnessTest) {
    20  	ctxb := context.Background()
    21  
    22  	if net.Alice.Cfg.RemoteWallet {
    23  		t.t.Skipf("Disabled in remotewallet impl")
    24  	}
    25  
    26  	// Create a Carol node to use in tests.
    27  	password := []byte("12345678")
    28  	carol, mnemonic, _, err := net.NewNodeWithSeed(
    29  		"carol", nil, password, false,
    30  	)
    31  	require.NoError(t.t, err)
    32  
    33  	// Helper to check if Carol has balance.
    34  	checkBalance := func(node *lntest.HarnessNode, wantBalance dcrutil.Amount) {
    35  		t.t.Helper()
    36  		require.NoError(t.t, wait.NoError(func() error {
    37  			ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
    38  			bal, err := node.WalletBalance(ctxt, &lnrpc.WalletBalanceRequest{})
    39  			if err != nil {
    40  				return err
    41  			}
    42  
    43  			if bal.ConfirmedBalance != int64(wantBalance) {
    44  				return fmt.Errorf("ConfirmedBalance %d != %f",
    45  					bal.ConfirmedBalance, dcrutil.AtomsPerCoin)
    46  			}
    47  
    48  			return nil
    49  		}, defaultTimeout))
    50  	}
    51  
    52  	// Create an additional account for carol.
    53  	accountName := "second"
    54  	ctxt, _ := context.WithTimeout(ctxb, defaultTimeout)
    55  	_, err = carol.WalletKitClient.DeriveNextAccount(ctxt, &walletrpc.DeriveNextAccountRequest{Name: accountName})
    56  	require.NoError(t.t, err)
    57  	accounts, err := carol.WalletKitClient.ListAccounts(ctxb, &walletrpc.ListAccountsRequest{})
    58  	require.NoError(t.t, err)
    59  	require.Len(t.t, accounts.Accounts, 2)
    60  
    61  	// Get an address from this account and send funds to it.
    62  	addrRes, err := carol.WalletKitClient.NextAddr(ctxt, &walletrpc.AddrRequest{Account: accountName})
    63  	require.NoError(t.t, err)
    64  
    65  	// Send coins to Alice, then from Alice to Carol.
    66  	net.SendCoins(t.t, 2*dcrutil.AtomsPerCoin, net.Alice)
    67  	ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
    68  	_, err = net.Alice.SendCoins(ctxt, &lnrpc.SendCoinsRequest{Addr: addrRes.Addr, Amount: dcrutil.AtomsPerCoin})
    69  	require.NoError(t.t, err)
    70  	mineBlocks(t, net, 1, 1)
    71  	checkBalance(carol, dcrutil.AtomsPerCoin)
    72  	listUnspentReq := &walletrpc.ListUnspentRequest{Account: accountName, MaxConfs: math.MaxInt32}
    73  	unspent, err := carol.WalletKitClient.ListUnspent(ctxb, listUnspentReq)
    74  	require.NoError(t.t, err)
    75  	require.Len(t.t, unspent.Utxos, 1)
    76  
    77  	// Stop and recreate carol, to see if the new account will be
    78  	// discovered.
    79  	_, err = net.SuspendNode(carol)
    80  	require.NoError(t.t, err)
    81  	carol, err = net.RestoreNodeWithSeed(
    82  		"carol", nil, password, mnemonic, "", 1000, nil,
    83  	)
    84  	defer shutdownAndAssert(net, t, carol)
    85  	require.NoError(t.t, err)
    86  	checkBalance(carol, dcrutil.AtomsPerCoin)
    87  	accounts, err = carol.WalletKitClient.ListAccounts(ctxb, &walletrpc.ListAccountsRequest{})
    88  	require.NoError(t.t, err)
    89  	require.Len(t.t, accounts.Accounts, 2)
    90  
    91  	// Gather the required data to build the SpendUTXOs request.
    92  	ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
    93  	_, minerHeight, err := net.Miner.Node.GetBestBlock(ctxt)
    94  	require.NoError(t.t, err)
    95  	utxo := unspent.Utxos[0]
    96  	key, err := carol.WalletKitClient.ExportPrivateKey(ctxb, &walletrpc.ExportPrivateKeyRequest{Address: utxo.Address})
    97  	require.NoError(t.t, err)
    98  
    99  	// Create Dave.
   100  	dave := net.NewNode(t.t, "dave", nil)
   101  	defer shutdownAndAssert(net, t, dave)
   102  
   103  	// Dave will spend the utxo from Carol's account into its own wallet.
   104  	spendReq := &walletrpc.SpendUTXOsRequest{
   105  		Utxos: []*walletrpc.SpendUTXOsRequest_UTXOAndKey{{
   106  			Txid:          utxo.Outpoint.TxidBytes,
   107  			Index:         utxo.Outpoint.OutputIndex,
   108  			PrivateKeyWif: key.Wif,
   109  			HeightHint:    uint32(minerHeight - utxo.Confirmations - 1),
   110  			Address:       utxo.Address,
   111  		}},
   112  	}
   113  	ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
   114  	spendRes, err := dave.WalletKitClient.SpendUTXOs(ctxt, spendReq)
   115  	require.NoError(t.t, err)
   116  
   117  	// Check that Dave sees the tx.
   118  	ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
   119  	getWtxReq := &walletrpc.GetWalletTxRequest{Txid: spendRes.Txid}
   120  	unminedTx, err := dave.WalletKitClient.GetWalletTx(ctxt, getWtxReq)
   121  	require.NoError(t.t, err)
   122  	require.Equal(t.t, int32(0), unminedTx.Confirmations)
   123  
   124  	// Mine the tx.
   125  	minedBlock := mineBlocks(t, net, 1, 1)[0]
   126  	minedBh := minedBlock.BlockHash()
   127  
   128  	// Dave now sees the mined tx.
   129  	time.Sleep(100 * time.Millisecond)
   130  	minedTx, err := dave.WalletKitClient.GetWalletTx(ctxt, getWtxReq)
   131  	require.NoError(t.t, err)
   132  	require.Equal(t.t, int32(1), minedTx.Confirmations)
   133  	require.Equal(t.t, minedBh[:], minedTx.BlockHash)
   134  
   135  	// Carol has no more balance and Dave has the balance minus tx fee.
   136  	txSize := (&input.TxSizeEstimator{}).AddP2PKHInput().AddP2PKHOutput().Size()
   137  	txFee := chainfee.AtomPerKByte(10000).FeeForSize(txSize)
   138  	checkBalance(carol, 0)
   139  	checkBalance(dave, dcrutil.AtomsPerCoin-txFee)
   140  
   141  	// Dave can spend these coins.
   142  	_, err = dave.SendCoins(ctxt, &lnrpc.SendCoinsRequest{Addr: addrRes.Addr, SendAll: true})
   143  	require.NoError(t.t, err)
   144  	mineBlocks(t, net, 1, 1)
   145  	checkBalance(dave, 0)
   146  	checkBalance(carol, dcrutil.AtomsPerCoin-txFee*2)
   147  }