wallet: derive change addresses from the provided key scope

Previously, the wallet would determine the key scope to use for change
addresses by locating the one compatible with P2WPKH addresses, but this
wasn't always safe like in the case when multiple key scopes that
supported these addresses existed within the address manager, leading
the change address to be created outside of the intended key scope.
This commit is contained in:
Wilmer Paulino 2020-03-30 15:30:53 -07:00
parent 7b2cbe89f8
commit 60fce250f4
No known key found for this signature in database
GPG key ID: 6DF57B9F9514972F
2 changed files with 14 additions and 13 deletions

View file

@ -135,15 +135,21 @@ func (w *Wallet) txToOutputs(outputs []*wire.TxOut, account uint32,
inputSource := makeInputSource(eligible)
changeSource := func() ([]byte, error) {
// Derive the change output script. As a hack to allow
// spending from the imported account, change addresses are
// created from account 0.
// Derive the change output script. We'll use the default key
// scope responsible for P2WPKH addresses to do so. As a hack to
// allow spending from the imported account, change addresses
// are created from account 0.
var changeAddr btcutil.Address
var err error
changeKeyScope := waddrmgr.KeyScopeBIP0084
if account == waddrmgr.ImportedAddrAccount {
changeAddr, err = w.newChangeAddress(addrmgrNs, 0)
changeAddr, err = w.newChangeAddress(
addrmgrNs, 0, changeKeyScope,
)
} else {
changeAddr, err = w.newChangeAddress(addrmgrNs, account)
changeAddr, err = w.newChangeAddress(
addrmgrNs, account, changeKeyScope,
)
}
if err != nil {
return nil, err

View file

@ -2946,7 +2946,7 @@ func (w *Wallet) NewChangeAddress(account uint32,
err = walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
var err error
addr, err = w.newChangeAddress(addrmgrNs, account)
addr, err = w.newChangeAddress(addrmgrNs, account, scope)
return err
})
if err != nil {
@ -2968,14 +2968,9 @@ func (w *Wallet) NewChangeAddress(account uint32,
// method in order to detect when an on-chain transaction pays to the address
// being created.
func (w *Wallet) newChangeAddress(addrmgrNs walletdb.ReadWriteBucket,
account uint32) (btcutil.Address, error) {
account uint32, scope waddrmgr.KeyScope) (btcutil.Address, error) {
// As we're making a change address, we'll fetch the type of manager
// that is able to make p2wkh output as they're the most efficient.
scopes := w.Manager.ScopesForExternalAddrType(
waddrmgr.WitnessPubKey,
)
manager, err := w.Manager.FetchScopedKeyManager(scopes[0])
manager, err := w.Manager.FetchScopedKeyManager(scope)
if err != nil {
return nil, err
}