Bugfix: Unspendable inputs handling
authorCryptoManiac <balthazar@yandex.ru>
Fri, 25 Jul 2014 17:51:11 +0000 (21:51 +0400)
committerCryptoManiac <balthazar@yandex.ru>
Fri, 25 Jul 2014 17:51:11 +0000 (21:51 +0400)
* Use script matching instead of destination matching to prevent possible compatibility issues;
* Split GetBalance, GetAvailableCredit and GetCredit to regular and watch-only counterparts.

16 files changed:
src/keystore.cpp
src/keystore.h
src/qt/overviewpage.cpp
src/qt/sendcoinsdialog.cpp
src/qt/transactiondesc.cpp
src/qt/transactionrecord.cpp
src/qt/walletmodel.cpp
src/qt/walletmodel.h
src/rpcdump.cpp
src/rpcwallet.cpp
src/script.cpp
src/script.h
src/wallet.cpp
src/wallet.h
src/walletdb.cpp
src/walletdb.h

index 089f2d5..b4783ec 100644 (file)
@@ -63,20 +63,23 @@ bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut)
     return false;
 }
 
-bool CBasicKeyStore::AddWatchOnly(const CTxDestination &dest)
+bool CBasicKeyStore::AddWatchOnly(const CScript &dest)
 {
     LOCK(cs_KeyStore);
-    CKeyID keyID;
-    CBitcoinAddress(dest).GetKeyID(keyID);
 
-    if (HaveKey(keyID))
-        return false;
+    CTxDestination address;
+    if (ExtractDestination(dest, address)) {
+        CKeyID keyID;
+        CBitcoinAddress(address).GetKeyID(keyID);
+        if (HaveKey(keyID))
+            return false;
+    }
 
     setWatchOnly.insert(dest);
     return true;
 }
 
-bool CBasicKeyStore::HaveWatchOnly(const CTxDestination &dest) const
+bool CBasicKeyStore::HaveWatchOnly(const CScript &dest) const
 {
     LOCK(cs_KeyStore);
     return setWatchOnly.count(dest) > 0;
@@ -145,8 +148,10 @@ bool CCryptoKeyStore::AddKey(const CKey& key)
     {
         LOCK(cs_KeyStore);
 
-        CTxDestination address = key.GetPubKey().GetID();
-        if (HaveWatchOnly(address))
+        CScript script;
+        script.SetDestination(key.GetPubKey().GetID());
+
+        if (HaveWatchOnly(script))
             return false;
 
         if (!IsCrypted())
index 9e5674f..34d94ef 100644 (file)
@@ -51,8 +51,8 @@ public:
     virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const =0;
 
     // Support for Watch-only addresses
-    virtual bool AddWatchOnly(const CTxDestination &dest) =0;
-    virtual bool HaveWatchOnly(const CTxDestination &dest) const =0;
+    virtual bool AddWatchOnly(const CScript &dest) =0;
+    virtual bool HaveWatchOnly(const CScript &dest) const =0;
 
     virtual bool GetSecret(const CKeyID &address, CSecret& vchSecret, bool &fCompressed) const
     {
@@ -66,7 +66,7 @@ public:
 
 typedef std::map<CKeyID, std::pair<CSecret, bool> > KeyMap;
 typedef std::map<CScriptID, CScript > ScriptMap;
-typedef std::set<CTxDestination> WatchOnlySet;
+typedef std::set<CScript> WatchOnlySet;
 
 /** Basic key store, that keeps keys in an address->secret map */
 class CBasicKeyStore : public CKeyStore
@@ -118,8 +118,8 @@ public:
     virtual bool HaveCScript(const CScriptID &hash) const;
     virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const;
 
-    virtual bool AddWatchOnly(const CTxDestination &dest);
-    virtual bool HaveWatchOnly(const CTxDestination &dest) const;
+    virtual bool AddWatchOnly(const CScript &dest);
+    virtual bool HaveWatchOnly(const CScript &dest) const;
 };
 
 typedef std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char> > > CryptedKeyMap;
index d2cd9ce..898f940 100644 (file)
@@ -179,9 +179,7 @@ void OverviewPage::setModel(WalletModel *model)
         ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
 
         // Keep up to date with wallet
-        qint64 nTotal=0, nWatchOnly=0;
-        model->getBalance(nTotal, nWatchOnly);
-        setBalance(nTotal, nWatchOnly, model->getStake(), model->getUnconfirmedBalance(), model->getImmatureBalance());
+        setBalance(model->getBalance(), model->getBalanceWatchOnly(), model->getStake(), model->getUnconfirmedBalance(), model->getImmatureBalance());
         connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64, qint64, qint64)));
 
         setNumTransactions(model->getNumTransactions());
index 34ad759..71ac191 100644 (file)
@@ -93,9 +93,7 @@ void SendCoinsDialog::setModel(WalletModel *model)
     }
     if(model && model->getOptionsModel())
     {
-        qint64 nTotal=0, nWatchOnly=0;
-        model->getBalance(nTotal, nWatchOnly);
-        setBalance(nTotal, nWatchOnly, model->getStake(), model->getUnconfirmedBalance(), model->getImmatureBalance());
+        setBalance(model->getBalance(), model->getBalanceWatchOnly(), model->getStake(), model->getUnconfirmedBalance(), model->getImmatureBalance());
         connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64, qint64, qint64)));
         connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
 
@@ -377,9 +375,7 @@ void SendCoinsDialog::updateDisplayUnit()
     if(model && model->getOptionsModel())
     {
         // Update labelBalance with the current balance and the current unit
-        qint64 total=0, watchOnly=0;
-        model->getBalance(total, watchOnly);
-        ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), total - watchOnly));
+        ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->getBalance() - model->getBalanceWatchOnly()));
     }
 }
 
index 4598e6e..8f1cc0f 100644 (file)
@@ -40,7 +40,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
         strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
 
         int64 nTime = wtx.GetTxTime();
-        int64 nCredit = wtx.GetCredit(false);
+        int64 nCredit = wtx.GetCredit();
         int64 nDebit = wtx.GetDebit();
         int64 nNet = nCredit - nDebit;
 
@@ -60,7 +60,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
         //
         // From
         //
-        if (wtx.IsCoinBase())
+        if (wtx.IsCoinBase() || wtx.IsCoinStake())
         {
             strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>";
         }
@@ -124,7 +124,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
             //
             int64 nUnmatured = 0;
             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
-                nUnmatured += wallet->GetCredit(txout, false);
+                nUnmatured += wallet->GetCredit(txout);
             strHTML += "<b>" + tr("Credit") + ":</b> ";
             if (wtx.IsInMainChain())
                 strHTML += BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
@@ -199,7 +199,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
                         strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "<br>";
                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
                     if (wallet->IsMine(txout))
-                        strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout, false)) + "<br>";
+                        strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "<br>";
             }
         }
 
@@ -229,7 +229,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
                     strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "<br>";
             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
                 if(wallet->IsMine(txout))
-                    strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout, false)) + "<br>";
+                    strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "<br>";
 
             strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
             strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
index 20c263e..8962d18 100644 (file)
@@ -25,7 +25,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
 {
     QList<TransactionRecord> parts;
     int64 nTime = wtx.GetTxTime();
-    int64 nCredit = wtx.GetCredit(false,true);
+    int64 nCredit = wtx.GetCredit(true);
     int64 nDebit = wtx.GetDebit();
     int64 nNet = nCredit - nDebit;
     uint256 hash = wtx.GetHash(), hashPrev = 0;
@@ -205,7 +205,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
     // For generated transactions, determine maturity
     if(type == TransactionRecord::Generated)
     {
-        int64 nCredit = wtx.GetCredit(false,true);
+        int64 nCredit = wtx.GetCredit(true);
         if (nCredit == 0)
         {
             status.maturity = TransactionStatus::Immature;
index b14388a..ee8affe 100644 (file)
@@ -41,9 +41,9 @@ qint64 WalletModel::getBalance() const
     return wallet->GetBalance();
 }
 
-void WalletModel::getBalance(qint64 &nTotal, qint64 &nWatchOnly) const
+qint64 WalletModel::getBalanceWatchOnly() const
 {
-    wallet->GetBalance(nTotal, nWatchOnly);
+    return wallet->GetBalanceWatchOnly();
 }
 
 qint64 WalletModel::getUnconfirmedBalance() const
@@ -91,9 +91,7 @@ void WalletModel::pollBalanceChanged()
 
 void WalletModel::checkBalanceChanged()
 {
-    qint64 newBalanceTotal=0, newBalanceWatchOnly=0;
-    getBalance(newBalanceTotal, newBalanceWatchOnly);
-
+    qint64 newBalanceTotal=getBalance(), newBalanceWatchOnly=getBalanceWatchOnly();
     qint64 newStake = getStake();
     qint64 newUnconfirmedBalance = getUnconfirmedBalance();
     qint64 newImmatureBalance = getImmatureBalance();
index 84be464..f155006 100644 (file)
@@ -64,7 +64,7 @@ public:
     TransactionTableModel *getTransactionTableModel();
 
     qint64 getBalance() const;
-    void   getBalance(qint64 &nTotal, qint64 &nWatchOnly) const;
+    qint64 getBalanceWatchOnly() const;
     qint64 getStake() const;
     qint64 getUnconfirmedBalance() const;
     qint64 getImmatureBalance() const;
index fe9df92..138fc00 100644 (file)
@@ -76,13 +76,18 @@ Value importaddress(const Array& params, bool fHelp)
     if (fHelp || params.size() < 1 || params.size() > 3)
         throw runtime_error(
             "importaddress <address> [label] [rescan=true]\n"
-            "Adds an address that can be watched as if it were in your wallet but cannot be used to spend.");
+            "Adds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend.");
 
+    CScript script;
     CBitcoinAddress address(params[0].get_str());
-    if (!address.IsValid())
-        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
-    CTxDestination dest;
-    dest = address.Get();
+    if (address.IsValid()) {
+        script.SetDestination(address.Get());
+    } else if (IsHex(params[0].get_str())) {
+        std::vector<unsigned char> data(ParseHex(params[0].get_str()));
+        script = CScript(data.begin(), data.end());
+    } else {
+        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Novacoin address or script");
+    }
 
     string strLabel = "";
     if (params.size() > 1)
@@ -97,13 +102,15 @@ Value importaddress(const Array& params, bool fHelp)
         LOCK2(cs_main, pwalletMain->cs_wallet);
 
         // Don't throw error in case an address is already there
-        if (pwalletMain->HaveWatchOnly(dest))
+        if (pwalletMain->HaveWatchOnly(script))
             return Value::null;
 
         pwalletMain->MarkDirty();
-        pwalletMain->SetAddressBookName(dest, strLabel);
 
-        if (!pwalletMain->AddWatchOnly(dest))
+        if (address.IsValid())
+            pwalletMain->SetAddressBookName(address.Get(), strLabel);
+
+        if (!pwalletMain->AddWatchOnly(script))
             throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
 
         if (fRescan)
index 5699c4f..3f03145 100644 (file)
@@ -69,15 +69,12 @@ Value getinfo(const Array& params, bool fHelp)
     proxyType proxy;
     GetProxy(NET_IPV4, proxy);
 
-    int64 nTotal = 0, nWatchOnly = 0;
-    pwalletMain->GetBalance(nTotal, nWatchOnly);
-
     Object obj, diff;
     obj.push_back(Pair("version",       FormatFullVersion()));
     obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
     obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
-    obj.push_back(Pair("balance",       ValueFromAmount(nTotal)));
-    obj.push_back(Pair("unspendable",       ValueFromAmount(nWatchOnly)));
+    obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
+    obj.push_back(Pair("unspendable",       ValueFromAmount(pwalletMain->GetBalanceWatchOnly())));
     obj.push_back(Pair("newmint",       ValueFromAmount(pwalletMain->GetNewMint())));
     obj.push_back(Pair("stake",         ValueFromAmount(pwalletMain->GetStake())));
     obj.push_back(Pair("blocks",        (int)nBestHeight));
@@ -726,9 +723,7 @@ Value sendmany(const Array& params, bool fHelp)
     bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
     if (!fCreated)
     {
-        int64 nTotal = 0, nWatchOnly = 0;
-        pwalletMain->GetBalance(nTotal, nWatchOnly);
-
+        int64 nTotal = pwalletMain->GetBalance(), nWatchOnly = pwalletMain->GetBalanceWatchOnly();
         if (totalAmount + nFeeRequired > nTotal - nWatchOnly)
             throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
         throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed");
@@ -1265,7 +1260,7 @@ Value gettransaction(const Array& params, bool fHelp)
 
         TxToJSON(wtx, 0, entry);
 
-        int64 nCredit = wtx.GetCredit(false);
+        int64 nCredit = wtx.GetCredit();
         int64 nDebit = wtx.GetDebit();
         int64 nNet = nCredit - nDebit;
         int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
index e9cf81b..ea44c63 100644 (file)
@@ -1435,13 +1435,11 @@ public:
     bool operator()(const CScriptID &scriptID) const { return keystore->HaveCScript(scriptID); }
 };
 
-isminetype IsMine(const CKeyStore &keystore, const CTxDestination &dest)
+isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest)
 {
-    if (boost::apply_visitor(CKeyStoreIsMineVisitor(&keystore), dest))
-        return MINE_SPENDABLE;
-    if (keystore.HaveWatchOnly(dest))
-        return MINE_WATCH_ONLY;
-    return MINE_NO;
+    CScript script;
+    script.SetDestination(dest);
+    return IsMine(keystore, script);
 }
 
 isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
@@ -1449,7 +1447,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
     vector<valtype> vSolutions;
     txnouttype whichType;
     if (!Solver(scriptPubKey, whichType, vSolutions)) {
-        if (keystore.HaveWatchOnly(scriptPubKey.GetID()))
+        if (keystore.HaveWatchOnly(scriptPubKey))
             return MINE_WATCH_ONLY;
         return MINE_NO;
     }
@@ -1464,15 +1462,11 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
         keyID = CPubKey(vSolutions[0]).GetID();
         if (keystore.HaveKey(keyID))
             return MINE_SPENDABLE;
-        if (keystore.HaveWatchOnly(keyID))
-            return MINE_WATCH_ONLY;
         break;
     case TX_PUBKEYHASH:
         keyID = CKeyID(uint160(vSolutions[0]));
         if (keystore.HaveKey(keyID))
             return MINE_SPENDABLE;
-        if (keystore.HaveWatchOnly(keyID))
-            return MINE_WATCH_ONLY;
         break;
     case TX_SCRIPTHASH:
     {
@@ -1480,11 +1474,9 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
         CScript subscript;
         if (keystore.GetCScript(scriptID, subscript)) {
             isminetype ret = IsMine(keystore, subscript);
-            if (ret)
+            if (ret == MINE_SPENDABLE)
                 return ret;
         }
-        if (keystore.HaveWatchOnly(scriptID))
-            return MINE_WATCH_ONLY;
         break;
     }
     case TX_MULTISIG:
@@ -1501,7 +1493,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
     }
     }
 
-    if (keystore.HaveWatchOnly(scriptPubKey.GetID()))
+    if (keystore.HaveWatchOnly(scriptPubKey))
         return MINE_WATCH_ONLY;
     return MINE_NO;
 }
index 4492f2a..b8cfbac 100644 (file)
@@ -623,7 +623,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
 int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
 bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
 isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
-isminetype IsMine(const CKeyStore& keystore, const CTxDestination &dest);
+isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest);
 void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys);
 bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
 bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
index fb12cb0..96e84b7 100644 (file)
@@ -102,7 +102,7 @@ bool CWallet::AddCScript(const CScript& redeemScript)
     return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript);
 }
 
-bool CWallet::AddWatchOnly(const CTxDestination &dest)
+bool CWallet::AddWatchOnly(const CScript &dest)
 {
     if (!CCryptoKeyStore::AddWatchOnly(dest))
         return false;
@@ -112,9 +112,8 @@ bool CWallet::AddWatchOnly(const CTxDestination &dest)
     return CWalletDB(strWalletFile).WriteWatchOnly(dest);
 }
 
-bool CWallet::LoadWatchOnly(const CTxDestination &dest)
+bool CWallet::LoadWatchOnly(const CScript &dest)
 {
-    printf("Loaded %s!\n", CBitcoinAddress(dest).ToString().c_str());
     return CCryptoKeyStore::AddWatchOnly(dest);
 }
 
@@ -621,17 +620,19 @@ int64 CWallet::GetDebit(const CTxIn &txin) const
 
 bool CWallet::IsChange(const CTxOut& txout) const
 {
-    CTxDestination address;
-
     // TODO: fix handling of 'change' outputs. The assumption is that any
-    // payment to a TX_PUBKEYHASH that is mine but isn't in the address book
+    // payment to a script that is ours, but isn't in the address book
     // is change. That assumption is likely to break when we implement multisignature
     // wallets that return change back into a multi-signature-protected address;
     // a better way of identifying which outputs are 'the send' and which are
     // 'the change' will need to be implemented (maybe extend CWalletTx to remember
     // which output, if any, was change).
-    if (ExtractDestination(txout.scriptPubKey, address) && ::IsMine(*this, address))
+    if (::IsMine(*this, txout.scriptPubKey))
     {
+        CTxDestination address;
+        if (!ExtractDestination(txout.scriptPubKey, address))
+            return true;
+
         LOCK(cs_wallet);
         if (!mapAddressBook.count(address))
             return true;
@@ -1034,26 +1035,27 @@ int64 CWallet::GetBalance() const
         {
             const CWalletTx* pcoin = &(*it).second;
             if (pcoin->IsTrusted())
-                nTotal += pcoin->GetAvailableCredit(false);
+                nTotal += pcoin->GetAvailableCredit();
         }
     }
 
     return nTotal;
 }
 
-void CWallet::GetBalance(int64 &nTotal, int64 &nWatchOnly) const
+int64 CWallet::GetBalanceWatchOnly() const
 {
+    int64 nTotal = 0;
     {
         LOCK(cs_wallet);
         for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
         {
             const CWalletTx* pcoin = &(*it).second;
-            if (pcoin->IsTrusted()) {
-                nWatchOnly += pcoin->GetAvailableCredit(true);
-                nTotal += pcoin->GetAvailableCredit(false);
-            }
+            if (pcoin->IsTrusted())
+                nTotal += pcoin->GetAvailableCreditWatchOnly();
         }
     }
+
+    return nTotal;
 }
 
 int64 CWallet::GetUnconfirmedBalance() const
index cb07d39..a2f9fca 100644 (file)
@@ -33,7 +33,6 @@ enum WalletFeature
 
     FEATURE_WALLETCRYPT = 40000, // wallet encryption
     FEATURE_COMPRPUBKEY = 60000, // compressed public keys
-
     FEATURE_LATEST = 60000
 };
 
@@ -150,9 +149,9 @@ public:
     bool LoadCScript(const CScript& redeemScript) { return CCryptoKeyStore::AddCScript(redeemScript); }
 
     // Adds a watch-only address to the store, and saves it to disk.
-    bool AddWatchOnly(const CTxDestination &dest);
+    bool AddWatchOnly(const CScript &dest);
     // Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)
-    bool LoadWatchOnly(const CTxDestination &dest);
+    bool LoadWatchOnly(const CScript &dest);
 
     bool Unlock(const SecureString& strWalletPassphrase);
     bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
@@ -185,7 +184,7 @@ public:
     void ReacceptWalletTransactions();
     void ResendWalletTransactions();
     int64 GetBalance() const;
-    void GetBalance(int64 &nTotal, int64 &nWatchOnly) const;
+    int64 GetBalanceWatchOnly() const;
     int64 GetUnconfirmedBalance() const;
     int64 GetImmatureBalance() const;
     int64 GetStake() const;
@@ -220,12 +219,19 @@ public:
     {
         return ::IsMine(*this, txout.scriptPubKey);
     }
-    int64 GetCredit(const CTxOut& txout, bool fWatchOnly=false) const
+    int64 GetCredit(const CTxOut& txout) const
     {
         if (!MoneyRange(txout.nValue))
             throw std::runtime_error("CWallet::GetCredit() : value out of range");
         isminetype ismine = IsMine(txout);
-        if (fWatchOnly && ismine != MINE_WATCH_ONLY)
+        return (ismine != MINE_NO ? txout.nValue : 0);
+    }
+    int64 GetCreditWatchOnly(const CTxOut& txout) const
+    {
+        if (!MoneyRange(txout.nValue))
+            throw std::runtime_error("CWallet::GetCreditWatchOnly() : value out of range");
+        isminetype ismine = IsMine(txout);
+        if (ismine != MINE_WATCH_ONLY)
             return 0;
         return (ismine != MINE_NO ? txout.nValue : 0);
     }
@@ -258,14 +264,23 @@ public:
         }
         return nDebit;
     }
-    int64 GetCredit(const CTransaction& tx, bool fWatchOnly=true) const
+    int64 GetCredit(const CTransaction& tx) const
     {
         int64 nCredit = 0;
         BOOST_FOREACH(const CTxOut& txout, tx.vout)
         {
-            if (!fWatchOnly || (fWatchOnly && IsMine(txout) == MINE_WATCH_ONLY))
-                nCredit += GetCredit(txout);
-
+            nCredit += GetCredit(txout);
+            if (!MoneyRange(nCredit))
+                throw std::runtime_error("CWallet::GetCredit() : value out of range");
+        }
+        return nCredit;
+    }
+    int64 GetCreditWatchOnly(const CTransaction& tx) const
+    {
+        int64 nCredit = 0;
+        BOOST_FOREACH(const CTxOut& txout, tx.vout)
+        {
+            nCredit += GetCreditWatchOnly(txout);
             if (!MoneyRange(nCredit))
                 throw std::runtime_error("CWallet::GetCredit() : value out of range");
         }
@@ -601,7 +616,7 @@ public:
         return nDebitCached;
     }
 
-    int64 GetCredit(bool fWatchOnly, bool fUseCache=true) const
+    int64 GetCredit(bool fUseCache=true) const
     {
         // Must wait until coinbase is safely deep enough in the chain before valuing it
         if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0)
@@ -609,35 +624,23 @@ public:
 
         // GetBalance can assume transactions in mapWallet won't change
         if (fUseCache) {
-            if (fWatchOnly && fCreditCached)
-                return nWatchOnlyCreditCached;
             if (fCreditCached)
                 return nCreditCached;
         }
 
-        if (fWatchOnly) {
-            nWatchOnlyCreditCached = pwallet->GetCredit(*this, true);
-            fWatchOnlyCreditCached = true;
-
-            return nWatchOnlyCreditCached;
-        }
-
         nCreditCached = pwallet->GetCredit(*this);
         fCreditCached = true;
 
         return nCreditCached;
     }
 
-    int64 GetAvailableCredit(bool fWatchOnly, bool fUseCache=true) const
+    int64 GetAvailableCredit(bool fUseCache=true) const
     {
         // Must wait until coinbase is safely deep enough in the chain before valuing it
         if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0)
             return 0;
 
         if (fUseCache) {
-            if (fWatchOnly && fAvailableWatchOnlyCreditCached)
-                return nAvailableWatchOnlyCreditCached;
-
             if (fAvailableCreditCached)
                 return nAvailableCreditCached;
         }
@@ -648,19 +651,62 @@ public:
             if (!IsSpent(i))
             {
                 const CTxOut &txout = vout[i];
-                nCredit += pwallet->GetCredit(txout, fWatchOnly);
+                nCredit += pwallet->GetCredit(txout);
                 if (!MoneyRange(nCredit))
                     throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
             }
         }
 
-        if (fWatchOnly) {
-            nAvailableWatchOnlyCreditCached = nCredit;
-            fAvailableWatchOnlyCreditCached = true;
-        } else {
-            nAvailableCreditCached = nCredit;
-            fAvailableCreditCached = true;
+        nAvailableCreditCached = nCredit;
+        fAvailableCreditCached = true;
+
+        return nCredit;
+    }
+
+    int64 GetCreditWatchOnly(bool fUseCache=true) const
+    {
+        // Must wait until coinbase is safely deep enough in the chain before valuing it
+        if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0)
+            return 0;
+
+        // GetBalance can assume transactions in mapWallet won't change
+        if (fUseCache) {
+            if (fWatchOnlyCreditCached)
+                return nWatchOnlyCreditCached;
+        }
+
+        nWatchOnlyCreditCached = pwallet->GetCreditWatchOnly(*this);
+        fWatchOnlyCreditCached = true;
+
+        return nWatchOnlyCreditCached;
+    }
+
+    int64 GetAvailableCreditWatchOnly(bool fUseCache=true) const
+    {
+        // Must wait until coinbase is safely deep enough in the chain before valuing it
+        if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0)
+            return 0;
+
+        if (fUseCache) {
+            if (fAvailableWatchOnlyCreditCached)
+                return nAvailableWatchOnlyCreditCached;
+        }
+
+        int64 nCredit = 0;
+        for (unsigned int i = 0; i < vout.size(); i++)
+        {
+            if (!IsSpent(i))
+            {
+                const CTxOut &txout = vout[i];
+                nCredit += pwallet->GetCreditWatchOnly(txout);
+                if (!MoneyRange(nCredit))
+                    throw std::runtime_error("CWalletTx::GetAvailableCreditWatchOnly() : value out of range");
+            }
         }
+
+        nAvailableWatchOnlyCreditCached = nCredit;
+        fAvailableWatchOnlyCreditCached = true;
+
         return nCredit;
     }
 
index 1519ff3..32dc595 100644 (file)
@@ -287,14 +287,14 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
                     wss.fAnyUnordered = true;
             }
         }
-        else if (strType == "watch")
+        else if (strType == "watchs")
         {
-            std::string strAddress;
-            ssKey >> strAddress;
+            CScript script;
+            ssKey >> script;
             char fYes;
             ssValue >> fYes;
             if (fYes == '1')
-                pwallet->LoadWatchOnly(CBitcoinAddress(strAddress).Get());
+                pwallet->LoadWatchOnly(script);
 
             // Watch-only addresses have no birthday information for now,
             // so set the wallet birthday to the beginning of time.
index e9d6404..31d6463 100644 (file)
@@ -123,10 +123,10 @@ public:
         return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false);
     }
 
-    bool WriteWatchOnly(const CTxDestination &dest)
+    bool WriteWatchOnly(const CScript &dest)
     {
         nWalletDBUpdated++;
-        return Write(std::make_pair(std::string("watch"), CBitcoinAddress(dest).ToString()), '1');
+        return Write(std::make_pair(std::string("watchs"), dest), '1');
     }
 
     bool WriteBestBlock(const CBlockLocator& locator)