github.com/johnathanhowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/wallet/money_test.go (about) 1 package wallet 2 3 import ( 4 "sort" 5 "testing" 6 7 "github.com/NebulousLabs/Sia/modules" 8 "github.com/NebulousLabs/Sia/types" 9 ) 10 11 // TestSendSiacoins probes the SendSiacoins method of the wallet. 12 func TestSendSiacoins(t *testing.T) { 13 if testing.Short() { 14 t.SkipNow() 15 } 16 wt, err := createWalletTester("TestSendSiacoins") 17 if err != nil { 18 t.Fatal(err) 19 } 20 defer wt.closeWt() 21 22 // Get the initial balance - should be 1 block. The unconfirmed balances 23 // should be 0. 24 confirmedBal, _, _ := wt.wallet.ConfirmedBalance() 25 unconfirmedOut, unconfirmedIn := wt.wallet.UnconfirmedBalance() 26 if confirmedBal.Cmp(types.CalculateCoinbase(1)) != 0 { 27 t.Error("unexpected confirmed balance") 28 } 29 if unconfirmedOut.Cmp(types.ZeroCurrency) != 0 { 30 t.Error("unconfirmed balance should be 0") 31 } 32 if unconfirmedIn.Cmp(types.ZeroCurrency) != 0 { 33 t.Error("unconfirmed balance should be 0") 34 } 35 36 // Send 5000 hastings. The wallet will automatically add a fee. Outgoing 37 // unconfirmed siacoins - incoming unconfirmed siacoins should equal 5000 + 38 // fee. 39 tpoolFee := types.SiacoinPrecision.Mul64(10) 40 _, err = wt.wallet.SendSiacoins(types.NewCurrency64(5000), types.UnlockHash{}) 41 if err != nil { 42 t.Fatal(err) 43 } 44 confirmedBal2, _, _ := wt.wallet.ConfirmedBalance() 45 unconfirmedOut2, unconfirmedIn2 := wt.wallet.UnconfirmedBalance() 46 if confirmedBal2.Cmp(confirmedBal) != 0 { 47 t.Error("confirmed balance changed without introduction of blocks") 48 } 49 if unconfirmedOut2.Cmp(unconfirmedIn2.Add(types.NewCurrency64(5000)).Add(tpoolFee)) != 0 { 50 t.Error("sending siacoins appears to be ineffective") 51 } 52 53 // Move the balance into the confirmed set. 54 b, _ := wt.miner.FindBlock() 55 err = wt.cs.AcceptBlock(b) 56 if err != nil { 57 t.Fatal(err) 58 } 59 confirmedBal3, _, _ := wt.wallet.ConfirmedBalance() 60 unconfirmedOut3, unconfirmedIn3 := wt.wallet.UnconfirmedBalance() 61 if confirmedBal3.Cmp(confirmedBal2.Add(types.CalculateCoinbase(2)).Sub(types.NewCurrency64(5000)).Sub(tpoolFee)) != 0 { 62 t.Error("confirmed balance did not adjust to the expected value") 63 } 64 if unconfirmedOut3.Cmp(types.ZeroCurrency) != 0 { 65 t.Error("unconfirmed balance should be 0") 66 } 67 if unconfirmedIn3.Cmp(types.ZeroCurrency) != 0 { 68 t.Error("unconfirmed balance should be 0") 69 } 70 } 71 72 // TestIntegrationSendOverUnder sends too many siacoins, resulting in an error, 73 // followed by sending few enough siacoins that the send should complete. 74 // 75 // This test is here because of a bug found in production where the wallet 76 // would mark outputs as spent before it knew that there was enough money to 77 // complete the transaction. This meant that, after trying to send too many 78 // coins, all outputs got marked 'sent'. This test reproduces those conditions 79 // to ensure it does not happen again. 80 func TestIntegrationSendOverUnder(t *testing.T) { 81 if testing.Short() { 82 t.SkipNow() 83 } 84 wt, err := createWalletTester("TestIntegrationSpendOverUnder") 85 if err != nil { 86 t.Fatal(err) 87 } 88 defer wt.closeWt() 89 90 // Spend too many siacoins. 91 tooManyCoins := types.SiacoinPrecision.Mul64(1e12) 92 _, err = wt.wallet.SendSiacoins(tooManyCoins, types.UnlockHash{}) 93 if err != modules.ErrLowBalance { 94 t.Error("low balance err not returned after attempting to send too many coins") 95 } 96 97 // Spend a reasonable amount of siacoins. 98 reasonableCoins := types.SiacoinPrecision.Mul64(100e3) 99 _, err = wt.wallet.SendSiacoins(reasonableCoins, types.UnlockHash{}) 100 if err != nil { 101 t.Error("unexpected error: ", err) 102 } 103 } 104 105 // TestIntegrationSpendHalfHalf spends more than half of the coins, and then 106 // more than half of the coins again, to make sure that the wallet is not 107 // reusing outputs that it has already spent. 108 func TestIntegrationSpendHalfHalf(t *testing.T) { 109 if testing.Short() { 110 t.SkipNow() 111 } 112 wt, err := createWalletTester("TestIntegrationSpendHalfHalf") 113 if err != nil { 114 t.Fatal(err) 115 } 116 defer wt.closeWt() 117 118 // Spend more than half of the coins twice. 119 halfPlus := types.SiacoinPrecision.Mul64(200e3) 120 _, err = wt.wallet.SendSiacoins(halfPlus, types.UnlockHash{}) 121 if err != nil { 122 t.Error("unexpected error: ", err) 123 } 124 _, err = wt.wallet.SendSiacoins(halfPlus, types.UnlockHash{1}) 125 if err != modules.ErrPotentialDoubleSpend { 126 t.Error("wallet appears to be reusing outputs when building transactions: ", err) 127 } 128 } 129 130 // TestIntegrationSpendUnconfirmed spends an unconfirmed siacoin output. 131 func TestIntegrationSpendUnconfirmed(t *testing.T) { 132 if testing.Short() { 133 t.SkipNow() 134 } 135 wt, err := createWalletTester("TestIntegrationSpendUnconfirmed") 136 if err != nil { 137 t.Fatal(err) 138 } 139 defer wt.closeWt() 140 141 // Spend the only output. 142 halfPlus := types.SiacoinPrecision.Mul64(200e3) 143 _, err = wt.wallet.SendSiacoins(halfPlus, types.UnlockHash{}) 144 if err != nil { 145 t.Error("unexpected error: ", err) 146 } 147 someMore := types.SiacoinPrecision.Mul64(75e3) 148 _, err = wt.wallet.SendSiacoins(someMore, types.UnlockHash{1}) 149 if err != nil { 150 t.Error("wallet appears to be struggling to spend unconfirmed outputs") 151 } 152 } 153 154 // TestIntegrationSortedOutputsSorting checks that the outputs are being correctly sorted 155 // by the currency value. 156 func TestIntegrationSortedOutputsSorting(t *testing.T) { 157 if testing.Short() { 158 t.SkipNow() 159 } 160 so := sortedOutputs{ 161 ids: []types.SiacoinOutputID{{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}}, 162 outputs: []types.SiacoinOutput{ 163 {Value: types.NewCurrency64(2)}, 164 {Value: types.NewCurrency64(3)}, 165 {Value: types.NewCurrency64(4)}, 166 {Value: types.NewCurrency64(7)}, 167 {Value: types.NewCurrency64(6)}, 168 {Value: types.NewCurrency64(0)}, 169 {Value: types.NewCurrency64(1)}, 170 {Value: types.NewCurrency64(5)}, 171 }, 172 } 173 sort.Sort(so) 174 175 expectedIDSorting := []types.SiacoinOutputID{{5}, {6}, {0}, {1}, {2}, {7}, {4}, {3}} 176 for i := uint64(0); i < 8; i++ { 177 if so.ids[i] != expectedIDSorting[i] { 178 t.Error("an id is out of place: ", i) 179 } 180 if so.outputs[i].Value.Cmp(types.NewCurrency64(i)) != 0 { 181 t.Error("a value is out of place: ", i) 182 } 183 } 184 }