1 package waddrmgr
2 3 import (
4 "crypto/sha256"
5 "encoding/binary"
6 "fmt"
7 "github.com/p9c/p9/pkg/chaincfg"
8 "time"
9 10 "github.com/p9c/p9/pkg/chainhash"
11 "github.com/p9c/p9/pkg/walletdb"
12 )
13 14 const (
15 // LatestMgrVersion is the most recent manager version.
16 LatestMgrVersion = 5
17 18 // latestMgrVersion is the most recent manager version as a variable so the
19 // tests can change it to force errors.
20 latestMgrVersion = uint32(LatestMgrVersion)
21 )
22 23 // ObtainUserInputFunc is a function that reads a user input and returns it as a
24 // byte stream. It is used to accept data required during upgrades, for e.g.
25 // wallet seed and private passphrase.
26 type ObtainUserInputFunc func() ([]byte, error)
27 28 // maybeConvertDbError converts the passed error to a ManagerError with an error
29 // code of ErrDatabase if it is not already a ManagerError. This is useful for
30 // potential errors returned from managed transaction an other parts of the
31 // walletdb database.
32 func maybeConvertDbError(ee error) (e error) {
33 // When the error is already a ManagerError, just return it.
34 if _, ok := ee.(ManagerError); ok {
35 return ee
36 }
37 return managerError(ErrDatabase, ee.Error(), e)
38 }
39 40 // syncStatus represents a address synchronization status stored in the
41 // database.
42 type syncStatus uint8
43 44 // These constants define the various supported sync status types.
45 //
46 // NOTE: These are currently unused but are being defined for the possibility of
47 // supporting sync status on a per-address basis.
48 const (
49 ssNone syncStatus = 0 // not iota as they need to be stable for db
50 // ssPartial syncStatus = 1
51 ssFull syncStatus = 2
52 )
53 54 // addressType represents a type of address stored in the database.
55 type addressType uint8
56 57 // These constants define the various supported address types.
58 const (
59 adtChain addressType = 0
60 adtImport addressType = 1 // not iota as they need to be stable for db
61 adtScript addressType = 2
62 )
63 64 // accountType represents a type of address stored in the database.
65 type accountType uint8
66 67 // These constants define the various supported account types.
68 const (
69 // accountDefault is the current "default" account type within the database.
70 // This is an account that re-uses the key derivation schema of BIP0044-like
71 // accounts.
72 accountDefault accountType = 0 // not iota as they need to be stable
73 )
74 75 // dbAccountRow houses information stored about an account in the database.
76 type dbAccountRow struct {
77 acctType accountType
78 rawData []byte // Varies based on account type field.
79 }
80 81 // dbDefaultAccountRow houses additional information stored about a default
82 // BIP0044-like account in the database.
83 type dbDefaultAccountRow struct {
84 dbAccountRow
85 pubKeyEncrypted []byte
86 privKeyEncrypted []byte
87 nextExternalIndex uint32
88 nextInternalIndex uint32
89 name string
90 }
91 92 // dbAddressRow houses common information stored about an address in the
93 // database.
94 type dbAddressRow struct {
95 addTime uint64
96 rawData []byte // Varies based on address type field.
97 account uint32
98 syncStatus syncStatus
99 addrType addressType
100 }
101 102 // dbChainAddressRow houses additional information stored about a chained
103 // address in the database.
104 type dbChainAddressRow struct {
105 dbAddressRow
106 branch uint32
107 index uint32
108 }
109 110 // dbImportedAddressRow houses additional information stored about an imported
111 // public key address in the database.
112 type dbImportedAddressRow struct {
113 dbAddressRow
114 encryptedPubKey []byte
115 encryptedPrivKey []byte
116 }
117 118 // dbImportedAddressRow houses additional information stored about a script
119 // address in the database.
120 type dbScriptAddressRow struct {
121 dbAddressRow
122 encryptedHash []byte
123 encryptedScript []byte
124 }
125 126 // Key names for various database fields. these are variables but only because
127 // they are not able to be constants
128 var (
129 // nullVal is null byte used as a flag value in a bucket entry
130 nullVal = []byte{0}
131 // Bucket names.
132 //
133 // scopeSchemaBucket is the name of the bucket that maps a particular manager
134 // scope to the type of addresses that should be derived for particular branches
135 // during key derivation.
136 scopeSchemaBucketName = []byte("scope-schema")
137 // scopeBucketNme is the name of the top-level bucket within the hierarchy. It
138 // maps: purpose || coinType to a new sub-bucket that will house a scoped
139 // address manager. All buckets below are a child of this bucket:
140 //
141 // scopeBucket -> scope -> acctBucket
142 // scopeBucket -> scope -> addrBucket
143 // scopeBucket -> scope -> usedAddrBucket
144 // scopeBucket -> scope -> addrAcctIdxBucket
145 // scopeBucket -> scope -> acctNameIdxBucket
146 // scopeBucket -> scope -> acctIDIdxBucketName
147 // scopeBucket -> scope -> metaBucket
148 // scopeBucket -> scope -> metaBucket -> lastAccountNameKey
149 // scopeBucket -> scope -> coinTypePrivKey
150 // scopeBucket -> scope -> coinTypePubKey
151 scopeBucketName = []byte("scope")
152 // coinTypePrivKeyName is the name of the key within a particular scope bucket
153 // that stores the encrypted cointype private keys. Each scope within the
154 // database will have its own set of coin type keys.
155 coinTypePrivKeyName = []byte("ctpriv")
156 // coinTypePrivKeyName is the name of the key within a particular scope bucket
157 // that stores the encrypted cointype public keys. Each scope will have its own
158 // set of coin type public keys.
159 coinTypePubKeyName = []byte("ctpub")
160 // acctBucketName is the bucket directly below the scope bucket in the
161 // hierarchy. This bucket stores all the information and indexes relevant to an
162 // account.
163 acctBucketName = []byte("acct")
164 // addrBucketName is the name of the bucket that stores a mapping of pubkey hash
165 // to address type. This will be used to quickly determine if a given address is
166 // under our control.
167 addrBucketName = []byte("addr")
168 // addrAcctIdxBucketName is used to index account addresses Entries in this
169 // index may map:
170 //
171 // * addr hash => account id
172 //
173 // * account bucket -> addr hash => null
174 //
175 // To fetch the account of an address, lookup the value using the address hash.
176 //
177 // To fetch all addresses of an account, fetch the account bucket, iterate over
178 // the keys and fetch the address row from the addr bucket.
179 //
180 // The index needs to be updated whenever an address is created e.g. NewAddress
181 addrAcctIdxBucketName = []byte("addracctidx")
182 // acctNameIdxBucketName is used to create an index mapping an account name
183 // string to the corresponding account id. The index needs to be updated
184 // whenever the account name and id changes e.g. RenameAccount
185 //
186 // string => account_id
187 acctNameIdxBucketName = []byte("acctnameidx")
188 // acctIDIdxBucketName is used to create an index mapping an account id to the
189 // corresponding account name string. The index needs to be updated whenever the
190 // account name and id changes e.g. RenameAccount
191 //
192 // account_id => string
193 acctIDIdxBucketName = []byte("acctididx")
194 // usedAddrBucketName is the name of the bucket that stores an addresses hash if
195 // the address has been used or not.
196 usedAddrBucketName = []byte("usedaddrs")
197 // meta is used to store meta-data about the address manager e.g. last account
198 // number
199 metaBucketName = []byte("meta")
200 // lastAccountName is used to store the metadata - last account in the manager
201 lastAccountName = []byte("lastaccount")
202 // mainBucketName is the name of the bucket that stores the encrypted crypto
203 // keys that encrypt all other generated keys, the watch only flag, the master
204 // private key (encrypted), the master HD private key (encrypted), and also
205 // versioning information.
206 mainBucketName = []byte("main")
207 // masterHDPrivName is the name of the key that stores the master HD private
208 // key. This key is encrypted with the master private crypto encryption key.
209 // This resides under the main bucket.
210 masterHDPrivName = []byte("mhdpriv")
211 // masterHDPubName is the name of the key that stores the master HD public key.
212 // This key is encrypted with the master public crypto encryption key. This
213 // reside under the main bucket.
214 masterHDPubName = []byte("mhdpub")
215 // syncBucketName is the name of the bucket that stores the current sync state
216 // of the root manager.
217 syncBucketName = []byte("sync")
218 // Db related key names (main bucket).
219 mgrVersionName = []byte("mgrver")
220 mgrCreateDateName = []byte("mgrcreated")
221 // Crypto related key names (main bucket).
222 masterPrivKeyName = []byte("mpriv")
223 masterPubKeyName = []byte("mpub")
224 cryptoPrivKeyName = []byte("cpriv")
225 cryptoPubKeyName = []byte("cpub")
226 cryptoScriptKeyName = []byte("cscript")
227 watchingOnlyName = []byte("watchonly")
228 // Sync related key names (sync bucket).
229 syncedToName = []byte("syncedto")
230 startBlockName = []byte("startblock")
231 birthdayName = []byte("birthday")
232 )
233 234 // uint32ToBytes converts a 32 bit unsigned integer into a 4-byte slice in
235 // little-endian order: 1 -> [1 0 0 0].
236 func uint32ToBytes(number uint32) []byte {
237 buf := make([]byte, 4)
238 binary.LittleEndian.PutUint32(buf, number)
239 return buf
240 }
241 242 // // uint64ToBytes converts a 64 bit unsigned integer into a 8-byte slice in
243 // // little-endian order: 1 -> [1 0 0 0 0 0 0 0].
244 // func uint64ToBytes(// number uint64) []byte {
245 // buf := make([]byte, 8)
246 // binary.LittleEndian.PutUint64(buf, number)
247 // return buf
248 // }
249 250 // stringToBytes converts a string into a variable length byte slice in
251 // little-endian order: "abc" -> [3 0 0 0 61 62 63]
252 func stringToBytes(s string) []byte {
253 // The serialized format is:
254 // <size><string>
255 //
256 // 4 bytes string size + string
257 size := len(s)
258 buf := make([]byte, 4+size)
259 copy(buf[0:4], uint32ToBytes(uint32(size)))
260 copy(buf[4:4+size], s)
261 return buf
262 }
263 264 // scopeKeySize is the size of a scope as stored within the database.
265 const scopeKeySize = 8
266 267 // scopeToBytes transforms a manager's scope into the form that will be used to
268 // retrieve the bucket that all information for a particular scope is stored
269 // under
270 func scopeToBytes(scope *KeyScope) [scopeKeySize]byte {
271 var scopeBytes [scopeKeySize]byte
272 binary.LittleEndian.PutUint32(scopeBytes[:], scope.Purpose)
273 binary.LittleEndian.PutUint32(scopeBytes[4:], scope.Coin)
274 return scopeBytes
275 }
276 277 // // scopeFromBytes decodes a serializes manager scope into its concrete manager
278 // // scope struct.
279 // func scopeFromBytes(// scopeBytes []byte) KeyScope {
280 // return KeyScope{
281 // Purpose: binary.LittleEndian.Uint32(scopeBytes[:]),
282 // Coin: binary.LittleEndian.Uint32(scopeBytes[4:]),
283 // }
284 // }
285 286 // scopeSchemaToBytes encodes the passed scope schema as a set of bytes suitable
287 // for storage within the database.
288 func scopeSchemaToBytes(schema *ScopeAddrSchema) []byte {
289 var schemaBytes [2]byte
290 schemaBytes[0] = byte(schema.InternalAddrType)
291 schemaBytes[1] = byte(schema.ExternalAddrType)
292 return schemaBytes[:]
293 }
294 295 // scopeSchemaFromBytes decodes a new scope schema instance from the set of
296 // serialized bytes.
297 func scopeSchemaFromBytes(schemaBytes []byte) *ScopeAddrSchema {
298 return &ScopeAddrSchema{
299 InternalAddrType: AddressType(schemaBytes[0]),
300 ExternalAddrType: AddressType(schemaBytes[1]),
301 }
302 }
303 304 // fetchScopeAddrSchema will attempt to retrieve the address schema for a
305 // particular manager scope stored within the database. These are used in order
306 // to properly type each address generated by the scope address manager.
307 func fetchScopeAddrSchema(
308 ns walletdb.ReadBucket,
309 scope *KeyScope,
310 ) (*ScopeAddrSchema, error) {
311 schemaBucket := ns.NestedReadBucket(scopeSchemaBucketName)
312 if schemaBucket == nil {
313 str := fmt.Sprintf("unable to find scope schema bucket")
314 return nil, managerError(ErrScopeNotFound, str, nil)
315 }
316 scopeKey := scopeToBytes(scope)
317 schemaBytes := schemaBucket.Get(scopeKey[:])
318 if schemaBytes == nil {
319 str := fmt.Sprintf("unable to find scope %v", scope)
320 return nil, managerError(ErrScopeNotFound, str, nil)
321 }
322 return scopeSchemaFromBytes(schemaBytes), nil
323 }
324 325 // putScopeAddrSchema attempts to store the passed addr scehma for the given
326 // manager scope.
327 func putScopeAddrTypes(ns walletdb.ReadWriteBucket, scope *KeyScope, schema *ScopeAddrSchema) (e error) {
328 scopeSchemaBucket := ns.NestedReadWriteBucket(scopeSchemaBucketName)
329 if scopeSchemaBucket == nil {
330 str := fmt.Sprintf("unable to find scope schema bucket")
331 return managerError(ErrScopeNotFound, str, nil)
332 }
333 scopeKey := scopeToBytes(scope)
334 schemaBytes := scopeSchemaToBytes(schema)
335 return scopeSchemaBucket.Put(scopeKey[:], schemaBytes)
336 }
337 338 func fetchReadScopeBucket(ns walletdb.ReadBucket, scope *KeyScope) (walletdb.ReadBucket, error) {
339 rootScopeBucket := ns.NestedReadBucket(scopeBucketName)
340 scopeKey := scopeToBytes(scope)
341 scopedBucket := rootScopeBucket.NestedReadBucket(scopeKey[:])
342 if scopedBucket == nil {
343 str := fmt.Sprintf("unable to find scope %v", scope)
344 return nil, managerError(ErrScopeNotFound, str, nil)
345 }
346 return scopedBucket, nil
347 }
348 349 func fetchWriteScopeBucket(
350 ns walletdb.ReadWriteBucket,
351 scope *KeyScope,
352 ) (walletdb.ReadWriteBucket, error) {
353 rootScopeBucket := ns.NestedReadWriteBucket(scopeBucketName)
354 scopeKey := scopeToBytes(scope)
355 scopedBucket := rootScopeBucket.NestedReadWriteBucket(scopeKey[:])
356 if scopedBucket == nil {
357 str := fmt.Sprintf("unable to find scope %v", scope)
358 return nil, managerError(ErrScopeNotFound, str, nil)
359 }
360 return scopedBucket, nil
361 }
362 363 // fetchManagerVersion fetches the current manager version from the database.
364 func fetchManagerVersion(ns walletdb.ReadBucket) (uint32, error) {
365 mainBucket := ns.NestedReadBucket(mainBucketName)
366 verBytes := mainBucket.Get(mgrVersionName)
367 if verBytes == nil {
368 str := "required version number not stored in database"
369 return 0, managerError(ErrDatabase, str, nil)
370 }
371 version := binary.LittleEndian.Uint32(verBytes)
372 return version, nil
373 }
374 375 // putManagerVersion stores the provided version to the database.
376 func putManagerVersion(ns walletdb.ReadWriteBucket, version uint32) (e error) {
377 bucket := ns.NestedReadWriteBucket(mainBucketName)
378 verBytes := uint32ToBytes(version)
379 if e = bucket.Put(mgrVersionName, verBytes); E.Chk(e) {
380 str := "failed to store version"
381 return managerError(ErrDatabase, str, e)
382 }
383 return nil
384 }
385 386 // fetchMasterKeyParams loads the master key parameters needed to derive them
387 // (when given the correct user-supplied passphrase) from the database. Either
388 // returned value can be nil, but in practice only the private key netparams
389 // will be nil for a watching-only database.
390 func fetchMasterKeyParams(ns walletdb.ReadBucket) ([]byte, []byte, error) {
391 bucket := ns.NestedReadBucket(mainBucketName)
392 // Load the master public key parameters. Required.
393 val := bucket.Get(masterPubKeyName)
394 if val == nil {
395 str := "required master public key parameters not stored in " +
396 "database"
397 return nil, nil, managerError(ErrDatabase, str, nil)
398 }
399 pubParams := make([]byte, len(val))
400 copy(pubParams, val)
401 // Load the master private key parameters if they were stored.
402 var privParams []byte
403 val = bucket.Get(masterPrivKeyName)
404 if val != nil {
405 privParams = make([]byte, len(val))
406 copy(privParams, val)
407 }
408 return pubParams, privParams, nil
409 }
410 411 // putMasterKeyParams stores the master key parameters needed to derive them to
412 // the database. Either parameter can be nil in which case no value is written
413 // for the parameter.
414 func putMasterKeyParams(ns walletdb.ReadWriteBucket, pubParams, privParams []byte) (e error) {
415 bucket := ns.NestedReadWriteBucket(mainBucketName)
416 if privParams != nil {
417 if e = bucket.Put(masterPrivKeyName, privParams); E.Chk(e) {
418 str := "failed to store master private key parameters"
419 return managerError(ErrDatabase, str, e)
420 }
421 }
422 if pubParams != nil {
423 if e = bucket.Put(masterPubKeyName, pubParams); E.Chk(e) {
424 str := "failed to store master public key parameters"
425 return managerError(ErrDatabase, str, e)
426 }
427 }
428 return nil
429 }
430 431 // fetchCoinTypeKeys loads the encrypted cointype keys which are in turn used to
432 // derive the extended keys for all accounts. Each cointype key is associated
433 // with a particular manager scoped.
434 func fetchCoinTypeKeys(ns walletdb.ReadBucket, scope *KeyScope) ([]byte, []byte, error) {
435 scopedBucket, e := fetchReadScopeBucket(ns, scope)
436 if e != nil {
437 return nil, nil, e
438 }
439 coinTypePubKeyEnc := scopedBucket.Get(coinTypePubKeyName)
440 if coinTypePubKeyEnc == nil {
441 str := "required encrypted cointype public key not stored in database"
442 return nil, nil, managerError(ErrDatabase, str, nil)
443 }
444 coinTypePrivKeyEnc := scopedBucket.Get(coinTypePrivKeyName)
445 if coinTypePrivKeyEnc == nil {
446 str := "required encrypted cointype private key not stored in database"
447 return nil, nil, managerError(ErrDatabase, str, nil)
448 }
449 return coinTypePubKeyEnc, coinTypePrivKeyEnc, nil
450 }
451 452 // putCoinTypeKeys stores the encrypted cointype keys which are in turn used to
453 // derive the extended keys for all accounts. Either parameter can be nil in
454 // which case no value is written for the parameter. Each cointype key is
455 // associated with a particular manager scope.
456 func putCoinTypeKeys(
457 ns walletdb.ReadWriteBucket, scope *KeyScope,
458 coinTypePubKeyEnc []byte, coinTypePrivKeyEnc []byte,
459 ) (e error) {
460 var scopedBucket walletdb.ReadWriteBucket
461 if scopedBucket, e = fetchWriteScopeBucket(ns, scope); E.Chk(e) {
462 return e
463 }
464 if coinTypePubKeyEnc != nil {
465 if e = scopedBucket.Put(coinTypePubKeyName, coinTypePubKeyEnc); E.Chk(e) {
466 str := "failed to store encrypted cointype public key"
467 return managerError(ErrDatabase, str, e)
468 }
469 }
470 if coinTypePrivKeyEnc != nil {
471 if e = scopedBucket.Put(coinTypePrivKeyName, coinTypePrivKeyEnc); E.Chk(e) {
472 str := "failed to store encrypted cointype private key"
473 return managerError(ErrDatabase, str, e)
474 }
475 }
476 return nil
477 }
478 479 // putMasterHDKeys stores the encrypted master HD keys in the top level main
480 // bucket. These are required in order to create any new manager scopes, as
481 // those are created via hardened derivation of the children of this key.
482 func putMasterHDKeys(ns walletdb.ReadWriteBucket, masterHDPrivEnc, masterHDPubEnc []byte) (e error) {
483 // As this is the key for the root manager, we don't need to fetch any
484 // particular scope, and can insert directly within the main bucket.
485 bucket := ns.NestedReadWriteBucket(mainBucketName)
486 // Now that we have the main bucket, we can directly store each of the relevant
487 // keys. If we're in watch only mode, then some or all of these keys might not
488 // be available.
489 if masterHDPrivEnc != nil {
490 if e = bucket.Put(masterHDPrivName, masterHDPrivEnc); E.Chk(e) {
491 str := "failed to store encrypted master HD private key"
492 return managerError(ErrDatabase, str, e)
493 }
494 }
495 if masterHDPubEnc != nil {
496 if e = bucket.Put(masterHDPubName, masterHDPubEnc); E.Chk(e) {
497 str := "failed to store encrypted master HD public key"
498 return managerError(ErrDatabase, str, e)
499 }
500 }
501 return nil
502 }
503 504 // fetchMasterHDKeys attempts to fetch both the master HD private and public
505 // keys from the database. If this is a watch only wallet, then it's possible
506 // that the master private key isn't stored.
507 func fetchMasterHDKeys(ns walletdb.ReadBucket) ([]byte, []byte, error) {
508 bucket := ns.NestedReadBucket(mainBucketName)
509 var masterHDPrivEnc, masterHDPubEnc []byte
510 // First, we'll try to fetch the master private key. If this database is watch
511 // only, or the master has been neutered, then this won't be found on disk.
512 key := bucket.Get(masterHDPrivName)
513 if key != nil {
514 masterHDPrivEnc = make([]byte, len(key))
515 copy(masterHDPrivEnc, key)
516 }
517 key = bucket.Get(masterHDPubName)
518 if key != nil {
519 masterHDPubEnc = make([]byte, len(key))
520 copy(masterHDPubEnc, key)
521 }
522 return masterHDPrivEnc, masterHDPubEnc, nil
523 }
524 525 // fetchCryptoKeys loads the encrypted crypto keys which are in turn used to
526 // protect the extended keys, imported keys, and scripts. Any of the returned
527 // values can be nil, but in practice only the crypto private and script keys
528 // will be nil for a watching-only database.
529 func fetchCryptoKeys(ns walletdb.ReadBucket) ([]byte, []byte, []byte, error) {
530 bucket := ns.NestedReadBucket(mainBucketName)
531 // Load the crypto public key parameters. Required.
532 val := bucket.Get(cryptoPubKeyName)
533 if val == nil {
534 str := "required encrypted crypto public not stored in database"
535 return nil, nil, nil, managerError(ErrDatabase, str, nil)
536 }
537 pubKey := make([]byte, len(val))
538 copy(pubKey, val)
539 // Load the crypto private key parameters if they were stored.
540 var privKey []byte
541 val = bucket.Get(cryptoPrivKeyName)
542 if val != nil {
543 privKey = make([]byte, len(val))
544 copy(privKey, val)
545 }
546 // Load the crypto script key parameters if they were stored.
547 var scriptKey []byte
548 val = bucket.Get(cryptoScriptKeyName)
549 if val != nil {
550 scriptKey = make([]byte, len(val))
551 copy(scriptKey, val)
552 }
553 return pubKey, privKey, scriptKey, nil
554 }
555 556 // putCryptoKeys stores the encrypted crypto keys which are in turn used to
557 // protect the extended and imported keys. Either parameter can be nil in which
558 // case no value is written for the parameter.
559 func putCryptoKeys(
560 ns walletdb.ReadWriteBucket, pubKeyEncrypted, privKeyEncrypted,
561 scriptKeyEncrypted []byte,
562 ) (e error) {
563 bucket := ns.NestedReadWriteBucket(mainBucketName)
564 if pubKeyEncrypted != nil {
565 if e = bucket.Put(cryptoPubKeyName, pubKeyEncrypted); E.Chk(e) {
566 str := "failed to store encrypted crypto public key"
567 return managerError(ErrDatabase, str, e)
568 }
569 }
570 if privKeyEncrypted != nil {
571 if e = bucket.Put(cryptoPrivKeyName, privKeyEncrypted); E.Chk(e) {
572 str := "failed to store encrypted crypto private key"
573 return managerError(ErrDatabase, str, e)
574 }
575 }
576 if scriptKeyEncrypted != nil {
577 if e = bucket.Put(cryptoScriptKeyName, scriptKeyEncrypted); E.Chk(e) {
578 str := "failed to store encrypted crypto script key"
579 return managerError(ErrDatabase, str, e)
580 }
581 }
582 return nil
583 }
584 585 // fetchWatchingOnly loads the watching-only flag from the database.
586 func fetchWatchingOnly(ns walletdb.ReadBucket) (bool, error) {
587 bucket := ns.NestedReadBucket(mainBucketName)
588 buf := bucket.Get(watchingOnlyName)
589 if len(buf) != 1 {
590 str := "malformed watching-only flag stored in database"
591 return false, managerError(ErrDatabase, str, nil)
592 }
593 return buf[0] != 0, nil
594 }
595 596 // putWatchingOnly stores the watching-only flag to the database.
597 func putWatchingOnly(ns walletdb.ReadWriteBucket, watchingOnly bool) (e error) {
598 bucket := ns.NestedReadWriteBucket(mainBucketName)
599 var encoded byte
600 if watchingOnly {
601 encoded = 1
602 }
603 if e = bucket.Put(watchingOnlyName, []byte{encoded}); E.Chk(e) {
604 str := "failed to store watching only flag"
605 return managerError(ErrDatabase, str, e)
606 }
607 return nil
608 }
609 610 // deserializeAccountRow deserializes the passed serialized account information.
611 // This is used as a common base for the various account types to deserialize
612 // the common parts.
613 func deserializeAccountRow(accountID []byte, serializedAccount []byte) (*dbAccountRow, error) {
614 // The serialized account format is:
615 //
616 // <acctType><rdlen><rawdata>
617 //
618 // 1 byte acctType + 4 bytes raw data length + raw data
619 //
620 // Given the above, the length of the entry must be at a minimum the constant
621 // value txsizes.
622 if len(serializedAccount) < 5 {
623 str := fmt.Sprintf(
624 "malformed serialized account for key %x",
625 accountID,
626 )
627 return nil, managerError(ErrDatabase, str, nil)
628 }
629 row := dbAccountRow{}
630 row.acctType = accountType(serializedAccount[0])
631 rdlen := binary.LittleEndian.Uint32(serializedAccount[1:5])
632 row.rawData = make([]byte, rdlen)
633 copy(row.rawData, serializedAccount[5:5+rdlen])
634 return &row, nil
635 }
636 637 // serializeAccountRow returns the serialization of the passed account row.
638 func serializeAccountRow(row *dbAccountRow) []byte {
639 // The serialized account format is:
640 //
641 // <acctType><rdlen><rawdata>
642 //
643 // 1 byte acctType + 4 bytes raw data length + raw data
644 rdlen := len(row.rawData)
645 buf := make([]byte, 5+rdlen)
646 buf[0] = byte(row.acctType)
647 binary.LittleEndian.PutUint32(buf[1:5], uint32(rdlen))
648 copy(buf[5:5+rdlen], row.rawData)
649 return buf
650 }
651 652 // deserializeDefaultAccountRow deserializes the raw data from the passed
653 // account row as a BIP0044-like account.
654 func deserializeDefaultAccountRow(accountID []byte, row *dbAccountRow) (*dbDefaultAccountRow, error) {
655 // The serialized BIP0044 account raw data format is:
656 //
657 // <encpubkeylen><encpubkey><encprivkeylen><encprivkey><nextextidx>
658 // <nextintidx><namelen><name>
659 //
660 // 4 bytes encrypted pubkey len + encrypted pubkey + 4 bytes encrypted
661 //
662 // privkey len + encrypted privkey + 4 bytes next external index +
663 //
664 // 4 bytes next internal index + 4 bytes name len + name
665 //
666 // Given the above, the length of the entry must be at a minimum the constant
667 // value txsizes.
668 if len(row.rawData) < 20 {
669 str := fmt.Sprintf("malformed serialized bip0044 account for key %x", accountID)
670 return nil, managerError(ErrDatabase, str, nil)
671 }
672 retRow := dbDefaultAccountRow{
673 dbAccountRow: *row,
674 }
675 pubLen := binary.LittleEndian.Uint32(row.rawData[0:4])
676 retRow.pubKeyEncrypted = make([]byte, pubLen)
677 copy(retRow.pubKeyEncrypted, row.rawData[4:4+pubLen])
678 offset := 4 + pubLen
679 privLen := binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
680 offset += 4
681 retRow.privKeyEncrypted = make([]byte, privLen)
682 copy(retRow.privKeyEncrypted, row.rawData[offset:offset+privLen])
683 offset += privLen
684 retRow.nextExternalIndex = binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
685 offset += 4
686 retRow.nextInternalIndex = binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
687 offset += 4
688 nameLen := binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
689 offset += 4
690 retRow.name = string(row.rawData[offset : offset+nameLen])
691 return &retRow, nil
692 }
693 694 // serializeDefaultAccountRow returns the serialization of the raw data field for a BIP0044-like account.
695 func serializeDefaultAccountRow(
696 encryptedPubKey, encryptedPrivKey []byte,
697 nextExternalIndex, nextInternalIndex uint32, name string,
698 ) []byte {
699 // The serialized BIP0044 account raw data format is:
700 //
701 // <encpubkeylen><encpubkey><encprivkeylen><encprivkey><nextextidx>
702 // <nextintidx><namelen><name>
703 //
704 // 4 bytes encrypted pubkey len + encrypted pubkey + 4 bytes encrypted
705 //
706 // privkey len + encrypted privkey + 4 bytes next external index +
707 //
708 // 4 bytes next internal index + 4 bytes name len + name
709 pubLen := uint32(len(encryptedPubKey))
710 privLen := uint32(len(encryptedPrivKey))
711 nameLen := uint32(len(name))
712 rawData := make([]byte, 20+pubLen+privLen+nameLen)
713 binary.LittleEndian.PutUint32(rawData[0:4], pubLen)
714 copy(rawData[4:4+pubLen], encryptedPubKey)
715 offset := 4 + pubLen
716 binary.LittleEndian.PutUint32(rawData[offset:offset+4], privLen)
717 offset += 4
718 copy(rawData[offset:offset+privLen], encryptedPrivKey)
719 offset += privLen
720 binary.LittleEndian.PutUint32(rawData[offset:offset+4], nextExternalIndex)
721 offset += 4
722 binary.LittleEndian.PutUint32(rawData[offset:offset+4], nextInternalIndex)
723 offset += 4
724 binary.LittleEndian.PutUint32(rawData[offset:offset+4], nameLen)
725 offset += 4
726 copy(rawData[offset:offset+nameLen], name)
727 return rawData
728 }
729 730 // forEachKeyScope calls the given function for each known manager scope within
731 // the set of scopes known by the root manager.
732 func forEachKeyScope(ns walletdb.ReadBucket, fn func(KeyScope) error) (e error) {
733 bucket := ns.NestedReadBucket(scopeBucketName)
734 return bucket.ForEach(
735 func(k, v []byte) (e error) {
736 // skip non-bucket
737 if len(k) != 8 {
738 return nil
739 }
740 scope := KeyScope{
741 Purpose: binary.LittleEndian.Uint32(k),
742 Coin: binary.LittleEndian.Uint32(k[4:]),
743 }
744 return fn(scope)
745 },
746 )
747 }
748 749 // forEachAccount calls the given function with each account stored in the
750 // manager, breaking early on error.
751 func forEachAccount(
752 ns walletdb.ReadBucket, scope *KeyScope,
753 fn func(account uint32) error,
754 ) (e error) {
755 var scopedBucket walletdb.ReadBucket
756 if scopedBucket, e = fetchReadScopeBucket(ns, scope); E.Chk(e) {
757 return e
758 }
759 acctBucket := scopedBucket.NestedReadBucket(acctBucketName)
760 return acctBucket.ForEach(
761 func(k, v []byte) (e error) {
762 // Skip buckets.
763 if v == nil {
764 return nil
765 }
766 return fn(binary.LittleEndian.Uint32(k))
767 },
768 )
769 }
770 771 // fetchLastAccount retrieves the last account from the database.
772 func fetchLastAccount(ns walletdb.ReadBucket, scope *KeyScope) (uint32, error) {
773 var scopedBucket walletdb.ReadBucket
774 var e error
775 if scopedBucket, e = fetchReadScopeBucket(ns, scope); E.Chk(e) {
776 return 0, e
777 }
778 metaBucket := scopedBucket.NestedReadBucket(metaBucketName)
779 val := metaBucket.Get(lastAccountName)
780 if len(val) != 4 {
781 str := fmt.Sprintf(
782 "malformed metadata '%s' stored in database",
783 lastAccountName,
784 )
785 return 0, managerError(ErrDatabase, str, nil)
786 }
787 account := binary.LittleEndian.Uint32(val[0:4])
788 return account, nil
789 }
790 791 // fetchAccountName retrieves the account name given an account number from the
792 // database.
793 func fetchAccountName(
794 ns walletdb.ReadBucket, scope *KeyScope,
795 account uint32,
796 ) (string, error) {
797 var scopedBucket walletdb.ReadBucket
798 var e error
799 if scopedBucket, e = fetchReadScopeBucket(ns, scope); E.Chk(e) {
800 return "", e
801 }
802 acctIDxBucket := scopedBucket.NestedReadBucket(acctIDIdxBucketName)
803 val := acctIDxBucket.Get(uint32ToBytes(account))
804 if val == nil {
805 str := fmt.Sprintf("account %d not found", account)
806 return "", managerError(ErrAccountNotFound, str, nil)
807 }
808 offset := uint32(0)
809 nameLen := binary.LittleEndian.Uint32(val[offset : offset+4])
810 offset += 4
811 acctName := string(val[offset : offset+nameLen])
812 return acctName, nil
813 }
814 815 // fetchAccountByName retrieves the account number given an account name from
816 // the database.
817 func fetchAccountByName(
818 ns walletdb.ReadBucket, scope *KeyScope,
819 name string,
820 ) (uint32, error) {
821 var scopedBucket walletdb.ReadBucket
822 var e error
823 if scopedBucket, e = fetchReadScopeBucket(ns, scope); E.Chk(e) {
824 return 0, e
825 }
826 idxBucket := scopedBucket.NestedReadBucket(acctNameIdxBucketName)
827 val := idxBucket.Get(stringToBytes(name))
828 if val == nil {
829 str := fmt.Sprintf("account name '%s' not found", name)
830 return 0, managerError(ErrAccountNotFound, str, nil)
831 }
832 return binary.LittleEndian.Uint32(val), nil
833 }
834 835 // fetchAccountInfo loads information about the passed account from the
836 // database.
837 func fetchAccountInfo(ns walletdb.ReadBucket, scope *KeyScope, account uint32,) (ii interface{}, e error) {
838 var scopedBucket walletdb.ReadBucket
839 if scopedBucket, e = fetchReadScopeBucket(ns, scope); E.Chk(e) {
840 return nil, e
841 }
842 acctBucket := scopedBucket.NestedReadBucket(acctBucketName)
843 accountID := uint32ToBytes(account)
844 serializedRow := acctBucket.Get(accountID)
845 if serializedRow == nil {
846 str := fmt.Sprintf("account %d not found", account)
847 return nil, managerError(ErrAccountNotFound, str, nil)
848 }
849 var row *dbAccountRow
850 if row, e = deserializeAccountRow(accountID, serializedRow); E.Chk(e) {
851 return nil, e
852 }
853 if row.acctType == accountDefault {
854 return deserializeDefaultAccountRow(accountID, row)
855 }
856 str := fmt.Sprintf("unsupported account type '%d'", row.acctType)
857 return nil, managerError(ErrDatabase, str, nil)
858 }
859 860 // deleteAccountNameIndex deletes the given key from the account name index of
861 // the database.
862 func deleteAccountNameIndex(
863 ns walletdb.ReadWriteBucket, scope *KeyScope,
864 name string,
865 ) (e error) {
866 var scopedBucket walletdb.ReadWriteBucket
867 if scopedBucket, e = fetchWriteScopeBucket(ns, scope); E.Chk(e) {
868 return e
869 }
870 bucket := scopedBucket.NestedReadWriteBucket(acctNameIdxBucketName)
871 // Delete the account name key
872 if e = bucket.Delete(stringToBytes(name)); E.Chk(e) {
873 str := fmt.Sprintf("failed to delete account name index key %s", name)
874 return managerError(ErrDatabase, str, e)
875 }
876 return nil
877 }
878 879 // deleteAccountIDIndex deletes the given key from the account id index of the
880 // database.
881 func deleteAccountIDIndex(
882 ns walletdb.ReadWriteBucket, scope *KeyScope,
883 account uint32,
884 ) (e error) {
885 var scopedBucket walletdb.ReadWriteBucket
886 if scopedBucket, e = fetchWriteScopeBucket(ns, scope); E.Chk(e) {
887 return e
888 }
889 bucket := scopedBucket.NestedReadWriteBucket(acctIDIdxBucketName)
890 // Delete the account id key
891 if e = bucket.Delete(uint32ToBytes(account)); E.Chk(e) {
892 str := fmt.Sprintf("failed to delete account id index key %d", account)
893 return managerError(ErrDatabase, str, e)
894 }
895 return nil
896 }
897 898 // putAccountNameIndex stores the given key to the account name index of the
899 // database.
900 func putAccountNameIndex(
901 ns walletdb.ReadWriteBucket, scope *KeyScope,
902 account uint32, name string,
903 ) (e error) {
904 var scopedBucket walletdb.ReadWriteBucket
905 if scopedBucket, e = fetchWriteScopeBucket(ns, scope); E.Chk(e) {
906 return e
907 }
908 bucket := scopedBucket.NestedReadWriteBucket(acctNameIdxBucketName)
909 // Write the account number keyed by the account name.
910 if e = bucket.Put(stringToBytes(name), uint32ToBytes(account)); E.Chk(e) {
911 str := fmt.Sprintf("failed to store account name index key %s", name)
912 return managerError(ErrDatabase, str, e)
913 }
914 return nil
915 }
916 917 // putAccountIDIndex stores the given key to the account id index of the
918 // database.
919 func putAccountIDIndex(
920 ns walletdb.ReadWriteBucket, scope *KeyScope,
921 account uint32, name string,
922 ) (e error) {
923 var scopedBucket walletdb.ReadWriteBucket
924 if scopedBucket, e = fetchWriteScopeBucket(ns, scope); E.Chk(e) {
925 return e
926 }
927 bucket := scopedBucket.NestedReadWriteBucket(acctIDIdxBucketName)
928 // Write the account number keyed by the account id.
929 if e = bucket.Put(uint32ToBytes(account), stringToBytes(name)); E.Chk(e) {
930 str := fmt.Sprintf("failed to store account id index key %s", name)
931 return managerError(ErrDatabase, str, e)
932 }
933 return nil
934 }
935 936 // putAddrAccountIndex stores the given key to the address account index of the
937 // database.
938 func putAddrAccountIndex(
939 ns walletdb.ReadWriteBucket, scope *KeyScope,
940 account uint32, addrHash []byte,
941 ) (e error) {
942 var scopedBucket walletdb.ReadWriteBucket
943 if scopedBucket, e = fetchWriteScopeBucket(ns, scope); E.Chk(e) {
944 return e
945 }
946 bucket := scopedBucket.NestedReadWriteBucket(addrAcctIdxBucketName)
947 // Write account keyed by address hash
948 if e = bucket.Put(addrHash, uint32ToBytes(account)); E.Chk(e) {
949 return nil
950 }
951 if bucket, e = bucket.CreateBucketIfNotExists(uint32ToBytes(account)); E.Chk(e) {
952 return e
953 }
954 // In account bucket, write a null value keyed by the address hash
955 if e = bucket.Put(addrHash, nullVal); E.Chk(e) {
956 str := fmt.Sprintf("failed to store address account index key %s", addrHash)
957 return managerError(ErrDatabase, str, e)
958 }
959 return nil
960 }
961 962 // putAccountRow stores the provided account information to the database. This
963 // is used a common base for storing the various account types.
964 func putAccountRow(
965 ns walletdb.ReadWriteBucket, scope *KeyScope,
966 account uint32, row *dbAccountRow,
967 ) (e error) {
968 var scopedBucket walletdb.ReadWriteBucket
969 if scopedBucket, e = fetchWriteScopeBucket(ns, scope); E.Chk(e) {
970 return e
971 }
972 bucket := scopedBucket.NestedReadWriteBucket(acctBucketName)
973 // Write the serialized value keyed by the account number.
974 if e = bucket.Put(uint32ToBytes(account), serializeAccountRow(row)); E.Chk(e) {
975 str := fmt.Sprintf("failed to store account %d", account)
976 return managerError(ErrDatabase, str, e)
977 }
978 return nil
979 }
980 981 // putAccountInfo stores the provided account information to the database.
982 func putAccountInfo(
983 ns walletdb.ReadWriteBucket, scope *KeyScope,
984 account uint32, encryptedPubKey, encryptedPrivKey []byte,
985 nextExternalIndex, nextInternalIndex uint32, name string,
986 ) (e error) {
987 rawData := serializeDefaultAccountRow(
988 encryptedPubKey, encryptedPrivKey, nextExternalIndex,
989 nextInternalIndex, name,
990 )
991 // TODO(roasbeef): pass scope bucket directly??
992 acctRow := dbAccountRow{
993 acctType: accountDefault,
994 rawData: rawData,
995 }
996 if e = putAccountRow(ns, scope, account, &acctRow); E.Chk(e) {
997 return e
998 }
999 // Update account id index.
1000 if e = putAccountIDIndex(ns, scope, account, name); E.Chk(e) {
1001 return e
1002 }
1003 // Update account name index.
1004 if e = putAccountNameIndex(ns, scope, account, name); E.Chk(e) {
1005 return e
1006 }
1007 return nil
1008 }
1009 1010 // putLastAccount stores the provided metadata - last account - to the database.
1011 func putLastAccount(
1012 ns walletdb.ReadWriteBucket, scope *KeyScope,
1013 account uint32,
1014 ) (e error) {
1015 var scopedBucket walletdb.ReadWriteBucket
1016 if scopedBucket, e = fetchWriteScopeBucket(ns, scope); E.Chk(e) {
1017 return e
1018 }
1019 bucket := scopedBucket.NestedReadWriteBucket(metaBucketName)
1020 if e = bucket.Put(lastAccountName, uint32ToBytes(account)); E.Chk(e) {
1021 str := fmt.Sprintf("failed to update metadata '%s'", lastAccountName)
1022 return managerError(ErrDatabase, str, e)
1023 }
1024 return nil
1025 }
1026 1027 // deserializeAddressRow deserializes the passed serialized address information.
1028 // This is used as a common base for the various address types to deserialize
1029 // the common parts.
1030 func deserializeAddressRow(serializedAddress []byte) (*dbAddressRow, error) {
1031 // The serialized address format is:
1032 //
1033 // <addrType><account><addedTime><syncStatus><rawdata>
1034 //
1035 // 1 byte addrType + 4 bytes account + 8 bytes addTime + 1 byte
1036 //
1037 // syncStatus + 4 bytes raw data length + raw data
1038 //
1039 // Given the above, the length of the entry must be at a minimum the constant
1040 // value txsizes.
1041 if len(serializedAddress) < 18 {
1042 str := "malformed serialized address"
1043 return nil, managerError(ErrDatabase, str, nil)
1044 }
1045 row := dbAddressRow{}
1046 row.addrType = addressType(serializedAddress[0])
1047 row.account = binary.LittleEndian.Uint32(serializedAddress[1:5])
1048 row.addTime = binary.LittleEndian.Uint64(serializedAddress[5:13])
1049 row.syncStatus = syncStatus(serializedAddress[13])
1050 rdlen := binary.LittleEndian.Uint32(serializedAddress[14:18])
1051 row.rawData = make([]byte, rdlen)
1052 copy(row.rawData, serializedAddress[18:18+rdlen])
1053 return &row, nil
1054 }
1055 1056 // serializeAddressRow returns the serialization of the passed address row.
1057 func serializeAddressRow(row *dbAddressRow) []byte {
1058 // The serialized address format is:
1059 //
1060 // <addrType><account><addedTime><syncStatus><commentlen><comment>
1061 // <rawdata>
1062 //
1063 // 1 byte addrType + 4 bytes account + 8 bytes addTime + 1 byte
1064 // syncStatus + 4 bytes raw data length + raw data
1065 rdlen := len(row.rawData)
1066 buf := make([]byte, 18+rdlen)
1067 buf[0] = byte(row.addrType)
1068 binary.LittleEndian.PutUint32(buf[1:5], row.account)
1069 binary.LittleEndian.PutUint64(buf[5:13], row.addTime)
1070 buf[13] = byte(row.syncStatus)
1071 binary.LittleEndian.PutUint32(buf[14:18], uint32(rdlen))
1072 copy(buf[18:18+rdlen], row.rawData)
1073 return buf
1074 }
1075 1076 // deserializeChainedAddress deserializes the raw data from the passed address
1077 // row as a chained address.
1078 func deserializeChainedAddress(row *dbAddressRow) (*dbChainAddressRow, error) {
1079 // The serialized chain address raw data format is:
1080 //
1081 // <branch><index>
1082 //
1083 // 4 bytes branch + 4 bytes address index
1084 if len(row.rawData) != 8 {
1085 str := "malformed serialized chained address"
1086 return nil, managerError(ErrDatabase, str, nil)
1087 }
1088 retRow := dbChainAddressRow{
1089 dbAddressRow: *row,
1090 }
1091 retRow.branch = binary.LittleEndian.Uint32(row.rawData[0:4])
1092 retRow.index = binary.LittleEndian.Uint32(row.rawData[4:8])
1093 return &retRow, nil
1094 }
1095 1096 // serializeChainedAddress returns the serialization of the raw data field for a
1097 // chained address.
1098 func serializeChainedAddress(branch, index uint32) []byte {
1099 // The serialized chain address raw data format is:
1100 //
1101 // <branch><index>
1102 //
1103 // 4 bytes branch + 4 bytes address index
1104 rawData := make([]byte, 8)
1105 binary.LittleEndian.PutUint32(rawData[0:4], branch)
1106 binary.LittleEndian.PutUint32(rawData[4:8], index)
1107 return rawData
1108 }
1109 1110 // deserializeImportedAddress deserializes the raw data from the passed address
1111 // row as an imported address.
1112 func deserializeImportedAddress(row *dbAddressRow) (*dbImportedAddressRow, error) {
1113 // The serialized imported address raw data format is:
1114 //
1115 // <encpubkeylen><encpubkey><encprivkeylen><encprivkey>
1116 //
1117 // 4 bytes encrypted pubkey len + encrypted pubkey + 4 bytes encrypted
1118 //
1119 // privkey len + encrypted privkey
1120 //
1121 // Given the above, the length of the entry must be at a minimum the constant
1122 // value txsizes.
1123 if len(row.rawData) < 8 {
1124 str := "malformed serialized imported address"
1125 return nil, managerError(ErrDatabase, str, nil)
1126 }
1127 retRow := dbImportedAddressRow{
1128 dbAddressRow: *row,
1129 }
1130 pubLen := binary.LittleEndian.Uint32(row.rawData[0:4])
1131 retRow.encryptedPubKey = make([]byte, pubLen)
1132 copy(retRow.encryptedPubKey, row.rawData[4:4+pubLen])
1133 offset := 4 + pubLen
1134 privLen := binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
1135 offset += 4
1136 retRow.encryptedPrivKey = make([]byte, privLen)
1137 copy(retRow.encryptedPrivKey, row.rawData[offset:offset+privLen])
1138 return &retRow, nil
1139 }
1140 1141 // serializeImportedAddress returns the serialization of the raw data field for
1142 // an imported address.
1143 func serializeImportedAddress(encryptedPubKey, encryptedPrivKey []byte) []byte {
1144 // The serialized imported address raw data format is:
1145 //
1146 // <encpubkeylen><encpubkey><encprivkeylen><encprivkey>
1147 //
1148 // 4 bytes encrypted pubkey len + encrypted pubkey + 4 bytes encrypted
1149 //
1150 // privkey len + encrypted privkey
1151 pubLen := uint32(len(encryptedPubKey))
1152 privLen := uint32(len(encryptedPrivKey))
1153 rawData := make([]byte, 8+pubLen+privLen)
1154 binary.LittleEndian.PutUint32(rawData[0:4], pubLen)
1155 copy(rawData[4:4+pubLen], encryptedPubKey)
1156 offset := 4 + pubLen
1157 binary.LittleEndian.PutUint32(rawData[offset:offset+4], privLen)
1158 offset += 4
1159 copy(rawData[offset:offset+privLen], encryptedPrivKey)
1160 return rawData
1161 }
1162 1163 // deserializeScriptAddress deserializes the raw data from the passed address
1164 // row as a script address.
1165 func deserializeScriptAddress(row *dbAddressRow) (*dbScriptAddressRow, error) {
1166 // The serialized script address raw data format is:
1167 //
1168 // <encscripthashlen><encscripthash><encscriptlen><encscript>
1169 //
1170 // 4 bytes encrypted script hash len + encrypted script hash + 4 bytes
1171 //
1172 // encrypted script len + encrypted script
1173 //
1174 // Given the above, the length of the entry must be at a minimum the constant
1175 // value txsizes.
1176 if len(row.rawData) < 8 {
1177 str := "malformed serialized script address"
1178 return nil, managerError(ErrDatabase, str, nil)
1179 }
1180 retRow := dbScriptAddressRow{
1181 dbAddressRow: *row,
1182 }
1183 hashLen := binary.LittleEndian.Uint32(row.rawData[0:4])
1184 retRow.encryptedHash = make([]byte, hashLen)
1185 copy(retRow.encryptedHash, row.rawData[4:4+hashLen])
1186 offset := 4 + hashLen
1187 scriptLen := binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
1188 offset += 4
1189 retRow.encryptedScript = make([]byte, scriptLen)
1190 copy(retRow.encryptedScript, row.rawData[offset:offset+scriptLen])
1191 return &retRow, nil
1192 }
1193 1194 // serializeScriptAddress returns the serialization of the raw data field for a
1195 // script address.
1196 func serializeScriptAddress(encryptedHash, encryptedScript []byte) []byte {
1197 // The serialized script address raw data format is:
1198 //
1199 // <encscripthashlen><encscripthash><encscriptlen><encscript>
1200 //
1201 // 4 bytes encrypted script hash len + encrypted script hash + 4 bytes
1202 //
1203 // encrypted script len + encrypted script
1204 hashLen := uint32(len(encryptedHash))
1205 scriptLen := uint32(len(encryptedScript))
1206 rawData := make([]byte, 8+hashLen+scriptLen)
1207 binary.LittleEndian.PutUint32(rawData[0:4], hashLen)
1208 copy(rawData[4:4+hashLen], encryptedHash)
1209 offset := 4 + hashLen
1210 binary.LittleEndian.PutUint32(rawData[offset:offset+4], scriptLen)
1211 offset += 4
1212 copy(rawData[offset:offset+scriptLen], encryptedScript)
1213 return rawData
1214 }
1215 1216 // fetchAddressByHash loads address information for the provided address hash
1217 // from the database. The returned value is one of the address rows for the
1218 // specific address type. The caller should use type assertions to ascertain the
1219 // type. The caller should prefix the error message with the address hash which
1220 // caused the failure.
1221 func fetchAddressByHash(
1222 ns walletdb.ReadBucket, scope *KeyScope,
1223 addrHash []byte,
1224 ) (interface{}, error) {
1225 var scopedBucket walletdb.ReadBucket
1226 var e error
1227 if scopedBucket, e = fetchReadScopeBucket(ns, scope); E.Chk(e) {
1228 return nil, e
1229 }
1230 bucket := scopedBucket.NestedReadBucket(addrBucketName)
1231 serializedRow := bucket.Get(addrHash)
1232 if serializedRow == nil {
1233 str := "address not found"
1234 return nil, managerError(ErrAddressNotFound, str, nil)
1235 }
1236 var row *dbAddressRow
1237 if row, e = deserializeAddressRow(serializedRow); E.Chk(e) {
1238 return nil, e
1239 }
1240 switch row.addrType {
1241 case adtChain:
1242 return deserializeChainedAddress(row)
1243 case adtImport:
1244 return deserializeImportedAddress(row)
1245 case adtScript:
1246 return deserializeScriptAddress(row)
1247 }
1248 str := fmt.Sprintf("unsupported address type '%d'", row.addrType)
1249 return nil, managerError(ErrDatabase, str, nil)
1250 }
1251 1252 // fetchAddressUsed returns true if the provided address id was flagged as used.
1253 func fetchAddressUsed(ns walletdb.ReadBucket, scope *KeyScope, addressID []byte) bool {
1254 var scopedBucket walletdb.ReadBucket
1255 var e error
1256 if scopedBucket, e = fetchReadScopeBucket(ns, scope); E.Chk(e) {
1257 return false
1258 }
1259 bucket := scopedBucket.NestedReadBucket(usedAddrBucketName)
1260 addrHash := sha256.Sum256(addressID)
1261 return bucket.Get(addrHash[:]) != nil
1262 }
1263 1264 // markAddressUsed flags the provided address id as used in the database.
1265 func markAddressUsed(
1266 ns walletdb.ReadWriteBucket, scope *KeyScope,
1267 addressID []byte,
1268 ) (e error) {
1269 var scopedBucket walletdb.ReadWriteBucket
1270 if scopedBucket, e = fetchWriteScopeBucket(ns, scope); E.Chk(e) {
1271 return e
1272 }
1273 bucket := scopedBucket.NestedReadWriteBucket(usedAddrBucketName)
1274 addrHash := sha256.Sum256(addressID)
1275 val := bucket.Get(addrHash[:])
1276 if val != nil {
1277 return nil
1278 }
1279 if e = bucket.Put(addrHash[:], []byte{0}); E.Chk(e) {
1280 str := fmt.Sprintf("failed to mark address used %x", addressID)
1281 return managerError(ErrDatabase, str, e)
1282 }
1283 return nil
1284 }
1285 1286 // fetchAddress loads address information for the provided address id from the
1287 // database. The returned value is one of the address rows for the specific
1288 // address type. The caller should use type assertions to ascertain the type.
1289 // The caller should prefix the error message with the address which caused the
1290 // failure.
1291 func fetchAddress(
1292 ns walletdb.ReadBucket, scope *KeyScope,
1293 addressID []byte,
1294 ) (interface{}, error) {
1295 addrHash := sha256.Sum256(addressID)
1296 return fetchAddressByHash(ns, scope, addrHash[:])
1297 }
1298 1299 // putAddress stores the provided address information to the database. This is
1300 // used a common base for storing the various address types.
1301 func putAddress(
1302 ns walletdb.ReadWriteBucket, scope *KeyScope,
1303 addressID []byte, row *dbAddressRow,
1304 ) (e error) {
1305 var scopedBucket walletdb.ReadWriteBucket
1306 if scopedBucket, e = fetchWriteScopeBucket(ns, scope); E.Chk(e) {
1307 return e
1308 }
1309 bucket := scopedBucket.NestedReadWriteBucket(addrBucketName)
1310 // Write the serialized value keyed by the hash of the address. The additional
1311 // hash is used to conceal the actual address while still allowed keyed lookups.
1312 addrHash := sha256.Sum256(addressID)
1313 if e = bucket.Put(addrHash[:], serializeAddressRow(row)); E.Chk(e) {
1314 str := fmt.Sprintf("failed to store address %x", addressID)
1315 return managerError(ErrDatabase, str, e)
1316 }
1317 // Update address account index
1318 return putAddrAccountIndex(ns, scope, row.account, addrHash[:])
1319 }
1320 1321 // putChainedAddress stores the provided chained address information to the
1322 // database.
1323 func putChainedAddress(
1324 ns walletdb.ReadWriteBucket, scope *KeyScope,
1325 addressID []byte, account uint32, status syncStatus, branch,
1326 index uint32, addrType addressType,
1327 ) (e error) {
1328 var scopedBucket walletdb.ReadWriteBucket
1329 if scopedBucket, e = fetchWriteScopeBucket(ns, scope); E.Chk(e) {
1330 return e
1331 }
1332 addrRow := dbAddressRow{
1333 addrType: addrType,
1334 account: account,
1335 addTime: uint64(time.Now().Unix()),
1336 syncStatus: status,
1337 rawData: serializeChainedAddress(branch, index),
1338 }
1339 if e = putAddress(ns, scope, addressID, &addrRow); E.Chk(e) {
1340 return e
1341 }
1342 // Update the next index for the appropriate internal or external branch.
1343 accountID := uint32ToBytes(account)
1344 bucket := scopedBucket.NestedReadWriteBucket(acctBucketName)
1345 serializedAccount := bucket.Get(accountID)
1346 // Deserialize the account row.
1347 var row *dbAccountRow
1348 if row, e = deserializeAccountRow(accountID, serializedAccount); E.Chk(e) {
1349 return e
1350 }
1351 var arow *dbDefaultAccountRow
1352 if arow, e = deserializeDefaultAccountRow(accountID, row); E.Chk(e) {
1353 return e
1354 }
1355 // Increment the appropriate next index depending on whether the branch is
1356 // internal or external.
1357 nextExternalIndex := arow.nextExternalIndex
1358 nextInternalIndex := arow.nextInternalIndex
1359 if branch == InternalBranch {
1360 nextInternalIndex = index + 1
1361 } else {
1362 nextExternalIndex = index + 1
1363 }
1364 // Reserialize the account with the updated index and store it.
1365 row.rawData = serializeDefaultAccountRow(
1366 arow.pubKeyEncrypted, arow.privKeyEncrypted, nextExternalIndex,
1367 nextInternalIndex, arow.name,
1368 )
1369 if e = bucket.Put(accountID, serializeAccountRow(row)); E.Chk(e) {
1370 str := fmt.Sprintf(
1371 "failed to update next index for "+
1372 "address %x, account %d", addressID, account,
1373 )
1374 return managerError(ErrDatabase, str, e)
1375 }
1376 return nil
1377 }
1378 1379 // putImportedAddress stores the provided imported address information to the
1380 // database.
1381 func putImportedAddress(
1382 ns walletdb.ReadWriteBucket, scope *KeyScope,
1383 addressID []byte, account uint32, status syncStatus,
1384 encryptedPubKey, encryptedPrivKey []byte,
1385 ) (e error) {
1386 rawData := serializeImportedAddress(encryptedPubKey, encryptedPrivKey)
1387 addrRow := dbAddressRow{
1388 addrType: adtImport,
1389 account: account,
1390 addTime: uint64(time.Now().Unix()),
1391 syncStatus: status,
1392 rawData: rawData,
1393 }
1394 return putAddress(ns, scope, addressID, &addrRow)
1395 }
1396 1397 // putScriptAddress stores the provided script address information to the
1398 // database.
1399 func putScriptAddress(
1400 ns walletdb.ReadWriteBucket, scope *KeyScope,
1401 addressID []byte, account uint32, status syncStatus,
1402 encryptedHash, encryptedScript []byte,
1403 ) (e error) {
1404 rawData := serializeScriptAddress(encryptedHash, encryptedScript)
1405 addrRow := dbAddressRow{
1406 addrType: adtScript,
1407 account: account,
1408 addTime: uint64(time.Now().Unix()),
1409 syncStatus: status,
1410 rawData: rawData,
1411 }
1412 if e = putAddress(ns, scope, addressID, &addrRow); E.Chk(e) {
1413 return e
1414 }
1415 return nil
1416 }
1417 1418 // existsAddress returns whether or not the address id exists in the database.
1419 func existsAddress(ns walletdb.ReadBucket, scope *KeyScope, addressID []byte) bool {
1420 var scopedBucket walletdb.ReadBucket
1421 var e error
1422 if scopedBucket, e = fetchReadScopeBucket(ns, scope); E.Chk(e) {
1423 return false
1424 }
1425 bucket := scopedBucket.NestedReadBucket(addrBucketName)
1426 addrHash := sha256.Sum256(addressID)
1427 return bucket.Get(addrHash[:]) != nil
1428 }
1429 1430 // fetchAddrAccount returns the account to which the given address belongs to.
1431 // It looks up the account using the addracctidx index which maps the address
1432 // hash to its corresponding account id.
1433 func fetchAddrAccount(
1434 ns walletdb.ReadBucket, scope *KeyScope,
1435 addressID []byte,
1436 ) (uint32, error) {
1437 var scopedBucket walletdb.ReadBucket
1438 var e error
1439 if scopedBucket, e = fetchReadScopeBucket(ns, scope); E.Chk(e) {
1440 return 0, e
1441 }
1442 bucket := scopedBucket.NestedReadBucket(addrAcctIdxBucketName)
1443 addrHash := sha256.Sum256(addressID)
1444 val := bucket.Get(addrHash[:])
1445 if val == nil {
1446 str := "address not found"
1447 return 0, managerError(ErrAddressNotFound, str, nil)
1448 }
1449 return binary.LittleEndian.Uint32(val), nil
1450 }
1451 1452 // forEachAccountAddress calls the given function with each address of the given
1453 // account stored in the manager, breaking early on error.
1454 func forEachAccountAddress(
1455 ns walletdb.ReadBucket, scope *KeyScope,
1456 account uint32, fn func(rowInterface interface{}) error,
1457 ) (e error) {
1458 var scopedBucket walletdb.ReadBucket
1459 if scopedBucket, e = fetchReadScopeBucket(ns, scope); E.Chk(e) {
1460 return e
1461 }
1462 bucket := scopedBucket.NestedReadBucket(addrAcctIdxBucketName).NestedReadBucket(uint32ToBytes(account))
1463 // If index bucket is missing the account, there hasn't been any address entries
1464 // yet
1465 if bucket == nil {
1466 return nil
1467 }
1468 if e = bucket.ForEach(
1469 func(k, v []byte) (e error) {
1470 // Skip buckets.
1471 if v == nil {
1472 return nil
1473 }
1474 var addrRow interface{}
1475 if addrRow, e = fetchAddressByHash(ns, scope, k); E.Chk(e) {
1476 if merr, ok := e.(*ManagerError); ok {
1477 desc := fmt.Sprintf(
1478 "failed to fetch address hash '%s': %v",
1479 k, merr.Description,
1480 )
1481 merr.Description = desc
1482 return merr
1483 }
1484 return e
1485 }
1486 return fn(addrRow)
1487 },
1488 ); E.Chk(e) {
1489 return maybeConvertDbError(e)
1490 }
1491 return nil
1492 }
1493 1494 // forEachActiveAddress calls the given function with each active address stored
1495 // in the manager, breaking early on error.
1496 func forEachActiveAddress(
1497 ns walletdb.ReadBucket, scope *KeyScope,
1498 fn func(rowInterface interface{}) error,
1499 ) (e error) {
1500 var scopedBucket walletdb.ReadBucket
1501 if scopedBucket, e = fetchReadScopeBucket(ns, scope); E.Chk(e) {
1502 return e
1503 }
1504 bucket := scopedBucket.NestedReadBucket(addrBucketName)
1505 if e = bucket.ForEach(
1506 func(k, v []byte) (e error) {
1507 // Skip buckets.
1508 if v == nil {
1509 return nil
1510 }
1511 // Deserialize the address row first to determine the field values.
1512 addrRow, e := fetchAddressByHash(ns, scope, k)
1513 if merr, ok := e.(*ManagerError); ok {
1514 desc := fmt.Sprintf(
1515 "failed to fetch address hash '%s': %v",
1516 k, merr.Description,
1517 )
1518 merr.Description = desc
1519 return merr
1520 }
1521 if e != nil {
1522 return e
1523 }
1524 return fn(addrRow)
1525 },
1526 ); E.Chk(e) {
1527 return maybeConvertDbError(e)
1528 }
1529 return nil
1530 }
1531 1532 // deletePrivateKeys removes all private key material from the database.
1533 //
1534 // NOTE: Care should be taken when calling this function. It is primarily
1535 // intended for use in converting to a watching-only copy.
1536 //
1537 // Removing the private keys from the main database without also marking it
1538 // watching-only will result in an unusable database.
1539 //
1540 // It will also make any imported scripts and private keys unrecoverable unless
1541 // there is a backup copy available.
1542 func deletePrivateKeys(ns walletdb.ReadWriteBucket) (e error) {
1543 bucket := ns.NestedReadWriteBucket(mainBucketName)
1544 // Delete the master private key netparams and the crypto private and script keys.
1545 if e = bucket.Delete(masterPrivKeyName); E.Chk(e) {
1546 str := "failed to delete master private key parameters"
1547 return managerError(ErrDatabase, str, e)
1548 }
1549 if e = bucket.Delete(cryptoPrivKeyName); E.Chk(e) {
1550 str := "failed to delete crypto private key"
1551 return managerError(ErrDatabase, str, e)
1552 }
1553 if e = bucket.Delete(cryptoScriptKeyName); E.Chk(e) {
1554 str := "failed to delete crypto script key"
1555 return managerError(ErrDatabase, str, e)
1556 }
1557 if e = bucket.Delete(masterHDPrivName); E.Chk(e) {
1558 str := "failed to delete master HD priv key"
1559 return managerError(ErrDatabase, str, e)
1560 }
1561 // With the master key and meta encryption keys deleted, we'll need to delete
1562 // the keys for all known scopes as well.
1563 scopeBucket := ns.NestedReadWriteBucket(scopeBucketName)
1564 e = scopeBucket.ForEach(
1565 func(scopeKey, _ []byte) (e error) {
1566 if len(scopeKey) != 8 {
1567 return nil
1568 }
1569 managerScopeBucket := scopeBucket.NestedReadWriteBucket(scopeKey)
1570 if e = managerScopeBucket.Delete(coinTypePrivKeyName); E.Chk(e) {
1571 str := "failed to delete cointype private key"
1572 return managerError(ErrDatabase, str, e)
1573 }
1574 // Delete the account extended private key for all accounts.
1575 bucket = managerScopeBucket.NestedReadWriteBucket(acctBucketName)
1576 e = bucket.ForEach(
1577 func(k, v []byte) (e error) {
1578 // Skip buckets.
1579 if v == nil {
1580 return nil
1581 }
1582 // Deserialize the account row first to determine the type.
1583 row, e := deserializeAccountRow(k, v)
1584 if e != nil {
1585 return e
1586 }
1587 if row.acctType == accountDefault {
1588 arow, e := deserializeDefaultAccountRow(k, row)
1589 if e != nil {
1590 return e
1591 }
1592 // Reserialize the account without the private key and store it.
1593 row.rawData = serializeDefaultAccountRow(
1594 arow.pubKeyEncrypted, nil,
1595 arow.nextExternalIndex, arow.nextInternalIndex,
1596 arow.name,
1597 )
1598 e = bucket.Put(k, serializeAccountRow(row))
1599 if e != nil {
1600 str := "failed to delete account private key"
1601 return managerError(ErrDatabase, str, e)
1602 }
1603 }
1604 return nil
1605 },
1606 )
1607 if e != nil {
1608 return maybeConvertDbError(e)
1609 }
1610 // Delete the private key for all imported addresses.
1611 bucket = managerScopeBucket.NestedReadWriteBucket(addrBucketName)
1612 e = bucket.ForEach(
1613 func(k, v []byte) (e error) {
1614 // Skip buckets.
1615 if v == nil {
1616 return nil
1617 }
1618 // Deserialize the address row first to determine the field values.
1619 row, e := deserializeAddressRow(v)
1620 if e != nil {
1621 return e
1622 }
1623 switch row.addrType {
1624 case adtImport:
1625 irow, e := deserializeImportedAddress(row)
1626 if e != nil {
1627 return e
1628 }
1629 // Reserialize the imported address without the private key and store it.
1630 row.rawData = serializeImportedAddress(
1631 irow.encryptedPubKey, nil,
1632 )
1633 e = bucket.Put(k, serializeAddressRow(row))
1634 if e != nil {
1635 str := "failed to delete imported private key"
1636 return managerError(ErrDatabase, str, e)
1637 }
1638 case adtScript:
1639 srow, e := deserializeScriptAddress(row)
1640 if e != nil {
1641 return e
1642 }
1643 // Reserialize the script address without the script and store it.
1644 row.rawData = serializeScriptAddress(
1645 srow.encryptedHash,
1646 nil,
1647 )
1648 e = bucket.Put(k, serializeAddressRow(row))
1649 if e != nil {
1650 str := "failed to delete imported script"
1651 return managerError(ErrDatabase, str, e)
1652 }
1653 }
1654 return nil
1655 },
1656 )
1657 if e != nil {
1658 return maybeConvertDbError(e)
1659 }
1660 return nil
1661 },
1662 )
1663 if e != nil {
1664 return maybeConvertDbError(e)
1665 }
1666 return nil
1667 }
1668 1669 // fetchSyncedTo loads the block stamp the manager is synced to from the
1670 // database.
1671 func fetchSyncedTo(ns walletdb.ReadBucket) (*BlockStamp, error) {
1672 bucket := ns.NestedReadBucket(syncBucketName)
1673 // The serialized synced to format is:
1674 //
1675 // <blockheight><blockhash><timestamp>
1676 //
1677 // 4 bytes block height + 32 bytes hash length
1678 buf := bucket.Get(syncedToName)
1679 if len(buf) < 36 {
1680 str := "malformed sync information stored in database"
1681 return nil, managerError(ErrDatabase, str, nil)
1682 }
1683 var bs BlockStamp
1684 bs.Height = int32(binary.LittleEndian.Uint32(buf[0:4]))
1685 copy(bs.Hash[:], buf[4:36])
1686 if len(buf) == 40 {
1687 bs.Timestamp = time.Unix(
1688 int64(binary.LittleEndian.Uint32(buf[36:])), 0,
1689 )
1690 }
1691 return &bs, nil
1692 }
1693 1694 // putSyncedTo stores the provided synced to blockstamp to the database.
1695 func putSyncedTo(ns walletdb.ReadWriteBucket, bs *BlockStamp) (e error) {
1696 bucket := ns.NestedReadWriteBucket(syncBucketName)
1697 errStr := fmt.Sprintf("failed to store sync information %v", bs.Hash)
1698 // If the block height is greater than zero, check that the previous block
1699 // height exists. This prevents reorg issues in the future. We use BigEndian so
1700 // that keys/values are added to the bucket in order, making writes more
1701 // efficient for some database backends.
1702 if bs.Height > 0 {
1703 if _, e = fetchBlockHash(ns, bs.Height-1); E.Chk(e) {
1704 return managerError(ErrDatabase, errStr, e)
1705 }
1706 }
1707 // Store the block hash by block height.
1708 height := make([]byte, 4)
1709 binary.BigEndian.PutUint32(height, uint32(bs.Height))
1710 if e = bucket.Put(height, bs.Hash[0:32]); E.Chk(e) {
1711 return managerError(ErrDatabase, errStr, e)
1712 }
1713 // The serialized synced to format is:
1714 //
1715 // <blockheight><blockhash><timestamp>
1716 //
1717 // 4 bytes block height + 32 bytes hash length + 4 byte timestamp length
1718 buf := make([]byte, 40)
1719 binary.LittleEndian.PutUint32(buf[0:4], uint32(bs.Height))
1720 copy(buf[4:36], bs.Hash[0:32])
1721 binary.LittleEndian.PutUint32(buf[36:], uint32(bs.Timestamp.Unix()))
1722 if e = bucket.Put(syncedToName, buf); E.Chk(e) {
1723 return managerError(ErrDatabase, errStr, e)
1724 }
1725 return nil
1726 }
1727 1728 // fetchBlockHash loads the block hash for the provided height from the database.
1729 func fetchBlockHash(ns walletdb.ReadBucket, height int32) (h *chainhash.Hash, e error) {
1730 bucket := ns.NestedReadBucket(syncBucketName)
1731 errStr := fmt.Sprintf("failed to fetch block hash for height %d", height)
1732 heightBytes := make([]byte, 4)
1733 binary.BigEndian.PutUint32(heightBytes, uint32(height))
1734 hashBytes := bucket.Get(heightBytes)
1735 if len(hashBytes) != 32 {
1736 e = fmt.Errorf("couldn't get hash from database")
1737 return nil, managerError(ErrDatabase, errStr, e)
1738 }
1739 var hash chainhash.Hash
1740 if e = hash.SetBytes(hashBytes); E.Chk(e) {
1741 return nil, managerError(ErrDatabase, errStr, e)
1742 }
1743 return &hash, nil
1744 }
1745 1746 // fetchStartBlock loads the start block stamp for the manager from the
1747 // database.
1748 func fetchStartBlock(ns walletdb.ReadBucket) (*BlockStamp, error) {
1749 bucket := ns.NestedReadBucket(syncBucketName)
1750 // The serialized start block format is:
1751 //
1752 // <blockheight><blockhash>
1753 //
1754 // 4 bytes block height + 32 bytes hash length
1755 buf := bucket.Get(startBlockName)
1756 if len(buf) != 36 {
1757 str := "malformed start block stored in database"
1758 return nil, managerError(ErrDatabase, str, nil)
1759 }
1760 var bs BlockStamp
1761 bs.Height = int32(binary.LittleEndian.Uint32(buf[0:4]))
1762 copy(bs.Hash[:], buf[4:36])
1763 return &bs, nil
1764 }
1765 1766 // putStartBlock stores the provided start block stamp to the database.
1767 func putStartBlock(ns walletdb.ReadWriteBucket, bs *BlockStamp) (e error) {
1768 bucket := ns.NestedReadWriteBucket(syncBucketName)
1769 // The serialized start block format is:
1770 //
1771 // <blockheight><blockhash>
1772 //
1773 // 4 bytes block height + 32 bytes hash length
1774 buf := make([]byte, 36)
1775 binary.LittleEndian.PutUint32(buf[0:4], uint32(bs.Height))
1776 copy(buf[4:36], bs.Hash[0:32])
1777 if e = bucket.Put(startBlockName, buf); E.Chk(e) {
1778 str := fmt.Sprintf("failed to store start block %v", bs.Hash)
1779 return managerError(ErrDatabase, str, e)
1780 }
1781 return nil
1782 }
1783 1784 // fetchBirthday loads the manager's bithday timestamp from the database.
1785 func fetchBirthday(ns walletdb.ReadBucket) (time.Time, error) {
1786 bucket := ns.NestedReadBucket(syncBucketName)
1787 var t time.Time
1788 buf := bucket.Get(birthdayName)
1789 if len(buf) != 8 {
1790 str := "malformed birthday stored in database"
1791 return t, managerError(ErrDatabase, str, nil)
1792 }
1793 t = time.Unix(int64(binary.BigEndian.Uint64(buf)), 0)
1794 return t, nil
1795 }
1796 1797 // putBirthday stores the provided birthday timestamp to the database.
1798 func putBirthday(ns walletdb.ReadWriteBucket, t time.Time) (e error) {
1799 bucket := ns.NestedReadWriteBucket(syncBucketName)
1800 buf := make([]byte, 8)
1801 binary.BigEndian.PutUint64(buf, uint64(t.Unix()))
1802 if e = bucket.Put(birthdayName, buf); E.Chk(e) {
1803 str := "failed to store birthday"
1804 return managerError(ErrDatabase, str, e)
1805 }
1806 return nil
1807 }
1808 1809 // managerExists returns whether or not the manager has already been created in
1810 // the given database namespace.
1811 func managerExists(ns walletdb.ReadBucket) bool {
1812 if ns == nil {
1813 return false
1814 }
1815 mainBucket := ns.NestedReadBucket(mainBucketName)
1816 return mainBucket != nil
1817 }
1818 1819 // createScopedManagerNS creates the namespace buckets for a new registered
1820 // manager scope within the top level bucket. All relevant sub-buckets that a
1821 // ScopedManager needs to perform its duties are also created.
1822 func createScopedManagerNS(ns walletdb.ReadWriteBucket, scope *KeyScope) (e error) {
1823 // First, we'll create the scope bucket itself for this particular
1824 // scope.
1825 scopeKey := scopeToBytes(scope)
1826 var scopeBucket walletdb.ReadWriteBucket
1827 if scopeBucket, e = ns.CreateBucket(scopeKey[:]); E.Chk(e) {
1828 str := "failed to create sync bucket"
1829 return managerError(ErrDatabase, str, e)
1830 }
1831 if _, e = scopeBucket.CreateBucket(acctBucketName); E.Chk(e) {
1832 str := "failed to create account bucket"
1833 return managerError(ErrDatabase, str, e)
1834 }
1835 if _, e = scopeBucket.CreateBucket(addrBucketName); E.Chk(e) {
1836 str := "failed to create address bucket"
1837 return managerError(ErrDatabase, str, e)
1838 }
1839 // usedAddrBucketName bucket was added after manager version 1 release
1840 if _, e = scopeBucket.CreateBucket(usedAddrBucketName); E.Chk(e) {
1841 str := "failed to create used addresses bucket"
1842 return managerError(ErrDatabase, str, e)
1843 }
1844 if _, e = scopeBucket.CreateBucket(addrAcctIdxBucketName); E.Chk(e) {
1845 str := "failed to create address index bucket"
1846 return managerError(ErrDatabase, str, e)
1847 }
1848 if _, e = scopeBucket.CreateBucket(acctNameIdxBucketName); E.Chk(e) {
1849 str := "failed to create an account name index bucket"
1850 return managerError(ErrDatabase, str, e)
1851 }
1852 if _, e = scopeBucket.CreateBucket(acctIDIdxBucketName); E.Chk(e) {
1853 str := "failed to create an account id index bucket"
1854 return managerError(ErrDatabase, str, e)
1855 }
1856 if _, e = scopeBucket.CreateBucket(metaBucketName); E.Chk(e) {
1857 str := "failed to create a meta bucket"
1858 return managerError(ErrDatabase, str, e)
1859 }
1860 return nil
1861 }
1862 1863 // createManagerNS creates the initial namespace structure needed for all of the
1864 // manager data. This includes things such as all of the buckets as well as the
1865 // version and creation date. In addition to creating the key space for the root
1866 // address manager, we'll also create internal scopes for all the default
1867 // manager scope types.
1868 func createManagerNS(
1869 ns walletdb.ReadWriteBucket,
1870 defaultScopes map[KeyScope]ScopeAddrSchema,
1871 ) (e error) {
1872 // First, we'll create all the relevant buckets that stem off of the main bucket.
1873 var mainBucket walletdb.ReadWriteBucket
1874 if mainBucket, e = ns.CreateBucket(mainBucketName); E.Chk(e) {
1875 str := "failed to create main bucket"
1876 return managerError(ErrDatabase, str, e)
1877 }
1878 if _, e = ns.CreateBucket(syncBucketName); E.Chk(e) {
1879 str := "failed to create sync bucket"
1880 return managerError(ErrDatabase, str, e)
1881 }
1882 // We'll also create the two top-level scope related buckets as preparation for
1883 // the operations below.
1884 var scopeBucket walletdb.ReadWriteBucket
1885 if scopeBucket, e = ns.CreateBucket(scopeBucketName); E.Chk(e) {
1886 str := "failed to create scope bucket"
1887 return managerError(ErrDatabase, str, e)
1888 }
1889 var scopeSchemas walletdb.ReadWriteBucket
1890 if scopeSchemas, e = ns.CreateBucket(scopeSchemaBucketName); E.Chk(e) {
1891 str := "failed to create scope schema bucket"
1892 return managerError(ErrDatabase, str, e)
1893 }
1894 // Next, we'll create the namespace for each of the relevant default manager
1895 // scopes.
1896 for sc, scc := range defaultScopes {
1897 // Before we create the entire namespace of this scope, we'll update the schema
1898 // mapping to note what types of addresses it prefers.
1899 scope := sc
1900 scopeSchema := scc
1901 scopeKey := scopeToBytes(&scope)
1902 schemaBytes := scopeSchemaToBytes(&scopeSchema)
1903 if e = scopeSchemas.Put(scopeKey[:], schemaBytes); E.Chk(e) {
1904 return e
1905 }
1906 if e = createScopedManagerNS(scopeBucket, &scope); E.Chk(e) {
1907 return e
1908 }
1909 if e = putLastAccount(ns, &scope, DefaultAccountNum); E.Chk(e) {
1910 return e
1911 }
1912 }
1913 if e = putManagerVersion(ns, latestMgrVersion); E.Chk(e) {
1914 return e
1915 }
1916 createDate := uint64(time.Now().Unix())
1917 var dateBytes [8]byte
1918 binary.LittleEndian.PutUint64(dateBytes[:], createDate)
1919 if e = mainBucket.Put(mgrCreateDateName, dateBytes[:]); E.Chk(e) {
1920 str := "failed to store database creation time"
1921 return managerError(ErrDatabase, str, e)
1922 }
1923 return nil
1924 }
1925 1926 // // upgradeToVersion2 upgrades the database from version 1 to version 2
1927 // // 'usedAddrBucketName' a bucket for storing addrs flagged as marked is
1928 // // initialized and it will be updated on the next rescan.
1929 //
1930 // func upgradeToVersion2(// ns walletdb.ReadWriteBucket) (e error) {
1931 // currentMgrVersion := uint32(2)
1932 // _, e := ns.CreateBucketIfNotExists(usedAddrBucketName)
1933 // if e != nil {
1934 // DB// str := "failed to create used addresses bucket"
1935 // return managerError(ErrDatabase, str, err)
1936 // }
1937 // return putManagerVersion(ns, currentMgrVersion)
1938 // }
1939 1940 // upgradeManager upgrades the data in the provided manager namespace to newer
1941 // versions as neeeded.
1942 func upgradeManager(
1943 db walletdb.DB, namespaceKey []byte, pubPassPhrase []byte,
1944 chainParams *chaincfg.Params, cbs *OpenCallbacks,
1945 ) (e error) {
1946 var version uint32
1947 if e = walletdb.View(
1948 db, func(tx walletdb.ReadTx) (e error) {
1949 ns := tx.ReadBucket(namespaceKey)
1950 version, e = fetchManagerVersion(ns)
1951 return e
1952 },
1953 ); E.Chk(e) {
1954 str := "failed to fetch version for update"
1955 return managerError(ErrDatabase, str, e)
1956 }
1957 if version < 5 {
1958 if e = walletdb.Update(
1959 db, func(tx walletdb.ReadWriteTx) (e error) {
1960 ns := tx.ReadWriteBucket(namespaceKey)
1961 return upgradeToVersion5(ns, pubPassPhrase)
1962 },
1963 ); E.Chk(e) {
1964 return e
1965 }
1966 // The manager is now at version 5.
1967 version = 5
1968 }
1969 // Ensure the manager is upgraded to the latest version. This check is to
1970 // intentionally cause a failure if the manager version is updated without
1971 // writing code to handle the upgrade.
1972 if version < latestMgrVersion {
1973 str := fmt.Sprintf(
1974 "the latest manager version is %d, but the "+
1975 "current version after upgrades is only %d",
1976 latestMgrVersion, version,
1977 )
1978 return managerError(ErrUpgrade, str, nil)
1979 }
1980 return nil
1981 }
1982 1983 // upgradeToVersion5 upgrades the database from version 4 to version 5. After
1984 // this update, the new ScopedKeyManager features cannot be used. This is due to
1985 // the fact that in version 5, we now store the encrypted master private keys on
1986 // disk. However, using the BIP0044 key scope, users will still be able to
1987 // create old p2pkh addresses.
1988 func upgradeToVersion5(ns walletdb.ReadWriteBucket, pubPassPhrase []byte) (e error) {
1989 // First, we'll check if there are any existing segwit addresses, which can't be
1990 // upgraded to the new version. If so, we abort and warn the user.
1991 if e = ns.NestedReadBucket(addrBucketName).ForEach(
1992 func(k []byte, v []byte) (e error) {
1993 row, e := deserializeAddressRow(v)
1994 if e != nil {
1995 return e
1996 }
1997 if row.addrType > adtScript {
1998 return fmt.Errorf(
1999 "segwit address exists in " +
2000 "wallet, can't upgrade from v4 to " +
2001 "v5: well, we tried ¯\\_(ツ)_/¯",
2002 )
2003 }
2004 return nil
2005 },
2006 ); E.Chk(e) {
2007 return e
2008 }
2009 // Next, we'll write out the new database version.
2010 if e = putManagerVersion(ns, 5); E.Chk(e) {
2011 return e
2012 }
2013 // First, we'll need to create the new buckets that are used in the new database
2014 // version.
2015 var scopeBucket walletdb.ReadWriteBucket
2016 if scopeBucket, e = ns.CreateBucket(scopeBucketName); E.Chk(e) {
2017 str := "failed to create scope bucket"
2018 return managerError(ErrDatabase, str, e)
2019 }
2020 var scopeSchemas walletdb.ReadWriteBucket
2021 if scopeSchemas, e = ns.CreateBucket(scopeSchemaBucketName); E.Chk(e) {
2022 str := "failed to create scope schema bucket"
2023 return managerError(ErrDatabase, str, e)
2024 }
2025 // With the buckets created, we can now create the default BIP0044 scope which
2026 // will be the only scope usable in the database after this update.
2027 scopeKey := scopeToBytes(&KeyScopeBIP0044)
2028 scopeSchema := ScopeAddrMap[KeyScopeBIP0044]
2029 schemaBytes := scopeSchemaToBytes(&scopeSchema)
2030 if e = scopeSchemas.Put(scopeKey[:], schemaBytes); E.Chk(e) {
2031 return e
2032 }
2033 if e = createScopedManagerNS(scopeBucket, &KeyScopeBIP0044); E.Chk(e) {
2034 return e
2035 }
2036 bip44Bucket := scopeBucket.NestedReadWriteBucket(scopeKey[:])
2037 // With the buckets created, we now need to port over *each* item in the prior
2038 // main bucket, into the new default scope.
2039 mainBucket := ns.NestedReadWriteBucket(mainBucketName)
2040 // First, we'll move over the encrypted coin type private and public keys to the
2041 // new sub-bucket.
2042 encCoinPrivKeys := mainBucket.Get(coinTypePrivKeyName)
2043 encCoinPubKeys := mainBucket.Get(coinTypePubKeyName)
2044 if e = bip44Bucket.Put(coinTypePrivKeyName, encCoinPrivKeys); E.Chk(e) {
2045 return e
2046 }
2047 if e = bip44Bucket.Put(coinTypePubKeyName, encCoinPubKeys); E.Chk(e) {
2048 return e
2049 }
2050 if e = mainBucket.Delete(coinTypePrivKeyName); E.Chk(e) {
2051 return e
2052 }
2053 if e = mainBucket.Delete(coinTypePubKeyName); E.Chk(e) {
2054 return e
2055 }
2056 // Next, we'll move over everything that was in the meta bucket to the meta
2057 // bucket within the new scope.
2058 metaBucket := ns.NestedReadWriteBucket(metaBucketName)
2059 lastAccount := metaBucket.Get(lastAccountName)
2060 if e = metaBucket.Delete(lastAccountName); E.Chk(e) {
2061 return e
2062 }
2063 scopedMetaBucket := bip44Bucket.NestedReadWriteBucket(metaBucketName)
2064 if e = scopedMetaBucket.Put(lastAccountName, lastAccount); E.Chk(e) {
2065 return e
2066 }
2067 // Finally, we'll recursively move over a set of keys which were formerly under
2068 // the main bucket, into the new scoped buckets. We'll do so by obtaining a
2069 // slice of all the keys that we need to modify and then recursing through each
2070 // of them, moving both nested buckets and key/value pairs.
2071 keysToMigrate := [][]byte{
2072 acctBucketName, addrBucketName, usedAddrBucketName,
2073 addrAcctIdxBucketName, acctNameIdxBucketName, acctIDIdxBucketName,
2074 }
2075 // Migrate each bucket recursively.
2076 for _, bucketKey := range keysToMigrate {
2077 if e = migrateRecursively(ns, bip44Bucket, bucketKey); E.Chk(e) {
2078 return e
2079 }
2080 }
2081 return nil
2082 }
2083 2084 // migrateRecursively moves a nested bucket from one bucket to another,
2085 // recursing into nested buckets as required.
2086 func migrateRecursively(
2087 src, dst walletdb.ReadWriteBucket,
2088 bucketKey []byte,
2089 ) (e error) {
2090 // Within this bucket key, we'll migrate over, then delete each key.
2091 bucketToMigrate := src.NestedReadWriteBucket(bucketKey)
2092 var newBucket walletdb.ReadWriteBucket
2093 if newBucket, e = dst.CreateBucketIfNotExists(bucketKey); E.Chk(e) {
2094 return e
2095 }
2096 if e = bucketToMigrate.ForEach(
2097 func(k, v []byte) (e error) {
2098 if nestedBucket := bucketToMigrate.
2099 NestedReadBucket(k); nestedBucket != nil {
2100 // We have a nested bucket, so recurse into it.
2101 return migrateRecursively(bucketToMigrate, newBucket, k)
2102 }
2103 if e := newBucket.Put(k, v); E.Chk(e) {
2104 return e
2105 }
2106 return bucketToMigrate.Delete(k)
2107 },
2108 ); E.Chk(e) {
2109 return e
2110 }
2111 // Finally, we'll delete the bucket itself.
2112 if e = src.DeleteNestedBucket(bucketKey); E.Chk(e) {
2113 return e
2114 }
2115 return nil
2116 }
2117