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:
parent
05d73f6899
commit
bd81968215
2 changed files with 82 additions and 20 deletions
|
@ -108,7 +108,7 @@ type ManagedPubKeyAddress interface {
|
||||||
// that backs the address via traditional methods from the HD root. For
|
// 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
|
// imported keys, the first value will be set to false to indicate that
|
||||||
// we don't know exactly how the key was derived.
|
// 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
|
// 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.
|
// the private key associated with the public key.
|
||||||
type managedAddress struct {
|
type managedAddress struct {
|
||||||
manager *ScopedKeyManager
|
manager *ScopedKeyManager
|
||||||
account uint32
|
derivationPath DerivationPath
|
||||||
address btcutil.Address
|
address btcutil.Address
|
||||||
imported bool
|
imported bool
|
||||||
internal bool
|
internal bool
|
||||||
|
@ -181,7 +181,7 @@ func (a *managedAddress) lock() {
|
||||||
//
|
//
|
||||||
// This is part of the ManagedAddress interface implementation.
|
// This is part of the ManagedAddress interface implementation.
|
||||||
func (a *managedAddress) Account() uint32 {
|
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
|
// 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)
|
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
|
// 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 *ScopedKeyManager, account uint32, pubKey *btcec.PublicKey,
|
func newManagedAddressWithoutPrivKey(m *ScopedKeyManager,
|
||||||
compressed bool, addrType AddressType) (*managedAddress, error) {
|
derivationPath DerivationPath, pubKey *btcec.PublicKey, 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
|
||||||
|
@ -387,7 +409,7 @@ func newManagedAddressWithoutPrivKey(m *ScopedKeyManager, account uint32, pubKey
|
||||||
return &managedAddress{
|
return &managedAddress{
|
||||||
manager: m,
|
manager: m,
|
||||||
address: address,
|
address: address,
|
||||||
account: account,
|
derivationPath: derivationPath,
|
||||||
imported: false,
|
imported: false,
|
||||||
internal: false,
|
internal: false,
|
||||||
addrType: addrType,
|
addrType: addrType,
|
||||||
|
@ -401,8 +423,9 @@ func newManagedAddressWithoutPrivKey(m *ScopedKeyManager, account uint32, pubKey
|
||||||
// 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(s *ScopedKeyManager, account uint32, privKey *btcec.PrivateKey,
|
func newManagedAddress(s *ScopedKeyManager, derivationPath DerivationPath,
|
||||||
compressed bool, addrType AddressType) (*managedAddress, error) {
|
privKey *btcec.PrivateKey, compressed bool,
|
||||||
|
addrType AddressType) (*managedAddress, error) {
|
||||||
|
|
||||||
// Encrypt the private key.
|
// 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.
|
// and then add the private key to it.
|
||||||
ecPubKey := (*btcec.PublicKey)(&privKey.PublicKey)
|
ecPubKey := (*btcec.PublicKey)(&privKey.PublicKey)
|
||||||
managedAddr, err := newManagedAddressWithoutPrivKey(
|
managedAddr, err := newManagedAddressWithoutPrivKey(
|
||||||
s, account, ecPubKey, compressed, addrType,
|
s, derivationPath, ecPubKey, compressed, addrType,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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
|
// 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(s *ScopedKeyManager, account uint32,
|
func newManagedAddressFromExtKey(s *ScopedKeyManager,
|
||||||
key *hdkeychain.ExtendedKey, addrType AddressType) (*managedAddress, error) {
|
derivationPath DerivationPath, 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.
|
||||||
|
@ -446,9 +470,10 @@ func newManagedAddressFromExtKey(s *ScopedKeyManager, account uint32,
|
||||||
return nil, err
|
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(
|
managedAddr, err = newManagedAddress(
|
||||||
s, account, privKey, true, addrType,
|
s, derivationPath, privKey, true, addrType,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -460,7 +485,8 @@ func newManagedAddressFromExtKey(s *ScopedKeyManager, account uint32,
|
||||||
}
|
}
|
||||||
|
|
||||||
managedAddr, err = newManagedAddressWithoutPrivKey(
|
managedAddr, err = newManagedAddressWithoutPrivKey(
|
||||||
s, account, pubKey, true, addrType,
|
s, derivationPath, pubKey, true,
|
||||||
|
addrType,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -221,11 +221,17 @@ func (s *ScopedKeyManager) keyToManaged(derivedKey *hdkeychain.ExtendedKey,
|
||||||
addrType = s.addrSchema.ExternalAddrType
|
addrType = s.addrSchema.ExternalAddrType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
derivationPath := DerivationPath{
|
||||||
|
Account: account,
|
||||||
|
Branch: branch,
|
||||||
|
Index: index,
|
||||||
|
}
|
||||||
|
|
||||||
// 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 passed key is private. Also, zero the key
|
// depending on whether the passed key is private. Also, zero the key
|
||||||
// after creating the managed address from it.
|
// after creating the managed address from it.
|
||||||
ma, err := newManagedAddressFromExtKey(
|
ma, err := newManagedAddressFromExtKey(
|
||||||
s, account, derivedKey, addrType,
|
s, derivationPath, derivedKey, addrType,
|
||||||
)
|
)
|
||||||
defer derivedKey.Zero()
|
defer derivedKey.Zero()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -515,9 +521,15 @@ func (s *ScopedKeyManager) importedAddressRowToManaged(row *dbImportedAddressRow
|
||||||
return nil, managerError(ErrCrypto, str, err)
|
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
|
compressed := len(pubBytes) == btcec.PubKeyBytesLenCompressed
|
||||||
ma, err := newManagedAddressWithoutPrivKey(
|
ma, err := newManagedAddressWithoutPrivKey(
|
||||||
s, row.account, pubKey, compressed,
|
s, derivationPath, pubKey, compressed,
|
||||||
s.addrSchema.ExternalAddrType,
|
s.addrSchema.ExternalAddrType,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -740,12 +752,21 @@ func (s *ScopedKeyManager) nextAddresses(ns walletdb.ReadWriteBucket,
|
||||||
break
|
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
|
// Create a new managed address based on the public or private
|
||||||
// key depending on whether the generated key is private.
|
// key depending on whether the generated key is private.
|
||||||
// Also, zero the next key after creating the managed address
|
// Also, zero the next key after creating the managed address
|
||||||
// from it.
|
// from it.
|
||||||
addr, err := newManagedAddressFromExtKey(
|
addr, err := newManagedAddressFromExtKey(
|
||||||
s, account, nextKey, addrType,
|
s, derivationPath, nextKey, addrType,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -920,12 +941,21 @@ func (s *ScopedKeyManager) extendAddresses(ns walletdb.ReadWriteBucket,
|
||||||
break
|
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
|
// Create a new managed address based on the public or private
|
||||||
// key depending on whether the generated key is private.
|
// key depending on whether the generated key is private.
|
||||||
// Also, zero the next key after creating the managed address
|
// Also, zero the next key after creating the managed address
|
||||||
// from it.
|
// from it.
|
||||||
addr, err := newManagedAddressFromExtKey(
|
addr, err := newManagedAddressFromExtKey(
|
||||||
s, account, nextKey, addrType,
|
s, derivationPath, nextKey, addrType,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1452,17 +1482,23 @@ func (s *ScopedKeyManager) ImportPrivateKey(ns walletdb.ReadWriteBucket,
|
||||||
s.rootManager.mtx.Unlock()
|
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.
|
// Create a new managed address based on the imported address.
|
||||||
var managedAddr *managedAddress
|
var managedAddr *managedAddress
|
||||||
if !s.rootManager.WatchOnly() {
|
if !s.rootManager.WatchOnly() {
|
||||||
managedAddr, err = newManagedAddress(
|
managedAddr, err = newManagedAddress(
|
||||||
s, ImportedAddrAccount, wif.PrivKey,
|
s, importedDerivationPath, wif.PrivKey,
|
||||||
wif.CompressPubKey, s.addrSchema.ExternalAddrType,
|
wif.CompressPubKey, s.addrSchema.ExternalAddrType,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
pubKey := (*btcec.PublicKey)(&wif.PrivKey.PublicKey)
|
pubKey := (*btcec.PublicKey)(&wif.PrivKey.PublicKey)
|
||||||
managedAddr, err = newManagedAddressWithoutPrivKey(
|
managedAddr, err = newManagedAddressWithoutPrivKey(
|
||||||
s, ImportedAddrAccount, pubKey, wif.CompressPubKey,
|
s, importedDerivationPath, pubKey, wif.CompressPubKey,
|
||||||
s.addrSchema.ExternalAddrType,
|
s.addrSchema.ExternalAddrType,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue