// Copyright (c) 2012-2013 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "coins.h" #include // calculate number of bytes for the bitmask, and its number of non-zero bytes // each bit in the bitmask represents the availability of one output, but the // availabilities of the first two outputs are encoded separately void CCoins::CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const { unsigned int nLastUsedByte = 0; for (unsigned int b = 0; 2+b*8 < vout.size(); b++) { bool fZero = true; for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++) { if (!vout[2+b*8+i].IsNull()) { fZero = false; continue; } } if (!fZero) { nLastUsedByte = b + 1; nNonzeroBytes++; } } nBytes += nLastUsedByte; } bool CCoins::Spend(const COutPoint &out, CTxInUndo &undo) { if (out.n >= vout.size()) return false; if (vout[out.n].IsNull()) return false; undo = CTxInUndo(vout[out.n]); vout[out.n].SetNull(); Cleanup(); if (vout.size() == 0) { undo.nHeight = nHeight; undo.fCoinBase = fCoinBase; undo.nVersion = this->nVersion; } return true; } bool CCoins::Spend(int nPos) { CTxInUndo undo; COutPoint out(0, nPos); return Spend(out, undo); } bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) { return false; } bool CCoinsView::SetCoins(const uint256 &txid, const CCoins &coins) { return false; } bool CCoinsView::HaveCoins(const uint256 &txid) { return false; } uint256 CCoinsView::GetBestBlock() { return uint256(0); } bool CCoinsView::SetBestBlock(const uint256 &hashBlock) { return false; } bool CCoinsView::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; } bool CCoinsView::GetStats(CCoinsStats &stats) { return false; } CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { } bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) { return base->GetCoins(txid, coins); } bool CCoinsViewBacked::SetCoins(const uint256 &txid, const CCoins &coins) { return base->SetCoins(txid, coins); } bool CCoinsViewBacked::HaveCoins(const uint256 &txid) { return base->HaveCoins(txid); } uint256 CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); } bool CCoinsViewBacked::SetBestBlock(const uint256 &hashBlock) { return base->SetBestBlock(hashBlock); } void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } bool CCoinsViewBacked::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); } bool CCoinsViewBacked::GetStats(CCoinsStats &stats) { return base->GetStats(stats); } CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), hashBlock(0) { } bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) { if (cacheCoins.count(txid)) { coins = cacheCoins[txid]; return true; } if (base->GetCoins(txid, coins)) { cacheCoins[txid] = coins; return true; } return false; } CCoinsMap::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) { CCoinsMap::iterator it = cacheCoins.lower_bound(txid); if (it != cacheCoins.end() && it->first == txid) return it; CCoins tmp; if (!base->GetCoins(txid,tmp)) return cacheCoins.end(); CCoinsMap::iterator ret = cacheCoins.insert(it, std::make_pair(txid, CCoins())); tmp.swap(ret->second); return ret; } CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) { CCoinsMap::iterator it = FetchCoins(txid); assert(it != cacheCoins.end()); return it->second; } bool CCoinsViewCache::SetCoins(const uint256 &txid, const CCoins &coins) { cacheCoins[txid] = coins; return true; } bool CCoinsViewCache::HaveCoins(const uint256 &txid) { return FetchCoins(txid) != cacheCoins.end(); } uint256 CCoinsViewCache::GetBestBlock() { if (hashBlock == uint256(0)) hashBlock = base->GetBestBlock(); return hashBlock; } bool CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) { hashBlock = hashBlockIn; return true; } bool CCoinsViewCache::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlockIn) { for (CCoinsMap::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++) cacheCoins[it->first] = it->second; hashBlock = hashBlockIn; return true; } bool CCoinsViewCache::Flush() { bool fOk = base->BatchWrite(cacheCoins, hashBlock); if (fOk) cacheCoins.clear(); return fOk; } unsigned int CCoinsViewCache::GetCacheSize() { return cacheCoins.size(); } const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) { const CCoins &coins = GetCoins(input.prevout.hash); assert(coins.IsAvailable(input.prevout.n)); return coins.vout[input.prevout.n]; } int64_t CCoinsViewCache::GetValueIn(const CTransaction& tx) { if (tx.IsCoinBase()) return 0; int64_t nResult = 0; for (unsigned int i = 0; i < tx.vin.size(); i++) nResult += GetOutputFor(tx.vin[i]).nValue; return nResult; } bool CCoinsViewCache::HaveInputs(const CTransaction& tx) { if (!tx.IsCoinBase()) { // first check whether information about the prevout hash is available for (unsigned int i = 0; i < tx.vin.size(); i++) { const COutPoint &prevout = tx.vin[i].prevout; if (!HaveCoins(prevout.hash)) return false; } // then check whether the actual outputs are available for (unsigned int i = 0; i < tx.vin.size(); i++) { const COutPoint &prevout = tx.vin[i].prevout; const CCoins &coins = GetCoins(prevout.hash); if (!coins.IsAvailable(prevout.n)) return false; } } return true; } double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) { if (tx.IsCoinBase()) return 0.0; double dResult = 0.0; BOOST_FOREACH(const CTxIn& txin, tx.vin) { const CCoins &coins = GetCoins(txin.prevout.hash); if (!coins.IsAvailable(txin.prevout.n)) continue; if (coins.nHeight < nHeight) { dResult += coins.vout[txin.prevout.n].nValue * (nHeight-coins.nHeight); } } return tx.ComputePriority(dResult); }