func serializeBIP0044AccountRow(row *dbBIP0044AccountRow, dbVersion uint32) []byte {
	pubLen := uint32(len(row.pubKeyEncrypted))
	privLen := uint32(len(row.privKeyEncrypted))
	nameLen := uint32(len(row.name))
	rowSize := 28 + pubLen + privLen + nameLen
	switch {
	case dbVersion < 5:
		rowSize -= 8
	}
	rawData := make([]byte, rowSize)
	binary.LittleEndian.PutUint32(rawData[0:4], pubLen)
	copy(rawData[4:4+pubLen], row.pubKeyEncrypted)
	offset := 4 + pubLen
	binary.LittleEndian.PutUint32(rawData[offset:offset+4], privLen)
	offset += 4
	copy(rawData[offset:offset+privLen], row.privKeyEncrypted)
	offset += privLen
	switch {
	case dbVersion == 1:
		binary.LittleEndian.PutUint32(rawData[offset:offset+4], row.nextExternalIndex)
		offset += 4
		binary.LittleEndian.PutUint32(rawData[offset:offset+4], row.nextInternalIndex)
		offset += 4
	case dbVersion >= 2:
		binary.LittleEndian.PutUint32(rawData[offset:offset+4], row.lastUsedExternalIndex)
		binary.LittleEndian.PutUint32(rawData[offset+4:offset+8], row.lastUsedInternalIndex)
		offset += 8
	}
	switch {
	case dbVersion >= 5:
		binary.LittleEndian.PutUint32(rawData[offset:offset+4], row.lastReturnedExternalIndex)
		binary.LittleEndian.PutUint32(rawData[offset+4:offset+8], row.lastReturnedInternalIndex)
		offset += 8
	}
	binary.LittleEndian.PutUint32(rawData[offset:offset+4], nameLen)
	offset += 4
	copy(rawData[offset:offset+nameLen], row.name)
	return rawData
}
serializeBIP0044AccountRow returns the serialization of the raw data field
for a BIP0044 account.
package udb
import (
	"crypto/sha256"
	"encoding/binary"
	"time"
	"decred.org/dcrwallet/v2/errors"
	"decred.org/dcrwallet/v2/kdf"
	"decred.org/dcrwallet/v2/wallet/walletdb"
)
var (
	latestMgrVersion uint32 = 6
)
type ObtainUserInputFunc func() ([]byte, error)
type addressType uint8
const (
	adtChain  addressType = iota  
	adtImport                     
	adtScript                     
)
type dbAccount interface {
	accountType() accountType
	rowData() []byte
}
type accountType uint8
const (
	actBIP0044Legacy accountType = iota
	actBIP0044
)
type dbAccountRow struct {
	acctType accountType
	rawData  []byte  
}
type dbBIP0044AccountRow struct {
	dbAccountRow
	pubKeyEncrypted           []byte
	privKeyEncrypted          []byte
	nextExternalIndex         uint32  
	nextInternalIndex         uint32  
	lastUsedExternalIndex     uint32  
	lastUsedInternalIndex     uint32  
	lastReturnedExternalIndex uint32  
	lastReturnedInternalIndex uint32  
	name                      string
	uniqueKey *kdf.Argon2idParams
}
func (r *dbBIP0044AccountRow) accountType() accountType { return actBIP0044Legacy }
func (r *dbBIP0044AccountRow) rowData() []byte          { return r.dbAccountRow.rawData }
type dbBIP0044Account struct {
	dbAccountRow
	pubKeyEncrypted  []byte
	privKeyEncrypted []byte
	lastUsedExternalIndex     uint32
	lastUsedInternalIndex     uint32
	lastReturnedExternalIndex uint32
	lastReturnedInternalIndex uint32
	name                      string
	uniqueKey                 *kdf.Argon2idParams
}
func (a *dbBIP0044Account) accountType() accountType { return actBIP0044 }
func (a *dbBIP0044Account) rowData() []byte          { return a.dbAccountRow.rawData }
func (a *dbBIP0044Account) serializeRow() []byte {
	data := make([]byte, 8+len(a.pubKeyEncrypted)+len(a.privKeyEncrypted))
	binary.LittleEndian.PutUint32(data, uint32(len(a.pubKeyEncrypted)))
	off := 4
	off += copy(data[off:], a.pubKeyEncrypted)
	binary.LittleEndian.PutUint32(data[off:], uint32(len(a.privKeyEncrypted)))
	off += 4
	copy(data[off:], a.privKeyEncrypted)
	a.rawData = data
	return data
}
func (a *dbBIP0044Account) deserializeRow(v []byte) error {
	if len(v) < 8 {
		err := errors.Errorf("BIP0044 account row bad len %d", len(v))
		return errors.E(errors.IO, err)
	}
	encPubLen := binary.LittleEndian.Uint32(v)
	off := uint32(4)
	encPub := append([]byte(nil), v[off:off+encPubLen]...)
	off += encPubLen
	encPrivLen := binary.LittleEndian.Uint32(v[off:])
	off += 4
	encPriv := append([]byte(nil), v[off:off+encPrivLen]...)
	off += encPrivLen
	if int(off) != len(v) {
		return errors.E(errors.IO, "extra bytes in BIP0044 account row")
	}
	a.pubKeyEncrypted = encPub
	a.privKeyEncrypted = encPriv
	a.rawData = v
	return nil
}
type dbAddressRow struct {
	addrType addressType
	account  uint32
	addTime  uint64
	rawData  []byte  
}
type dbChainAddressRow struct {
	dbAddressRow
	branch uint32
	index  uint32
}
type dbImportedAddressRow struct {
	dbAddressRow
	encryptedPubKey  []byte
	encryptedPrivKey []byte
}
type dbScriptAddressRow struct {
	dbAddressRow
	encryptedHash []byte
	script        []byte
}
var (
	nullVal = []byte{0}
	acctBucketName     = []byte("acct")
	acctVarsBucketName = []byte("acctvars")
	addrBucketName     = []byte("addr")
	addrAcctIdxBucketName = []byte("addracctidx")
	acctNameIdxBucketName = []byte("acctnameidx")
	acctIDIdxBucketName = []byte("acctididx")
	metaBucketName = []byte("meta")
	addrPoolMetaKeyLen = 15
	addrPoolKeyPrefixExt = []byte("addrpoolext")
	addrPoolKeyPrefixInt = []byte("addrpoolint")
	lastAccountName = []byte("lastaccount")
	lastImportedAccountName = []byte("lastimportedaccount")
	mainBucketName = []byte("main")
	mgrVersionName    = []byte("mgrver")
	mgrCreateDateName = []byte("mgrcreated")
	seedName                    = []byte("seed")
	masterPrivKeyName           = []byte("mpriv")
	masterPubKeyName            = []byte("mpub")
	cryptoPrivKeyName           = []byte("cpriv")
	cryptoPubKeyName            = []byte("cpub")
	cryptoScriptKeyName         = []byte("cscript")  
	coinTypeLegacyPrivKeyName   = []byte("ctpriv")
	coinTypeLegacyPubKeyName    = []byte("ctpub")
	coinTypeSLIP0044PrivKeyName = []byte("ctpriv-slip0044")
	coinTypeSLIP0044PubKeyName  = []byte("ctpub-slip0044")
	watchingOnlyName            = []byte("watchonly")
	slip0044Account0RowName     = []byte("slip0044acct0")
	usedAddrBucketName = []byte("usedaddrs")
)
func uint32ToBytes(number uint32) []byte {
	buf := make([]byte, 4)
	binary.LittleEndian.PutUint32(buf, number)
	return buf
}
func stringToBytes(s string) []byte {
	size := len(s)
	buf := make([]byte, 4+size)
	copy(buf[0:4], uint32ToBytes(uint32(size)))
	copy(buf[4:4+size], s)
	return buf
}
func fetchManagerVersion(ns walletdb.ReadBucket) (uint32, error) {
	mainBucket := ns.NestedReadBucket(mainBucketName)
	verBytes := mainBucket.Get(mgrVersionName)
	if verBytes == nil {
		return 0, errors.E(errors.IO, "missing address manager version")
	}
	version := binary.LittleEndian.Uint32(verBytes)
	return version, nil
}
func putManagerVersion(ns walletdb.ReadWriteBucket, version uint32) error {
	bucket := ns.NestedReadWriteBucket(mainBucketName)
	verBytes := uint32ToBytes(version)
	err := bucket.Put(mgrVersionName, verBytes)
	if err != nil {
		return errors.E(errors.IO, err)
	}
	return nil
}
func fetchMasterKeyParams(ns walletdb.ReadBucket) ([]byte, []byte, error) {
	bucket := ns.NestedReadBucket(mainBucketName)
	val := bucket.Get(masterPubKeyName)
	if val == nil {
		return nil, nil, errors.E(errors.IO, "missing master pubkey params")
	}
	pubParams := make([]byte, len(val))
	copy(pubParams, val)
	var privParams []byte
	val = bucket.Get(masterPrivKeyName)
	if val != nil {
		privParams = make([]byte, len(val))
		copy(privParams, val)
	}
	return pubParams, privParams, nil
}
func putMasterKeyParams(ns walletdb.ReadWriteBucket, pubParams, privParams []byte) error {
	bucket := ns.NestedReadWriteBucket(mainBucketName)
	if privParams != nil {
		err := bucket.Put(masterPrivKeyName, privParams)
		if err != nil {
			return errors.E(errors.IO, err)
		}
	}
	if pubParams != nil {
		err := bucket.Put(masterPubKeyName, pubParams)
		if err != nil {
			return errors.E(errors.IO, err)
		}
	}
	return nil
}
func fetchCoinTypeKeys(ns walletdb.ReadBucket) ([]byte, []byte, error) {
	bucket := ns.NestedReadBucket(mainBucketName)
	var coinTypeSLIP0044 bool
	coinTypePubKeyEnc := bucket.Get(coinTypeLegacyPubKeyName)
	if coinTypePubKeyEnc == nil {
		coinTypeSLIP0044 = true
		coinTypePubKeyEnc = bucket.Get(coinTypeSLIP0044PubKeyName)
	}
	if coinTypePubKeyEnc == nil {
		return nil, nil, errors.E(errors.IO, "missing encrypted cointype pubkey")
	}
	coinTypePrivKeyName := coinTypeLegacyPrivKeyName
	if coinTypeSLIP0044 {
		coinTypePrivKeyName = coinTypeSLIP0044PrivKeyName
	}
	coinTypePrivKeyEnc := bucket.Get(coinTypePrivKeyName)
	if coinTypePrivKeyEnc == nil {
		return nil, nil, errors.E(errors.IO, "missing encrypted cointype privkey")
	}
	return coinTypePubKeyEnc, coinTypePrivKeyEnc, nil
}
func putCoinTypeLegacyKeys(ns walletdb.ReadWriteBucket, coinTypePubKeyEnc []byte, coinTypePrivKeyEnc []byte) error {
	bucket := ns.NestedReadWriteBucket(mainBucketName)
	if coinTypePubKeyEnc != nil {
		err := bucket.Put(coinTypeLegacyPubKeyName, coinTypePubKeyEnc)
		if err != nil {
			return errors.E(errors.IO, err)
		}
	}
	if coinTypePrivKeyEnc != nil {
		err := bucket.Put(coinTypeLegacyPrivKeyName, coinTypePrivKeyEnc)
		if err != nil {
			return errors.E(errors.IO, err)
		}
	}
	return nil
}
func putCoinTypeSLIP0044Keys(ns walletdb.ReadWriteBucket, coinTypePubKeyEnc []byte, coinTypePrivKeyEnc []byte) error {
	bucket := ns.NestedReadWriteBucket(mainBucketName)
	if coinTypePubKeyEnc != nil {
		err := bucket.Put(coinTypeSLIP0044PubKeyName, coinTypePubKeyEnc)
		if err != nil {
			return errors.E(errors.IO, err)
		}
	}
	if coinTypePrivKeyEnc != nil {
		err := bucket.Put(coinTypeSLIP0044PrivKeyName, coinTypePrivKeyEnc)
		if err != nil {
			return errors.E(errors.IO, err)
		}
	}
	return nil
}
func fetchCryptoKeys(ns walletdb.ReadBucket) ([]byte, []byte, error) {
	bucket := ns.NestedReadBucket(mainBucketName)
	val := bucket.Get(cryptoPubKeyName)
	if val == nil {
		return nil, nil, errors.E(errors.IO, "missing encrypted crypto pubkey")
	}
	pubKey := make([]byte, len(val))
	copy(pubKey, val)
	var privKey []byte
	val = bucket.Get(cryptoPrivKeyName)
	if val != nil {
		privKey = make([]byte, len(val))
		copy(privKey, val)
	}
	return pubKey, privKey, nil
}
func putCryptoKeys(ns walletdb.ReadWriteBucket, pubKeyEncrypted, privKeyEncrypted []byte) error {
	bucket := ns.NestedReadWriteBucket(mainBucketName)
	if pubKeyEncrypted != nil {
		err := bucket.Put(cryptoPubKeyName, pubKeyEncrypted)
		if err != nil {
			return errors.E(errors.IO, err)
		}
	}
	if privKeyEncrypted != nil {
		err := bucket.Put(cryptoPrivKeyName, privKeyEncrypted)
		if err != nil {
			return errors.E(errors.IO, err)
		}
	}
	return nil
}
func fetchWatchingOnly(ns walletdb.ReadBucket) (bool, error) {
	bucket := ns.NestedReadBucket(mainBucketName)
	buf := bucket.Get(watchingOnlyName)
	if len(buf) != 1 {
		return false, errors.E(errors.IO, errors.Errorf("bad watching-only flag len %d", len(buf)))
	}
	return buf[0] != 0, nil
}
func putWatchingOnly(ns walletdb.ReadWriteBucket, watchingOnly bool) error {
	bucket := ns.NestedReadWriteBucket(mainBucketName)
	var encoded byte
	if watchingOnly {
		encoded = 1
	}
	if err := bucket.Put(watchingOnlyName, []byte{encoded}); err != nil {
		return errors.E(errors.IO, err)
	}
	return nil
}
func deserializeAccountRow(accountID []byte, serializedAccount []byte) (*dbAccountRow, error) {
	if len(serializedAccount) < 5 {
		return nil, errors.E(errors.IO, errors.Errorf("bad account len %d", len(serializedAccount)))
	}
	row := dbAccountRow{}
	row.acctType = accountType(serializedAccount[0])
	rdlen := binary.LittleEndian.Uint32(serializedAccount[1:5])
	row.rawData = make([]byte, rdlen)
	copy(row.rawData, serializedAccount[5:5+rdlen])
	return &row, nil
}
func serializeAccountRow(row *dbAccountRow) []byte {
	rdlen := len(row.rawData)
	buf := make([]byte, 5+rdlen)
	buf[0] = byte(row.acctType)
	binary.LittleEndian.PutUint32(buf[1:5], uint32(rdlen))
	copy(buf[5:5+rdlen], row.rawData)
	return buf
}
func deserializeBIP0044AccountRow(accountID []byte, row *dbAccountRow, dbVersion uint32) (*dbBIP0044AccountRow, error) {
	switch {
	case dbVersion < 5 && len(row.rawData) < 20,
		dbVersion >= 5 && len(row.rawData) < 28:
		return nil, errors.E(errors.IO, errors.Errorf("bip0044 account %x bad len %d", accountID, len(row.rawData)))
	}
	retRow := dbBIP0044AccountRow{
		dbAccountRow: *row,
	}
	pubLen := binary.LittleEndian.Uint32(row.rawData[0:4])
	retRow.pubKeyEncrypted = make([]byte, pubLen)
	copy(retRow.pubKeyEncrypted, row.rawData[4:4+pubLen])
	offset := 4 + pubLen
	privLen := binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
	offset += 4
	retRow.privKeyEncrypted = make([]byte, privLen)
	copy(retRow.privKeyEncrypted, row.rawData[offset:offset+privLen])
	offset += privLen
	switch {
	case dbVersion == 1:
		retRow.nextExternalIndex = binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
		offset += 4
		retRow.nextInternalIndex = binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
		offset += 4
	case dbVersion >= 2:
		retRow.lastUsedExternalIndex = binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
		retRow.lastUsedInternalIndex = binary.LittleEndian.Uint32(row.rawData[offset+4 : offset+8])
		offset += 8
	}
	switch {
	case dbVersion >= 5:
		retRow.lastReturnedExternalIndex = binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
		retRow.lastReturnedInternalIndex = binary.LittleEndian.Uint32(row.rawData[offset+4 : offset+8])
		offset += 8
	}
	nameLen := binary.LittleEndian.Uint32(row.rawData[offset : offset+4])
	offset += 4
	retRow.name = string(row.rawData[offset : offset+nameLen])
	return &retRow, nil
}