Merge pull request #764 from guggero/import-key-scope

wallet: watch-only account import improvements
This commit is contained in:
Olaoluwa Osuntokun 2021-09-16 14:30:31 -07:00 committed by GitHub
commit d0868cb9dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 58 additions and 6 deletions

View file

@ -204,6 +204,30 @@ func (w *Wallet) ImportAccount(name string, accountPubKey *hdkeychain.ExtendedKe
return accountProps, err
}
// ImportAccountWithScope imports an account backed by an account extended
// public key for a specific key scope which is known in advance.
// The master key fingerprint denotes the fingerprint of the root key
// corresponding to the account public key (also known as the key with
// derivation path m/). This may be required by some hardware wallets for proper
// identification and signing.
func (w *Wallet) ImportAccountWithScope(name string,
accountPubKey *hdkeychain.ExtendedKey, masterKeyFingerprint uint32,
keyScope waddrmgr.KeyScope, addrSchema waddrmgr.ScopeAddrSchema) (
*waddrmgr.AccountProperties, error) {
var accountProps *waddrmgr.AccountProperties
err := walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
var err error
accountProps, err = w.importAccountScope(
ns, name, accountPubKey, masterKeyFingerprint, keyScope,
&addrSchema,
)
return err
})
return accountProps, err
}
// importAccount is the internal implementation of ImportAccount -- one should
// reference its documentation for this method.
func (w *Wallet) importAccount(ns walletdb.ReadWriteBucket, name string,
@ -221,9 +245,27 @@ func (w *Wallet) importAccount(ns walletdb.ReadWriteBucket, name string,
if err != nil {
return nil, err
}
return w.importAccountScope(
ns, name, accountPubKey, masterKeyFingerprint, keyScope,
addrSchema,
)
}
// importAccountScope imports a watch-only account for a given scope.
func (w *Wallet) importAccountScope(ns walletdb.ReadWriteBucket, name string,
accountPubKey *hdkeychain.ExtendedKey, masterKeyFingerprint uint32,
keyScope waddrmgr.KeyScope, addrSchema *waddrmgr.ScopeAddrSchema) (
*waddrmgr.AccountProperties, error) {
scopedMgr, err := w.Manager.FetchScopedKeyManager(keyScope)
if err != nil {
return nil, err
scopedMgr, err = w.Manager.NewScopedKeyManager(
ns, keyScope, *addrSchema,
)
if err != nil {
return nil, err
}
}
account, err := scopedMgr.NewAccountWatchingOnly(

View file

@ -1169,17 +1169,27 @@ out:
for {
select {
case txr := <-w.createTxRequests:
heldUnlock, err := w.holdUnlock()
if err != nil {
txr.resp <- createTxResponse{nil, err}
continue
// If the wallet can be locked because it contains
// private key material, we need to prevent it from
// doing so while we are assembling the transaction.
release := func() {}
if !w.Manager.WatchOnly() {
heldUnlock, err := w.holdUnlock()
if err != nil {
txr.resp <- createTxResponse{nil, err}
continue
}
release = heldUnlock.release
}
tx, err := w.txToOutputs(
txr.outputs, txr.keyScope, txr.account,
txr.minconf, txr.feeSatPerKB,
txr.coinSelectionStrategy, txr.dryRun,
)
heldUnlock.release()
release()
txr.resp <- createTxResponse{tx, err}
case <-quit:
break out