aboutsummaryrefslogtreecommitdiff
path: root/src/coins.cpp
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2013-11-05 02:47:07 +0100
committerPieter Wuille <pieter.wuille@gmail.com>2013-11-10 19:37:56 +0100
commita0fa20a12b69717636050dd8742713b1d82ae524 (patch)
treed1db4dc173a9f4d24904a1636f5cf82cd3c1c737 /src/coins.cpp
parent84674082b0c4cfcdd54fb97a29bc841aa7f691c2 (diff)
downloadbitcoin-a0fa20a12b69717636050dd8742713b1d82ae524.tar.xz
Move CCoins-related logic to coins.{cpp.h}
Diffstat (limited to 'src/coins.cpp')
-rw-r--r--src/coins.cpp180
1 files changed, 180 insertions, 0 deletions
diff --git a/src/coins.cpp b/src/coins.cpp
new file mode 100644
index 0000000000..ed82c9df8b
--- /dev/null
+++ b/src/coins.cpp
@@ -0,0 +1,180 @@
+// 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 <assert.h>
+
+// 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 std::map<uint256, CCoins> &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 std::map<uint256, CCoins> &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;
+}
+
+std::map<uint256,CCoins>::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) {
+ std::map<uint256,CCoins>::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();
+ std::map<uint256,CCoins>::iterator ret = cacheCoins.insert(it, std::make_pair(txid, CCoins()));
+ tmp.swap(ret->second);
+ return ret;
+}
+
+CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) {
+ std::map<uint256,CCoins>::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 std::map<uint256, CCoins> &mapCoins, const uint256 &hashBlockIn) {
+ for (std::map<uint256, CCoins>::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;
+}