]> Git Repo - VerusCoin.git/blob - src/coins.cpp
Merge pull request #5214
[VerusCoin.git] / src / coins.cpp
1 // Copyright (c) 2012-2013 The Bitcoin developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include "coins.h"
6
7 #include "random.h"
8
9 #include <assert.h>
10
11 // calculate number of bytes for the bitmask, and its number of non-zero bytes
12 // each bit in the bitmask represents the availability of one output, but the
13 // availabilities of the first two outputs are encoded separately
14 void CCoins::CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const {
15     unsigned int nLastUsedByte = 0;
16     for (unsigned int b = 0; 2+b*8 < vout.size(); b++) {
17         bool fZero = true;
18         for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++) {
19             if (!vout[2+b*8+i].IsNull()) {
20                 fZero = false;
21                 continue;
22             }
23         }
24         if (!fZero) {
25             nLastUsedByte = b + 1;
26             nNonzeroBytes++;
27         }
28     }
29     nBytes += nLastUsedByte;
30 }
31
32 bool CCoins::Spend(const COutPoint &out, CTxInUndo &undo) {
33     if (out.n >= vout.size())
34         return false;
35     if (vout[out.n].IsNull())
36         return false;
37     undo = CTxInUndo(vout[out.n]);
38     vout[out.n].SetNull();
39     Cleanup();
40     if (vout.size() == 0) {
41         undo.nHeight = nHeight;
42         undo.fCoinBase = fCoinBase;
43         undo.nVersion = this->nVersion;
44     }
45     return true;
46 }
47
48 bool CCoins::Spend(int nPos) {
49     CTxInUndo undo;
50     COutPoint out(0, nPos);
51     return Spend(out, undo);
52 }
53
54
55 bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; }
56 bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; }
57 uint256 CCoinsView::GetBestBlock() const { return uint256(0); }
58 bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
59 bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; }
60
61
62 CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
63 bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); }
64 bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); }
65 uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
66 void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
67 bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
68 bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); }
69
70 CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
71
72 CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false), hashBlock(0) { }
73
74 CCoinsViewCache::~CCoinsViewCache()
75 {
76     assert(!hasModifier);
77 }
78
79 CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const {
80     CCoinsMap::iterator it = cacheCoins.find(txid);
81     if (it != cacheCoins.end())
82         return it;
83     CCoins tmp;
84     if (!base->GetCoins(txid, tmp))
85         return cacheCoins.end();
86     CCoinsMap::iterator ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())).first;
87     tmp.swap(ret->second.coins);
88     if (ret->second.coins.IsPruned()) {
89         // The parent only has an empty entry for this txid; we can consider our
90         // version as fresh.
91         ret->second.flags = CCoinsCacheEntry::FRESH;
92     }
93     return ret;
94 }
95
96 bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const {
97     CCoinsMap::const_iterator it = FetchCoins(txid);
98     if (it != cacheCoins.end()) {
99         coins = it->second.coins;
100         return true;
101     }
102     return false;
103 }
104
105 CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) {
106     assert(!hasModifier);
107     hasModifier = true;
108     std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry()));
109     if (ret.second) {
110         if (!base->GetCoins(txid, ret.first->second.coins)) {
111             // The parent view does not have this entry; mark it as fresh.
112             ret.first->second.coins.Clear();
113             ret.first->second.flags = CCoinsCacheEntry::FRESH;
114         } else if (ret.first->second.coins.IsPruned()) {
115             // The parent view only has a pruned entry for this; mark it as fresh.
116             ret.first->second.flags = CCoinsCacheEntry::FRESH;
117         }
118     }
119     // Assume that whenever ModifyCoins is called, the entry will be modified.
120     ret.first->second.flags |= CCoinsCacheEntry::DIRTY;
121     return CCoinsModifier(*this, ret.first);
122 }
123
124 const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const {
125     CCoinsMap::const_iterator it = FetchCoins(txid);
126     if (it == cacheCoins.end()) {
127         return NULL;
128     } else {
129         return &it->second.coins;
130     }
131 }
132
133 bool CCoinsViewCache::HaveCoins(const uint256 &txid) const {
134     CCoinsMap::const_iterator it = FetchCoins(txid);
135     // We're using vtx.empty() instead of IsPruned here for performance reasons,
136     // as we only care about the case where an transaction was replaced entirely
137     // in a reorganization (which wipes vout entirely, as opposed to spending
138     // which just cleans individual outputs).
139     return (it != cacheCoins.end() && !it->second.coins.vout.empty());
140 }
141
142 uint256 CCoinsViewCache::GetBestBlock() const {
143     if (hashBlock == uint256(0))
144         hashBlock = base->GetBestBlock();
145     return hashBlock;
146 }
147
148 void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
149     hashBlock = hashBlockIn;
150 }
151
152 bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn) {
153     assert(!hasModifier);
154     for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
155         if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
156             CCoinsMap::iterator itUs = cacheCoins.find(it->first);
157             if (itUs == cacheCoins.end()) {
158                 if (!it->second.coins.IsPruned()) {
159                     // The parent cache does not have an entry, while the child
160                     // cache does have (a non-pruned) one. Move the data up, and
161                     // mark it as fresh (if the grandparent did have it, we
162                     // would have pulled it in at first GetCoins).
163                     assert(it->second.flags & CCoinsCacheEntry::FRESH);
164                     CCoinsCacheEntry& entry = cacheCoins[it->first];
165                     entry.coins.swap(it->second.coins);
166                     entry.flags = CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH;
167                 }
168             } else {
169                 if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) {
170                     // The grandparent does not have an entry, and the child is
171                     // modified and being pruned. This means we can just delete
172                     // it from the parent.
173                     cacheCoins.erase(itUs);
174                 } else {
175                     // A normal modification.
176                     itUs->second.coins.swap(it->second.coins);
177                     itUs->second.flags |= CCoinsCacheEntry::DIRTY;
178                 }
179             }
180         }
181         CCoinsMap::iterator itOld = it++;
182         mapCoins.erase(itOld);
183     }
184     hashBlock = hashBlockIn;
185     return true;
186 }
187
188 bool CCoinsViewCache::Flush() {
189     bool fOk = base->BatchWrite(cacheCoins, hashBlock);
190     cacheCoins.clear();
191     return fOk;
192 }
193
194 unsigned int CCoinsViewCache::GetCacheSize() const {
195     return cacheCoins.size();
196 }
197
198 const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) const
199 {
200     const CCoins* coins = AccessCoins(input.prevout.hash);
201     assert(coins && coins->IsAvailable(input.prevout.n));
202     return coins->vout[input.prevout.n];
203 }
204
205 CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
206 {
207     if (tx.IsCoinBase())
208         return 0;
209
210     CAmount nResult = 0;
211     for (unsigned int i = 0; i < tx.vin.size(); i++)
212         nResult += GetOutputFor(tx.vin[i]).nValue;
213
214     return nResult;
215 }
216
217 bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
218 {
219     if (!tx.IsCoinBase()) {
220         for (unsigned int i = 0; i < tx.vin.size(); i++) {
221             const COutPoint &prevout = tx.vin[i].prevout;
222             const CCoins* coins = AccessCoins(prevout.hash);
223             if (!coins || !coins->IsAvailable(prevout.n)) {
224                 return false;
225             }
226         }
227     }
228     return true;
229 }
230
231 double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
232 {
233     if (tx.IsCoinBase())
234         return 0.0;
235     double dResult = 0.0;
236     BOOST_FOREACH(const CTxIn& txin, tx.vin)
237     {
238         const CCoins* coins = AccessCoins(txin.prevout.hash);
239         assert(coins);
240         if (!coins->IsAvailable(txin.prevout.n)) continue;
241         if (coins->nHeight < nHeight) {
242             dResult += coins->vout[txin.prevout.n].nValue * (nHeight-coins->nHeight);
243         }
244     }
245     return tx.ComputePriority(dResult);
246 }
247
248 CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_) : cache(cache_), it(it_) {}
249
250 CCoinsModifier::~CCoinsModifier()
251 {
252     assert(cache.hasModifier);
253     cache.hasModifier = false;
254     it->second.coins.Cleanup();
255     if ((it->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) {
256         cache.cacheCoins.erase(it);
257     }
258 }
This page took 0.044358 seconds and 4 git commands to generate.