waddrmgr: use proper version for account key of non-watch-only accounts
This commit is contained in:
parent
adb3d77c86
commit
9d909110f9
2 changed files with 105 additions and 0 deletions
|
@ -144,6 +144,8 @@ type addrKey string
|
||||||
type accountInfo struct {
|
type accountInfo struct {
|
||||||
acctName string
|
acctName string
|
||||||
|
|
||||||
|
acctType accountType
|
||||||
|
|
||||||
// The account key is used to derive the branches which in turn derive
|
// The account key is used to derive the branches which in turn derive
|
||||||
// the internal and external addresses. The accountKeyPriv will be nil
|
// the internal and external addresses. The accountKeyPriv will be nil
|
||||||
// when the address manager is locked.
|
// when the address manager is locked.
|
||||||
|
|
|
@ -1,18 +1,50 @@
|
||||||
package waddrmgr
|
package waddrmgr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/btcsuite/btcd/txscript"
|
||||||
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
"github.com/btcsuite/btcutil/hdkeychain"
|
"github.com/btcsuite/btcutil/hdkeychain"
|
||||||
"github.com/btcsuite/btcwallet/internal/zero"
|
"github.com/btcsuite/btcwallet/internal/zero"
|
||||||
"github.com/btcsuite/btcwallet/walletdb"
|
"github.com/btcsuite/btcwallet/walletdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// HDVersion represents the different supported schemes of hierarchical
|
||||||
|
// derivation.
|
||||||
|
type HDVersion uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
// HDVersionMainNetBIP0044 is the HDVersion for BIP-0044 on the main
|
||||||
|
// network.
|
||||||
|
HDVersionMainNetBIP0044 HDVersion = 0x0488b21e // xpub
|
||||||
|
|
||||||
|
// HDVersionMainNetBIP0049 is the HDVersion for BIP-0049 on the main
|
||||||
|
// network.
|
||||||
|
HDVersionMainNetBIP0049 HDVersion = 0x049d7cb2 // ypub
|
||||||
|
|
||||||
|
// HDVersionMainNetBIP0084 is the HDVersion for BIP-0084 on the main
|
||||||
|
// network.
|
||||||
|
HDVersionMainNetBIP0084 HDVersion = 0x04b24746 // zpub
|
||||||
|
|
||||||
|
// HDVersionTestNetBIP0044 is the HDVersion for BIP-0044 on the test
|
||||||
|
// network.
|
||||||
|
HDVersionTestNetBIP0044 HDVersion = 0x043587cf // tpub
|
||||||
|
|
||||||
|
// HDVersionTestNetBIP0049 is the HDVersion for BIP-0049 on the test
|
||||||
|
// network.
|
||||||
|
HDVersionTestNetBIP0049 HDVersion = 0x044a5262 // upub
|
||||||
|
|
||||||
|
// HDVersionTestNetBIP0084 is the HDVersion for BIP-0084 on the test
|
||||||
|
// network.
|
||||||
|
HDVersionTestNetBIP0084 HDVersion = 0x045f1cf6 // vpub
|
||||||
|
)
|
||||||
|
|
||||||
// DerivationPath represents a derivation path from a particular key manager's
|
// DerivationPath represents a derivation path from a particular key manager's
|
||||||
// scope. Each ScopedKeyManager starts key derivation from the end of their
|
// scope. Each ScopedKeyManager starts key derivation from the end of their
|
||||||
// cointype hardened key: m/purpose'/cointype'. The fields in this struct allow
|
// cointype hardened key: m/purpose'/cointype'. The fields in this struct allow
|
||||||
|
@ -331,6 +363,7 @@ func (s *ScopedKeyManager) loadAccountInfo(ns walletdb.ReadBucket,
|
||||||
case *dbDefaultAccountRow:
|
case *dbDefaultAccountRow:
|
||||||
acctInfo = &accountInfo{
|
acctInfo = &accountInfo{
|
||||||
acctName: row.name,
|
acctName: row.name,
|
||||||
|
acctType: row.acctType,
|
||||||
acctKeyEncrypted: row.privKeyEncrypted,
|
acctKeyEncrypted: row.privKeyEncrypted,
|
||||||
nextExternalIndex: row.nextExternalIndex,
|
nextExternalIndex: row.nextExternalIndex,
|
||||||
nextInternalIndex: row.nextInternalIndex,
|
nextInternalIndex: row.nextInternalIndex,
|
||||||
|
@ -363,6 +396,7 @@ func (s *ScopedKeyManager) loadAccountInfo(ns walletdb.ReadBucket,
|
||||||
case *dbWatchOnlyAccountRow:
|
case *dbWatchOnlyAccountRow:
|
||||||
acctInfo = &accountInfo{
|
acctInfo = &accountInfo{
|
||||||
acctName: row.name,
|
acctName: row.name,
|
||||||
|
acctType: row.acctType,
|
||||||
nextExternalIndex: row.nextExternalIndex,
|
nextExternalIndex: row.nextExternalIndex,
|
||||||
nextInternalIndex: row.nextInternalIndex,
|
nextInternalIndex: row.nextInternalIndex,
|
||||||
addrSchema: row.addrSchema,
|
addrSchema: row.addrSchema,
|
||||||
|
@ -472,6 +506,29 @@ func (s *ScopedKeyManager) AccountProperties(ns walletdb.ReadBucket,
|
||||||
props.IsWatchOnly = s.rootManager.WatchOnly() ||
|
props.IsWatchOnly = s.rootManager.WatchOnly() ||
|
||||||
acctInfo.acctKeyPriv == nil
|
acctInfo.acctKeyPriv == nil
|
||||||
props.AddrSchema = acctInfo.addrSchema
|
props.AddrSchema = acctInfo.addrSchema
|
||||||
|
|
||||||
|
// Export the account public key with the correct version
|
||||||
|
// corresponding to the manager's key scope for non-watch-only
|
||||||
|
// accounts. This isn't done for watch-only accounts to maintain
|
||||||
|
// the account public key consistent with what the caller
|
||||||
|
// provided. Note that his is only done for the default key
|
||||||
|
// scopes, as we only know the HD versions for those.
|
||||||
|
isDefaultKeyScope := false
|
||||||
|
for _, scope := range DefaultKeyScopes {
|
||||||
|
if s.scope == scope {
|
||||||
|
isDefaultKeyScope = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if acctInfo.acctType == accountDefault && isDefaultKeyScope {
|
||||||
|
props.AccountPubKey, err = s.cloneKeyWithVersion(
|
||||||
|
acctInfo.acctKeyPub,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to retrieve "+
|
||||||
|
"account public key: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
props.AccountName = ImportedAddrAccountName // reserved, nonchangable
|
props.AccountName = ImportedAddrAccountName // reserved, nonchangable
|
||||||
props.IsWatchOnly = s.rootManager.WatchOnly()
|
props.IsWatchOnly = s.rootManager.WatchOnly()
|
||||||
|
@ -2118,3 +2175,49 @@ func (s *ScopedKeyManager) ForEachInternalActiveAddress(ns walletdb.ReadBucket,
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cloneKeyWithVersion clones an extended key to use the version corresponding
|
||||||
|
// to the manager's key scope. This should only be used for non-watch-only
|
||||||
|
// accounts as they are stored within the database using the legacy BIP-0044
|
||||||
|
// version by default.
|
||||||
|
func (s *ScopedKeyManager) cloneKeyWithVersion(key *hdkeychain.ExtendedKey) (
|
||||||
|
*hdkeychain.ExtendedKey, error) {
|
||||||
|
|
||||||
|
// Determine the appropriate version based on the current network and
|
||||||
|
// key scope.
|
||||||
|
var version HDVersion
|
||||||
|
net := s.rootManager.ChainParams().Net
|
||||||
|
switch net {
|
||||||
|
case wire.MainNet:
|
||||||
|
switch s.scope {
|
||||||
|
case KeyScopeBIP0044:
|
||||||
|
version = HDVersionMainNetBIP0044
|
||||||
|
case KeyScopeBIP0049Plus:
|
||||||
|
version = HDVersionMainNetBIP0049
|
||||||
|
case KeyScopeBIP0084:
|
||||||
|
version = HDVersionMainNetBIP0084
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported scope %v", s.scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
case wire.TestNet, wire.TestNet3:
|
||||||
|
switch s.scope {
|
||||||
|
case KeyScopeBIP0044:
|
||||||
|
version = HDVersionTestNetBIP0044
|
||||||
|
case KeyScopeBIP0049Plus:
|
||||||
|
version = HDVersionTestNetBIP0049
|
||||||
|
case KeyScopeBIP0084:
|
||||||
|
version = HDVersionTestNetBIP0084
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported scope %v", s.scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported net %v", net)
|
||||||
|
}
|
||||||
|
|
||||||
|
var versionBytes [4]byte
|
||||||
|
binary.BigEndian.PutUint32(versionBytes[:], uint32(version))
|
||||||
|
|
||||||
|
return key.CloneWithVersion(versionBytes[:])
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue