waddrmgr: update all addresses to be aware of new addr scopes

This commit is contained in:
Olaoluwa Osuntokun 2018-02-13 21:32:51 -08:00
parent 641efbbd31
commit 9a8da416ef

View file

@ -76,6 +76,11 @@ type ManagedAddress interface {
// Used returns true if the backing address has been used in a transaction. // Used returns true if the backing address has been used in a transaction.
Used(ns walletdb.ReadBucket) bool Used(ns walletdb.ReadBucket) bool
// AddrType returns the address type of the managed address. This can
// be used to quickly discern the address type without further
// processing
AddrType() AddressType
} }
// ManagedPubKeyAddress extends ManagedAddress and additionally provides the // ManagedPubKeyAddress extends ManagedAddress and additionally provides the
@ -98,13 +103,6 @@ type ManagedPubKeyAddress interface {
// ExportPrivKey returns the private key associated with the address // ExportPrivKey returns the private key associated with the address
// serialized as Wallet Import Format (WIF). // serialized as Wallet Import Format (WIF).
ExportPrivKey() (*btcutil.WIF, error) ExportPrivKey() (*btcutil.WIF, error)
// IsNestedWitness returns true if the managed address is an instance of pw2wkh
// nested within p2sh.
IsNestedWitness() bool
// IsWitness returns true if the managed address is a p2wkh address.
IsWitness() bool
} }
// ManagedScriptAddress extends ManagedAddress and represents a pay-to-script-hash // ManagedScriptAddress extends ManagedAddress and represents a pay-to-script-hash
@ -120,14 +118,14 @@ type ManagedScriptAddress interface {
// managedAddress represents a public key address. It also may or may not have // managedAddress represents a public key address. It also may or may not have
// the private key associated with the public key. // the private key associated with the public key.
type managedAddress struct { type managedAddress struct {
manager *Manager manager *ScopedKeyManager
account uint32 account uint32
address btcutil.Address address btcutil.Address
imported bool imported bool
internal bool internal bool
compressed bool compressed bool
used bool used bool
addrType addressType addrType AddressType
pubKey *btcec.PublicKey pubKey *btcec.PublicKey
privKeyEncrypted []byte privKeyEncrypted []byte
privKeyCT []byte // non-nil if unlocked privKeyCT []byte // non-nil if unlocked
@ -180,6 +178,14 @@ func (a *managedAddress) Account() uint32 {
return a.account return a.account
} }
// AddrType returns the address type of the managed address. This can be used
// to quickly discern the address type without further processing
//
// This is part of the ManagedAddress interface implementation.
func (a *managedAddress) AddrType() AddressType {
return a.addrType
}
// Address returns the btcutil.Address which represents the managed address. // Address returns the btcutil.Address which represents the managed address.
// This will be a pay-to-pubkey-hash address. // This will be a pay-to-pubkey-hash address.
// //
@ -266,7 +272,7 @@ func (a *managedAddress) ExportPubKey() string {
// This is part of the ManagedPubKeyAddress interface implementation. // This is part of the ManagedPubKeyAddress interface implementation.
func (a *managedAddress) PrivKey() (*btcec.PrivateKey, error) { func (a *managedAddress) PrivKey() (*btcec.PrivateKey, error) {
// No private keys are available for a watching-only address manager. // No private keys are available for a watching-only address manager.
if a.manager.watchingOnly { if a.manager.rootManager.WatchOnly() {
return nil, managerError(ErrWatchingOnly, errWatchingOnly, nil) return nil, managerError(ErrWatchingOnly, errWatchingOnly, nil)
} }
@ -274,14 +280,14 @@ func (a *managedAddress) PrivKey() (*btcec.PrivateKey, error) {
defer a.manager.mtx.Unlock() defer a.manager.mtx.Unlock()
// Account manager must be unlocked to decrypt the private key. // Account manager must be unlocked to decrypt the private key.
if a.manager.locked { if a.manager.rootManager.Locked() {
return nil, managerError(ErrLocked, errLocked, nil) return nil, managerError(ErrLocked, errLocked, nil)
} }
// Decrypt the key as needed. Also, make sure it's a copy since the // Decrypt the key as needed. Also, make sure it's a copy since the
// private key stored in memory can be cleared at any time. Otherwise // private key stored in memory can be cleared at any time. Otherwise
// the returned private key could be invalidated from under the caller. // the returned private key could be invalidated from under the caller.
privKeyCopy, err := a.unlock(a.manager.cryptoKeyPriv) privKeyCopy, err := a.unlock(a.manager.rootManager.cryptoKeyPriv)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -301,25 +307,14 @@ func (a *managedAddress) ExportPrivKey() (*btcutil.WIF, error) {
return nil, err return nil, err
} }
return btcutil.NewWIF(pk, a.manager.chainParams, a.compressed) return btcutil.NewWIF(pk, a.manager.rootManager.chainParams, a.compressed)
}
// IsNestedWitness returns true if the managed address is an instance of pw2wkh
// nested within p2sh.
func (a *managedAddress) IsNestedWitness() bool {
return a.addrType == adtChainNestedWitness
}
// IsWitness returns true if the managed address is a p2wkh address.
func (a *managedAddress) IsWitness() bool {
return a.addrType == adtChainWitness
} }
// newManagedAddressWithoutPrivKey returns a new managed address based on the // newManagedAddressWithoutPrivKey returns a new managed address based on the
// passed account, public key, and whether or not the public key should be // passed account, public key, and whether or not the public key should be
// compressed. // compressed.
func newManagedAddressWithoutPrivKey(m *Manager, account uint32, pubKey *btcec.PublicKey, func newManagedAddressWithoutPrivKey(m *ScopedKeyManager, account uint32, pubKey *btcec.PublicKey,
compressed bool, addrType addressType) (*managedAddress, error) { compressed bool, addrType AddressType) (*managedAddress, error) {
// Create a pay-to-pubkey-hash address from the public key. // Create a pay-to-pubkey-hash address from the public key.
var pubKeyHash []byte var pubKeyHash []byte
@ -333,15 +328,17 @@ func newManagedAddressWithoutPrivKey(m *Manager, account uint32, pubKey *btcec.P
var err error var err error
switch addrType { switch addrType {
// TODO(roasbeef): only use these types in the db?
case adtChainNestedWitness: case NestedWitnessPubKey:
// For this address type we'l generate an address which is // For this address type we'l generate an address which is
// backwards compatible to Bitcoin nodes running 0.6.0 onwards, but // backwards compatible to Bitcoin nodes running 0.6.0 onwards, but
// allows us to take advantage of segwit's scripting improvments, // allows us to take advantage of segwit's scripting improvments,
// and malleability fixes. // and malleability fixes.
// First, we'll generate a normal p2wkh address from the pubkey hash. // First, we'll generate a normal p2wkh address from the pubkey hash.
witAddr, err := btcutil.NewAddressWitnessPubKeyHash(pubKeyHash, m.chainParams) witAddr, err := btcutil.NewAddressWitnessPubKeyHash(
pubKeyHash, m.rootManager.chainParams,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -357,20 +354,25 @@ func newManagedAddressWithoutPrivKey(m *Manager, account uint32, pubKey *btcec.P
// to a p2sh address. In order to spend, we first use the // to a p2sh address. In order to spend, we first use the
// witnessProgram as the sigScript, then present the proper // witnessProgram as the sigScript, then present the proper
// <sig, pubkey> pair as the witness. // <sig, pubkey> pair as the witness.
address, err = btcutil.NewAddressScriptHash(witnessProgram, m.chainParams) address, err = btcutil.NewAddressScriptHash(
witnessProgram, m.rootManager.chainParams,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
case adtImport:
// TODO(roasbeef): truly proper? case PubKeyHash:
fallthrough address, err = btcutil.NewAddressPubKeyHash(
case adtChain: pubKeyHash, m.rootManager.chainParams,
address, err = btcutil.NewAddressPubKeyHash(pubKeyHash, m.chainParams) )
if err != nil { if err != nil {
return nil, err return nil, err
} }
case adtChainWitness:
address, err = btcutil.NewAddressWitnessPubKeyHash(pubKeyHash, m.chainParams) case WitnessPubKey:
address, err = btcutil.NewAddressWitnessPubKeyHash(
pubKeyHash, m.rootManager.chainParams,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -393,15 +395,15 @@ func newManagedAddressWithoutPrivKey(m *Manager, account uint32, pubKey *btcec.P
// newManagedAddress returns a new managed address based on the passed account, // newManagedAddress returns a new managed address based on the passed account,
// private key, and whether or not the public key is compressed. The managed // private key, and whether or not the public key is compressed. The managed
// address will have access to the private and public keys. // address will have access to the private and public keys.
func newManagedAddress(m *Manager, account uint32, privKey *btcec.PrivateKey, func newManagedAddress(s *ScopedKeyManager, account uint32, privKey *btcec.PrivateKey,
compressed bool, addrType addressType) (*managedAddress, error) { compressed bool, addrType AddressType) (*managedAddress, error) {
// Encrypt the private key. // Encrypt the private key.
// //
// NOTE: The privKeyBytes here are set into the managed address which // NOTE: The privKeyBytes here are set into the managed address which
// are cleared when locked, so they aren't cleared here. // are cleared when locked, so they aren't cleared here.
privKeyBytes := privKey.Serialize() privKeyBytes := privKey.Serialize()
privKeyEncrypted, err := m.cryptoKeyPriv.Encrypt(privKeyBytes) privKeyEncrypted, err := s.rootManager.cryptoKeyPriv.Encrypt(privKeyBytes)
if err != nil { if err != nil {
str := "failed to encrypt private key" str := "failed to encrypt private key"
return nil, managerError(ErrCrypto, str, err) return nil, managerError(ErrCrypto, str, err)
@ -410,8 +412,9 @@ func newManagedAddress(m *Manager, account uint32, privKey *btcec.PrivateKey,
// Leverage the code to create a managed address without a private key // Leverage the code to create a managed address without a private key
// and then add the private key to it. // and then add the private key to it.
ecPubKey := (*btcec.PublicKey)(&privKey.PublicKey) ecPubKey := (*btcec.PublicKey)(&privKey.PublicKey)
managedAddr, err := newManagedAddressWithoutPrivKey(m, account, managedAddr, err := newManagedAddressWithoutPrivKey(
ecPubKey, compressed, addrType) s, account, ecPubKey, compressed, addrType,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -425,8 +428,8 @@ func newManagedAddress(m *Manager, account uint32, privKey *btcec.PrivateKey,
// account and extended key. The managed address will have access to the // account and extended key. The managed address will have access to the
// private and public keys if the provided extended key is private, otherwise it // private and public keys if the provided extended key is private, otherwise it
// will only have access to the public key. // will only have access to the public key.
func newManagedAddressFromExtKey(m *Manager, account uint32, func newManagedAddressFromExtKey(s *ScopedKeyManager, account uint32,
key *hdkeychain.ExtendedKey, addrType addressType) (*managedAddress, error) { key *hdkeychain.ExtendedKey, addrType AddressType) (*managedAddress, error) {
// Create a new managed address based on the public or private key // Create a new managed address based on the public or private key
// depending on whether the generated key is private. // depending on whether the generated key is private.
@ -438,8 +441,9 @@ func newManagedAddressFromExtKey(m *Manager, account uint32,
} }
// Ensure the temp private key big integer is cleared after use. // Ensure the temp private key big integer is cleared after use.
managedAddr, err = newManagedAddress(m, account, privKey, true, managedAddr, err = newManagedAddress(
addrType) s, account, privKey, true, addrType,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -449,8 +453,9 @@ func newManagedAddressFromExtKey(m *Manager, account uint32,
return nil, err return nil, err
} }
managedAddr, err = newManagedAddressWithoutPrivKey(m, account, managedAddr, err = newManagedAddressWithoutPrivKey(
pubKey, true, addrType) s, account, pubKey, true, addrType,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -461,7 +466,7 @@ func newManagedAddressFromExtKey(m *Manager, account uint32,
// scriptAddress represents a pay-to-script-hash address. // scriptAddress represents a pay-to-script-hash address.
type scriptAddress struct { type scriptAddress struct {
manager *Manager manager *ScopedKeyManager
account uint32 account uint32
address *btcutil.AddressScriptHash address *btcutil.AddressScriptHash
scriptEncrypted []byte scriptEncrypted []byte
@ -515,6 +520,14 @@ func (a *scriptAddress) Account() uint32 {
return a.account return a.account
} }
// AddrType returns the address type of the managed address. This can be used
// to quickly discern the address type without further processing
//
// This is part of the ManagedAddress interface implementation.
func (a *scriptAddress) AddrType() AddressType {
return Script
}
// Address returns the btcutil.Address which represents the managed address. // Address returns the btcutil.Address which represents the managed address.
// This will be a pay-to-script-hash address. // This will be a pay-to-script-hash address.
// //
@ -565,7 +578,7 @@ func (a *scriptAddress) Used(ns walletdb.ReadBucket) bool {
// This implements the ScriptAddress interface. // This implements the ScriptAddress interface.
func (a *scriptAddress) Script() ([]byte, error) { func (a *scriptAddress) Script() ([]byte, error) {
// No script is available for a watching-only address manager. // No script is available for a watching-only address manager.
if a.manager.watchingOnly { if a.manager.rootManager.WatchOnly() {
return nil, managerError(ErrWatchingOnly, errWatchingOnly, nil) return nil, managerError(ErrWatchingOnly, errWatchingOnly, nil)
} }
@ -573,20 +586,23 @@ func (a *scriptAddress) Script() ([]byte, error) {
defer a.manager.mtx.Unlock() defer a.manager.mtx.Unlock()
// Account manager must be unlocked to decrypt the script. // Account manager must be unlocked to decrypt the script.
if a.manager.locked { if a.manager.rootManager.Locked() {
return nil, managerError(ErrLocked, errLocked, nil) return nil, managerError(ErrLocked, errLocked, nil)
} }
// Decrypt the script as needed. Also, make sure it's a copy since the // Decrypt the script as needed. Also, make sure it's a copy since the
// script stored in memory can be cleared at any time. Otherwise, // script stored in memory can be cleared at any time. Otherwise,
// the returned script could be invalidated from under the caller. // the returned script could be invalidated from under the caller.
return a.unlock(a.manager.cryptoKeyScript) return a.unlock(a.manager.rootManager.cryptoKeyScript)
} }
// newScriptAddress initializes and returns a new pay-to-script-hash address. // newScriptAddress initializes and returns a new pay-to-script-hash address.
func newScriptAddress(m *Manager, account uint32, scriptHash, scriptEncrypted []byte) (*scriptAddress, error) { func newScriptAddress(m *ScopedKeyManager, account uint32, scriptHash,
address, err := btcutil.NewAddressScriptHashFromHash(scriptHash, scriptEncrypted []byte) (*scriptAddress, error) {
m.chainParams)
address, err := btcutil.NewAddressScriptHashFromHash(
scriptHash, m.rootManager.chainParams,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }