aboutsummaryrefslogtreecommitdiff
path: root/src/wallet.cpp
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2014-07-07 14:56:16 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2014-07-07 16:06:28 +0200
commitf748ff730b4570a19610db67aa9ded28ba98a8c5 (patch)
tree2fc11dfafa57ce4f675d29f8b5cddb98ea70f738 /src/wallet.cpp
parentafe380ef0f1c70185fc7c50e1a75e589ff3382dd (diff)
parenta3e192a3274817517671f624d5744297905e20d2 (diff)
Merge pull request #4045
a3e192a replaced MINE_ with ISMINE_ (JaSK) 53a2148 fixed bug where validateaddress doesn't display information (JaSK) f28707a fixed bug in ListReceived() (JaSK) 519dd1c Added MINE_ALL = (spendable|watchonly) (JaSK) 23b0506 Fixed some stuff in TransactionDesc (JaSK) 80dda36 removed default argument values for ismine filter (JaSK) d5087d1 Use script matching rather than destination matching for watch-only. (Pieter Wuille) 0fa2f88 added includedWatchonly argument to listreceivedbyaddress/...account (JaSK) f87ba3d added includeWatchonly argument to 'gettransaction' because it affects balance calculation (JaSK) a5c6c5d fixed tiny glitch and improved readability like laanwj suggested (JaSK) d7d5d23 Added argument to listtransactions and listsinceblock to include watchonly addresses (JaSK) 952877e Showing 'involvesWatchonly' property for transactions returned by 'listtransactions' and 'listsinceblock'. It is only appended when the transaction involves a watchonly address. (JaSK) 83f3543 Added argument to listaccounts to include watchonly addresses (JaSK) d4640d7 Added argument to getbalance to include watchonly addresses and fixed errors in balance calculation. (JaSK) d2692f6 Watchonly transactions are marked in transaction history (JaSK) ffd40da Watchonly balances are shown separately in gui. (JaSK) 2935b21 qt: Hide unspendable outputs in coin control (Wladimir J. van der Laan) c898846 Add support for watch-only addresses (Pieter Wuille)
Diffstat (limited to 'src/wallet.cpp')
-rw-r--r--src/wallet.cpp113
1 files changed, 90 insertions, 23 deletions
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 090c1b5ab3..ea99b89a5a 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -149,6 +149,21 @@ bool CWallet::LoadCScript(const CScript& redeemScript)
return CCryptoKeyStore::AddCScript(redeemScript);
}
+bool CWallet::AddWatchOnly(const CScript &dest)
+{
+ if (!CCryptoKeyStore::AddWatchOnly(dest))
+ return false;
+ nTimeFirstKey = 1; // No birthday information for watch-only keys.
+ if (!fFileBacked)
+ return true;
+ return CWalletDB(strWalletFile).WriteWatchOnly(dest);
+}
+
+bool CWallet::LoadWatchOnly(const CScript &dest)
+{
+ return CCryptoKeyStore::AddWatchOnly(dest);
+}
+
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
{
CCrypter crypter;
@@ -684,7 +699,7 @@ void CWallet::EraseFromWallet(const uint256 &hash)
}
-bool CWallet::IsMine(const CTxIn &txin) const
+isminetype CWallet::IsMine(const CTxIn &txin) const
{
{
LOCK(cs_wallet);
@@ -693,14 +708,13 @@ bool CWallet::IsMine(const CTxIn &txin) const
{
const CWalletTx& prev = (*mi).second;
if (txin.prevout.n < prev.vout.size())
- if (IsMine(prev.vout[txin.prevout.n]))
- return true;
+ return IsMine(prev.vout[txin.prevout.n]);
}
}
- return false;
+ return ISMINE_NO;
}
-int64_t CWallet::GetDebit(const CTxIn &txin) const
+int64_t CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
{
{
LOCK(cs_wallet);
@@ -709,7 +723,7 @@ int64_t 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;
}
}
@@ -718,17 +732,19 @@ int64_t 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 is not 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;
@@ -782,7 +798,7 @@ int CWalletTx::GetRequestCount() const
}
void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived,
- list<pair<CTxDestination, int64_t> >& listSent, int64_t& nFee, string& strSentAccount) const
+ list<pair<CTxDestination, int64_t> >& listSent, int64_t& nFee, string& strSentAccount, const isminefilter& filter) const
{
nFee = 0;
listReceived.clear();
@@ -790,7 +806,7 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived,
strSentAccount = strFromAccount;
// Compute fee:
- int64_t nDebit = GetDebit();
+ int64_t nDebit = GetDebit(filter);
if (nDebit > 0) // debit>0 means we signed/sent this transaction
{
int64_t nValueOut = GetValueOut();
@@ -800,7 +816,8 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived,
// 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)
@@ -809,9 +826,8 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived,
// 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
@@ -835,7 +851,7 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived,
}
void CWalletTx::GetAccountAmounts(const string& strAccount, int64_t& nReceived,
- int64_t& nSent, int64_t& nFee) const
+ int64_t& nSent, int64_t& nFee, const isminefilter& filter) const
{
nReceived = nSent = nFee = 0;
@@ -843,7 +859,7 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, int64_t& nReceived,
string strSentAccount;
list<pair<CTxDestination, int64_t> > listReceived;
list<pair<CTxDestination, int64_t> > listSent;
- GetAmounts(listReceived, listSent, allFee, strSentAccount);
+ GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
if (strAccount == strSentAccount)
{
@@ -1055,7 +1071,52 @@ int64_t CWallet::GetImmatureBalance() const
return nTotal;
}
-// populate vCoins with vector of spendable COutputs
+int64_t CWallet::GetWatchOnlyBalance() const
+{
+ int64_t 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())
+ nTotal += pcoin->GetAvailableWatchOnlyCredit();
+ }
+ }
+
+ return nTotal;
+}
+
+int64_t CWallet::GetUnconfirmedWatchOnlyBalance() const
+{
+ int64_t nTotal = 0;
+ {
+ LOCK(cs_wallet);
+ for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx* pcoin = &(*it).second;
+ if (!IsFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
+ nTotal += pcoin->GetAvailableWatchOnlyCredit();
+ }
+ }
+ return nTotal;
+}
+
+int64_t CWallet::GetImmatureWatchOnlyBalance() const
+{
+ int64_t nTotal = 0;
+ {
+ LOCK(cs_wallet);
+ for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx* pcoin = &(*it).second;
+ nTotal += pcoin->GetImmatureWatchOnlyCredit();
+ }
+ }
+ return nTotal;
+}
+
+// populate vCoins with vector of available COutputs.
void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl) const
{
vCoins.clear();
@@ -1081,10 +1142,11 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
continue;
for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
- if (!(IsSpent(wtxid, i)) && IsMine(pcoin->vout[i]) &&
+ isminetype mine = IsMine(pcoin->vout[i]);
+ if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
!IsLockedCoin((*it).first, i) && pcoin->vout[i].nValue > 0 &&
(!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i)))
- vCoins.push_back(COutput(pcoin, i, nDepth));
+ vCoins.push_back(COutput(pcoin, i, nDepth, mine & ISMINE_SPENDABLE));
}
}
}
@@ -1151,11 +1213,14 @@ bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfT
random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
- BOOST_FOREACH(COutput output, vCoins)
+ BOOST_FOREACH(const COutput &output, vCoins)
{
+ if (!output.fSpendable)
+ continue;
+
const CWalletTx *pcoin = output.tx;
- if (output.nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
+ if (output.nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs))
continue;
int i = output.i;
@@ -1244,6 +1309,8 @@ bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsign
{
BOOST_FOREACH(const COutput& out, vCoins)
{
+ if(!out.fSpendable)
+ continue;
nValueRet += out.tx->vout[out.i].nValue;
setCoinsRet.insert(make_pair(out.tx, out.i));
}
@@ -1804,7 +1871,7 @@ std::map<CTxDestination, int64_t> CWallet::GetAddressBalances()
continue;
int nDepth = pcoin->GetDepthInMainChain();
- if (nDepth < (pcoin->IsFromMe() ? 0 : 1))
+ if (nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? 0 : 1))
continue;
for (unsigned int i = 0; i < pcoin->vout.size(); i++)