X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fwallet.cpp;h=1d735d3f9380b13b94a045873f19adfec08c9f72;hb=6bd80c2d737da9422283de5dd3033e318dcb96b7;hp=85bf6acebac6d55e7a0111f181023847f84a8201;hpb=40530c08006088e6f610063f1c49428aa0b272f6;p=novacoin.git diff --git a/src/wallet.cpp b/src/wallet.cpp index 85bf6ac..1d735d3 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -33,6 +33,15 @@ struct CompareValueOnly } }; +const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const +{ + LOCK(cs_wallet); + std::map::const_iterator it = mapWallet.find(hash); + if (it == mapWallet.end()) + return NULL; + return &(it->second); +} + CPubKey CWallet::GenerateNewKey() { bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets @@ -752,7 +761,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) // Add a transaction to the wallet, or update it. // pblock is optional, but should be provided if the transaction is known to be in a block. // If fUpdate is true, existing transactions will be updated. -bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock) +bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate) { uint256 hash = tx.GetHash(); { @@ -801,6 +810,74 @@ isminetype CWallet::IsMine(const CTxIn &txin) const return MINE_NO; } +// marks certain txout's as spent +// returns true if any update took place +bool CWalletTx::UpdateSpent(const std::vector& vfNewSpent) +{ + bool fReturn = false; + for (unsigned int i = 0; i < vfNewSpent.size(); i++) + { + if (i == vfSpent.size()) + break; + + if (vfNewSpent[i] && !vfSpent[i]) + { + vfSpent[i] = true; + fReturn = true; + fAvailableCreditCached = fAvailableWatchCreditCached = false; + } + } + return fReturn; +} + +// make sure balances are recalculated +void CWalletTx::MarkDirty() +{ + fCreditCached = false; + fAvailableCreditCached = fAvailableWatchCreditCached = false; + fDebitCached = fWatchDebitCached = false; + fChangeCached = false; +} + +void CWalletTx::BindWallet(CWallet *pwalletIn) +{ + pwallet = pwalletIn; + MarkDirty(); +} + +void CWalletTx::MarkSpent(unsigned int nOut) +{ + if (nOut >= vout.size()) + throw std::runtime_error("CWalletTx::MarkSpent() : nOut out of range"); + vfSpent.resize(vout.size()); + if (!vfSpent[nOut]) + { + vfSpent[nOut] = true; + fAvailableCreditCached = fAvailableWatchCreditCached = false; + } +} + +void CWalletTx::MarkUnspent(unsigned int nOut) +{ + if (nOut >= vout.size()) + throw std::runtime_error("CWalletTx::MarkUnspent() : nOut out of range"); + vfSpent.resize(vout.size()); + if (vfSpent[nOut]) + { + vfSpent[nOut] = false; + fAvailableCreditCached = fAvailableWatchCreditCached = false; + } +} + +bool CWalletTx::IsSpent(unsigned int nOut) const +{ + if (nOut >= vout.size()) + throw std::runtime_error("CWalletTx::IsSpent() : nOut out of range"); + if (nOut >= vfSpent.size()) + return false; + return (!!vfSpent[nOut]); +} + int64_t CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const { { @@ -817,6 +894,18 @@ int64_t CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const return 0; } +isminetype CWallet::IsMine(const CTxOut& txout) const +{ + return ::IsMine(*this, txout.scriptPubKey); +} + +int64_t CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) const +{ + if (!MoneyRange(txout.nValue)) + throw std::runtime_error("CWallet::GetCredit() : value out of range"); + return (IsMine(txout) & filter ? txout.nValue : 0); +} + bool CWallet::IsChange(const CTxOut& txout) const { // TODO: fix handling of 'change' outputs. The assumption is that any @@ -839,6 +928,62 @@ bool CWallet::IsChange(const CTxOut& txout) const return false; } +int64_t CWallet::GetChange(const CTxOut& txout) const +{ + if (!MoneyRange(txout.nValue)) + throw std::runtime_error("CWallet::GetChange() : value out of range"); + return (IsChange(txout) ? txout.nValue : 0); +} + +bool CWallet::IsMine(const CTransaction& tx) const +{ + BOOST_FOREACH(const CTxOut& txout, tx.vout) + if (IsMine(txout) && txout.nValue >= nMinimumInputValue) + return true; + return false; +} + +bool CWallet::IsFromMe(const CTransaction& tx) const +{ + return (GetDebit(tx, MINE_ALL) > 0); +} + +int64_t CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) const +{ + int64_t nDebit = 0; + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + nDebit += GetDebit(txin, filter); + if (!MoneyRange(nDebit)) + throw std::runtime_error("CWallet::GetDebit() : value out of range"); + } + return nDebit; +} + +int64_t CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) const +{ + int64_t nCredit = 0; + BOOST_FOREACH(const CTxOut& txout, tx.vout) + { + nCredit += GetCredit(txout, filter); + if (!MoneyRange(nCredit)) + throw std::runtime_error("CWallet::GetCredit() : value out of range"); + } + return nCredit; +} + +int64_t CWallet::GetChange(const CTransaction& tx) const +{ + int64_t nChange = 0; + BOOST_FOREACH(const CTxOut& txout, tx.vout) + { + nChange += GetChange(txout); + if (!MoneyRange(nChange)) + throw std::runtime_error("CWallet::GetChange() : value out of range"); + } + return nChange; +} + int64_t CWalletTx::GetTxTime() const { return nTime; @@ -883,6 +1028,206 @@ int CWalletTx::GetRequestCount() const return nRequests; } +bool CWalletTx::InMempool() const +{ + LOCK(mempool.cs); + if (mempool.exists(GetHash())) { + return true; + } + return false; +} + +bool CWalletTx::IsTrusted() const +{ + // Quick answer in most cases + if (!IsFinal()) + return false; + int nDepth = GetDepthInMainChain(); + if (nDepth >= 1) + return true; + if (nDepth < 0) + return false; + if (!fConfChange || !IsFromMe(MINE_ALL)) // using wtx's cached debit + return false; + + // Don't trust unconfirmed transactions from us unless they are in the mempool. + if (!InMempool()) + return false; + + // Trusted if all inputs are from us and are in the mempool: + BOOST_FOREACH(const CTxIn& txin, vin) + { + // Transactions not sent by us: not trusted + const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash); + if (parent == NULL) + return false; + const CTxOut& parentOut = parent->vout[txin.prevout.n]; + if (pwallet->IsMine(parentOut) != MINE_SPENDABLE) + return false; + } + return true; +} + +int64_t CWalletTx::GetDebit(const isminefilter& filter) const +{ + if (vin.empty()) + return 0; + + int64_t 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_t CWalletTx::GetCredit(const isminefilter& filter) const +{ + // Must wait until coinbase is safely deep enough in the chain before valuing it + if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0) + return 0; + + int64_t credit = 0; + if (filter & MINE_SPENDABLE) + { + // GetBalance can assume transactions in mapWallet won't change + if (fCreditCached) + credit += nCreditCached; + else + { + nCreditCached = pwallet->GetCredit(*this, MINE_SPENDABLE); + fCreditCached = true; + credit += nCreditCached; + } + } + if (filter & MINE_WATCH_ONLY) + { + if (fWatchCreditCached) + credit += nWatchCreditCached; + else + { + nWatchCreditCached = pwallet->GetCredit(*this, MINE_WATCH_ONLY); + fWatchCreditCached = true; + credit += nWatchCreditCached; + } + } + return credit; +} + +int64_t CWalletTx::GetImmatureCredit(bool fUseCache) const +{ + if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) + { + if (fUseCache && fImmatureCreditCached) + return nImmatureCreditCached; + nImmatureCreditCached = pwallet->GetCredit(*this, MINE_SPENDABLE); + fImmatureCreditCached = true; + return nImmatureCreditCached; + } + + return 0; +} + +int64_t CWalletTx::GetImmatureWatchOnlyCredit(bool fUseCache) const +{ + if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) + { + if (fUseCache && fImmatureWatchCreditCached) + return nImmatureWatchCreditCached; + nImmatureWatchCreditCached = pwallet->GetCredit(*this, MINE_WATCH_ONLY); + fImmatureWatchCreditCached = true; + return nImmatureWatchCreditCached; + } + + return 0; +} + + +int64_t CWalletTx::GetAvailableCredit(bool fUseCache) 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 (fAvailableCreditCached) + return nAvailableCreditCached; + } + + int64_t nCredit = 0; + for (unsigned int i = 0; i < vout.size(); i++) + { + if (!IsSpent(i)) + { + const CTxOut &txout = vout[i]; + nCredit += pwallet->GetCredit(txout, MINE_SPENDABLE); + if (!MoneyRange(nCredit)) + throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range"); + } + } + + nAvailableCreditCached = nCredit; + fAvailableCreditCached = true; + + return nCredit; +} + +int64_t CWalletTx::GetAvailableWatchCredit(bool fUseCache) 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 (fAvailableWatchCreditCached) + return nAvailableWatchCreditCached; + } + + int64_t nCredit = 0; + for (unsigned int i = 0; i < vout.size(); i++) + { + if (!IsSpent(i)) + { + const CTxOut &txout = vout[i]; + nCredit += pwallet->GetCredit(txout, MINE_WATCH_ONLY); + if (!MoneyRange(nCredit)) + throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range"); + } + } + + nAvailableWatchCreditCached = nCredit; + fAvailableWatchCreditCached = true; + + return nCredit; +} + +int64_t CWalletTx::GetChange() const +{ + if (fChangeCached) + return nChangeCached; + nChangeCached = pwallet->GetChange(*this); + fChangeCached = true; + return nChangeCached; +} + void CWalletTx::GetAmounts(int64_t& nGeneratedImmature, int64_t& nGeneratedMature, list >& listReceived, list >& listSent, int64_t& nFee, string& strSentAccount, const isminefilter& filter) const { @@ -1076,7 +1421,7 @@ int CWallet::ScanForWalletTransaction(const uint256& hashTx) { CTransaction tx; tx.ReadFromDisk(COutPoint(hashTx, 0)); - if (AddToWalletIfInvolvingMe(tx, NULL, true, true)) + if (AddToWalletIfInvolvingMe(tx, NULL, true)) return 1; return 0; }