From 93a18a3650292afbb441a47d1fa1b94aeb0164e3 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Sat, 15 Feb 2014 16:38:28 -0500 Subject: Remove CWalletTx::vfSpent Use the spent outpoint multimap to figure out which wallet transaction outputs are unspent, instead of a vfSpent array that is saved to disk. --- src/wallet.h | 125 ++++++++++++----------------------------------------------- 1 file changed, 25 insertions(+), 100 deletions(-) (limited to 'src/wallet.h') diff --git a/src/wallet.h b/src/wallet.h index eb192f1ca6..7feb86d294 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -108,11 +108,15 @@ private: int64_t nNextResend; int64_t nLastResend; - // Used to detect and report conflicted transactions: - typedef std::multimap TxConflicts; - TxConflicts mapTxConflicts; - void AddToConflicts(const uint256& wtxhash); - void SyncMetaData(std::pair); + // Used to keep track of spent outpoints, and + // detect and report conflicts (double-spends or + // mutated transactions where the mutant gets mined). + typedef std::multimap TxSpends; + TxSpends mapTxSpends; + void AddToSpends(const COutPoint& outpoint, const uint256& wtxid); + void AddToSpends(const uint256& wtxid); + + void SyncMetaData(std::pair); public: /// Main wallet lock. @@ -169,12 +173,16 @@ public: int64_t nTimeFirstKey; + const CWalletTx* GetWalletTx(const uint256& hash) const; + // check whether we are allowed to upgrade (or already support) to the named feature bool CanSupportFeature(enum WalletFeature wf) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; } void AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL) const; bool SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, int64_t& nValueRet) const; + bool IsSpent(const uint256& hash, unsigned int n) const; + bool IsLockedCoin(uint256 hash, unsigned int n) const; void LockCoin(COutPoint& output); void UnlockCoin(COutPoint& output); @@ -234,7 +242,6 @@ public: void SyncTransaction(const uint256 &hash, const CTransaction& tx, const CBlock* pblock); bool AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate); void EraseFromWallet(const uint256 &hash); - void WalletUpdateSpent(const CTransaction& prevout); int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); void ReacceptWalletTransactions(); void ResendWalletTransactions(); @@ -439,7 +446,6 @@ private: const CWallet* pwallet; public: - std::vector vtxPrev; mapValue_t mapValue; std::vector > vOrderForm; unsigned int fTimeReceivedIsTxTime; @@ -447,7 +453,6 @@ public: unsigned int nTimeSmart; char fFromMe; std::string strFromAccount; - std::vector vfSpent; // which outputs are already spent int64_t nOrderPos; // position in ordered transaction list // memory only @@ -485,7 +490,6 @@ public: void Init(const CWallet* pwalletIn) { pwallet = pwalletIn; - vtxPrev.clear(); mapValue.clear(); vOrderForm.clear(); fTimeReceivedIsTxTime = false; @@ -493,7 +497,6 @@ public: nTimeSmart = 0; fFromMe = false; strFromAccount.clear(); - vfSpent.clear(); fDebitCached = false; fCreditCached = false; fImmatureCreditCached = false; @@ -518,15 +521,6 @@ public: { pthis->mapValue["fromaccount"] = pthis->strFromAccount; - std::string str; - BOOST_FOREACH(char f, vfSpent) - { - str += (f ? '1' : '0'); - if (f) - fSpent = true; - } - pthis->mapValue["spent"] = str; - WriteOrderPos(pthis->nOrderPos, pthis->mapValue); if (nTimeSmart) @@ -534,7 +528,8 @@ public: } nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion,ser_action); - READWRITE(vtxPrev); + std::vector vUnused; // Used to be vtxPrev + READWRITE(vUnused); READWRITE(mapValue); READWRITE(vOrderForm); READWRITE(fTimeReceivedIsTxTime); @@ -546,12 +541,6 @@ public: { pthis->strFromAccount = pthis->mapValue["fromaccount"]; - if (mapValue.count("spent")) - BOOST_FOREACH(char c, pthis->mapValue["spent"]) - pthis->vfSpent.push_back(c != '0'); - else - pthis->vfSpent.assign(vout.size(), fSpent); - ReadOrderPos(pthis->nOrderPos, pthis->mapValue); pthis->nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(pthis->mapValue["timesmart"]) : 0; @@ -564,26 +553,6 @@ public: pthis->mapValue.erase("timesmart"); ) - // marks certain txout's as spent - // returns true if any update took place - bool 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 = false; - } - } - return fReturn; - } - // make sure balances are recalculated void MarkDirty() { @@ -599,27 +568,6 @@ public: MarkDirty(); } - void 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 = false; - } - } - - bool 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 GetDebit() const { if (vin.empty()) @@ -661,6 +609,9 @@ public: int64_t GetAvailableCredit(bool fUseCache=true) const { + if (pwallet == 0) + return 0; + // Must wait until coinbase is safely deep enough in the chain before valuing it if (IsCoinBase() && GetBlocksToMaturity() > 0) return 0; @@ -671,7 +622,7 @@ public: int64_t nCredit = 0; for (unsigned int i = 0; i < vout.size(); i++) { - if (!IsSpent(i)) + if (!pwallet->IsSpent(GetHash(), i)) { const CTxOut &txout = vout[i]; nCredit += pwallet->GetCredit(txout); @@ -719,38 +670,14 @@ public: if (!bSpendZeroConfChange || !IsFromMe()) // using wtx's cached debit return false; - // If no confirmations but it's from us, we can still - // consider it confirmed if all dependencies are confirmed - std::map mapPrev; - std::vector vWorkQueue; - vWorkQueue.reserve(vtxPrev.size()+1); - vWorkQueue.push_back(this); - for (unsigned int i = 0; i < vWorkQueue.size(); i++) + // Trusted if all inputs are from us and are in the mempool: + BOOST_FOREACH(const CTxIn& txin, vin) { - const CMerkleTx* ptx = vWorkQueue[i]; - - if (!IsFinalTx(*ptx)) + // Transactions not sent by us: not trusted + const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash); + const CTxOut& parentOut = parent->vout[txin.prevout.n]; + if (parent == NULL || !pwallet->IsMine(parentOut)) return false; - int nPDepth = ptx->GetDepthInMainChain(); - if (nPDepth >= 1) - continue; - if (nPDepth < 0) - return false; - if (!pwallet->IsFromMe(*ptx)) - return false; - - if (mapPrev.empty()) - { - BOOST_FOREACH(const CMerkleTx& tx, vtxPrev) - mapPrev[tx.GetHash()] = &tx; - } - - BOOST_FOREACH(const CTxIn& txin, ptx->vin) - { - if (!mapPrev.count(txin.prevout.hash)) - return false; - vWorkQueue.push_back(mapPrev[txin.prevout.hash]); - } } return true; } @@ -760,8 +687,6 @@ public: int64_t GetTxTime() const; int GetRequestCount() const; - void AddSupportingTransactions(); - bool AcceptWalletTransaction(); void RelayWalletTransaction(); std::set GetConflicts() const; -- cgit v1.2.3