mirror of
https://github.com/LBRYFoundation/lbcwallet.git
synced 2025-08-23 17:47:29 +00:00
wallet: prevent input signing for transactions on watch-only accounts
Watch-only accounts don't have any type of private key information stored, so we avoid populating input signatures in those cases.
This commit is contained in:
parent
2301069644
commit
f5845dfb42
4 changed files with 97 additions and 6 deletions
|
@ -405,6 +405,29 @@ func (m *Manager) watchOnly() bool {
|
||||||
return m.watchingOnly
|
return m.watchingOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsWatchOnlyAccount determines if the account with the given key scope is set
|
||||||
|
// up as watch-only.
|
||||||
|
func (m *Manager) IsWatchOnlyAccount(ns walletdb.ReadBucket, keyScope KeyScope,
|
||||||
|
account uint32) (bool, error) {
|
||||||
|
|
||||||
|
if m.WatchOnly() {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume the default imported account has no private keys.
|
||||||
|
//
|
||||||
|
// TODO: Actually check whether it does.
|
||||||
|
if account == ImportedAddrAccount {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
scopedMgr, err := m.FetchScopedKeyManager(keyScope)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return scopedMgr.IsWatchOnlyAccount(ns, account)
|
||||||
|
}
|
||||||
|
|
||||||
// lock performs a best try effort to remove and zero all secret keys associated
|
// lock performs a best try effort to remove and zero all secret keys associated
|
||||||
// with the address manager.
|
// with the address manager.
|
||||||
//
|
//
|
||||||
|
|
|
@ -2186,6 +2186,22 @@ func (s *ScopedKeyManager) ForEachInternalActiveAddress(ns walletdb.ReadBucket,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsWatchOnlyAccount determines if the given account belonging to this scoped
|
||||||
|
// manager is set up as watch-only.
|
||||||
|
func (s *ScopedKeyManager) IsWatchOnlyAccount(ns walletdb.ReadBucket,
|
||||||
|
account uint32) (bool, error) {
|
||||||
|
|
||||||
|
s.mtx.Lock()
|
||||||
|
defer s.mtx.Unlock()
|
||||||
|
|
||||||
|
acctInfo, err := s.loadAccountInfo(ns, account)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return acctInfo.acctKeyPriv == nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// cloneKeyWithVersion clones an extended key to use the version corresponding
|
// 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
|
// 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
|
// accounts as they are stored within the database using the legacy BIP-0044
|
||||||
|
|
|
@ -163,6 +163,27 @@ func (w *Wallet) txToOutputs(outputs []*wire.TxOut, keyScope *waddrmgr.KeyScope,
|
||||||
return tx, nil
|
return tx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Before committing the transaction, we'll sign our inputs. If the
|
||||||
|
// inputs are part of a watch-only account, there's no private key
|
||||||
|
// information stored, so we'll skip signing such.
|
||||||
|
var watchOnly bool
|
||||||
|
if keyScope == nil {
|
||||||
|
// If a key scope wasn't specified, then coin selection was
|
||||||
|
// performed from the default wallet accounts (NP2WKH, P2WKH),
|
||||||
|
// so any key scope provided doesn't impact the result of this
|
||||||
|
// call.
|
||||||
|
watchOnly, err = w.Manager.IsWatchOnlyAccount(
|
||||||
|
addrmgrNs, waddrmgr.KeyScopeBIP0084, account,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
watchOnly, err = w.Manager.IsWatchOnlyAccount(
|
||||||
|
addrmgrNs, *keyScope, account,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !watchOnly {
|
||||||
err = tx.AddAllInputScripts(secretSource{w.Manager, addrmgrNs})
|
err = tx.AddAllInputScripts(secretSource{w.Manager, addrmgrNs})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -172,6 +193,7 @@ func (w *Wallet) txToOutputs(outputs []*wire.TxOut, keyScope *waddrmgr.KeyScope,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := dbtx.Commit(); err != nil {
|
if err := dbtx.Commit(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/btcsuite/btcwallet/waddrmgr"
|
"github.com/btcsuite/btcwallet/waddrmgr"
|
||||||
"github.com/btcsuite/btcwallet/wallet/txauthor"
|
"github.com/btcsuite/btcwallet/wallet/txauthor"
|
||||||
"github.com/btcsuite/btcwallet/wallet/txrules"
|
"github.com/btcsuite/btcwallet/wallet/txrules"
|
||||||
|
"github.com/btcsuite/btcwallet/walletdb"
|
||||||
"github.com/btcsuite/btcwallet/wtxmgr"
|
"github.com/btcsuite/btcwallet/wtxmgr"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -313,8 +314,37 @@ func (w *Wallet) FinalizePsbt(keyScope *waddrmgr.KeyScope, account uint32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, we'll sign the input as is, and populate the input
|
// Finally, if the input doesn't belong to a watch-only account,
|
||||||
// with the witness and sigScript (if needed).
|
// then we'll sign it as is, and populate the input with the
|
||||||
|
// witness and sigScript (if needed).
|
||||||
|
watchOnly := false
|
||||||
|
err = walletdb.View(w.db, func(tx walletdb.ReadTx) error {
|
||||||
|
ns := tx.ReadBucket(waddrmgrNamespaceKey)
|
||||||
|
var err error
|
||||||
|
if keyScope == nil {
|
||||||
|
// If a key scope wasn't specified, then coin
|
||||||
|
// selection was performed from the default
|
||||||
|
// wallet accounts (NP2WKH, P2WKH), so any key
|
||||||
|
// scope provided doesn't impact the result of
|
||||||
|
// this call.
|
||||||
|
watchOnly, err = w.Manager.IsWatchOnlyAccount(
|
||||||
|
ns, waddrmgr.KeyScopeBIP0084, account,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
watchOnly, err = w.Manager.IsWatchOnlyAccount(
|
||||||
|
ns, *keyScope, account,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to determine if account is "+
|
||||||
|
"watch-only: %v", err)
|
||||||
|
}
|
||||||
|
if watchOnly {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
witness, sigScript, err := w.ComputeInputScript(
|
witness, sigScript, err := w.ComputeInputScript(
|
||||||
tx, signOutput, idx, sigHashes, in.SighashType, nil,
|
tx, signOutput, idx, sigHashes, in.SighashType, nil,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Add table
Reference in a new issue