waddrmgr: add new DerivationInfo method to managedAddress, update ScopedKeyManager

In this commit, we add the new DerivationInfo method to the current
default implementation of the ManagedPubKeyAddress interface. In doing
this, we replace the account field with the derivationPath, as we can
obtain the account field from the derivationPath itself.
This commit is contained in:
Olaoluwa Osuntokun 2018-08-13 18:44:46 -07:00
parent 05d73f6899
commit bd81968215
No known key found for this signature in database
GPG key ID: 964EA263DD637C21
2 changed files with 82 additions and 20 deletions

View file

@ -108,7 +108,7 @@ type ManagedPubKeyAddress interface {
// that backs the address via traditional methods from the HD root. For
// imported keys, the first value will be set to false to indicate that
// we don't know exactly how the key was derived.
DerivationInfo() (bool, KeyScope, DerivationPath)
DerivationInfo() (KeyScope, DerivationPath, bool)
}
// ManagedScriptAddress extends ManagedAddress and represents a pay-to-script-hash
@ -125,7 +125,7 @@ type ManagedScriptAddress interface {
// the private key associated with the public key.
type managedAddress struct {
manager *ScopedKeyManager
account uint32
derivationPath DerivationPath
address btcutil.Address
imported bool
internal bool
@ -181,7 +181,7 @@ func (a *managedAddress) lock() {
//
// This is part of the ManagedAddress interface implementation.
func (a *managedAddress) Account() uint32 {
return a.account
return a.derivationPath.Account
}
// AddrType returns the address type of the managed address. This can be used
@ -316,11 +316,33 @@ func (a *managedAddress) ExportPrivKey() (*btcutil.WIF, error) {
return btcutil.NewWIF(pk, a.manager.rootManager.chainParams, a.compressed)
}
// Derivationinfo contains the information required to derive the key that
// backs the address via traditional methods from the HD root. For imported
// keys, the first value will be set to false to indicate that we don't know
// exactly how the key was derived.
//
// This is part of the ManagedPubKeyAddress interface implementation.
func (a *managedAddress) DerivationInfo() (KeyScope, DerivationPath, bool) {
var (
scope KeyScope
path DerivationPath
)
// If this key is imported, then we can't return any information as we
// don't know precisely how the key was derived.
if a.imported {
return scope, path, false
}
return a.manager.Scope(), a.derivationPath, true
}
// newManagedAddressWithoutPrivKey returns a new managed address based on the
// passed account, public key, and whether or not the public key should be
// compressed.
func newManagedAddressWithoutPrivKey(m *ScopedKeyManager, account uint32, pubKey *btcec.PublicKey,
compressed bool, addrType AddressType) (*managedAddress, error) {
func newManagedAddressWithoutPrivKey(m *ScopedKeyManager,
derivationPath DerivationPath, pubKey *btcec.PublicKey, compressed bool,
addrType AddressType) (*managedAddress, error) {
// Create a pay-to-pubkey-hash address from the public key.
var pubKeyHash []byte
@ -387,7 +409,7 @@ func newManagedAddressWithoutPrivKey(m *ScopedKeyManager, account uint32, pubKey
return &managedAddress{
manager: m,
address: address,
account: account,
derivationPath: derivationPath,
imported: false,
internal: false,
addrType: addrType,
@ -401,8 +423,9 @@ func newManagedAddressWithoutPrivKey(m *ScopedKeyManager, account uint32, pubKey
// newManagedAddress returns a new managed address based on the passed account,
// private key, and whether or not the public key is compressed. The managed
// address will have access to the private and public keys.
func newManagedAddress(s *ScopedKeyManager, account uint32, privKey *btcec.PrivateKey,
compressed bool, addrType AddressType) (*managedAddress, error) {
func newManagedAddress(s *ScopedKeyManager, derivationPath DerivationPath,
privKey *btcec.PrivateKey, compressed bool,
addrType AddressType) (*managedAddress, error) {
// Encrypt the private key.
//
@ -419,7 +442,7 @@ func newManagedAddress(s *ScopedKeyManager, account uint32, privKey *btcec.Priva
// and then add the private key to it.
ecPubKey := (*btcec.PublicKey)(&privKey.PublicKey)
managedAddr, err := newManagedAddressWithoutPrivKey(
s, account, ecPubKey, compressed, addrType,
s, derivationPath, ecPubKey, compressed, addrType,
)
if err != nil {
return nil, err
@ -434,8 +457,9 @@ func newManagedAddress(s *ScopedKeyManager, account uint32, privKey *btcec.Priva
// 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
// will only have access to the public key.
func newManagedAddressFromExtKey(s *ScopedKeyManager, account uint32,
key *hdkeychain.ExtendedKey, addrType AddressType) (*managedAddress, error) {
func newManagedAddressFromExtKey(s *ScopedKeyManager,
derivationPath DerivationPath, key *hdkeychain.ExtendedKey,
addrType AddressType) (*managedAddress, error) {
// Create a new managed address based on the public or private key
// depending on whether the generated key is private.
@ -446,9 +470,10 @@ func newManagedAddressFromExtKey(s *ScopedKeyManager, account uint32,
return nil, err
}
// 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(
s, account, privKey, true, addrType,
s, derivationPath, privKey, true, addrType,
)
if err != nil {
return nil, err
@ -460,7 +485,8 @@ func newManagedAddressFromExtKey(s *ScopedKeyManager, account uint32,
}
managedAddr, err = newManagedAddressWithoutPrivKey(
s, account, pubKey, true, addrType,
s, derivationPath, pubKey, true,
addrType,
)
if err != nil {
return nil, err

View file

@ -221,11 +221,17 @@ func (s *ScopedKeyManager) keyToManaged(derivedKey *hdkeychain.ExtendedKey,
addrType = s.addrSchema.ExternalAddrType
}
derivationPath := DerivationPath{
Account: account,
Branch: branch,
Index: index,
}
// Create a new managed address based on the public or private key
// depending on whether the passed key is private. Also, zero the key
// after creating the managed address from it.
ma, err := newManagedAddressFromExtKey(
s, account, derivedKey, addrType,
s, derivationPath, derivedKey, addrType,
)
defer derivedKey.Zero()
if err != nil {
@ -515,9 +521,15 @@ func (s *ScopedKeyManager) importedAddressRowToManaged(row *dbImportedAddressRow
return nil, managerError(ErrCrypto, str, err)
}
// Since this is an imported address, we won't populate the full
// derivation path, as we don't have enough information to do so.
derivationPath := DerivationPath{
Account: row.account,
}
compressed := len(pubBytes) == btcec.PubKeyBytesLenCompressed
ma, err := newManagedAddressWithoutPrivKey(
s, row.account, pubKey, compressed,
s, derivationPath, pubKey, compressed,
s.addrSchema.ExternalAddrType,
)
if err != nil {
@ -740,12 +752,21 @@ func (s *ScopedKeyManager) nextAddresses(ns walletdb.ReadWriteBucket,
break
}
// Now that we know this key can be used, we'll create the
// proper derivation path so this information can be available
// to callers.
derivationPath := DerivationPath{
Account: account,
Branch: branchNum,
Index: nextIndex - 1,
}
// Create a new managed address based on the public or private
// key depending on whether the generated key is private.
// Also, zero the next key after creating the managed address
// from it.
addr, err := newManagedAddressFromExtKey(
s, account, nextKey, addrType,
s, derivationPath, nextKey, addrType,
)
if err != nil {
return nil, err
@ -920,12 +941,21 @@ func (s *ScopedKeyManager) extendAddresses(ns walletdb.ReadWriteBucket,
break
}
// Now that we know this key can be used, we'll create the
// proper derivation path so this information can be available
// to callers.
derivationPath := DerivationPath{
Account: account,
Branch: branchNum,
Index: nextIndex - 1,
}
// Create a new managed address based on the public or private
// key depending on whether the generated key is private.
// Also, zero the next key after creating the managed address
// from it.
addr, err := newManagedAddressFromExtKey(
s, account, nextKey, addrType,
s, derivationPath, nextKey, addrType,
)
if err != nil {
return err
@ -1452,17 +1482,23 @@ func (s *ScopedKeyManager) ImportPrivateKey(ns walletdb.ReadWriteBucket,
s.rootManager.mtx.Unlock()
}
// The full derivation path for an imported key is incomplete as we
// don't know exactly how it was derived.
importedDerivationPath := DerivationPath{
Account: ImportedAddrAccount,
}
// Create a new managed address based on the imported address.
var managedAddr *managedAddress
if !s.rootManager.WatchOnly() {
managedAddr, err = newManagedAddress(
s, ImportedAddrAccount, wif.PrivKey,
s, importedDerivationPath, wif.PrivKey,
wif.CompressPubKey, s.addrSchema.ExternalAddrType,
)
} else {
pubKey := (*btcec.PublicKey)(&wif.PrivKey.PublicKey)
managedAddr, err = newManagedAddressWithoutPrivKey(
s, ImportedAddrAccount, pubKey, wif.CompressPubKey,
s, importedDerivationPath, pubKey, wif.CompressPubKey,
s.addrSchema.ExternalAddrType,
)
}