github.com/johnathanhowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/wallet/encrypt_test.go (about) 1 package wallet 2 3 import ( 4 "bytes" 5 "crypto/rand" 6 "path/filepath" 7 "testing" 8 9 "github.com/NebulousLabs/Sia/crypto" 10 "github.com/NebulousLabs/Sia/modules" 11 "github.com/NebulousLabs/Sia/types" 12 ) 13 14 // postEncryptionTesting runs a series of checks on the wallet after it has 15 // been encrypted, to make sure that locking, unlocking, and spending after 16 // unlocking are all happening in the correct order and returning the correct 17 // errors. 18 func postEncryptionTesting(m modules.TestMiner, w *Wallet, masterKey crypto.TwofishKey) { 19 if !w.Encrypted() { 20 panic("wallet is not encrypted when starting postEncryptionTesting") 21 } 22 if w.Unlocked() { 23 panic("wallet is unlocked when starting postEncryptionTesting") 24 } 25 if len(w.seeds) != 0 { 26 panic("wallet has seeds in it when startin postEncryptionTesting") 27 } 28 29 // Try unlocking and using the wallet. 30 err := w.Unlock(masterKey) 31 if err != nil { 32 panic(err) 33 } 34 err = w.Unlock(masterKey) 35 if err != errAlreadyUnlocked { 36 panic(err) 37 } 38 // Mine enough coins so that a balance appears (and some buffer for the 39 // send later). 40 for i := types.BlockHeight(0); i <= types.MaturityDelay+1; i++ { 41 _, err := m.AddBlock() 42 if err != nil { 43 panic(err) 44 } 45 } 46 siacoinBal, _, _ := w.ConfirmedBalance() 47 if siacoinBal.Cmp(types.NewCurrency64(0)) <= 0 { 48 panic("wallet balance reported as 0 after maturing some mined blocks") 49 } 50 err = w.Unlock(masterKey) 51 if err != errAlreadyUnlocked { 52 panic(err) 53 } 54 55 // Lock, unlock, and trying using the wallet some more. 56 err = w.Lock() 57 if err != nil { 58 panic(err) 59 } 60 err = w.Lock() 61 if err != modules.ErrLockedWallet { 62 panic(err) 63 } 64 err = w.Unlock(crypto.TwofishKey{}) 65 if err != modules.ErrBadEncryptionKey { 66 panic(err) 67 } 68 err = w.Unlock(masterKey) 69 if err != nil { 70 panic(err) 71 } 72 // Verify that the secret keys have been restored by sending coins to the 73 // void. Send more coins than are received by mining a block. 74 _, err = w.SendSiacoins(types.CalculateCoinbase(0), types.UnlockHash{}) 75 if err != nil { 76 panic(err) 77 } 78 _, err = m.AddBlock() 79 if err != nil { 80 panic(err) 81 } 82 siacoinBal2, _, _ := w.ConfirmedBalance() 83 if siacoinBal2.Cmp(siacoinBal) >= 0 { 84 panic("balance did not increase") 85 } 86 } 87 88 // TestIntegrationPreEncryption checks that the wallet operates as expected 89 // prior to encryption. 90 func TestIntegrationPreEncryption(t *testing.T) { 91 wt, err := createBlankWalletTester("TestIntegrationPreEncryption") 92 if err != nil { 93 t.Fatal(err) 94 } 95 defer wt.closeWt() 96 // Check that the wallet knows it's not encrypted. 97 if wt.wallet.Encrypted() { 98 t.Error("wallet is reporting that it has been encrypted") 99 } 100 err = wt.wallet.Lock() 101 if err != modules.ErrLockedWallet { 102 t.Fatal(err) 103 } 104 err = wt.wallet.Unlock(crypto.TwofishKey{}) 105 if err != errUnencryptedWallet { 106 t.Fatal(err) 107 } 108 109 // Create a second wallet using the same directory - make sure that if any 110 // files have been created, the wallet is still being treated as new. 111 w1, err := New(wt.cs, wt.tpool, filepath.Join(wt.persistDir, modules.WalletDir)) 112 if err != nil { 113 t.Fatal(err) 114 } 115 if w1.Encrypted() { 116 t.Error("wallet is reporting that it has been encrypted when no such action has occurred") 117 } 118 if w1.Unlocked() { 119 t.Error("new wallet is not being treated as locked") 120 } 121 122 } 123 124 // TestIntegrationUserSuppliedEncryption probes the encryption process when the 125 // user manually supplies an encryption key. 126 func TestIntegrationUserSuppliedEncryption(t *testing.T) { 127 if testing.Short() { 128 t.SkipNow() 129 } 130 131 // Create and wallet and user-specified key, then encrypt the wallet and 132 // run post-encryption tests on it. 133 wt, err := createBlankWalletTester("TestIntegrationUserSuppliedEncryption") 134 if err != nil { 135 t.Fatal(err) 136 } 137 defer wt.closeWt() 138 var masterKey crypto.TwofishKey 139 _, err = rand.Read(masterKey[:]) 140 if err != nil { 141 t.Fatal(err) 142 } 143 _, err = wt.wallet.Encrypt(masterKey) 144 if err != nil { 145 t.Error(err) 146 } 147 postEncryptionTesting(wt.miner, wt.wallet, masterKey) 148 } 149 150 // TestIntegrationBlankEncryption probes the encryption process when the user 151 // supplies a blank encryption key during the encryption process. 152 func TestIntegrationBlankEncryption(t *testing.T) { 153 if testing.Short() { 154 t.SkipNow() 155 } 156 157 // Create the wallet. 158 wt, err := createBlankWalletTester("TestIntegrationBlankEncryption") 159 if err != nil { 160 t.Fatal(err) 161 } 162 defer wt.closeWt() 163 // Encrypt the wallet using a blank key. 164 seed, err := wt.wallet.Encrypt(crypto.TwofishKey{}) 165 if err != nil { 166 t.Error(err) 167 } 168 169 // Try unlocking the wallet using a blank key. 170 err = wt.wallet.Unlock(crypto.TwofishKey{}) 171 if err != modules.ErrBadEncryptionKey { 172 t.Fatal(err) 173 } 174 // Try unlocking the wallet using the correct key. 175 err = wt.wallet.Unlock(crypto.TwofishKey(crypto.HashObject(seed))) 176 if err != nil { 177 t.Fatal(err) 178 } 179 err = wt.wallet.Lock() 180 if err != nil { 181 t.Fatal(err) 182 } 183 postEncryptionTesting(wt.miner, wt.wallet, crypto.TwofishKey(crypto.HashObject(seed))) 184 } 185 186 // TestLock checks that lock correctly wipes keys when locking the wallet, 187 // while still being able to track the balance of the wallet. 188 func TestLock(t *testing.T) { 189 if testing.Short() { 190 t.SkipNow() 191 } 192 wt, err := createWalletTester("TestLock") 193 if err != nil { 194 t.Fatal(err) 195 } 196 defer wt.closeWt() 197 198 // Grab a block for work - miner will not supply blocks after the wallet 199 // has been locked, and the test needs to mine a block after locking the 200 // wallet to verify that the balance reporting of a locked wallet is 201 // correct. 202 block, target, err := wt.miner.BlockForWork() 203 if err != nil { 204 t.Fatal(err) 205 } 206 207 // Lock the wallet. 208 siacoinBalance, _, _ := wt.wallet.ConfirmedBalance() 209 err = wt.wallet.Lock() 210 if err != nil { 211 t.Error(err) 212 } 213 // Compare to the original balance. 214 siacoinBalance2, _, _ := wt.wallet.ConfirmedBalance() 215 if siacoinBalance2.Cmp(siacoinBalance) != 0 { 216 t.Error("siacoin balance reporting changed upon closing the wallet") 217 } 218 // Check that the keys and seeds were wiped. 219 wipedKey := make([]byte, crypto.SecretKeySize) 220 for _, key := range wt.wallet.keys { 221 for i := range key.SecretKeys { 222 if !bytes.Equal(wipedKey, key.SecretKeys[i][:]) { 223 t.Error("Key was not wiped after closing the wallet") 224 } 225 } 226 } 227 if len(wt.wallet.seeds) != 0 { 228 t.Error("seeds not wiped from wallet") 229 } 230 if !bytes.Equal(wipedKey[:crypto.EntropySize], wt.wallet.primarySeed[:]) { 231 t.Error("primary seed not wiped from memory") 232 } 233 234 // Solve the block generated earlier and add it to the consensus set, this 235 // should boost the balance of the wallet. 236 solvedBlock, _ := wt.miner.SolveBlock(block, target) 237 err = wt.cs.AcceptBlock(solvedBlock) 238 if err != nil { 239 t.Fatal(err) 240 } 241 siacoinBalance3, _, _ := wt.wallet.ConfirmedBalance() 242 if siacoinBalance3.Cmp(siacoinBalance2) <= 0 { 243 t.Error("balance should increase after a block was mined") 244 } 245 }