func newManagedAddressWithoutPrivKey(m *ScopedKeyManager,
	derivationPath DerivationPath, pubKey *bchec.PublicKey, compressed bool,
	addrType AddressType) (*managedAddress, error) {
	var pubKeyHash []byte
	if compressed {
		pubKeyHash = bchutil.Hash160(pubKey.SerializeCompressed())
	} else {
		pubKeyHash = bchutil.Hash160(pubKey.SerializeUncompressed())
	}
	var address bchutil.Address
	var err error
	switch addrType {
	case PubKeyHash:
		address, err = bchutil.NewAddressPubKeyHash(
			pubKeyHash, m.rootManager.chainParams,
		)
		if err != nil {
			return nil, err
		}
	case RawPubKey:
		if compressed {
			address, err = bchutil.NewAddressPubKey(pubKey.SerializeCompressed(), m.rootManager.chainParams)
		} else {
			address, err = bchutil.NewAddressPubKey(pubKey.SerializeUncompressed(), m.rootManager.chainParams)
		}
	}
	return &managedAddress{
		manager:          m,
		address:          address,
		derivationPath:   derivationPath,
		imported:         false,
		internal:         false,
		addrType:         addrType,
		compressed:       compressed,
		pubKey:           pubKey,
		privKeyEncrypted: nil,
		privKeyCT:        nil,
	}, nil
}
newManagedAddressWithoutPrivKey returns a new managed address based on the
passed account, public key, and whether or not the public key should be
compressed.
package waddrmgr
import (
	"encoding/hex"
	"fmt"
	"sync"
	"github.com/gcash/bchd/bchec"
	"github.com/gcash/bchutil"
	"github.com/gcash/bchutil/hdkeychain"
	"github.com/gcash/bchwallet/internal/zero"
	"github.com/gcash/bchwallet/walletdb"
)
type AddressType uint8
const (
	PubKeyHash AddressType = iota
	Script
	RawPubKey
)
type ManagedAddress interface {
	Account() uint32
	Address() bchutil.Address
	AddrHash() []byte
	Imported() bool
	Internal() bool
	Compressed() bool
	Used(ns walletdb.ReadBucket) bool
	AddrType() AddressType
}
type ManagedPubKeyAddress interface {
	ManagedAddress
	PubKey() *bchec.PublicKey
	ExportPubKey() string
	PrivKey() (*bchec.PrivateKey, error)
	ExportPrivKey() (*bchutil.WIF, error)
	DerivationInfo() (KeyScope, DerivationPath, bool)
}
type ManagedScriptAddress interface {
	ManagedAddress
	Script() ([]byte, error)
}
type managedAddress struct {
	manager          *ScopedKeyManager
	derivationPath   DerivationPath
	address          bchutil.Address
	imported         bool
	internal         bool
	compressed       bool
	used             bool
	addrType         AddressType
	pubKey           *bchec.PublicKey
	privKeyEncrypted []byte
	privKeyCT        []byte  
	privKeyMutex     sync.Mutex
}
var _ ManagedPubKeyAddress = (*managedAddress)(nil)
func (a *managedAddress) unlock(key EncryptorDecryptor) ([]byte, error) {
	a.privKeyMutex.Lock()
	defer a.privKeyMutex.Unlock()
	if len(a.privKeyCT) == 0 {
		privKey, err := key.Decrypt(a.privKeyEncrypted)
		if err != nil {
			str := fmt.Sprintf("failed to decrypt private key for "+
				"%s", a.address)
			return nil, managerError(ErrCrypto, str, err)
		}
		a.privKeyCT = privKey
	}
	privKeyCopy := make([]byte, len(a.privKeyCT))
	copy(privKeyCopy, a.privKeyCT)
	return privKeyCopy, nil
}
func (a *managedAddress) lock() {
	a.privKeyMutex.Lock()
	zero.Bytes(a.privKeyCT)
	a.privKeyCT = nil
	a.privKeyMutex.Unlock()
}
func (a *managedAddress) Account() uint32 {
	return a.derivationPath.Account
}
func (a *managedAddress) AddrType() AddressType {
	return a.addrType
}
func (a *managedAddress) Address() bchutil.Address {
	return a.address
}
func (a *managedAddress) AddrHash() []byte {
	var hash []byte
	switch n := a.address.(type) {
	case *bchutil.AddressPubKeyHash:
		hash = n.Hash160()[:]
	case *bchutil.AddressScriptHash:
		hash = n.Hash160()[:]
	}
	return hash
}
func (a *managedAddress) Imported() bool {
	return a.imported
}
func (a *managedAddress) Internal() bool {
	return a.internal
}
func (a *managedAddress) Compressed() bool {
	return a.compressed
}
func (a *managedAddress) Used(ns walletdb.ReadBucket) bool {
	return a.manager.fetchUsed(ns, a.AddrHash())
}
func (a *managedAddress) PubKey() *bchec.PublicKey {
	return a.pubKey
}
func (a *managedAddress) pubKeyBytes() []byte {
	if a.compressed {
		return a.pubKey.SerializeCompressed()
	}
	return a.pubKey.SerializeUncompressed()
}
func (a *managedAddress) ExportPubKey() string {
	return hex.EncodeToString(a.pubKeyBytes())
}
func (a *managedAddress) PrivKey() (*bchec.PrivateKey, error) {
	if a.manager.rootManager.WatchOnly() {
		return nil, managerError(ErrWatchingOnly, errWatchingOnly, nil)
	}
	a.manager.mtx.Lock()
	defer a.manager.mtx.Unlock()
	if a.manager.rootManager.IsLocked() {
		return nil, managerError(ErrLocked, errLocked, nil)
	}
	privKeyCopy, err := a.unlock(a.manager.rootManager.cryptoKeyPriv)
	if err != nil {
		return nil, err
	}
	privKey, _ := bchec.PrivKeyFromBytes(bchec.S256(), privKeyCopy)
	zero.Bytes(privKeyCopy)
	return privKey, nil
}
func (a *managedAddress) ExportPrivKey() (*bchutil.WIF, error) {
	pk, err := a.PrivKey()
	if err != nil {
		return nil, err
	}
	return bchutil.NewWIF(pk, a.manager.rootManager.chainParams, a.compressed)
}
func (a *managedAddress) DerivationInfo() (KeyScope, DerivationPath, bool) {
	var (
		scope KeyScope
		path  DerivationPath
	)
	if a.imported {
		return scope, path, false
	}
	return a.manager.Scope(), a.derivationPath, true
}