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 }