decred.org/dcrwallet/v3@v3.1.0/wallet/udb/addressdb.go (about)

     1  // Copyright (c) 2014 The btcsuite developers
     2  // Copyright (c) 2015-2018 The Decred developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package udb
     7  
     8  import (
     9  	"crypto/sha256"
    10  	"encoding/binary"
    11  	"time"
    12  
    13  	"decred.org/dcrwallet/v3/errors"
    14  	"decred.org/dcrwallet/v3/kdf"
    15  	"decred.org/dcrwallet/v3/wallet/walletdb"
    16  )
    17  
    18  var (
    19  	// latestMgrVersion is the most recent manager version as a variable so
    20  	// the tests can change it to force errors.
    21  	latestMgrVersion uint32 = 6
    22  )
    23  
    24  // ObtainUserInputFunc is a function that reads a user input and returns it as
    25  // a byte stream. It is used to accept data required during upgrades, for e.g.
    26  // wallet seed and private passphrase.
    27  type ObtainUserInputFunc func() ([]byte, error)
    28  
    29  // addressType represents a type of address stored in the database.
    30  type addressType uint8
    31  
    32  // These constants define the various supported address types.
    33  // They must remain stable as their values are recorded to the DB.
    34  const (
    35  	adtChain  addressType = iota // seed-derived BIP0044
    36  	adtImport                    // individually imported privkey
    37  	adtScript                    // individually imported p2sh script
    38  )
    39  
    40  type dbAccount interface {
    41  	accountType() accountType
    42  	rowData() []byte
    43  }
    44  
    45  // accountType represents a type of address stored in the database.
    46  type accountType uint8
    47  
    48  // These constants define the various supported account types.
    49  // They must remain stable as their values are recorded to the DB.
    50  const (
    51  	actBIP0044Legacy accountType = iota
    52  	actBIP0044
    53  	importedVoting
    54  )
    55  
    56  // dbAccountRow houses information stored about an account in the database.
    57  type dbAccountRow struct {
    58  	acctType accountType
    59  	rawData  []byte // Varies based on account type field.
    60  }
    61  
    62  // dbBIP0044AccountRow houses additional information stored about a BIP0044
    63  // account in the database.
    64  type dbBIP0044AccountRow struct {
    65  	dbAccountRow
    66  	pubKeyEncrypted           []byte
    67  	privKeyEncrypted          []byte
    68  	nextExternalIndex         uint32 // Removed by version 2
    69  	nextInternalIndex         uint32 // Removed by version 2
    70  	lastUsedExternalIndex     uint32 // Added in version 2
    71  	lastUsedInternalIndex     uint32 // Added in version 2
    72  	lastReturnedExternalIndex uint32 // Added in version 5
    73  	lastReturnedInternalIndex uint32 // Added in version 5
    74  	name                      string
    75  }
    76  
    77  func (r *dbBIP0044AccountRow) accountType() accountType { return actBIP0044Legacy }
    78  func (r *dbBIP0044AccountRow) rowData() []byte          { return r.dbAccountRow.rawData }
    79  
    80  // dbBIP0044Account records both the static metadata for a BIP0044 account, as
    81  // well as the variables which change over time.
    82  type dbBIP0044Account struct {
    83  	dbAccountRow
    84  	pubKeyEncrypted  []byte
    85  	privKeyEncrypted []byte
    86  
    87  	// variables subbucket is used to record remaining fields
    88  	lastUsedExternalIndex     uint32
    89  	lastUsedInternalIndex     uint32
    90  	lastReturnedExternalIndex uint32
    91  	lastReturnedInternalIndex uint32
    92  	name                      string
    93  	uniqueKey                 *kdf.Argon2idParams
    94  }
    95  
    96  func (a *dbBIP0044Account) accountType() accountType { return a.dbAccountRow.acctType }
    97  func (a *dbBIP0044Account) rowData() []byte          { return a.dbAccountRow.rawData }
    98  
    99  func (a *dbBIP0044Account) serializeRow() []byte {
   100  	// Format:
   101  	//   <len + encpubkey><len + encprivkey>
   102  
   103  	data := make([]byte, 8+len(a.pubKeyEncrypted)+len(a.privKeyEncrypted))
   104  	binary.LittleEndian.PutUint32(data, uint32(len(a.pubKeyEncrypted)))
   105  	off := 4
   106  	off += copy(data[off:], a.pubKeyEncrypted)
   107  	binary.LittleEndian.PutUint32(data[off:], uint32(len(a.privKeyEncrypted)))
   108  	off += 4
   109  	copy(data[off:], a.privKeyEncrypted)
   110  
   111  	a.rawData = data
   112  	return data
   113  }
   114  
   115  func (a *dbBIP0044Account) deserializeRow(v []byte) error {
   116  	if len(v) < 8 {
   117  		err := errors.Errorf("BIP0044 account row bad len %d", len(v))
   118  		return errors.E(errors.IO, err)
   119  	}
   120  
   121  	encPubLen := binary.LittleEndian.Uint32(v)
   122  	off := uint32(4)
   123  	encPub := append([]byte(nil), v[off:off+encPubLen]...)
   124  	off += encPubLen
   125  	encPrivLen := binary.LittleEndian.Uint32(v[off:])
   126  	off += 4
   127  	encPriv := append([]byte(nil), v[off:off+encPrivLen]...)
   128  	off += encPrivLen
   129  	if int(off) != len(v) {
   130  		return errors.E(errors.IO, "extra bytes in BIP0044 account row")
   131  	}
   132  
   133  	a.pubKeyEncrypted = encPub
   134  	a.privKeyEncrypted = encPriv
   135  	a.rawData = v
   136  	return nil
   137  }
   138  
   139  // dbAddressRow houses common information stored about an address in the
   140  // database.
   141  type dbAddressRow struct {
   142  	addrType addressType
   143  	account  uint32
   144  	addTime  uint64
   145  	rawData  []byte // Varies based on address type field.
   146  }
   147  
   148  // dbChainAddressRow houses additional information stored about a chained
   149  // address in the database.
   150  type dbChainAddressRow struct {
   151  	dbAddressRow
   152  	branch uint32
   153  	index  uint32
   154  }
   155  
   156  // dbImportedAddressRow houses additional information stored about an imported
   157  // public key address in the database.
   158  type dbImportedAddressRow struct {
   159  	dbAddressRow
   160  	encryptedPubKey  []byte
   161  	encryptedPrivKey []byte
   162  }
   163  
   164  // dbImportedAddressRow houses additional information stored about a script
   165  // address in the database.
   166  type dbScriptAddressRow struct {
   167  	dbAddressRow
   168  	encryptedHash []byte
   169  	script        []byte
   170  }
   171  
   172  // Key names for various database fields.
   173  var (
   174  	// nullVall is null byte used as a flag value in a bucket entry
   175  	nullVal = []byte{0}
   176  
   177  	// Bucket names.
   178  	acctBucketName     = []byte("acct")
   179  	acctVarsBucketName = []byte("acctvars")
   180  	addrBucketName     = []byte("addr")
   181  
   182  	// addrAcctIdxBucketName is used to index account addresses
   183  	// Entries in this index may map:
   184  	// * addr hash => account id
   185  	// * account bucket -> addr hash => null
   186  	// To fetch the account of an address, lookup the value using
   187  	// the address hash.
   188  	// To fetch all addresses of an account, fetch the account bucket, iterate
   189  	// over the keys and fetch the address row from the addr bucket.
   190  	// The index needs to be updated whenever an address is created e.g.
   191  	// NewAddress
   192  	addrAcctIdxBucketName = []byte("addracctidx")
   193  
   194  	// acctNameIdxBucketName is used to create an index
   195  	// mapping an account name string to the corresponding
   196  	// account id.
   197  	// The index needs to be updated whenever the account name
   198  	// and id changes e.g. RenameAccount
   199  	acctNameIdxBucketName = []byte("acctnameidx")
   200  
   201  	// acctIDIdxBucketName is used to create an index
   202  	// mapping an account id to the corresponding
   203  	// account name string.
   204  	// The index needs to be updated whenever the account name
   205  	// and id changes e.g. RenameAccount
   206  	acctIDIdxBucketName = []byte("acctididx")
   207  
   208  	// meta is used to store meta-data about the address manager
   209  	// e.g. last account number
   210  	metaBucketName = []byte("meta")
   211  
   212  	// addrPoolMetaKeyLen is the byte length of the address pool
   213  	// prefixes. It is 11 bytes for the prefix and 4 bytes for
   214  	// the account number.
   215  	addrPoolMetaKeyLen = 15
   216  
   217  	// addrPoolKeyPrefixExt is the prefix for keys mapping the
   218  	// last used address pool index to a BIP0044 account. The
   219  	// BIP0044 account is appended to this slice in order to
   220  	// derive the key. This is the external branch.
   221  	// e.g. in pseudocode:
   222  	// key = append([]byte("addrpoolext"), []byte(account))
   223  	//
   224  	// This was removed by database version 2.
   225  	addrPoolKeyPrefixExt = []byte("addrpoolext")
   226  
   227  	// addrPoolKeyPrefixInt is the prefix for keys mapping the
   228  	// last used address pool index to a BIP0044 account. The
   229  	// BIP0044 account is appended to this slice in order to
   230  	// derive the key. This is the internal branch.
   231  	//
   232  	// This was removed by database version 2.
   233  	addrPoolKeyPrefixInt = []byte("addrpoolint")
   234  
   235  	// lastAccountName is used to store the metadata - last account
   236  	// in the manager
   237  	lastAccountName = []byte("lastaccount")
   238  
   239  	// lastImportedAccountName is the metadata key use for the last imported
   240  	// xpub account.
   241  	lastImportedAccountName = []byte("lastimportedaccount")
   242  
   243  	mainBucketName = []byte("main")
   244  
   245  	// Db related key names (main bucket).
   246  	mgrVersionName    = []byte("mgrver")
   247  	mgrCreateDateName = []byte("mgrcreated")
   248  
   249  	// Crypto related key names (main bucket).
   250  	seedName                    = []byte("seed")
   251  	masterPrivKeyName           = []byte("mpriv")
   252  	masterPubKeyName            = []byte("mpub")
   253  	cryptoPrivKeyName           = []byte("cpriv")
   254  	cryptoPubKeyName            = []byte("cpub")
   255  	cryptoScriptKeyName         = []byte("cscript") // removed in db v14
   256  	coinTypeLegacyPrivKeyName   = []byte("ctpriv")
   257  	coinTypeLegacyPubKeyName    = []byte("ctpub")
   258  	coinTypeSLIP0044PrivKeyName = []byte("ctpriv-slip0044")
   259  	coinTypeSLIP0044PubKeyName  = []byte("ctpub-slip0044")
   260  	watchingOnlyName            = []byte("watchonly")
   261  	slip0044Account0RowName     = []byte("slip0044acct0")
   262  
   263  	// Used addresses (used bucket).  This was removed by database version 2.
   264  	usedAddrBucketName = []byte("usedaddrs")
   265  )
   266  
   267  // uint32ToBytes converts a 32 bit unsigned integer into a 4-byte slice in
   268  // little-endian order: 1 -> [1 0 0 0].
   269  func uint32ToBytes(number uint32) []byte {
   270  	buf := make([]byte, 4)
   271  	binary.LittleEndian.PutUint32(buf, number)
   272  	return buf
   273  }
   274  
   275  // stringToBytes converts a string into a variable length byte slice in
   276  // little-endian order: "abc" -> [3 0 0 0 61 62 63]
   277  func stringToBytes(s string) []byte {
   278  	// The serialized format is:
   279  	//   <size><string>
   280  	//
   281  	// 4 bytes string size + string
   282  	size := len(s)
   283  	buf := make([]byte, 4+size)
   284  	copy(buf[0:4], uint32ToBytes(uint32(size)))
   285  	copy(buf[4:4+size], s)
   286  	return buf
   287  }
   288  
   289  // fetchManagerVersion fetches the current manager version from the database.
   290  // Should only be called on managers in unmigrated DBs.
   291  func fetchManagerVersion(ns walletdb.ReadBucket) (uint32, error) {
   292  	mainBucket := ns.NestedReadBucket(mainBucketName)
   293  	verBytes := mainBucket.Get(mgrVersionName)
   294  	if verBytes == nil {
   295  		return 0, errors.E(errors.IO, "missing address manager version")
   296  	}
   297  	version := binary.LittleEndian.Uint32(verBytes)
   298  	return version, nil
   299  }
   300  
   301  // putManagerVersion stores the provided version to the database.  Should only
   302  // be called on managers in unmigrated DBs.
   303  func putManagerVersion(ns walletdb.ReadWriteBucket, version uint32) error {
   304  	bucket := ns.NestedReadWriteBucket(mainBucketName)
   305  
   306  	verBytes := uint32ToBytes(version)
   307  	err := bucket.Put(mgrVersionName, verBytes)
   308  	if err != nil {
   309  		return errors.E(errors.IO, err)
   310  	}
   311  	return nil
   312  }
   313  
   314  // fetchMasterKeyParams loads the master key parameters needed to derive them
   315  // (when given the correct user-supplied passphrase) from the database.  Either
   316  // returned value can be nil, but in practice only the private key params will
   317  // be nil for a watching-only database.
   318  func fetchMasterKeyParams(ns walletdb.ReadBucket) ([]byte, []byte, error) {
   319  	bucket := ns.NestedReadBucket(mainBucketName)
   320  
   321  	// Load the master public key parameters.  Required.
   322  	val := bucket.Get(masterPubKeyName)
   323  	if val == nil {
   324  		return nil, nil, errors.E(errors.IO, "missing master pubkey params")
   325  	}
   326  	pubParams := make([]byte, len(val))
   327  	copy(pubParams, val)
   328  
   329  	// Load the master private key parameters if they were stored.
   330  	var privParams []byte
   331  	val = bucket.Get(masterPrivKeyName)
   332  	if val != nil {
   333  		privParams = make([]byte, len(val))
   334  		copy(privParams, val)
   335  	}
   336  
   337  	return pubParams, privParams, nil
   338  }
   339  
   340  // putMasterKeyParams stores the master key parameters needed to derive them
   341  // to the database.  Either parameter can be nil in which case no value is
   342  // written for the parameter.
   343  func putMasterKeyParams(ns walletdb.ReadWriteBucket, pubParams, privParams []byte) error {
   344  	bucket := ns.NestedReadWriteBucket(mainBucketName)
   345  
   346  	if privParams != nil {
   347  		err := bucket.Put(masterPrivKeyName, privParams)
   348  		if err != nil {
   349  			return errors.E(errors.IO, err)
   350  		}
   351  	}
   352  
   353  	if pubParams != nil {
   354  		err := bucket.Put(masterPubKeyName, pubParams)
   355  		if err != nil {
   356  			return errors.E(errors.IO, err)
   357  		}
   358  	}
   359  
   360  	return nil
   361  }
   362  
   363  // fetchCoinTypeKeys loads the encrypted cointype keys which are in turn used to
   364  // derive the extended keys for all accounts.  If both the legacy and SLIP0044
   365  // coin type keys are saved, the legacy keys are used for backwards
   366  // compatibility reasons.
   367  func fetchCoinTypeKeys(ns walletdb.ReadBucket) ([]byte, []byte, error) {
   368  	bucket := ns.NestedReadBucket(mainBucketName)
   369  
   370  	var coinTypeSLIP0044 bool
   371  
   372  	coinTypePubKeyEnc := bucket.Get(coinTypeLegacyPubKeyName)
   373  	if coinTypePubKeyEnc == nil {
   374  		coinTypeSLIP0044 = true
   375  		coinTypePubKeyEnc = bucket.Get(coinTypeSLIP0044PubKeyName)
   376  	}
   377  	if coinTypePubKeyEnc == nil {
   378  		return nil, nil, errors.E(errors.IO, "missing encrypted cointype pubkey")
   379  	}
   380  
   381  	coinTypePrivKeyName := coinTypeLegacyPrivKeyName
   382  	if coinTypeSLIP0044 {
   383  		coinTypePrivKeyName = coinTypeSLIP0044PrivKeyName
   384  	}
   385  	coinTypePrivKeyEnc := bucket.Get(coinTypePrivKeyName)
   386  	if coinTypePrivKeyEnc == nil {
   387  		return nil, nil, errors.E(errors.IO, "missing encrypted cointype privkey")
   388  	}
   389  
   390  	return coinTypePubKeyEnc, coinTypePrivKeyEnc, nil
   391  }
   392  
   393  // putCoinTypeLegacyKeys stores the encrypted legacy cointype keys which are in
   394  // turn used to derive the extended keys for all accounts.  Either parameter can
   395  // be nil in which case no value is written for the parameter.
   396  func putCoinTypeLegacyKeys(ns walletdb.ReadWriteBucket, coinTypePubKeyEnc []byte, coinTypePrivKeyEnc []byte) error {
   397  	bucket := ns.NestedReadWriteBucket(mainBucketName)
   398  
   399  	if coinTypePubKeyEnc != nil {
   400  		err := bucket.Put(coinTypeLegacyPubKeyName, coinTypePubKeyEnc)
   401  		if err != nil {
   402  			return errors.E(errors.IO, err)
   403  		}
   404  	}
   405  
   406  	if coinTypePrivKeyEnc != nil {
   407  		err := bucket.Put(coinTypeLegacyPrivKeyName, coinTypePrivKeyEnc)
   408  		if err != nil {
   409  			return errors.E(errors.IO, err)
   410  		}
   411  	}
   412  
   413  	return nil
   414  }
   415  
   416  // putCoinTypeSLIP0044Keys stores the encrypted SLIP0044 cointype keys which are
   417  // in turn used to derive the extended keys for all accounts.  Either parameter
   418  // can be nil in which case no value is written for the parameter.
   419  func putCoinTypeSLIP0044Keys(ns walletdb.ReadWriteBucket, coinTypePubKeyEnc []byte, coinTypePrivKeyEnc []byte) error {
   420  	bucket := ns.NestedReadWriteBucket(mainBucketName)
   421  
   422  	if coinTypePubKeyEnc != nil {
   423  		err := bucket.Put(coinTypeSLIP0044PubKeyName, coinTypePubKeyEnc)
   424  		if err != nil {
   425  			return errors.E(errors.IO, err)
   426  		}
   427  	}
   428  
   429  	if coinTypePrivKeyEnc != nil {
   430  		err := bucket.Put(coinTypeSLIP0044PrivKeyName, coinTypePrivKeyEnc)
   431  		if err != nil {
   432  			return errors.E(errors.IO, err)
   433  		}
   434  	}
   435  
   436  	return nil
   437  }
   438  
   439  // fetchCryptoKeys loads the encrypted crypto keys which are in turn used to
   440  // protect the extended keys and imported keys.  Any of the returned values can
   441  // be nil, but in practice only the crypto private key will be nil for a
   442  // watching-only database.
   443  func fetchCryptoKeys(ns walletdb.ReadBucket) ([]byte, []byte, error) {
   444  	bucket := ns.NestedReadBucket(mainBucketName)
   445  
   446  	// Load the crypto public key parameters.  Required.
   447  	val := bucket.Get(cryptoPubKeyName)
   448  	if val == nil {
   449  		return nil, nil, errors.E(errors.IO, "missing encrypted crypto pubkey")
   450  	}
   451  	pubKey := make([]byte, len(val))
   452  	copy(pubKey, val)
   453  
   454  	// Load the crypto private key parameters if they were stored.
   455  	var privKey []byte
   456  	val = bucket.Get(cryptoPrivKeyName)
   457  	if val != nil {
   458  		privKey = make([]byte, len(val))
   459  		copy(privKey, val)
   460  	}
   461  
   462  	return pubKey, privKey, nil
   463  }
   464  
   465  // putCryptoKeys stores the encrypted crypto keys which are in turn used to
   466  // protect the extended and imported keys.  Either parameter can be nil in which
   467  // case no value is written for the parameter.
   468  func putCryptoKeys(ns walletdb.ReadWriteBucket, pubKeyEncrypted, privKeyEncrypted []byte) error {
   469  	bucket := ns.NestedReadWriteBucket(mainBucketName)
   470  
   471  	if pubKeyEncrypted != nil {
   472  		err := bucket.Put(cryptoPubKeyName, pubKeyEncrypted)
   473  		if err != nil {
   474  			return errors.E(errors.IO, err)
   475  		}
   476  	}
   477  
   478  	if privKeyEncrypted != nil {
   479  		err := bucket.Put(cryptoPrivKeyName, privKeyEncrypted)
   480  		if err != nil {
   481  			return errors.E(errors.IO, err)
   482  		}
   483  	}
   484  
   485  	return nil
   486  }
   487  
   488  // fetchWatchingOnly loads the watching-only flag from the database.
   489  func fetchWatchingOnly(ns walletdb.ReadBucket) (bool, error) {
   490  	bucket := ns.NestedReadBucket(mainBucketName)
   491  
   492  	buf := bucket.Get(watchingOnlyName)
   493  	if len(buf) != 1 {
   494  		return false, errors.E(errors.IO, errors.Errorf("bad watching-only flag len %d", len(buf)))
   495  	}
   496  
   497  	return buf[0] != 0, nil
   498  }
   499  
   500  // putWatchingOnly stores the watching-only flag to the database.
   501  func putWatchingOnly(ns walletdb.ReadWriteBucket, watchingOnly bool) error {
   502  	bucket := ns.NestedReadWriteBucket(mainBucketName)
   503  
   504  	var encoded byte
   505  	if watchingOnly {
   506  		encoded = 1
   507  	}
   508  
   509  	if err := bucket.Put(watchingOnlyName, []byte{encoded}); err != nil {
   510  		return errors.E(errors.IO, err)
   511  	}
   512  	return nil
   513  }
   514  
   515  // deserializeAccountRow deserializes the passed serialized account information.
   516  // This is used as a common base for the various account types to deserialize
   517  // the common parts.
   518  func deserializeAccountRow(accountID []byte, serializedAccount []byte) (*dbAccountRow, error) {
   519  	// The serialized account format is:
   520  	//   <acctType><rdlen><rawdata>
   521  	//
   522  	// 1 byte acctType + 4 bytes raw data length + raw data
   523  
   524  	// Given the above, the length of the entry must be at a minimum
   525  	// the constant value sizes.
   526  	if len(serializedAccount) < 5 {
   527  		return nil, errors.E(errors.IO, errors.Errorf("bad account len %d", len(serializedAccount)))
   528  	}
   529  
   530  	row := dbAccountRow{}
   531  	row.acctType = accountType(serializedAccount[0])
   532  	rdlen := binary.LittleEndian.Uint32(serializedAccount[1:5])
   533  	row.rawData = make([]byte, rdlen)
   534  	copy(row.rawData, serializedAccount[5:5+rdlen])
   535  
   536  	return &row, nil
   537  }
   538  
   539  // serializeAccountRow returns the serialization of the passed account row.
   540  func serializeAccountRow(row *dbAccountRow) []byte {
   541  	// The serialized account format is:
   542  	//   <acctType><rdlen><rawdata>
   543  	//
   544  	// 1 byte acctType + 4 bytes raw data length + raw data
   545  	rdlen := len(row.rawData)
   546  	buf := make([]byte, 5+rdlen)
   547  	buf[0] = byte(row.acctType)
   548  	binary.LittleEndian.PutUint32(buf[1:5], uint32(rdlen))
   549  	copy(buf[5:5+rdlen], row.rawData)
   550  	return buf
   551  }
   552  
   553  // deserializeBIP0044AccountRow deserializes the raw data from the passed
   554  // account row as a BIP0044 account.
   555  func deserializeBIP0044AccountRow(accountID []byte, row *dbAccountRow, dbVersion uint32) (*dbBIP0044AccountRow, error) {
   556  	// The serialized BIP0044 account raw data format is:
   557  	//   <encpubkeylen><encpubkey><encprivkeylen><encprivkey><lastusedext>
   558  	//   <lastusedint><lastretext><lastretint><namelen><name>
   559  	//
   560  	// 4 bytes encrypted pubkey len + encrypted pubkey + 4 bytes encrypted
   561  	// privkey len + encrypted privkey + 4 bytes last used external index +
   562  	// 4 bytes last used internal index + 4 bytes last returned external +
   563  	// 4 bytes last returned internal + 4 bytes name len + name
   564  
   565  	// Given the above, the length of the entry must be at a minimum
   566  	// the constant value sizes.
   567  	switch {
   568  	case dbVersion < 5 && len(row.rawData) < 20,
   569  		dbVersion >= 5 && len(row.rawData) < 28:
   570  		return nil, errors.E(errors.IO, errors.Errorf("bip0044 account %x bad len %d", accountID, len(row.rawData)))
   571  	}
   572  
   573  	retRow := dbBIP0044AccountRow{
   574  		dbAccountRow: *row,
   575  	}
   576  
   577  	pubLen := binary.LittleEndian.Uint32(row.rawData[0:4])
   578  	retRow.pubKeyEncrypted = make([]byte, pubLen)
   579  	copy(retRow.pubKeyEncrypted, row.rawData[4:4+pubLen])
   580  	offset := 4 + pubLen
   581  	privLen := binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
   582  	offset += 4
   583  	retRow.privKeyEncrypted = make([]byte, privLen)
   584  	copy(retRow.privKeyEncrypted, row.rawData[offset:offset+privLen])
   585  	offset += privLen
   586  	switch {
   587  	case dbVersion == 1:
   588  		retRow.nextExternalIndex = binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
   589  		offset += 4
   590  		retRow.nextInternalIndex = binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
   591  		offset += 4
   592  	case dbVersion >= 2:
   593  		retRow.lastUsedExternalIndex = binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
   594  		retRow.lastUsedInternalIndex = binary.LittleEndian.Uint32(row.rawData[offset+4 : offset+8])
   595  		offset += 8
   596  	}
   597  	switch {
   598  	case dbVersion >= 5:
   599  		retRow.lastReturnedExternalIndex = binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
   600  		retRow.lastReturnedInternalIndex = binary.LittleEndian.Uint32(row.rawData[offset+4 : offset+8])
   601  		offset += 8
   602  	}
   603  	nameLen := binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
   604  	offset += 4
   605  	retRow.name = string(row.rawData[offset : offset+nameLen])
   606  
   607  	return &retRow, nil
   608  }
   609  
   610  // serializeBIP0044AccountRow returns the serialization of the raw data field
   611  // for a BIP0044 account.
   612  func serializeBIP0044AccountRow(row *dbBIP0044AccountRow, dbVersion uint32) []byte {
   613  	// The serialized BIP0044 account raw data format is:
   614  	//   <encpubkeylen><encpubkey><encprivkeylen><encprivkey><lastusedext>
   615  	//   <lastusedint><lastretext><lastretint><namelen><name>
   616  	//
   617  	// 4 bytes encrypted pubkey len + encrypted pubkey + 4 bytes encrypted
   618  	// privkey len + encrypted privkey + 4 bytes last used external index +
   619  	// 4 bytes last used internal index + 4 bytes last returned external +
   620  	// 4 bytes last returned internal + 4 bytes name len + name
   621  	pubLen := uint32(len(row.pubKeyEncrypted))
   622  	privLen := uint32(len(row.privKeyEncrypted))
   623  	nameLen := uint32(len(row.name))
   624  	rowSize := 28 + pubLen + privLen + nameLen
   625  	switch {
   626  	case dbVersion < 5:
   627  		rowSize -= 8
   628  	}
   629  	rawData := make([]byte, rowSize)
   630  	binary.LittleEndian.PutUint32(rawData[0:4], pubLen)
   631  	copy(rawData[4:4+pubLen], row.pubKeyEncrypted)
   632  	offset := 4 + pubLen
   633  	binary.LittleEndian.PutUint32(rawData[offset:offset+4], privLen)
   634  	offset += 4
   635  	copy(rawData[offset:offset+privLen], row.privKeyEncrypted)
   636  	offset += privLen
   637  	switch {
   638  	case dbVersion == 1:
   639  		binary.LittleEndian.PutUint32(rawData[offset:offset+4], row.nextExternalIndex)
   640  		offset += 4
   641  		binary.LittleEndian.PutUint32(rawData[offset:offset+4], row.nextInternalIndex)
   642  		offset += 4
   643  	case dbVersion >= 2:
   644  		binary.LittleEndian.PutUint32(rawData[offset:offset+4], row.lastUsedExternalIndex)
   645  		binary.LittleEndian.PutUint32(rawData[offset+4:offset+8], row.lastUsedInternalIndex)
   646  		offset += 8
   647  	}
   648  	switch {
   649  	case dbVersion >= 5:
   650  		binary.LittleEndian.PutUint32(rawData[offset:offset+4], row.lastReturnedExternalIndex)
   651  		binary.LittleEndian.PutUint32(rawData[offset+4:offset+8], row.lastReturnedInternalIndex)
   652  		offset += 8
   653  	}
   654  	binary.LittleEndian.PutUint32(rawData[offset:offset+4], nameLen)
   655  	offset += 4
   656  	copy(rawData[offset:offset+nameLen], row.name)
   657  	return rawData
   658  }
   659  
   660  func bip0044AccountInfo(pubKeyEnc, privKeyEnc []byte, nextExtIndex, nextIntIndex,
   661  	lastUsedExtIndex, lastUsedIntIndex, lastRetExtIndex, lastRetIntIndex uint32,
   662  	name string, dbVersion uint32) *dbBIP0044AccountRow {
   663  
   664  	row := &dbBIP0044AccountRow{
   665  		dbAccountRow: dbAccountRow{
   666  			acctType: actBIP0044Legacy,
   667  			rawData:  nil,
   668  		},
   669  		pubKeyEncrypted:           pubKeyEnc,
   670  		privKeyEncrypted:          privKeyEnc,
   671  		nextExternalIndex:         0,
   672  		nextInternalIndex:         0,
   673  		lastUsedExternalIndex:     0,
   674  		lastUsedInternalIndex:     0,
   675  		lastReturnedExternalIndex: 0,
   676  		lastReturnedInternalIndex: 0,
   677  		name:                      name,
   678  	}
   679  	switch {
   680  	case dbVersion == 1:
   681  		row.nextExternalIndex = nextExtIndex
   682  		row.nextInternalIndex = nextIntIndex
   683  	case dbVersion >= 2:
   684  		row.lastUsedExternalIndex = lastUsedExtIndex
   685  		row.lastUsedInternalIndex = lastUsedIntIndex
   686  	}
   687  	switch {
   688  	case dbVersion >= 5:
   689  		row.lastReturnedExternalIndex = lastRetExtIndex
   690  		row.lastReturnedInternalIndex = lastRetIntIndex
   691  	}
   692  	row.rawData = serializeBIP0044AccountRow(row, dbVersion)
   693  	return row
   694  }
   695  
   696  // forEachAccount calls the given function with each account stored in
   697  // the manager, breaking early on error.
   698  func forEachAccount(ns walletdb.ReadBucket, fn func(account uint32) error) error {
   699  	bucket := ns.NestedReadBucket(acctBucketName)
   700  
   701  	return bucket.ForEach(func(k, v []byte) error {
   702  		// Skip buckets.
   703  		if v == nil {
   704  			return nil
   705  		}
   706  		return fn(binary.LittleEndian.Uint32(k))
   707  	})
   708  }
   709  
   710  // fetchLastAccount retreives the last BIP0044 account from the database.
   711  func fetchLastAccount(ns walletdb.ReadBucket) (uint32, error) {
   712  	bucket := ns.NestedReadBucket(metaBucketName)
   713  
   714  	val := bucket.Get(lastAccountName)
   715  	if len(val) != 4 {
   716  		return 0, errors.E(errors.IO, errors.Errorf("bad last account len %d", len(val)))
   717  	}
   718  	account := binary.LittleEndian.Uint32(val[0:4])
   719  	return account, nil
   720  }
   721  
   722  // fetchLastAccount retreives the last imported xpub account from the
   723  // database.
   724  func fetchLastImportedAccount(ns walletdb.ReadBucket) (uint32, error) {
   725  	bucket := ns.NestedReadBucket(metaBucketName)
   726  
   727  	val := bucket.Get(lastImportedAccountName)
   728  	// TODO: add this, set to old imported account num in db upgrade
   729  	// TODO: also remove this hack
   730  	if len(val) == 0 {
   731  		return ImportedAddrAccount, nil
   732  	}
   733  	if len(val) != 4 {
   734  		return 0, errors.E(errors.IO, errors.Errorf("bad last imported account len %d", len(val)))
   735  	}
   736  	account := binary.LittleEndian.Uint32(val[0:4])
   737  	if account <= MaxAccountNum {
   738  		return 0, errors.E(errors.IO, errors.Errorf("bad imported xpub account value %d", account))
   739  	}
   740  	return account, nil
   741  }
   742  
   743  // fetchAccountName retreives the account name given an account number from
   744  // the database.
   745  func fetchAccountName(ns walletdb.ReadBucket, account uint32) (string, error) {
   746  	bucket := ns.NestedReadBucket(acctIDIdxBucketName)
   747  
   748  	val := bucket.Get(uint32ToBytes(account))
   749  	if val == nil {
   750  		return "", errors.E(errors.NotExist, errors.Errorf("no account %d", account))
   751  	}
   752  	offset := uint32(0)
   753  	nameLen := binary.LittleEndian.Uint32(val[offset : offset+4])
   754  	offset += 4
   755  	acctName := string(val[offset : offset+nameLen])
   756  	return acctName, nil
   757  }
   758  
   759  // fetchAccountByName retreives the account number given an account name
   760  // from the database.
   761  func fetchAccountByName(ns walletdb.ReadBucket, name string) (uint32, error) {
   762  	bucket := ns.NestedReadBucket(acctNameIdxBucketName)
   763  
   764  	val := bucket.Get(stringToBytes(name))
   765  	if val == nil {
   766  		return 0, errors.E(errors.NotExist, errors.Errorf("no account %q", name))
   767  	}
   768  
   769  	return binary.LittleEndian.Uint32(val), nil
   770  }
   771  
   772  // fetchAccountRow loads the row serializing details regarding an account.
   773  // This function does not perform any further parsing based on the account type.
   774  func fetchAccountRow(ns walletdb.ReadBucket, account uint32, dbVersion uint32) (*dbAccountRow, error) {
   775  	bucket := ns.NestedReadBucket(acctBucketName)
   776  
   777  	accountID := uint32ToBytes(account)
   778  	serializedRow := bucket.Get(accountID)
   779  	if serializedRow == nil {
   780  		return nil, errors.E(errors.NotExist, errors.Errorf("no account %d", account))
   781  	}
   782  
   783  	return deserializeAccountRow(accountID, serializedRow)
   784  }
   785  
   786  // fetchAccountInfo loads information about the passed account from the
   787  // database.
   788  func fetchAccountInfo(ns walletdb.ReadBucket, account uint32, dbVersion uint32) (*dbBIP0044AccountRow, error) {
   789  	row, err := fetchAccountRow(ns, account, dbVersion)
   790  	if err != nil {
   791  		return nil, err
   792  	}
   793  
   794  	accountID := uint32ToBytes(account)
   795  	switch row.acctType {
   796  	case actBIP0044Legacy, importedVoting:
   797  		return deserializeBIP0044AccountRow(accountID, row, dbVersion)
   798  	}
   799  
   800  	return nil, errors.E(errors.IO, errors.Errorf("unknown account type %d", row.acctType))
   801  }
   802  
   803  func fetchDBAccount(ns walletdb.ReadBucket, account uint32, dbVersion uint32) (dbAccount, error) {
   804  	row, err := fetchAccountRow(ns, account, dbVersion)
   805  	if err != nil {
   806  		return nil, err
   807  	}
   808  
   809  	accountID := uint32ToBytes(account)
   810  	switch row.acctType {
   811  	case actBIP0044Legacy:
   812  		if dbVersion >= accountVariablesVersion {
   813  			err := errors.Errorf("legacy BIP0044 account row unsupported "+
   814  				"in db version %v", dbVersion)
   815  			return nil, errors.E(err)
   816  		}
   817  		return deserializeBIP0044AccountRow(accountID, row, dbVersion)
   818  	case actBIP0044, importedVoting:
   819  		bucketKey := uint32ToBytes(account)
   820  		varsBucket := ns.NestedReadBucket(acctVarsBucketName).
   821  			NestedReadBucket(bucketKey)
   822  
   823  		var r accountVarReader
   824  		lastUsedExt := r.getAccountUint32Var(varsBucket, acctVarLastUsedExternal)
   825  		lastUsedInt := r.getAccountUint32Var(varsBucket, acctVarLastUsedInternal)
   826  		lastRetExt := r.getAccountUint32Var(varsBucket, acctVarLastReturnedExternal)
   827  		lastRetInt := r.getAccountUint32Var(varsBucket, acctVarLastReturnedInternal)
   828  		name := r.getAccountStringVar(varsBucket, acctVarName)
   829  		kdfParams := r.getAccountKDFVar(varsBucket, acctVarKDF)
   830  		if r.err != nil {
   831  			return nil, errors.E(errors.IO, err)
   832  		}
   833  
   834  		a := new(dbBIP0044Account)
   835  		a.dbAccountRow = *row
   836  		err := a.deserializeRow(row.rawData)
   837  		if err != nil {
   838  			return nil, err
   839  		}
   840  		a.lastUsedExternalIndex = lastUsedExt
   841  		a.lastUsedInternalIndex = lastUsedInt
   842  		a.lastReturnedExternalIndex = lastRetExt
   843  		a.lastReturnedInternalIndex = lastRetInt
   844  		a.name = name
   845  		a.uniqueKey = kdfParams
   846  
   847  		return a, nil
   848  	}
   849  
   850  	return nil, errors.E(errors.IO, errors.Errorf("unknown account type %d", row.acctType))
   851  }
   852  
   853  func accountVarsBucket(ns walletdb.ReadWriteBucket, account uint32) walletdb.ReadWriteBucket {
   854  	accountKey := uint32ToBytes(account)
   855  	return ns.NestedReadWriteBucket(acctVarsBucketName).NestedReadWriteBucket(accountKey)
   856  }
   857  
   858  // deleteAccountNameIndex deletes the given key from the account name index of the database.
   859  func deleteAccountNameIndex(ns walletdb.ReadWriteBucket, name string) error {
   860  	bucket := ns.NestedReadWriteBucket(acctNameIdxBucketName)
   861  
   862  	// Delete the account name key
   863  	err := bucket.Delete(stringToBytes(name))
   864  	if err != nil {
   865  		return errors.E(errors.IO, err)
   866  	}
   867  	return nil
   868  }
   869  
   870  // deleteAccounIdIndex deletes the given key from the account id index of the database.
   871  func deleteAccountIDIndex(ns walletdb.ReadWriteBucket, account uint32) error {
   872  	bucket := ns.NestedReadWriteBucket(acctIDIdxBucketName)
   873  
   874  	// Delete the account id key
   875  	err := bucket.Delete(uint32ToBytes(account))
   876  	if err != nil {
   877  		return errors.E(errors.IO, err)
   878  	}
   879  	return nil
   880  }
   881  
   882  // putAccountNameIndex stores the given key to the account name index of the database.
   883  func putAccountNameIndex(ns walletdb.ReadWriteBucket, account uint32, name string) error {
   884  	bucket := ns.NestedReadWriteBucket(acctNameIdxBucketName)
   885  
   886  	// Write the account number keyed by the account name.
   887  	err := bucket.Put(stringToBytes(name), uint32ToBytes(account))
   888  	if err != nil {
   889  		return errors.E(errors.IO, err)
   890  	}
   891  	return nil
   892  }
   893  
   894  // putAccountIDIndex stores the given key to the account id index of the database.
   895  func putAccountIDIndex(ns walletdb.ReadWriteBucket, account uint32, name string) error {
   896  	bucket := ns.NestedReadWriteBucket(acctIDIdxBucketName)
   897  
   898  	// Write the account number keyed by the account id.
   899  	err := bucket.Put(uint32ToBytes(account), stringToBytes(name))
   900  	if err != nil {
   901  		return errors.E(errors.IO, err)
   902  	}
   903  	return nil
   904  }
   905  
   906  // putAddrAccountIndex stores the given key to the address account index of the database.
   907  func putAddrAccountIndex(ns walletdb.ReadWriteBucket, account uint32, addrHash []byte) error {
   908  	bucket := ns.NestedReadWriteBucket(addrAcctIdxBucketName)
   909  
   910  	// Write account keyed by address hash
   911  	err := bucket.Put(addrHash, uint32ToBytes(account))
   912  	if err != nil {
   913  		return errors.E(errors.IO, err)
   914  	}
   915  
   916  	bucket, err = bucket.CreateBucketIfNotExists(uint32ToBytes(account))
   917  	if err != nil {
   918  		return errors.E(errors.IO, err)
   919  	}
   920  	// In account bucket, write a null value keyed by the address hash
   921  	err = bucket.Put(addrHash, nullVal)
   922  	if err != nil {
   923  		return errors.E(errors.IO, err)
   924  	}
   925  	return nil
   926  }
   927  
   928  // putAccountRow stores the provided account information to the database.  This
   929  // is used a common base for storing the various account types.
   930  func putAccountRow(ns walletdb.ReadWriteBucket, account uint32, row *dbAccountRow) error {
   931  	bucket := ns.NestedReadWriteBucket(acctBucketName)
   932  
   933  	// Write the serialized value keyed by the account number.
   934  	err := bucket.Put(uint32ToBytes(account), serializeAccountRow(row))
   935  	if err != nil {
   936  		return errors.E(errors.IO, err)
   937  	}
   938  	return nil
   939  }
   940  
   941  // putBIP0044AccountInfo stores the provided account information to the database.
   942  func putBIP0044AccountInfo(ns walletdb.ReadWriteBucket, account uint32, row *dbBIP0044AccountRow) error {
   943  	if err := putAccountRow(ns, account, &row.dbAccountRow); err != nil {
   944  		return err
   945  	}
   946  	// Update account id index
   947  	if err := putAccountIDIndex(ns, account, row.name); err != nil {
   948  		return err
   949  	}
   950  	// Update account name index
   951  	return putAccountNameIndex(ns, account, row.name)
   952  }
   953  
   954  // putNewBIP0044Account writes a new account to the database, storing the
   955  // account row and all account variables.
   956  func putNewBIP0044Account(ns walletdb.ReadWriteBucket, account uint32, a *dbBIP0044Account) error {
   957  	err := putAccountRow(ns, account, &a.dbAccountRow)
   958  	if err != nil {
   959  		return err
   960  	}
   961  	// Index the account by name
   962  	err = putAccountIDIndex(ns, account, a.name)
   963  	if err != nil {
   964  		return err
   965  	}
   966  	err = putAccountNameIndex(ns, account, a.name)
   967  	if err != nil {
   968  		return err
   969  	}
   970  	// Create the bucket for this account's variables
   971  	bucketKey := uint32ToBytes(account)
   972  	varsBucket, err := ns.NestedReadWriteBucket(acctVarsBucketName).
   973  		CreateBucketIfNotExists(bucketKey)
   974  	if err != nil {
   975  		return err
   976  	}
   977  	// Write the account's variables
   978  	err = putAccountUint32Var(varsBucket, acctVarLastUsedExternal, a.lastUsedExternalIndex)
   979  	if err != nil {
   980  		return err
   981  	}
   982  	err = putAccountUint32Var(varsBucket, acctVarLastUsedInternal, a.lastUsedInternalIndex)
   983  	if err != nil {
   984  		return err
   985  	}
   986  	err = putAccountUint32Var(varsBucket, acctVarLastReturnedExternal, a.lastReturnedExternalIndex)
   987  	if err != nil {
   988  		return err
   989  	}
   990  	err = putAccountUint32Var(varsBucket, acctVarLastReturnedInternal, a.lastReturnedInternalIndex)
   991  	if err != nil {
   992  		return err
   993  	}
   994  	err = putAccountStringVar(varsBucket, acctVarName, a.name)
   995  	if err != nil {
   996  		return err
   997  	}
   998  	if a.uniqueKey != nil {
   999  		err = putAccountKDFVar(varsBucket, acctVarKDF, a.uniqueKey)
  1000  		if err != nil {
  1001  			return err
  1002  		}
  1003  	}
  1004  
  1005  	return nil
  1006  }
  1007  
  1008  // putLastAccount stores the provided metadata - last account - to the database.
  1009  func putLastAccount(ns walletdb.ReadWriteBucket, account uint32) error {
  1010  	bucket := ns.NestedReadWriteBucket(metaBucketName)
  1011  
  1012  	err := bucket.Put(lastAccountName, uint32ToBytes(account))
  1013  	if err != nil {
  1014  		return errors.E(errors.IO, err)
  1015  	}
  1016  	return nil
  1017  }
  1018  
  1019  // putLastImportedAccount stores the provided metadata - last account - to the database.
  1020  func putLastImportedAccount(ns walletdb.ReadWriteBucket, account uint32) error {
  1021  	bucket := ns.NestedReadWriteBucket(metaBucketName)
  1022  
  1023  	err := bucket.Put(lastImportedAccountName, uint32ToBytes(account))
  1024  	if err != nil {
  1025  		return errors.E(errors.IO, err)
  1026  	}
  1027  	return nil
  1028  }
  1029  
  1030  // Account variable keys
  1031  var (
  1032  	acctVarLastUsedExternal     = []byte("extused")
  1033  	acctVarLastUsedInternal     = []byte("intused")
  1034  	acctVarLastReturnedExternal = []byte("extret")
  1035  	acctVarLastReturnedInternal = []byte("intret")
  1036  	acctVarName                 = []byte("name")
  1037  	acctVarKDF                  = []byte("kdf-params")
  1038  )
  1039  
  1040  func putAccountUint32Var(varsBucket walletdb.ReadWriteBucket, varName []byte, value uint32) error {
  1041  	v := make([]byte, 4)
  1042  	binary.LittleEndian.PutUint32(v, value)
  1043  	err := varsBucket.Put(varName, v)
  1044  	if err != nil {
  1045  		return errors.E(errors.IO, err)
  1046  	}
  1047  	return nil
  1048  }
  1049  
  1050  func putAccountStringVar(varsBucket walletdb.ReadWriteBucket, varName []byte, value string) error {
  1051  	err := varsBucket.Put(varName, []byte(value))
  1052  	if err != nil {
  1053  		return errors.E(errors.IO, err)
  1054  	}
  1055  	return nil
  1056  }
  1057  
  1058  func putAccountKDFVar(varsBucket walletdb.ReadWriteBucket, varName []byte, value *kdf.Argon2idParams) error {
  1059  	marshaled, err := value.MarshalBinary()
  1060  	if err != nil {
  1061  		return err
  1062  	}
  1063  	err = varsBucket.Put(varName, marshaled)
  1064  	if err != nil {
  1065  		return errors.E(errors.IO, err)
  1066  	}
  1067  	return nil
  1068  }
  1069  
  1070  type accountVarReader struct {
  1071  	err error
  1072  }
  1073  
  1074  func (r *accountVarReader) getAccountUint32Var(varsBucket walletdb.ReadBucket, varName []byte) uint32 {
  1075  	if r.err != nil {
  1076  		return 0
  1077  	}
  1078  	value := varsBucket.Get(varName)
  1079  	if len(value) != 4 {
  1080  		err := errors.Errorf(`bad len %d for uint32 value "%s"`, len(value), varName)
  1081  		r.err = errors.E(errors.IO, err)
  1082  		return 0
  1083  	}
  1084  	return binary.LittleEndian.Uint32(value)
  1085  }
  1086  
  1087  func (r *accountVarReader) getAccountStringVar(varsBucket walletdb.ReadBucket, varName []byte) string {
  1088  	if r.err != nil {
  1089  		return ""
  1090  	}
  1091  	value := varsBucket.Get(varName)
  1092  	return string(value)
  1093  }
  1094  
  1095  func (r *accountVarReader) getAccountKDFVar(varsBucket walletdb.ReadBucket, varName []byte) *kdf.Argon2idParams {
  1096  	if r.err != nil {
  1097  		return nil
  1098  	}
  1099  	value := varsBucket.Get(varName)
  1100  	if value == nil {
  1101  		return nil
  1102  	}
  1103  	params := new(kdf.Argon2idParams)
  1104  	r.err = params.UnmarshalBinary(value)
  1105  	return params
  1106  }
  1107  
  1108  // deserializeAddressRow deserializes the passed serialized address information.
  1109  // This is used as a common base for the various address types to deserialize
  1110  // the common parts.
  1111  func deserializeAddressRow(serializedAddress []byte) (*dbAddressRow, error) {
  1112  	// The serialized address format is:
  1113  	//   <addrType><account><addedTime><syncStatus><rawdata>
  1114  	//
  1115  	// 1 byte addrType + 4 bytes account + 8 bytes addTime + 1 byte
  1116  	// syncStatus + 4 bytes raw data length + raw data
  1117  
  1118  	// Given the above, the length of the entry must be at a minimum
  1119  	// the constant value sizes.
  1120  	if len(serializedAddress) < 18 {
  1121  		return nil, errors.E(errors.IO, errors.Errorf("bad address len %d", len(serializedAddress)))
  1122  	}
  1123  
  1124  	row := dbAddressRow{}
  1125  	row.addrType = addressType(serializedAddress[0])
  1126  	row.account = binary.LittleEndian.Uint32(serializedAddress[1:5])
  1127  	row.addTime = binary.LittleEndian.Uint64(serializedAddress[5:13])
  1128  	rdlen := binary.LittleEndian.Uint32(serializedAddress[14:18])
  1129  	row.rawData = make([]byte, rdlen)
  1130  	copy(row.rawData, serializedAddress[18:18+rdlen])
  1131  
  1132  	return &row, nil
  1133  }
  1134  
  1135  // serializeAddressRow returns the serialization of the passed address row.
  1136  func serializeAddressRow(row *dbAddressRow) []byte {
  1137  	// The serialized address format is:
  1138  	//   <addrType><account><addedTime><syncStatus><commentlen><comment>
  1139  	//   <rawdata>
  1140  	//
  1141  	// 1 byte addrType + 4 bytes account + 8 bytes addTime + 1 byte
  1142  	// syncStatus + 4 bytes raw data length + raw data
  1143  	rdlen := len(row.rawData)
  1144  	buf := make([]byte, 18+rdlen)
  1145  	buf[0] = byte(row.addrType)
  1146  	binary.LittleEndian.PutUint32(buf[1:5], row.account)
  1147  	binary.LittleEndian.PutUint64(buf[5:13], row.addTime)
  1148  	buf[13] = 0 // not used
  1149  	binary.LittleEndian.PutUint32(buf[14:18], uint32(rdlen))
  1150  	copy(buf[18:18+rdlen], row.rawData)
  1151  	return buf
  1152  }
  1153  
  1154  // deserializeChainedAddress deserializes the raw data from the passed address
  1155  // row as a chained address.
  1156  func deserializeChainedAddress(row *dbAddressRow) (*dbChainAddressRow, error) {
  1157  	// The serialized chain address raw data format is:
  1158  	//   <branch><index>
  1159  	//
  1160  	// 4 bytes branch + 4 bytes address index
  1161  	if len(row.rawData) != 8 {
  1162  		return nil, errors.E(errors.IO, errors.Errorf("bad chained address len %d", len(row.rawData)))
  1163  	}
  1164  
  1165  	retRow := dbChainAddressRow{
  1166  		dbAddressRow: *row,
  1167  	}
  1168  
  1169  	retRow.branch = binary.LittleEndian.Uint32(row.rawData[0:4])
  1170  	retRow.index = binary.LittleEndian.Uint32(row.rawData[4:8])
  1171  
  1172  	return &retRow, nil
  1173  }
  1174  
  1175  // serializeChainedAddress returns the serialization of the raw data field for
  1176  // a chained address.
  1177  func serializeChainedAddress(branch, index uint32) []byte {
  1178  	// The serialized chain address raw data format is:
  1179  	//   <branch><index>
  1180  	//
  1181  	// 4 bytes branch + 4 bytes address index
  1182  	rawData := make([]byte, 8)
  1183  	binary.LittleEndian.PutUint32(rawData[0:4], branch)
  1184  	binary.LittleEndian.PutUint32(rawData[4:8], index)
  1185  	return rawData
  1186  }
  1187  
  1188  // deserializeImportedAddress deserializes the raw data from the passed address
  1189  // row as an imported address.
  1190  func deserializeImportedAddress(row *dbAddressRow) (*dbImportedAddressRow, error) {
  1191  	// The serialized imported address raw data format is:
  1192  	//   <encpubkeylen><encpubkey><encprivkeylen><encprivkey>
  1193  	//
  1194  	// 4 bytes encrypted pubkey len + encrypted pubkey + 4 bytes encrypted
  1195  	// privkey len + encrypted privkey
  1196  
  1197  	// Given the above, the length of the entry must be at a minimum
  1198  	// the constant value sizes.
  1199  	if len(row.rawData) < 8 {
  1200  		return nil, errors.E(errors.IO, errors.Errorf("bad imported address len %d", len(row.rawData)))
  1201  	}
  1202  
  1203  	retRow := dbImportedAddressRow{
  1204  		dbAddressRow: *row,
  1205  	}
  1206  
  1207  	pubLen := binary.LittleEndian.Uint32(row.rawData[0:4])
  1208  	retRow.encryptedPubKey = make([]byte, pubLen)
  1209  	copy(retRow.encryptedPubKey, row.rawData[4:4+pubLen])
  1210  	offset := 4 + pubLen
  1211  	privLen := binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
  1212  	offset += 4
  1213  	retRow.encryptedPrivKey = make([]byte, privLen)
  1214  	copy(retRow.encryptedPrivKey, row.rawData[offset:offset+privLen])
  1215  
  1216  	return &retRow, nil
  1217  }
  1218  
  1219  // serializeImportedAddress returns the serialization of the raw data field for
  1220  // an imported address.
  1221  func serializeImportedAddress(encryptedPubKey, encryptedPrivKey []byte) []byte {
  1222  	// The serialized imported address raw data format is:
  1223  	//   <encpubkeylen><encpubkey><encprivkeylen><encprivkey>
  1224  	//
  1225  	// 4 bytes encrypted pubkey len + encrypted pubkey + 4 bytes encrypted
  1226  	// privkey len + encrypted privkey
  1227  	pubLen := uint32(len(encryptedPubKey))
  1228  	privLen := uint32(len(encryptedPrivKey))
  1229  	rawData := make([]byte, 8+pubLen+privLen)
  1230  	binary.LittleEndian.PutUint32(rawData[0:4], pubLen)
  1231  	copy(rawData[4:4+pubLen], encryptedPubKey)
  1232  	offset := 4 + pubLen
  1233  	binary.LittleEndian.PutUint32(rawData[offset:offset+4], privLen)
  1234  	offset += 4
  1235  	copy(rawData[offset:offset+privLen], encryptedPrivKey)
  1236  	return rawData
  1237  }
  1238  
  1239  // deserializeScriptAddress deserializes the raw data from the passed address
  1240  // row as a script address.
  1241  func deserializeScriptAddress(row *dbAddressRow) (*dbScriptAddressRow, error) {
  1242  	// The serialized script address raw data format is:
  1243  	//   <encscripthashlen><encscripthash><scriptlen><script>
  1244  	//
  1245  	// 4 bytes encrypted script hash len + encrypted script hash + 4 bytes
  1246  	// script len + script
  1247  
  1248  	// Given the above, the length of the entry must be at a minimum
  1249  	// the constant value sizes.
  1250  	if len(row.rawData) < 8 {
  1251  		return nil, errors.E(errors.IO, errors.Errorf("bad script address len %d", len(row.rawData)))
  1252  	}
  1253  
  1254  	retRow := dbScriptAddressRow{
  1255  		dbAddressRow: *row,
  1256  	}
  1257  
  1258  	hashLen := binary.LittleEndian.Uint32(row.rawData[0:4])
  1259  	retRow.encryptedHash = make([]byte, hashLen)
  1260  	copy(retRow.encryptedHash, row.rawData[4:4+hashLen])
  1261  	offset := 4 + hashLen
  1262  	scriptLen := binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
  1263  	offset += 4
  1264  	retRow.script = make([]byte, scriptLen)
  1265  	copy(retRow.script, row.rawData[offset:offset+scriptLen])
  1266  
  1267  	return &retRow, nil
  1268  }
  1269  
  1270  // serializeScriptAddress returns the serialization of the raw data field for
  1271  // a script address.
  1272  func serializeScriptAddress(encryptedHash, script []byte) []byte {
  1273  	// The serialized script address raw data format is:
  1274  	//   <encscripthashlen><encscripthash><scriptlen><script>
  1275  	//
  1276  	// 4 bytes encrypted script hash len + encrypted script hash + 4 bytes
  1277  	// script len + script
  1278  
  1279  	hashLen := uint32(len(encryptedHash))
  1280  	scriptLen := uint32(len(script))
  1281  	rawData := make([]byte, 8+hashLen+scriptLen)
  1282  	binary.LittleEndian.PutUint32(rawData[0:4], hashLen)
  1283  	copy(rawData[4:4+hashLen], encryptedHash)
  1284  	offset := 4 + hashLen
  1285  	binary.LittleEndian.PutUint32(rawData[offset:offset+4], scriptLen)
  1286  	offset += 4
  1287  	copy(rawData[offset:offset+scriptLen], script)
  1288  	return rawData
  1289  }
  1290  
  1291  // fetchAddressByHash loads address information for the provided address hash
  1292  // from the database.  The returned value is one of the address rows for the
  1293  // specific address type.  The caller should use type assertions to ascertain
  1294  // the type.  The caller should prefix the error message with the address hash
  1295  // which caused the failure.
  1296  func fetchAddressByHash(ns walletdb.ReadBucket, addrHash []byte) (interface{}, error) {
  1297  	bucket := ns.NestedReadBucket(addrBucketName)
  1298  
  1299  	serializedRow := bucket.Get(addrHash)
  1300  	if serializedRow == nil {
  1301  		return nil, errors.E(errors.NotExist, errors.Errorf("no address with hash %x", addrHash))
  1302  	}
  1303  
  1304  	row, err := deserializeAddressRow(serializedRow)
  1305  	if err != nil {
  1306  		return nil, err
  1307  	}
  1308  
  1309  	switch row.addrType {
  1310  	case adtChain:
  1311  		return deserializeChainedAddress(row)
  1312  	case adtImport:
  1313  		return deserializeImportedAddress(row)
  1314  	case adtScript:
  1315  		return deserializeScriptAddress(row)
  1316  	}
  1317  
  1318  	return nil, errors.E(errors.IO, errors.Errorf("unknown address type %d", row.addrType))
  1319  }
  1320  
  1321  // fetchAddress loads address information for the provided address id from the
  1322  // database.  The returned value is one of the address rows for the specific
  1323  // address type.  The caller should use type assertions to ascertain the type.
  1324  // The caller should prefix the error message with the address which caused the
  1325  // failure.
  1326  func fetchAddress(ns walletdb.ReadBucket, addressID []byte) (interface{}, error) {
  1327  	addrHash := sha256.Sum256(addressID)
  1328  	addr, err := fetchAddressByHash(ns, addrHash[:])
  1329  	if errors.Is(err, errors.NotExist) {
  1330  		return nil, errors.E(errors.NotExist, errors.Errorf("no address with id %x", addressID))
  1331  	}
  1332  	return addr, err
  1333  }
  1334  
  1335  // putAddress stores the provided address information to the database.  This
  1336  // is used a common base for storing the various address types.
  1337  func putAddress(ns walletdb.ReadWriteBucket, addressID []byte, row *dbAddressRow) error {
  1338  	bucket := ns.NestedReadWriteBucket(addrBucketName)
  1339  
  1340  	// Write the serialized value keyed by the hash of the address.  The
  1341  	// additional hash is used to conceal the actual address while still
  1342  	// allowed keyed lookups.
  1343  	addrHash := sha256.Sum256(addressID)
  1344  	err := bucket.Put(addrHash[:], serializeAddressRow(row))
  1345  	if err != nil {
  1346  		return errors.E(errors.IO, err)
  1347  	}
  1348  	// Update address account index
  1349  	return putAddrAccountIndex(ns, row.account, addrHash[:])
  1350  }
  1351  
  1352  // putChainedAddress stores the provided chained address information to the
  1353  // database.
  1354  func putChainedAddress(ns walletdb.ReadWriteBucket, addressID []byte, account uint32,
  1355  	branch, index uint32) error {
  1356  
  1357  	addrRow := dbAddressRow{
  1358  		addrType: adtChain,
  1359  		account:  account,
  1360  		addTime:  uint64(time.Now().Unix()),
  1361  		rawData:  serializeChainedAddress(branch, index),
  1362  	}
  1363  	return putAddress(ns, addressID, &addrRow)
  1364  }
  1365  
  1366  // putImportedAddress stores the provided imported address information to the
  1367  // database.
  1368  func putImportedAddress(ns walletdb.ReadWriteBucket, addressID []byte, account uint32,
  1369  	encryptedPubKey, encryptedPrivKey []byte) error {
  1370  
  1371  	rawData := serializeImportedAddress(encryptedPubKey, encryptedPrivKey)
  1372  	addrRow := dbAddressRow{
  1373  		addrType: adtImport,
  1374  		account:  account,
  1375  		addTime:  uint64(time.Now().Unix()),
  1376  		rawData:  rawData,
  1377  	}
  1378  	return putAddress(ns, addressID, &addrRow)
  1379  }
  1380  
  1381  // putScriptAddress stores the provided script address information to the
  1382  // database.
  1383  func putScriptAddress(ns walletdb.ReadWriteBucket, addressID []byte, account uint32,
  1384  	encryptedHash, script []byte) error {
  1385  
  1386  	rawData := serializeScriptAddress(encryptedHash, script)
  1387  	addrRow := dbAddressRow{
  1388  		addrType: adtScript,
  1389  		account:  account,
  1390  		addTime:  uint64(time.Now().Unix()),
  1391  		rawData:  rawData,
  1392  	}
  1393  	return putAddress(ns, addressID, &addrRow)
  1394  }
  1395  
  1396  // existsAddress returns whether or not the address id exists in the database.
  1397  func existsAddress(ns walletdb.ReadBucket, addressID []byte) bool {
  1398  	bucket := ns.NestedReadBucket(addrBucketName)
  1399  
  1400  	addrHash := sha256.Sum256(addressID)
  1401  	return bucket.Get(addrHash[:]) != nil
  1402  }
  1403  
  1404  // fetchAddrAccount returns the account to which the given address belongs to.
  1405  // It looks up the account using the addracctidx index which maps the address
  1406  // hash to its corresponding account id.
  1407  func fetchAddrAccount(ns walletdb.ReadBucket, addressID []byte) (uint32, error) {
  1408  	bucket := ns.NestedReadBucket(addrAcctIdxBucketName)
  1409  
  1410  	addrHash := sha256.Sum256(addressID)
  1411  	val := bucket.Get(addrHash[:])
  1412  	if val == nil {
  1413  		return 0, errors.E(errors.NotExist, errors.Errorf("no address for id %x", addressID))
  1414  	}
  1415  	return binary.LittleEndian.Uint32(val), nil
  1416  }
  1417  
  1418  // forEachAccountAddress calls the given function with each address of
  1419  // the given account stored in the manager, breaking early on error.
  1420  func forEachAccountAddress(ns walletdb.ReadBucket, account uint32, fn func(rowInterface interface{}) error) error {
  1421  	bucket := ns.NestedReadBucket(addrAcctIdxBucketName).
  1422  		NestedReadBucket(uint32ToBytes(account))
  1423  	// if index bucket is missing the account, there hasn't been any address
  1424  	// entries yet
  1425  	if bucket == nil {
  1426  		return nil
  1427  	}
  1428  
  1429  	c := bucket.ReadCursor()
  1430  	defer c.Close()
  1431  	for k, v := c.First(); k != nil; k, v = c.Next() {
  1432  		// Skip buckets.
  1433  		if v == nil {
  1434  			continue
  1435  		}
  1436  		addrRow, err := fetchAddressByHash(ns, k)
  1437  		if err != nil {
  1438  			return errors.E(errors.IO, err)
  1439  		}
  1440  
  1441  		err = fn(addrRow)
  1442  		if err != nil {
  1443  			return err
  1444  		}
  1445  	}
  1446  	return nil
  1447  }
  1448  
  1449  // forEachActiveAddress calls the given function with each active address
  1450  // stored in the manager, breaking early on error.
  1451  func forEachActiveAddress(ns walletdb.ReadBucket, fn func(rowInterface interface{}) error) error {
  1452  	bucket := ns.NestedReadBucket(addrBucketName)
  1453  	c := bucket.ReadCursor()
  1454  	defer c.Close()
  1455  	for k, v := c.First(); k != nil; k, v = c.Next() {
  1456  		// Skip buckets.
  1457  		if v == nil {
  1458  			continue
  1459  		}
  1460  
  1461  		// Deserialize the address row first to determine the field
  1462  		// values.
  1463  		addrRow, err := fetchAddressByHash(ns, k)
  1464  		if err != nil {
  1465  			return errors.E(errors.IO, err)
  1466  		}
  1467  
  1468  		err = fn(addrRow)
  1469  		if err != nil {
  1470  			return err
  1471  		}
  1472  	}
  1473  	return nil
  1474  }
  1475  
  1476  // deletePrivateKeys removes all private key material from the database.
  1477  //
  1478  // NOTE: Care should be taken when calling this function.  It is primarily
  1479  // intended for use in converting to a watching-only copy.  Removing the private
  1480  // keys from the main database without also marking it watching-only will result
  1481  // in an unusable database.  It will also make any private keys unrecoverable
  1482  // unless there is a backup copy available.
  1483  func deletePrivateKeys(ns walletdb.ReadWriteBucket, dbVersion uint32) error {
  1484  	bucket := ns.NestedReadWriteBucket(mainBucketName)
  1485  
  1486  	// Delete the master private key params and the crypto private keys.
  1487  	if err := bucket.Delete(masterPrivKeyName); err != nil {
  1488  		return errors.E(errors.IO, err)
  1489  	}
  1490  	if err := bucket.Delete(cryptoPrivKeyName); err != nil {
  1491  		return errors.E(errors.IO, err)
  1492  	}
  1493  	if err := bucket.Delete(coinTypeLegacyPrivKeyName); err != nil {
  1494  		return errors.E(errors.IO, err)
  1495  	}
  1496  	if err := bucket.Delete(coinTypeSLIP0044PrivKeyName); err != nil {
  1497  		return errors.E(errors.IO, err)
  1498  	}
  1499  
  1500  	BIP0044Set := map[string]*dbAccountRow{}
  1501  
  1502  	// Fetch all BIP0044 accounts.
  1503  	bucket = ns.NestedReadWriteBucket(acctBucketName)
  1504  	c := bucket.ReadCursor()
  1505  	for k, v := c.First(); k != nil; k, v = c.Next() {
  1506  		// Skip buckets.
  1507  		if v == nil {
  1508  			continue
  1509  		}
  1510  
  1511  		// Deserialize the account row first to determine the type.
  1512  		row, err := deserializeAccountRow(k, v)
  1513  		if err != nil {
  1514  			c.Close()
  1515  			return err
  1516  		}
  1517  
  1518  		switch row.acctType {
  1519  		case actBIP0044Legacy:
  1520  			BIP0044Set[string(k)] = row
  1521  		}
  1522  	}
  1523  	c.Close()
  1524  
  1525  	// Delete the account extended private key for all BIP0044 accounts.
  1526  	for k, row := range BIP0044Set {
  1527  		arow, err := deserializeBIP0044AccountRow([]byte(k), row, dbVersion)
  1528  		if err != nil {
  1529  			return err
  1530  		}
  1531  
  1532  		// Reserialize the account without the private key and
  1533  		// store it.
  1534  		row := bip0044AccountInfo(arow.pubKeyEncrypted, nil,
  1535  			arow.nextExternalIndex, arow.nextInternalIndex,
  1536  			arow.lastUsedExternalIndex, arow.lastUsedInternalIndex,
  1537  			arow.lastReturnedExternalIndex, arow.lastReturnedInternalIndex,
  1538  			arow.name, dbVersion)
  1539  		err = bucket.Put([]byte(k), serializeAccountRow(&row.dbAccountRow))
  1540  		if err != nil {
  1541  			return errors.E(errors.IO, err)
  1542  		}
  1543  	}
  1544  
  1545  	importedAddrSet := map[string]*dbAddressRow{}
  1546  
  1547  	// Fetch all imported addresses.
  1548  	bucket = ns.NestedReadWriteBucket(addrBucketName)
  1549  	c = bucket.ReadCursor()
  1550  	for k, v := c.First(); k != nil; k, v = c.Next() {
  1551  		// Skip buckets.
  1552  		if v == nil {
  1553  			continue
  1554  		}
  1555  
  1556  		// Deserialize the address row first to determine the field
  1557  		// values.
  1558  		row, err := deserializeAddressRow(v)
  1559  		if err != nil {
  1560  			c.Close()
  1561  			return err
  1562  		}
  1563  
  1564  		switch row.addrType {
  1565  		case adtImport:
  1566  			importedAddrSet[string(k)] = row
  1567  		}
  1568  	}
  1569  	c.Close()
  1570  
  1571  	// Delete the private key for all imported addresses.
  1572  	for k, row := range importedAddrSet {
  1573  		irow, err := deserializeImportedAddress(row)
  1574  		if err != nil {
  1575  			return err
  1576  		}
  1577  
  1578  		// Reserialize the imported address without the private
  1579  		// key and store it.
  1580  		row.rawData = serializeImportedAddress(
  1581  			irow.encryptedPubKey, nil)
  1582  		err = bucket.Put([]byte(k), serializeAddressRow(row))
  1583  		if err != nil {
  1584  			return errors.E(errors.IO, err)
  1585  		}
  1586  	}
  1587  
  1588  	return nil
  1589  }
  1590  
  1591  // accountNumberToAddrPoolKey converts an account into a meta-bucket key for
  1592  // the storage of the next to use address index as the value.
  1593  func accountNumberToAddrPoolKey(isInternal bool, account uint32) []byte {
  1594  	k := make([]byte, addrPoolMetaKeyLen)
  1595  	if isInternal {
  1596  		copy(k, addrPoolKeyPrefixInt)
  1597  		binary.LittleEndian.PutUint32(k[addrPoolMetaKeyLen-4:], account)
  1598  	} else {
  1599  		copy(k, addrPoolKeyPrefixExt)
  1600  		binary.LittleEndian.PutUint32(k[addrPoolMetaKeyLen-4:], account)
  1601  	}
  1602  
  1603  	return k
  1604  }
  1605  
  1606  // putNextToUseAddrPoolIdx stores an address pool address index for a
  1607  // given account and branch in the meta bucket of the address manager
  1608  // database.
  1609  func putNextToUseAddrPoolIdx(ns walletdb.ReadWriteBucket, isInternal bool, account uint32, index uint32) error {
  1610  	bucket := ns.NestedReadWriteBucket(metaBucketName)
  1611  	k := accountNumberToAddrPoolKey(isInternal, account)
  1612  	v := make([]byte, 4)
  1613  	binary.LittleEndian.PutUint32(v, index)
  1614  
  1615  	err := bucket.Put(k, v)
  1616  	if err != nil {
  1617  		return errors.E(errors.IO, err)
  1618  	}
  1619  
  1620  	return nil
  1621  }
  1622  
  1623  // managerExists returns whether or not the manager has already been created
  1624  // in the given database namespace.
  1625  func managerExists(ns walletdb.ReadBucket) bool {
  1626  	mainBucket := ns.NestedReadBucket(mainBucketName)
  1627  	return mainBucket != nil
  1628  }
  1629  
  1630  // createManagerNS creates the initial namespace structure needed for all of the
  1631  // manager data.  This includes things such as all of the buckets as well as the
  1632  // version and creation date.
  1633  func createManagerNS(ns walletdb.ReadWriteBucket) error {
  1634  	mainBucket, err := ns.CreateBucket(mainBucketName)
  1635  	if err != nil {
  1636  		return errors.E(errors.IO, err)
  1637  	}
  1638  
  1639  	_, err = ns.CreateBucket(addrBucketName)
  1640  	if err != nil {
  1641  		return errors.E(errors.IO, err)
  1642  	}
  1643  
  1644  	_, err = ns.CreateBucket(acctBucketName)
  1645  	if err != nil {
  1646  		return errors.E(errors.IO, err)
  1647  	}
  1648  
  1649  	_, err = ns.CreateBucket(addrAcctIdxBucketName)
  1650  	if err != nil {
  1651  		return errors.E(errors.IO, err)
  1652  	}
  1653  
  1654  	// usedAddrBucketName bucket was added after manager version 1 release
  1655  	_, err = ns.CreateBucket(usedAddrBucketName)
  1656  	if err != nil {
  1657  		return errors.E(errors.IO, err)
  1658  	}
  1659  
  1660  	_, err = ns.CreateBucket(acctNameIdxBucketName)
  1661  	if err != nil {
  1662  		return errors.E(errors.IO, err)
  1663  	}
  1664  
  1665  	_, err = ns.CreateBucket(acctIDIdxBucketName)
  1666  	if err != nil {
  1667  		return errors.E(errors.IO, err)
  1668  	}
  1669  
  1670  	_, err = ns.CreateBucket(metaBucketName)
  1671  	if err != nil {
  1672  		return errors.E(errors.IO, err)
  1673  	}
  1674  
  1675  	if err := putLastAccount(ns, DefaultAccountNum); err != nil {
  1676  		return err
  1677  	}
  1678  
  1679  	if err := putManagerVersion(ns, latestMgrVersion); err != nil {
  1680  		return err
  1681  	}
  1682  
  1683  	createDate := uint64(time.Now().Unix())
  1684  	var dateBytes [8]byte
  1685  	binary.LittleEndian.PutUint64(dateBytes[:], createDate)
  1686  	err = mainBucket.Put(mgrCreateDateName, dateBytes[:])
  1687  	if err != nil {
  1688  		return errors.E(errors.IO, err)
  1689  	}
  1690  
  1691  	return nil
  1692  }
  1693  
  1694  // upgradeToVersion5 upgrades the database from version 4 to version 5.
  1695  // Version 5 uses the metadata bucket to store the address pool indexes,
  1696  // so lastAddrs can be removed from the db.
  1697  func upgradeToVersion5(ns walletdb.ReadWriteBucket) error {
  1698  	lastDefaultAddsrName := []byte("lastaddrs")
  1699  
  1700  	bucket := ns.NestedReadWriteBucket(mainBucketName)
  1701  	err := bucket.Delete(lastDefaultAddsrName)
  1702  	if err != nil {
  1703  		return errors.E(errors.IO, err)
  1704  	}
  1705  
  1706  	return putManagerVersion(ns, 5)
  1707  }
  1708  
  1709  // upgradeToVersion6 upgrades the database from version 5 to 6.  Version 6
  1710  // removes the synchronization buckets that were no longer updated after
  1711  // switching the wallet to storing all block headers.
  1712  func upgradeToVersion6(ns walletdb.ReadWriteBucket) error {
  1713  	syncBucketName := []byte("sync")
  1714  	err := ns.DeleteNestedBucket(syncBucketName)
  1715  	if err != nil {
  1716  		return errors.E(errors.IO, err)
  1717  	}
  1718  	return putManagerVersion(ns, 6)
  1719  }
  1720  
  1721  // upgradeManager upgrades the data in the provided manager namespace to newer
  1722  // versions as neeeded.
  1723  func upgradeManager(ns walletdb.ReadWriteBucket) error {
  1724  	version, err := fetchManagerVersion(ns)
  1725  	if err != nil {
  1726  		return err
  1727  	}
  1728  
  1729  	// Below is some example code on how to properly perform DB
  1730  	// upgrades. Use it as a model for future upgrades.
  1731  	//
  1732  	// Upgrade one version at a time so it is possible to upgrade across
  1733  	// an aribtary number of versions without needing to write a bunch of
  1734  	// additional code to go directly from version X to Y.
  1735  	// if version < 2 {
  1736  	// 	// Upgrade from version 1 to 2.
  1737  	//	if err := upgradeToVersion2(namespace); err != nil {
  1738  	//		return err
  1739  	//	}
  1740  	//
  1741  	//	// The manager is now at version 2.
  1742  	//	version = 2
  1743  	// }
  1744  	// if version < 3 {
  1745  	// 	// Upgrade from version 2 to 3.
  1746  	//	if err := upgradeToVersion3(namespace); err != nil {
  1747  	//		return err
  1748  	//	}
  1749  	//
  1750  	//	// The manager is now at version 3.
  1751  	//	version = 3
  1752  	// }
  1753  
  1754  	if version < 5 {
  1755  		err := upgradeToVersion5(ns)
  1756  		if err != nil {
  1757  			return err
  1758  		}
  1759  
  1760  		// The manager is now at version 5.
  1761  		version = 5
  1762  	}
  1763  
  1764  	if version < 6 {
  1765  		err := upgradeToVersion6(ns)
  1766  		if err != nil {
  1767  			return err
  1768  		}
  1769  
  1770  		// The manager is now at version 6.
  1771  		version = 6
  1772  	}
  1773  
  1774  	// Ensure the manager version is equal to the version used by the code.
  1775  	// This causes failures if the database was not upgraded to the latest
  1776  	// version or if there is a newer version that this code does not
  1777  	// understand.
  1778  	if version != latestMgrVersion {
  1779  		return errors.E(errors.Invalid, errors.Errorf("incompatible address manager version %d", version))
  1780  	}
  1781  
  1782  	return nil
  1783  }