From 4ffa25aa74b459ff189a74b8cb40f1c07e34e36c Mon Sep 17 00:00:00 2001 From: CryptoManiac Date: Sat, 26 Jul 2014 17:05:19 +0400 Subject: [PATCH] Implement IsMine filter --- src/qt/transactiondesc.cpp | 14 ++-- src/qt/transactionrecord.cpp | 26 ++++++- src/qt/walletmodel.cpp | 2 +- src/rpcwallet.cpp | 75 ++++++++++++----- src/script.h | 3 + src/wallet.cpp | 106 ++++++++++++++++++------ src/wallet.h | 186 +++++++++++++++++++++++------------------ 7 files changed, 272 insertions(+), 140 deletions(-) diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 8f1cc0f..f6d9c8c 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -40,8 +40,8 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) strHTML += ""; int64 nTime = wtx.GetTxTime(); - int64 nCredit = wtx.GetCredit(); - int64 nDebit = wtx.GetDebit(); + int64 nCredit = wtx.GetCredit(MINE_ALL); + int64 nDebit = wtx.GetDebit(MINE_ALL); int64 nNet = nCredit - nDebit; strHTML += "" + tr("Status") + ": " + FormatTxStatus(wtx); @@ -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); + nUnmatured += wallet->GetCredit(txout, MINE_ALL); strHTML += "" + tr("Credit") + ": "; if (wtx.IsInMainChain()) strHTML += BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")"; @@ -196,10 +196,10 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) // BOOST_FOREACH(const CTxIn& txin, wtx.vin) if (wallet->IsMine(txin)) - strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "
"; + strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin, MINE_ALL)) + "
"; BOOST_FOREACH(const CTxOut& txout, wtx.vout) if (wallet->IsMine(txout)) - strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "
"; + strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout, MINE_ALL)) + "
"; } } @@ -226,10 +226,10 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) strHTML += "

" + tr("Debug information") + "

"; BOOST_FOREACH(const CTxIn& txin, wtx.vin) if(wallet->IsMine(txin)) - strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "
"; + strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin, MINE_ALL)) + "
"; BOOST_FOREACH(const CTxOut& txout, wtx.vout) if(wallet->IsMine(txout)) - strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "
"; + strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout, MINE_ALL)) + "
"; strHTML += "
" + tr("Transaction") + ":
"; strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true); diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 8962d18..bd6155b 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -26,7 +26,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet * QList parts; int64 nTime = wtx.GetTxTime(); int64 nCredit = wtx.GetCredit(true); - int64 nDebit = wtx.GetDebit(); + int64 nDebit = wtx.GetDebit(MINE_ALL); int64 nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(), hashPrev = 0; std::map mapValue = wtx.mapValue; @@ -205,6 +205,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx) // For generated transactions, determine maturity if(type == TransactionRecord::Generated) { +/* int64 nCredit = wtx.GetCredit(true); if (nCredit == 0) { @@ -227,6 +228,29 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx) { status.maturity = TransactionStatus::Mature; } +*/ + + if (wtx.GetBlocksToMaturity() > 0) + { + status.maturity = TransactionStatus::Immature; + + if (wtx.IsInMainChain()) + { + status.matures_in = wtx.GetBlocksToMaturity(); + + // Check if the block was requested by anyone + if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) + status.maturity = TransactionStatus::MaturesWarning; + } + else + { + status.maturity = TransactionStatus::NotAccepted; + } + } + else + { + status.maturity = TransactionStatus::Mature; + } } } diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index ee8affe..ad954de 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -43,7 +43,7 @@ qint64 WalletModel::getBalance() const qint64 WalletModel::getBalanceWatchOnly() const { - return wallet->GetBalanceWatchOnly(); + return wallet->GetWatchOnlyBalance(); } qint64 WalletModel::getUnconfirmedBalance() const diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 3f03145..8558036 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -74,7 +74,7 @@ Value getinfo(const Array& params, bool fHelp) obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION)); obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); - obj.push_back(Pair("unspendable", ValueFromAmount(pwalletMain->GetBalanceWatchOnly()))); + obj.push_back(Pair("unspendable", ValueFromAmount(pwalletMain->GetWatchOnlyBalance()))); obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint()))); obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake()))); obj.push_back(Pair("blocks", (int)nBestHeight)); @@ -481,7 +481,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp) } -int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth) +int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter) { int64 nBalance = 0; @@ -493,7 +493,7 @@ int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinD continue; int64 nGenerated, nReceived, nSent, nFee; - wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee); + wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee, filter); if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth) nBalance += nReceived; @@ -506,10 +506,10 @@ int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinD return nBalance; } -int64 GetAccountBalance(const string& strAccount, int nMinDepth) +int64 GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter) { CWalletDB walletdb(pwalletMain->strWalletFile); - return GetAccountBalance(walletdb, strAccount, nMinDepth); + return GetAccountBalance(walletdb, strAccount, nMinDepth, filter); } @@ -517,9 +517,10 @@ Value getbalance(const Array& params, bool fHelp) { if (fHelp || params.size() > 2) throw runtime_error( - "getbalance [account] [minconf=1]\n" + "getbalance [account] [minconf=1] [watchonly=0]\n" "If [account] is not specified, returns the server's total available balance.\n" - "If [account] is specified, returns the balance in the account."); + "If [account] is specified, returns the balance in the account.\n" + "if [includeWatchonly] is specified, include balance in watchonly addresses (see 'importaddress')."); if (params.size() == 0) return ValueFromAmount(pwalletMain->GetBalance()); @@ -527,6 +528,10 @@ Value getbalance(const Array& params, bool fHelp) int nMinDepth = 1; if (params.size() > 1) nMinDepth = params[1].get_int(); + isminefilter filter = MINE_SPENDABLE; + if(params.size() > 2) + if(params[2].get_bool()) + filter = filter | MINE_WATCH_ONLY; if (params[0].get_str() == "*") { // Calculate total balance a different way from GetBalance() @@ -545,7 +550,7 @@ Value getbalance(const Array& params, bool fHelp) string strSentAccount; list > listReceived; list > listSent; - wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount); + wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount, filter); if (wtx.GetDepthInMainChain() >= nMinDepth) { BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived) @@ -561,7 +566,7 @@ Value getbalance(const Array& params, bool fHelp) string strAccount = AccountFromValue(params[0]); - int64 nBalance = GetAccountBalance(strAccount, nMinDepth); + int64 nBalance = GetAccountBalance(strAccount, nMinDepth, filter); return ValueFromAmount(nBalance); } @@ -652,7 +657,7 @@ Value sendfrom(const Array& params, bool fHelp) EnsureWalletIsUnlocked(); // Check funds - int64 nBalance = GetAccountBalance(strAccount, nMinDepth); + int64 nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE); if (nAmount > nBalance) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); @@ -713,7 +718,7 @@ Value sendmany(const Array& params, bool fHelp) EnsureWalletIsUnlocked(); // Check funds - int64 nBalance = GetAccountBalance(strAccount, nMinDepth); + int64 nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE); if (totalAmount > nBalance) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); @@ -723,7 +728,7 @@ Value sendmany(const Array& params, bool fHelp) bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired); if (!fCreated) { - int64 nTotal = pwalletMain->GetBalance(), nWatchOnly = pwalletMain->GetBalanceWatchOnly(); + int64 nTotal = pwalletMain->GetBalance(), nWatchOnly = pwalletMain->GetWatchOnlyBalance(); if (totalAmount + nFeeRequired > nTotal - nWatchOnly) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed"); @@ -966,16 +971,17 @@ static void MaybePushAddress(Object & entry, const CTxDestination &dest) entry.push_back(Pair("address", addr.ToString())); } -void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret) +void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter) { int64 nGeneratedImmature, nGeneratedMature, nFee; string strSentAccount; list > listReceived; list > listSent; - wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount); + wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, filter); bool fAllAccounts = (strAccount == string("*")); + bool involvesWatchonly = wtx.IsFromMe(MINE_WATCH_ONLY); // Generated blocks assigned to account "" if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == "")) @@ -1004,6 +1010,8 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe { Object entry; entry.push_back(Pair("account", strSentAccount)); + if(involvesWatchonly || (::IsMine(*pwalletMain, s.first) & MINE_WATCH_ONLY)) + entry.push_back(Pair("involvesWatchonly", true)); MaybePushAddress(entry, s.first); if (wtx.GetDepthInMainChain() < 0) { @@ -1032,6 +1040,8 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe { Object entry; entry.push_back(Pair("account", account)); + if(involvesWatchonly || (::IsMine(*pwalletMain, r.first) & MINE_WATCH_ONLY)) + entry.push_back(Pair("involvesWatchonly", true)); MaybePushAddress(entry, r.first); if (wtx.IsCoinBase()) { @@ -1087,6 +1097,11 @@ Value listtransactions(const Array& params, bool fHelp) if (params.size() > 2) nFrom = params[2].get_int(); + isminefilter filter = MINE_SPENDABLE; + if(params.size() > 3) + if(params[3].get_bool()) + filter = filter | MINE_WATCH_ONLY; + if (nCount < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count"); if (nFrom < 0) @@ -1102,7 +1117,7 @@ Value listtransactions(const Array& params, bool fHelp) { CWalletTx *const pwtx = (*it).second.first; if (pwtx != 0) - ListTransactions(*pwtx, strAccount, 0, true, ret); + ListTransactions(*pwtx, strAccount, 0, true, ret, filter); CAccountingEntry *const pacentry = (*it).second.second; if (pacentry != 0) AcentryToJSON(*pacentry, strAccount, ret); @@ -1139,6 +1154,12 @@ Value listaccounts(const Array& params, bool fHelp) if (params.size() > 0) nMinDepth = params[0].get_int(); + isminefilter includeWatchonly = MINE_SPENDABLE; + if(params.size() > 1) + if(params[1].get_bool()) + includeWatchonly = includeWatchonly | MINE_WATCH_ONLY; + + map mapAccountBalances; BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) { if (IsMine(*pwalletMain, entry.first)) // This address belongs to me @@ -1152,7 +1173,7 @@ Value listaccounts(const Array& params, bool fHelp) string strSentAccount; list > listReceived; list > listSent; - wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount); + wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, includeWatchonly); mapAccountBalances[strSentAccount] -= nFee; BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent) mapAccountBalances[strSentAccount] -= s.second; @@ -1188,6 +1209,7 @@ Value listsinceblock(const Array& params, bool fHelp) CBlockIndex *pindex = NULL; int target_confirms = 1; + isminefilter filter = MINE_SPENDABLE; if (params.size() > 0) { @@ -1205,6 +1227,10 @@ Value listsinceblock(const Array& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter"); } + if(params.size() > 2) + if(params[2].get_bool()) + filter = filter | MINE_WATCH_ONLY; + int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1; Array transactions; @@ -1214,7 +1240,7 @@ Value listsinceblock(const Array& params, bool fHelp) CWalletTx tx = (*it).second; if (depth == -1 || tx.GetDepthInMainChain() < depth) - ListTransactions(tx, "*", 0, true, transactions); + ListTransactions(tx, "*", 0, true, transactions, filter); } uint256 lastblock; @@ -1252,6 +1278,11 @@ Value gettransaction(const Array& params, bool fHelp) uint256 hash; hash.SetHex(params[0].get_str()); + isminefilter filter = MINE_SPENDABLE; + if(params.size() > 1) + if(params[1].get_bool()) + filter = filter | MINE_WATCH_ONLY; + Object entry; if (pwalletMain->mapWallet.count(hash)) @@ -1260,19 +1291,19 @@ Value gettransaction(const Array& params, bool fHelp) TxToJSON(wtx, 0, entry); - int64 nCredit = wtx.GetCredit(); - int64 nDebit = wtx.GetDebit(); + int64 nCredit = wtx.GetCredit(filter); + int64 nDebit = wtx.GetDebit(filter); int64 nNet = nCredit - nDebit; - int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0); + int64 nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0); entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee))); - if (wtx.IsFromMe()) + if (wtx.IsFromMe(filter)) entry.push_back(Pair("fee", ValueFromAmount(nFee))); WalletTxToJSON(wtx, entry); Array details; - ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details); + ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details, filter); entry.push_back(Pair("details", details)); } else diff --git a/src/script.h b/src/script.h index b8cfbac..90ea4fa 100644 --- a/src/script.h +++ b/src/script.h @@ -25,8 +25,11 @@ enum isminetype MINE_NO = 0, MINE_WATCH_ONLY = 1, MINE_SPENDABLE = 2, + MINE_ALL = MINE_WATCH_ONLY | MINE_SPENDABLE }; +typedef uint8_t isminefilter; + /** Signature hash types/flags */ enum { diff --git a/src/wallet.cpp b/src/wallet.cpp index 96e84b7..e1dc9eb 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -385,7 +385,7 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx, bool fBlock) printf("WalletUpdateSpent: bad wtx %s\n", wtx.GetHash().ToString().c_str()); else if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n])) { - printf("WalletUpdateSpent found spent coin %snvc %s\n", FormatMoney(wtx.GetCredit(false)).c_str(), wtx.GetHash().ToString().c_str()); + printf("WalletUpdateSpent found spent coin %snvc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); wtx.MarkSpent(txin.prevout.n); wtx.WriteToDisk(); NotifyTransactionChanged(this, txin.prevout.hash, CT_UPDATED); @@ -602,7 +602,7 @@ isminetype CWallet::IsMine(const CTxIn &txin) const return MINE_NO; } -int64 CWallet::GetDebit(const CTxIn &txin) const +int64 CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const { { LOCK(cs_wallet); @@ -611,7 +611,7 @@ int64 CWallet::GetDebit(const CTxIn &txin) const { const CWalletTx& prev = (*mi).second; if (txin.prevout.n < prev.vout.size()) - if (IsMine(prev.vout[txin.prevout.n])) + if (IsMine(prev.vout[txin.prevout.n]) & filter) return prev.vout[txin.prevout.n].nValue; } } @@ -686,7 +686,7 @@ int CWalletTx::GetRequestCount() const } void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list >& listReceived, - list >& listSent, int64& nFee, string& strSentAccount) const + list >& listSent, int64& nFee, string& strSentAccount, const isminefilter& filter) const { nGeneratedImmature = nGeneratedMature = nFee = 0; listReceived.clear(); @@ -696,14 +696,14 @@ void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, l if (IsCoinBase() || IsCoinStake()) { if (GetBlocksToMaturity() > 0) - nGeneratedImmature = pwallet->GetCredit(*this); + nGeneratedImmature = pwallet->GetCredit(*this, filter); else - nGeneratedMature = GetCredit(false); + nGeneratedMature = GetCredit(filter); return; } // Compute fee: - int64 nDebit = GetDebit(); + int64 nDebit = GetDebit(filter); if (nDebit > 0) // debit>0 means we signed/sent this transaction { int64 nValueOut = GetValueOut(); @@ -713,7 +713,7 @@ void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, l // Sent/received. BOOST_FOREACH(const CTxOut& txout, vout) { - bool fIsMine; + isminetype fIsMine = pwallet->IsMine(txout); // Only need to handle txouts if AT LEAST one of these is true: // 1) they debit from us (sent) // 2) the output is to us (received) @@ -722,9 +722,8 @@ void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, l // Don't report 'change' txouts if (pwallet->IsChange(txout)) continue; - fIsMine = pwallet->IsMine(txout); } - else if (!(fIsMine = pwallet->IsMine(txout))) + else if (!(fIsMine & filter)) continue; // In either case, we need to get the destination address @@ -741,14 +740,14 @@ void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, l listSent.push_back(make_pair(address, txout.nValue)); // If we are receiving the output, add it as a "received" entry - if (fIsMine) + if (fIsMine & filter) listReceived.push_back(make_pair(address, txout.nValue)); } } void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived, - int64& nSent, int64& nFee) const + int64& nSent, int64& nFee, const isminefilter& filter) const { nGenerated = nReceived = nSent = nFee = 0; @@ -757,7 +756,7 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, i string strSentAccount; list > listReceived; list > listSent; - GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount); + GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount, filter); if (strAccount == "") nGenerated = allGeneratedMature; @@ -922,7 +921,7 @@ void CWallet::ReacceptWalletTransactions() } if (fUpdated) { - printf("ReacceptWalletTransactions found spent coin %snvc %s\n", FormatMoney(wtx.GetCredit(false)).c_str(), wtx.GetHash().ToString().c_str()); + printf("ReacceptWalletTransactions found spent coin %snvc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); wtx.MarkDirty(); wtx.WriteToDisk(); } @@ -1042,7 +1041,7 @@ int64 CWallet::GetBalance() const return nTotal; } -int64 CWallet::GetBalanceWatchOnly() const +int64 CWallet::GetWatchOnlyBalance() const { int64 nTotal = 0; { @@ -1051,7 +1050,7 @@ int64 CWallet::GetBalanceWatchOnly() const { const CWalletTx* pcoin = &(*it).second; if (pcoin->IsTrusted()) - nTotal += pcoin->GetAvailableCreditWatchOnly(); + nTotal += pcoin->GetAvailableWatchCredit(); } } @@ -1067,7 +1066,22 @@ int64 CWallet::GetUnconfirmedBalance() const { const CWalletTx* pcoin = &(*it).second; if (!pcoin->IsFinal() || !pcoin->IsTrusted()) - nTotal += pcoin->GetAvailableCredit(false); + nTotal += pcoin->GetAvailableCredit(); + } + } + return nTotal; +} + +int64 CWallet::GetUnconfirmedWatchOnlyBalance() const +{ + int64 nTotal = 0; + { + LOCK(cs_wallet); + for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + const CWalletTx* pcoin = &(*it).second; + if (!pcoin->IsFinal() || !pcoin->IsTrusted()) + nTotal += pcoin->GetAvailableWatchCredit(); } } return nTotal; @@ -1080,9 +1094,22 @@ int64 CWallet::GetImmatureBalance() const LOCK(cs_wallet); for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx& pcoin = (*it).second; - if (pcoin.IsCoinBase() && pcoin.GetBlocksToMaturity() > 0 && pcoin.IsInMainChain()) - nTotal += GetCredit(pcoin); + const CWalletTx* pcoin = &(*it).second; + nTotal += pcoin->GetImmatureCredit(); + } + } + return nTotal; +} + +int64 CWallet::GetImmatureWatchOnlyBalance() const +{ + int64 nTotal = 0; + { + LOCK(cs_wallet); + for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + const CWalletTx* pcoin = &(*it).second; + nTotal += pcoin->GetImmatureWatchOnlyCredit(); } } return nTotal; @@ -1188,7 +1215,6 @@ static void ApproximateBestSubset(vectorIsCoinStake() && pcoin->GetBlocksToMaturity() > 0 && pcoin->GetDepthInMainChain() > 0) - nTotal += CWallet::GetCredit(*pcoin); + nTotal += CWallet::GetCredit(*pcoin, MINE_ALL); + } + return nTotal; +} + +int64 CWallet::GetWatchOnlyStake() const +{ + int64 nTotal = 0; + LOCK(cs_wallet); + for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + const CWalletTx* pcoin = &(*it).second; + if (pcoin->IsCoinStake() && pcoin->GetBlocksToMaturity() > 0 && pcoin->GetDepthInMainChain() > 0) + nTotal += CWallet::GetCredit(*pcoin, MINE_WATCH_ONLY); } return nTotal; } @@ -1210,7 +1249,20 @@ int64 CWallet::GetNewMint() const { const CWalletTx* pcoin = &(*it).second; if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0 && pcoin->GetDepthInMainChain() > 0) - nTotal += CWallet::GetCredit(*pcoin); + nTotal += CWallet::GetCredit(*pcoin, MINE_ALL); + } + return nTotal; +} + +int64 CWallet::GetWatchOnlyNewMint() const +{ + int64 nTotal = 0; + LOCK(cs_wallet); + for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + const CWalletTx* pcoin = &(*it).second; + if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0 && pcoin->GetDepthInMainChain() > 0) + nTotal += CWallet::GetCredit(*pcoin, MINE_WATCH_ONLY); } return nTotal; } @@ -1236,7 +1288,7 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, unsigned int nSpendTime, in const CWalletTx *pcoin = output.tx; - if (output.nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs)) + if (output.nDepth < (pcoin->IsFromMe(MINE_ALL) ? nConfMine : nConfTheirs)) continue; int i = output.i; @@ -2053,12 +2105,12 @@ void CWallet::PrintWallet(const CBlock& block) if (block.IsProofOfWork() && mapWallet.count(block.vtx[0].GetHash())) { CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()]; - printf(" mine: %d %d %"PRI64d"", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit(false)); + printf(" mine: %d %d %"PRI64d"", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); } if (block.IsProofOfStake() && mapWallet.count(block.vtx[1].GetHash())) { CWalletTx& wtx = mapWallet[block.vtx[1].GetHash()]; - printf(" stake: %d %d %"PRI64d"", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit(false)); + printf(" stake: %d %d %"PRI64d"", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); } } @@ -2275,7 +2327,7 @@ std::map CWallet::GetAddressBalances() continue; int nDepth = pcoin->GetDepthInMainChain(); - if (nDepth < (pcoin->IsFromMe() ? 0 : 1)) + if (nDepth < (pcoin->IsFromMe(MINE_ALL) ? 0 : 1)) continue; for (unsigned int i = 0; i < pcoin->vout.size(); i++) diff --git a/src/wallet.h b/src/wallet.h index a2f9fca..3d07f57 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -184,11 +184,15 @@ public: void ReacceptWalletTransactions(); void ResendWalletTransactions(); int64 GetBalance() const; - int64 GetBalanceWatchOnly() const; + int64 GetWatchOnlyBalance() const; int64 GetUnconfirmedBalance() const; + int64 GetUnconfirmedWatchOnlyBalance() const; int64 GetImmatureBalance() const; + int64 GetImmatureWatchOnlyBalance() const; int64 GetStake() const; int64 GetNewMint() const; + int64 GetWatchOnlyStake() const; + int64 GetWatchOnlyNewMint() const; bool CreateTransaction(const std::vector >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, const CCoinControl *coinControl=NULL); bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, const CCoinControl *coinControl=NULL); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); @@ -214,26 +218,16 @@ public: std::map GetAddressBalances(); isminetype IsMine(const CTxIn& txin) const; - int64 GetDebit(const CTxIn& txin) const; + int64 GetDebit(const CTxIn& txin, const isminefilter& filter) const; isminetype IsMine(const CTxOut& txout) const { return ::IsMine(*this, txout.scriptPubKey); } - int64 GetCredit(const CTxOut& txout) const + int64 GetCredit(const CTxOut& txout, const isminefilter& filter) const { if (!MoneyRange(txout.nValue)) throw std::runtime_error("CWallet::GetCredit() : value out of range"); - isminetype ismine = IsMine(txout); - 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); + return (IsMine(txout) & filter ? txout.nValue : 0); } bool IsChange(const CTxOut& txout) const; int64 GetChange(const CTxOut& txout) const @@ -251,36 +245,25 @@ public: } bool IsFromMe(const CTransaction& tx) const { - return (GetDebit(tx) > 0); + return (GetDebit(tx, MINE_ALL) > 0); } - int64 GetDebit(const CTransaction& tx) const + int64 GetDebit(const CTransaction& tx, const isminefilter& filter) const { int64 nDebit = 0; BOOST_FOREACH(const CTxIn& txin, tx.vin) { - nDebit += GetDebit(txin); + nDebit += GetDebit(txin, filter); if (!MoneyRange(nDebit)) throw std::runtime_error("CWallet::GetDebit() : value out of range"); } return nDebit; } - int64 GetCredit(const CTransaction& tx) const - { - int64 nCredit = 0; - BOOST_FOREACH(const CTxOut& txout, tx.vout) - { - 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 GetCredit(const CTransaction& tx, const isminefilter& filter) const { int64 nCredit = 0; BOOST_FOREACH(const CTxOut& txout, tx.vout) { - nCredit += GetCreditWatchOnly(txout); + nCredit += GetCredit(txout, filter); if (!MoneyRange(nCredit)) throw std::runtime_error("CWallet::GetCredit() : value out of range"); } @@ -421,16 +404,22 @@ public: // memory only mutable bool fDebitCached; + mutable bool fWatchDebitCached; mutable bool fCreditCached; - mutable bool fWatchOnlyCreditCached; + mutable bool fWatchCreditCached; mutable bool fAvailableCreditCached; - mutable bool fAvailableWatchOnlyCreditCached; + mutable bool fImmatureCreditCached; + mutable bool fImmatureWatchCreditCached; + mutable bool fAvailableWatchCreditCached; mutable bool fChangeCached; mutable int64 nDebitCached; + mutable int64 nWatchDebitCached; mutable int64 nCreditCached; - mutable int64 nWatchOnlyCreditCached; + mutable int64 nWatchCreditCached; mutable int64 nAvailableCreditCached; - mutable int64 nAvailableWatchOnlyCreditCached; + mutable int64 nImmatureCreditCached; + mutable int64 nImmatureWatchCreditCached; + mutable int64 nAvailableWatchCreditCached; mutable int64 nChangeCached; CWalletTx() @@ -466,16 +455,18 @@ public: strFromAccount.clear(); vfSpent.clear(); fDebitCached = false; + fWatchDebitCached = false; fCreditCached = false; - fWatchOnlyCreditCached = false; + fWatchCreditCached = false; fAvailableCreditCached = false; - fAvailableWatchOnlyCreditCached = false; + fAvailableWatchCreditCached = false; fChangeCached = false; nDebitCached = 0; + nWatchDebitCached = 0; nCreditCached = 0; - nWatchOnlyCreditCached = 0; + nWatchCreditCached = 0; nAvailableCreditCached = 0; - nAvailableWatchOnlyCreditCached = 0; + nAvailableWatchCreditCached = 0; nChangeCached = 0; nOrderPos = -1; } @@ -551,7 +542,7 @@ public: { vfSpent[i] = true; fReturn = true; - fAvailableCreditCached = fAvailableWatchOnlyCreditCached = false; + fAvailableCreditCached = fAvailableWatchCreditCached = false; } } return fReturn; @@ -561,8 +552,8 @@ public: void MarkDirty() { fCreditCached = false; - fAvailableCreditCached = fAvailableWatchOnlyCreditCached = false; - fDebitCached = false; + fAvailableCreditCached = fAvailableWatchCreditCached = false; + fDebitCached = fWatchDebitCached = false; fChangeCached = false; } @@ -580,7 +571,7 @@ public: if (!vfSpent[nOut]) { vfSpent[nOut] = true; - fAvailableCreditCached = fAvailableWatchOnlyCreditCached = false; + fAvailableCreditCached = fAvailableWatchCreditCached = false; } } @@ -592,7 +583,7 @@ public: if (vfSpent[nOut]) { vfSpent[nOut] = false; - fAvailableCreditCached = fAvailableWatchOnlyCreditCached = false; + fAvailableCreditCached = fAvailableWatchCreditCached = false; } } @@ -605,15 +596,36 @@ public: return (!!vfSpent[nOut]); } - int64 GetDebit() const + int64 GetDebit(const isminefilter& filter) const { if (vin.empty()) return 0; - if (fDebitCached) - return nDebitCached; - nDebitCached = pwallet->GetDebit(*this); - fDebitCached = true; - return nDebitCached; + + int64 nDebit = 0; + if (filter & MINE_SPENDABLE) + { + if (fDebitCached) + nDebit += nDebitCached; + else + { + nDebitCached = pwallet->GetDebit(*this, MINE_SPENDABLE); + fDebitCached = true; + nDebit += nDebitCached; + } + } + if (filter & MINE_WATCH_ONLY) + { + if (fWatchDebitCached) + nDebit += nWatchDebitCached; + else + { + nWatchDebitCached = pwallet->GetDebit(*this, MINE_WATCH_ONLY); + fWatchDebitCached = true; + nDebit += nWatchDebitCached; + } + } + + return nDebit; } int64 GetCredit(bool fUseCache=true) const @@ -628,12 +640,41 @@ public: return nCreditCached; } - nCreditCached = pwallet->GetCredit(*this); + nCreditCached = pwallet->GetCredit(*this, MINE_ALL); fCreditCached = true; return nCreditCached; } + int64 GetImmatureCredit(bool fUseCache=true) const + { + if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0 && IsInMainChain()) + { + if (fUseCache && fImmatureCreditCached) + return nImmatureCreditCached; + nImmatureCreditCached = pwallet->GetCredit(*this, MINE_SPENDABLE); + fImmatureCreditCached = true; + return nImmatureCreditCached; + } + + return 0; + } + + int64 GetImmatureWatchOnlyCredit(bool fUseCache=true) const + { + if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0 && IsInMainChain()) + { + if (fUseCache && fImmatureWatchCreditCached) + return nImmatureWatchCreditCached; + nImmatureWatchCreditCached = pwallet->GetCredit(*this, MINE_WATCH_ONLY); + fImmatureWatchCreditCached = true; + return nImmatureWatchCreditCached; + } + + return 0; + } + + int64 GetAvailableCredit(bool fUseCache=true) const { // Must wait until coinbase is safely deep enough in the chain before valuing it @@ -651,7 +692,7 @@ public: if (!IsSpent(i)) { const CTxOut &txout = vout[i]; - nCredit += pwallet->GetCredit(txout); + nCredit += pwallet->GetCredit(txout, MINE_SPENDABLE); if (!MoneyRange(nCredit)) throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range"); } @@ -663,33 +704,15 @@ public: return nCredit; } - int64 GetCreditWatchOnly(bool fUseCache=true) const + int64 GetAvailableWatchCredit(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; + if (fAvailableWatchCreditCached) + return nAvailableWatchCreditCached; } int64 nCredit = 0; @@ -698,19 +721,18 @@ public: if (!IsSpent(i)) { const CTxOut &txout = vout[i]; - nCredit += pwallet->GetCreditWatchOnly(txout); + nCredit += pwallet->GetCredit(txout, MINE_WATCH_ONLY); if (!MoneyRange(nCredit)) - throw std::runtime_error("CWalletTx::GetAvailableCreditWatchOnly() : value out of range"); + throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range"); } } - nAvailableWatchOnlyCreditCached = nCredit; - fAvailableWatchOnlyCreditCached = true; + nAvailableWatchCreditCached = nCredit; + fAvailableWatchCreditCached = true; return nCredit; } - int64 GetChange() const { if (fChangeCached) @@ -721,14 +743,14 @@ public: } void GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, std::list >& listReceived, - std::list >& listSent, int64& nFee, std::string& strSentAccount) const; + std::list >& listSent, int64& nFee, std::string& strSentAccount, const isminefilter& filter) const; void GetAccountAmounts(const std::string& strAccount, int64& nGenerated, int64& nReceived, - int64& nSent, int64& nFee) const; + int64& nSent, int64& nFee, const isminefilter& filter) const; - bool IsFromMe() const + bool IsFromMe(const isminefilter& filter) const { - return (GetDebit() > 0); + return (GetDebit(filter) > 0); } bool IsTrusted() const @@ -738,7 +760,7 @@ public: return false; if (GetDepthInMainChain() >= 1) return true; - if (fConfChange || !IsFromMe()) // using wtx's cached debit + if (fConfChange || !IsFromMe(MINE_ALL)) // using wtx's cached debit return false; // If no confirmations but it's from us, we can still -- 1.7.1