import: add support for watchonly addresses/pubkeys [WIP] #23

Closed
roylee17 wants to merge 1 commit from support-imported-watchonly-account into master
4 changed files with 67 additions and 22 deletions

View file

@ -920,6 +920,9 @@ func getReceivedByAccount(icmd interface{}, w *wallet.Wallet) (interface{}, erro
return nil, err
}
acctIndex := int(account)
if account == waddrmgr.ImportedWatchonlyAddrAccount {
acctIndex = len(results) - 2
}
if account == waddrmgr.ImportedAddrAccount {
acctIndex = len(results) - 1
}
@ -1692,7 +1695,7 @@ func sendToAddress(icmd interface{}, w *wallet.Wallet) (interface{}, error) {
}
// sendtoaddress always spends from the default account, this matches bitcoind
return sendPairs(w, pairs, waddrmgr.KeyScopeBIP0044, waddrmgr.DefaultAccountNum, 1,
return sendPairs(w, pairs, waddrmgr.KeyScopeBIP0084, waddrmgr.DefaultAccountNum, 1,
txrules.DefaultRelayFeePerKb)
}

View file

@ -102,7 +102,8 @@ func isReservedAccountName(name string) bool {
// isReservedAccountNum returns true if the account number is reserved.
// Reserved accounts may not be renamed.
func isReservedAccountNum(acct uint32) bool {
return acct == ImportedAddrAccount
return acct == ImportedAddrAccount ||
acct == ImportedWatchonlyAddrAccount
}
// ScryptOptions is used to hold the scrypt parameters needed when deriving new
@ -428,6 +429,7 @@ func (m *Manager) IsWatchOnlyAccount(ns walletdb.ReadBucket, keyScope KeyScope,
if account == ImportedAddrAccount {
return false, nil
}
if account == ImportedWatchonlyAddrAccount {
return true, nil
}
@ -1785,10 +1787,23 @@ func createManagerKeyScope(ns walletdb.ReadWriteBucket,
return err
}
return putDefaultAccountInfo(
err = putDefaultAccountInfo(
ns, &scope, ImportedAddrAccount, nil, nil, 0, 0,
ImportedAddrAccountName,
)
if err != nil {
return err
}
err = putDefaultAccountInfo(
ns, &scope, ImportedWatchonlyAddrAccount, nil, nil, 0, 0,
ImportedWatchonlyAddrAccountName,
)
if err != nil {
return err
}
return nil
}
// Create creates a new address manager in the given namespace.

View file

@ -206,6 +206,13 @@ var (
ImportedDerivationPath = DerivationPath{
InternalAccount: ImportedAddrAccount,
}
// ImportedWatchonlyDerivationPath is the derivation path for an
// imported address. The Account, Branch, and Index members are not
// known, so they are left blank.
ImportedWatchonlyDerivationPath = DerivationPath{
InternalAccount: ImportedWatchonlyAddrAccount,
}
)
// ScopedKeyManager is a sub key manager under the main root key manager. The
@ -529,17 +536,47 @@ func (s *ScopedKeyManager) AccountProperties(ns walletdb.ReadBucket,
}
// Until keys can be imported into any account, special handling is
// required for the imported account.
// required for the imported accounts.
//
// loadAccountInfo errors when using it on the imported account since
// the accountInfo struct is filled with a BIP0044 account's extended
// keys, and the imported accounts has none.
//
// Since only the imported account allows imports currently, the number
// Since only the imported accounts allow imports currently, the number
// of imported keys for any other account is zero, and since the
// imported account cannot contain non-imported keys, the external and
// internal key counts for it are zero.
if account != ImportedAddrAccount {
if account == ImportedAddrAccount {
props.AccountName = ImportedAddrAccountName // reserved, nonchangable
props.IsWatchOnly = false
// Could be more efficient if this was tracked by the db.
var importedKeyCount uint32
count := func(interface{}) error {
importedKeyCount++
return nil
}
err := forEachAccountAddress(ns, &s.scope, ImportedAddrAccount, count)
if err != nil {
return nil, err
}
props.ImportedKeyCount = importedKeyCount
} else if account == ImportedWatchonlyAddrAccount {
props.AccountName = ImportedWatchonlyAddrAccountName // reserved, nonchangable
props.IsWatchOnly = true
// Could be more efficient if this was tracked by the db.
var importedKeyCount uint32
count := func(interface{}) error {
importedKeyCount++
return nil
}
err := forEachAccountAddress(ns, &s.scope, ImportedWatchonlyAddrAccount, count)
if err != nil {
return nil, err
}
props.ImportedKeyCount = importedKeyCount
} else {
acctInfo, err := s.loadAccountInfo(ns, account)
if err != nil {
return nil, err
@ -575,21 +612,6 @@ func (s *ScopedKeyManager) AccountProperties(ns walletdb.ReadBucket,
"account public key: %v", err)
}
}
} else {
props.AccountName = ImportedAddrAccountName // reserved, nonchangable
props.IsWatchOnly = s.rootManager.WatchOnly()
// Could be more efficient if this was tracked by the db.
var importedKeyCount uint32
count := func(interface{}) error {
importedKeyCount++
return nil
}
err := forEachAccountAddress(ns, &s.scope, ImportedAddrAccount, count)
if err != nil {
return nil, err
}
props.ImportedKeyCount = importedKeyCount
}
return props, nil

View file

@ -2457,8 +2457,8 @@ func (w *Wallet) AccountBalances(scope waddrmgr.KeyScope,
results[i].AccountNumber = uint32(i)
results[i].AccountName = accountName
}
results[len(results)-2].AccountName = waddrmgr.ImportedAddrAccountName
results[len(results)-1].AccountNumber = waddrmgr.ImportedAddrAccount
results[len(results)-1].AccountName = waddrmgr.ImportedAddrAccountName
// Fetch all unspent outputs, and iterate over them tallying each
// account's balance where the output script pays to an account address
@ -2488,6 +2488,8 @@ func (w *Wallet) AccountBalances(scope waddrmgr.KeyScope,
continue
}
switch {
case outputAcct == waddrmgr.ImportedWatchonlyAddrAccount:
results[len(results)-2].AccountBalance += output.Amount
case outputAcct == waddrmgr.ImportedAddrAccount:
results[len(results)-1].AccountBalance += output.Amount
case outputAcct > lastAcct:
@ -3080,6 +3082,9 @@ func (w *Wallet) TotalReceivedForAccounts(scope waddrmgr.KeyScope,
}
if err == nil {
acctIndex := int(outputAcct)
if outputAcct == waddrmgr.ImportedWatchonlyAddrAccount {
acctIndex = len(results) - 2
}
if outputAcct == waddrmgr.ImportedAddrAccount {
acctIndex = len(results) - 1
}