db.go raw

   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