github.com/johnathanhowell/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 */