github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/wallet/persist_legacy.go (about)

     1  package wallet
     2  
     3  /*
     4  import (
     5  	"path/filepath"
     6  
     7  	"github.com/NebulousLabs/Sia/crypto"
     8  	"github.com/NebulousLabs/Sia/encoding"
     9  	"github.com/NebulousLabs/Sia/types"
    10  )
    11  
    12  // a savedKey contains a single-signature key and all the tools needed to spend
    13  // outputs at its address.
    14  type savedKey struct {
    15  	SecretKey        crypto.SecretKey
    16  	UnlockConditions types.UnlockConditions
    17  	Visible          bool
    18  }
    19  
    20  // saveKeys saves the current set of keys known to the wallet to a file.
    21  func (w *Wallet) saveKeys(filepath string) error {
    22  	// Convert the key map to a slice and write to disk.
    23  	keySlice := make([]savedKey, 0, len(w.keys))
    24  	for _, key := range w.keys {
    25  		_, exists := w.visibleAddresses[key.unlockConditions.UnlockHash()]
    26  		keySlice = append(keySlice, savedKey{key.secretKey, key.unlockConditions, exists})
    27  	}
    28  	return encoding.WriteFile(filepath, keySlice)
    29  }
    30  
    31  // saveSiafundTracking save the addresses that track siafunds.
    32  func (w *Wallet) saveSiafundTracking(filepath string) error {
    33  	// Put the siafund tracking addresses into a slice and write to disk.
    34  	siafundSlice := make([]types.UnlockHash, 0, len(w.siafundAddresses))
    35  	for sa, _ := range w.siafundAddresses {
    36  		siafundSlice = append(siafundSlice, sa)
    37  	}
    38  	return encoding.WriteFile(filepath, siafundSlice)
    39  }
    40  
    41  // save writes the contents of a wallet to a file.
    42  func (w *Wallet) save() error {
    43  	// Save the siacoin keys to disk.
    44  	err := w.saveKeys(filepath.Join(w.persistDir, "wallet.backup"))
    45  	if err != nil {
    46  		return err
    47  	}
    48  	err = w.saveKeys(filepath.Join(w.persistDir, "wallet.dat"))
    49  	if err != nil {
    50  		return err
    51  	}
    52  
    53  	// outputs.dat is intentionally a bit of a misleading name. If I called it
    54  	// 'siafunds.dat' or something similar, people might think it's okay to
    55  	// delete their siafund keys, which is NOT okay. Instead of potentially
    56  	// having this confusion, I chose a less suggestive name.
    57  	err = w.saveSiafundTracking(filepath.Join(w.persistDir, "outputs.backup"))
    58  	if err != nil {
    59  		return err
    60  	}
    61  	// Save the primary copy.
    62  	err = w.saveSiafundTracking(filepath.Join(w.persistDir, "outputs.dat"))
    63  	if err != nil {
    64  		return err
    65  	}
    66  
    67  	return nil
    68  }
    69  
    70  // loadKeys takes a set of keys and loads them into the wallet.
    71  func (w *Wallet) loadKeys(savedKeys []savedKey) error {
    72  	height := w.consensusHeight
    73  	for _, skey := range savedKeys {
    74  		// Skip this key if it's already known to the wallet.
    75  		_, exists := w.keys[skey.UnlockConditions.UnlockHash()]
    76  		if exists {
    77  			continue
    78  		}
    79  
    80  		// Create an entry in w.keys for each savedKey.
    81  		w.keys[skey.UnlockConditions.UnlockHash()] = &key{
    82  			spendable:        height >= skey.UnlockConditions.Timelock,
    83  			unlockConditions: skey.UnlockConditions,
    84  			secretKey:        skey.SecretKey,
    85  			outputs:          make(map[types.SiacoinOutputID]*knownOutput),
    86  		}
    87  
    88  		// If Timelock != 0, also add to set of timelockedKeys.
    89  		if tl := skey.UnlockConditions.Timelock; tl != 0 {
    90  			w.timelockedKeys[tl] = append(w.timelockedKeys[tl], skey.UnlockConditions.UnlockHash())
    91  		}
    92  
    93  		if skey.Visible {
    94  			w.visibleAddresses[skey.UnlockConditions.UnlockHash()] = struct{}{}
    95  		}
    96  	}
    97  
    98  	// If there are no visible addresses, create one.
    99  	if len(w.visibleAddresses) == 0 {
   100  		_, _, err := w.coinAddress(true)
   101  		if err != nil {
   102  			return err
   103  		}
   104  	}
   105  
   106  	return nil
   107  }
   108  
   109  // loadWallet pulls a wallet from disk into memory, merging it with whatever
   110  // wallet is already in memory. The result is a combined wallet that has all of
   111  // the addresses.
   112  func (w *Wallet) loadWallet(filepath string) error {
   113  	var savedKeys []savedKey
   114  	err := encoding.ReadFile(filepath, &savedKeys)
   115  	if err != nil {
   116  		return err
   117  	}
   118  	err = w.loadKeys(savedKeys)
   119  	if err != nil {
   120  		return err
   121  	}
   122  	return nil
   123  }
   124  
   125  // loadSiafundTracking loads siafund addresses for tracking.
   126  func (w *Wallet) loadSiafundTracking(filepath string) error {
   127  	// Load the siafunds file, which is intentionally called 'outputs.dat'.
   128  	var siafundAddresses []types.UnlockHash
   129  	err := encoding.ReadFile(filepath, &siafundAddresses)
   130  	if err != nil {
   131  		return err
   132  	}
   133  
   134  	// Load the addresses into the wallet.
   135  	for _, sa := range siafundAddresses {
   136  		w.siafundAddresses[sa] = struct{}{}
   137  	}
   138  	return nil
   139  }
   140  
   141  // load reads the contents of a wallet from a file.
   142  func (w *Wallet) load() error {
   143  	err := w.loadWallet(filepath.Join(w.persistDir, "wallet.dat"))
   144  	if err != nil {
   145  		// try loading the backup
   146  		// TODO: display/log a warning
   147  		err = w.loadWallet(filepath.Join(w.persistDir, "wallet.backup"))
   148  		if err != nil {
   149  			return err
   150  		}
   151  	}
   152  
   153  	// Load the siafunds file, which is intentionally called 'outputs.dat'.
   154  	err = w.loadSiafundTracking(filepath.Join(w.persistDir, "outputs.dat"))
   155  	if err != nil {
   156  		// try loading the backup
   157  		// TODO: display/log a warning?
   158  		err = w.loadSiafundTracking(filepath.Join(w.persistDir, "outputs.backup"))
   159  		if err != nil {
   160  			return err
   161  		}
   162  	}
   163  
   164  	return w.save()
   165  }
   166  
   167  // MergeWallet merges another wallet with the already-loaded wallet, creating a
   168  // new wallet that contains all of the addresses from each. This is useful for
   169  // loading backups.
   170  func (w *Wallet) MergeWallet(filepath string) error {
   171  	err := w.loadWallet(filepath)
   172  	if err != nil {
   173  		return err
   174  	}
   175  	return w.save()
   176  }
   177  */