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  }