]>
Commit | Line | Data |
---|---|---|
f914f1a7 | 1 | // Copyright (c) 2012-2014 The Bitcoin Core developers |
fa94b9d5 | 2 | // Distributed under the MIT software license, see the accompanying |
a0fa20a1 PW |
3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
4 | ||
5 | #include "coins.h" | |
6 | ||
046392dc | 7 | #include "memusage.h" |
bc42503f | 8 | #include "random.h" |
520ced14 | 9 | #include "version.h" |
ec19e8e2 | 10 | #include "policy/fees.h" |
bc42503f | 11 | |
a0fa20a1 PW |
12 | #include <assert.h> |
13 | ||
fa94b9d5 MF |
14 | /** |
15 | * calculate number of bytes for the bitmask, and its number of non-zero bytes | |
16 | * each bit in the bitmask represents the availability of one output, but the | |
17 | * availabilities of the first two outputs are encoded separately | |
18 | */ | |
a0fa20a1 PW |
19 | void CCoins::CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const { |
20 | unsigned int nLastUsedByte = 0; | |
21 | for (unsigned int b = 0; 2+b*8 < vout.size(); b++) { | |
22 | bool fZero = true; | |
23 | for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++) { | |
24 | if (!vout[2+b*8+i].IsNull()) { | |
25 | fZero = false; | |
26 | continue; | |
27 | } | |
28 | } | |
29 | if (!fZero) { | |
30 | nLastUsedByte = b + 1; | |
31 | nNonzeroBytes++; | |
32 | } | |
33 | } | |
34 | nBytes += nLastUsedByte; | |
35 | } | |
36 | ||
c444c620 | 37 | bool CCoins::Spend(uint32_t nPos) |
38 | { | |
39 | if (nPos >= vout.size() || vout[nPos].IsNull()) | |
a0fa20a1 | 40 | return false; |
c444c620 | 41 | vout[nPos].SetNull(); |
a0fa20a1 | 42 | Cleanup(); |
a0fa20a1 PW |
43 | return true; |
44 | } | |
434f3284 | 45 | bool CCoinsView::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return false; } |
9e511dbb | 46 | bool CCoinsView::GetNullifier(const uint256 &nullifier) const { return false; } |
a3dc587a | 47 | bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; } |
a3dc587a | 48 | bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; } |
4f152496 | 49 | uint256 CCoinsView::GetBestBlock() const { return uint256(); } |
9f25631d SB |
50 | uint256 CCoinsView::GetBestAnchor() const { return uint256(); }; |
51 | bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, | |
52 | const uint256 &hashBlock, | |
53 | const uint256 &hashAnchor, | |
45d6bee9 | 54 | CAnchorsMap &mapAnchors, |
bb64be52 | 55 | CNullifiersMap &mapNullifiers) { return false; } |
a3dc587a | 56 | bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; } |
a0fa20a1 PW |
57 | |
58 | ||
7c70438d | 59 | CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { } |
9f25631d | 60 | |
434f3284 | 61 | bool CCoinsViewBacked::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return base->GetAnchorAt(rt, tree); } |
9e511dbb | 62 | bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier) const { return base->GetNullifier(nullifier); } |
a3dc587a | 63 | bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); } |
a3dc587a DK |
64 | bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); } |
65 | uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); } | |
9f25631d | 66 | uint256 CCoinsViewBacked::GetBestAnchor() const { return base->GetBestAnchor(); } |
a0fa20a1 | 67 | void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } |
9f25631d SB |
68 | bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, |
69 | const uint256 &hashBlock, | |
70 | const uint256 &hashAnchor, | |
45d6bee9 | 71 | CAnchorsMap &mapAnchors, |
bb64be52 | 72 | CNullifiersMap &mapNullifiers) { return base->BatchWrite(mapCoins, hashBlock, hashAnchor, mapAnchors, mapNullifiers); } |
a3dc587a | 73 | bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); } |
a0fa20a1 | 74 | |
bc42503f PW |
75 | CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {} |
76 | ||
046392dc | 77 | CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false), cachedCoinsUsage(0) { } |
a0fa20a1 | 78 | |
f28aec01 PW |
79 | CCoinsViewCache::~CCoinsViewCache() |
80 | { | |
81 | assert(!hasModifier); | |
a0fa20a1 PW |
82 | } |
83 | ||
046392dc | 84 | size_t CCoinsViewCache::DynamicMemoryUsage() const { |
7f3c7a68 SB |
85 | return memusage::DynamicUsage(cacheCoins) + |
86 | memusage::DynamicUsage(cacheAnchors) + | |
1d184d53 | 87 | memusage::DynamicUsage(cacheNullifiers) + |
7f3c7a68 | 88 | cachedCoinsUsage; |
046392dc PW |
89 | } |
90 | ||
f28aec01 | 91 | CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const { |
bc42503f PW |
92 | CCoinsMap::iterator it = cacheCoins.find(txid); |
93 | if (it != cacheCoins.end()) | |
a0fa20a1 PW |
94 | return it; |
95 | CCoins tmp; | |
058b08c1 | 96 | if (!base->GetCoins(txid, tmp)) |
a0fa20a1 | 97 | return cacheCoins.end(); |
058b08c1 PW |
98 | CCoinsMap::iterator ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())).first; |
99 | tmp.swap(ret->second.coins); | |
100 | if (ret->second.coins.IsPruned()) { | |
101 | // The parent only has an empty entry for this txid; we can consider our | |
102 | // version as fresh. | |
103 | ret->second.flags = CCoinsCacheEntry::FRESH; | |
104 | } | |
6bd1d60c | 105 | cachedCoinsUsage += ret->second.coins.DynamicMemoryUsage(); |
a0fa20a1 PW |
106 | return ret; |
107 | } | |
108 | ||
9f25631d | 109 | |
434f3284 | 110 | bool CCoinsViewCache::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { |
9f25631d SB |
111 | CAnchorsMap::const_iterator it = cacheAnchors.find(rt); |
112 | if (it != cacheAnchors.end()) { | |
113 | if (it->second.entered) { | |
434f3284 | 114 | tree = it->second.tree; |
9f25631d SB |
115 | return true; |
116 | } else { | |
117 | return false; | |
118 | } | |
119 | } | |
120 | ||
9f25631d SB |
121 | if (!base->GetAnchorAt(rt, tree)) { |
122 | return false; | |
123 | } | |
124 | ||
cf471983 SB |
125 | CAnchorsMap::iterator ret = cacheAnchors.insert(std::make_pair(rt, CAnchorsCacheEntry())).first; |
126 | ret->second.entered = true; | |
434f3284 | 127 | ret->second.tree = tree; |
43a03e3b | 128 | cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage(); |
9f25631d SB |
129 | |
130 | return true; | |
131 | } | |
132 | ||
9e511dbb SB |
133 | bool CCoinsViewCache::GetNullifier(const uint256 &nullifier) const { |
134 | CNullifiersMap::iterator it = cacheNullifiers.find(nullifier); | |
1d184d53 | 135 | if (it != cacheNullifiers.end()) |
45d6bee9 SB |
136 | return it->second.entered; |
137 | ||
9e511dbb SB |
138 | CNullifiersCacheEntry entry; |
139 | bool tmp = base->GetNullifier(nullifier); | |
45d6bee9 SB |
140 | entry.entered = tmp; |
141 | ||
9e511dbb | 142 | cacheNullifiers.insert(std::make_pair(nullifier, entry)); |
45d6bee9 | 143 | |
45d6bee9 SB |
144 | return tmp; |
145 | } | |
9f25631d | 146 | |
434f3284 SB |
147 | void CCoinsViewCache::PushAnchor(const ZCIncrementalMerkleTree &tree) { |
148 | uint256 newrt = tree.root(); | |
9f25631d SB |
149 | |
150 | auto currentRoot = GetBestAnchor(); | |
151 | ||
152 | // We don't want to overwrite an anchor we already have. | |
153 | // This occurs when a block doesn't modify mapAnchors at all, | |
b7e4abd6 | 154 | // because there are no joinsplits. We could get around this a |
9f25631d SB |
155 | // different way (make all blocks modify mapAnchors somehow) |
156 | // but this is simpler to reason about. | |
157 | if (currentRoot != newrt) { | |
7f3c7a68 SB |
158 | auto insertRet = cacheAnchors.insert(std::make_pair(newrt, CAnchorsCacheEntry())); |
159 | CAnchorsMap::iterator ret = insertRet.first; | |
9f25631d SB |
160 | |
161 | ret->second.entered = true; | |
434f3284 | 162 | ret->second.tree = tree; |
9f25631d SB |
163 | ret->second.flags = CAnchorsCacheEntry::DIRTY; |
164 | ||
7f3c7a68 SB |
165 | if (insertRet.second) { |
166 | // An insert took place | |
43a03e3b | 167 | cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage(); |
7f3c7a68 SB |
168 | } |
169 | ||
9f25631d SB |
170 | hashAnchor = newrt; |
171 | } | |
172 | } | |
173 | ||
174 | void CCoinsViewCache::PopAnchor(const uint256 &newrt) { | |
175 | auto currentRoot = GetBestAnchor(); | |
176 | ||
177 | // Blocks might not change the commitment tree, in which | |
178 | // case restoring the "old" anchor during a reorg must | |
179 | // have no effect. | |
180 | if (currentRoot != newrt) { | |
ebd9aa11 SB |
181 | // Bring the current best anchor into our local cache |
182 | // so that its tree exists in memory. | |
183 | { | |
184 | ZCIncrementalMerkleTree tree; | |
185 | assert(GetAnchorAt(currentRoot, tree)); | |
186 | } | |
9f25631d | 187 | |
ebd9aa11 SB |
188 | // Mark the anchor as unentered, removing it from view |
189 | cacheAnchors[currentRoot].entered = false; | |
190 | ||
191 | // Mark the cache entry as dirty so it's propagated | |
192 | cacheAnchors[currentRoot].flags = CAnchorsCacheEntry::DIRTY; | |
9f25631d | 193 | |
ebd9aa11 | 194 | // Mark the new root as the best anchor |
9f25631d SB |
195 | hashAnchor = newrt; |
196 | } | |
197 | } | |
198 | ||
9e511dbb SB |
199 | void CCoinsViewCache::SetNullifier(const uint256 &nullifier, bool spent) { |
200 | std::pair<CNullifiersMap::iterator, bool> ret = cacheNullifiers.insert(std::make_pair(nullifier, CNullifiersCacheEntry())); | |
45d6bee9 | 201 | ret.first->second.entered = spent; |
9e511dbb | 202 | ret.first->second.flags |= CNullifiersCacheEntry::DIRTY; |
45d6bee9 SB |
203 | } |
204 | ||
058b08c1 PW |
205 | bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const { |
206 | CCoinsMap::const_iterator it = FetchCoins(txid); | |
207 | if (it != cacheCoins.end()) { | |
208 | coins = it->second.coins; | |
209 | return true; | |
210 | } | |
211 | return false; | |
a3dc587a DK |
212 | } |
213 | ||
f28aec01 PW |
214 | CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) { |
215 | assert(!hasModifier); | |
058b08c1 | 216 | std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())); |
046392dc | 217 | size_t cachedCoinUsage = 0; |
f28aec01 | 218 | if (ret.second) { |
058b08c1 PW |
219 | if (!base->GetCoins(txid, ret.first->second.coins)) { |
220 | // The parent view does not have this entry; mark it as fresh. | |
221 | ret.first->second.coins.Clear(); | |
222 | ret.first->second.flags = CCoinsCacheEntry::FRESH; | |
223 | } else if (ret.first->second.coins.IsPruned()) { | |
224 | // The parent view only has a pruned entry for this; mark it as fresh. | |
225 | ret.first->second.flags = CCoinsCacheEntry::FRESH; | |
226 | } | |
046392dc | 227 | } else { |
6bd1d60c | 228 | cachedCoinUsage = ret.first->second.coins.DynamicMemoryUsage(); |
f28aec01 | 229 | } |
058b08c1 PW |
230 | // Assume that whenever ModifyCoins is called, the entry will be modified. |
231 | ret.first->second.flags |= CCoinsCacheEntry::DIRTY; | |
046392dc | 232 | return CCoinsModifier(*this, ret.first, cachedCoinUsage); |
a0fa20a1 PW |
233 | } |
234 | ||
629d75fa PW |
235 | const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const { |
236 | CCoinsMap::const_iterator it = FetchCoins(txid); | |
237 | if (it == cacheCoins.end()) { | |
238 | return NULL; | |
239 | } else { | |
058b08c1 | 240 | return &it->second.coins; |
629d75fa | 241 | } |
a3dc587a DK |
242 | } |
243 | ||
a3dc587a DK |
244 | bool CCoinsViewCache::HaveCoins(const uint256 &txid) const { |
245 | CCoinsMap::const_iterator it = FetchCoins(txid); | |
d4d3fbd8 | 246 | // We're using vtx.empty() instead of IsPruned here for performance reasons, |
fa94b9d5 | 247 | // as we only care about the case where a transaction was replaced entirely |
d4d3fbd8 PW |
248 | // in a reorganization (which wipes vout entirely, as opposed to spending |
249 | // which just cleans individual outputs). | |
058b08c1 | 250 | return (it != cacheCoins.end() && !it->second.coins.vout.empty()); |
a0fa20a1 PW |
251 | } |
252 | ||
a3dc587a | 253 | uint256 CCoinsViewCache::GetBestBlock() const { |
4f152496 | 254 | if (hashBlock.IsNull()) |
a0fa20a1 PW |
255 | hashBlock = base->GetBestBlock(); |
256 | return hashBlock; | |
257 | } | |
258 | ||
9f25631d SB |
259 | |
260 | uint256 CCoinsViewCache::GetBestAnchor() const { | |
261 | if (hashAnchor.IsNull()) | |
262 | hashAnchor = base->GetBestAnchor(); | |
263 | return hashAnchor; | |
264 | } | |
265 | ||
c9d1a81c | 266 | void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) { |
a0fa20a1 | 267 | hashBlock = hashBlockIn; |
a0fa20a1 PW |
268 | } |
269 | ||
9f25631d SB |
270 | bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, |
271 | const uint256 &hashBlockIn, | |
272 | const uint256 &hashAnchorIn, | |
45d6bee9 | 273 | CAnchorsMap &mapAnchors, |
bb64be52 | 274 | CNullifiersMap &mapNullifiers) { |
f28aec01 | 275 | assert(!hasModifier); |
b0875eb3 | 276 | for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { |
058b08c1 PW |
277 | if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization). |
278 | CCoinsMap::iterator itUs = cacheCoins.find(it->first); | |
279 | if (itUs == cacheCoins.end()) { | |
280 | if (!it->second.coins.IsPruned()) { | |
281 | // The parent cache does not have an entry, while the child | |
282 | // cache does have (a non-pruned) one. Move the data up, and | |
283 | // mark it as fresh (if the grandparent did have it, we | |
284 | // would have pulled it in at first GetCoins). | |
285 | assert(it->second.flags & CCoinsCacheEntry::FRESH); | |
286 | CCoinsCacheEntry& entry = cacheCoins[it->first]; | |
287 | entry.coins.swap(it->second.coins); | |
6bd1d60c | 288 | cachedCoinsUsage += entry.coins.DynamicMemoryUsage(); |
058b08c1 PW |
289 | entry.flags = CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH; |
290 | } | |
291 | } else { | |
292 | if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) { | |
293 | // The grandparent does not have an entry, and the child is | |
294 | // modified and being pruned. This means we can just delete | |
295 | // it from the parent. | |
6bd1d60c | 296 | cachedCoinsUsage -= itUs->second.coins.DynamicMemoryUsage(); |
058b08c1 PW |
297 | cacheCoins.erase(itUs); |
298 | } else { | |
299 | // A normal modification. | |
6bd1d60c | 300 | cachedCoinsUsage -= itUs->second.coins.DynamicMemoryUsage(); |
058b08c1 | 301 | itUs->second.coins.swap(it->second.coins); |
6bd1d60c | 302 | cachedCoinsUsage += itUs->second.coins.DynamicMemoryUsage(); |
058b08c1 PW |
303 | itUs->second.flags |= CCoinsCacheEntry::DIRTY; |
304 | } | |
305 | } | |
306 | } | |
b0875eb3 PW |
307 | CCoinsMap::iterator itOld = it++; |
308 | mapCoins.erase(itOld); | |
309 | } | |
9f25631d SB |
310 | |
311 | for (CAnchorsMap::iterator child_it = mapAnchors.begin(); child_it != mapAnchors.end();) | |
312 | { | |
313 | if (child_it->second.flags & CAnchorsCacheEntry::DIRTY) { | |
314 | CAnchorsMap::iterator parent_it = cacheAnchors.find(child_it->first); | |
315 | ||
316 | if (parent_it == cacheAnchors.end()) { | |
f398a947 SB |
317 | CAnchorsCacheEntry& entry = cacheAnchors[child_it->first]; |
318 | entry.entered = child_it->second.entered; | |
319 | entry.tree = child_it->second.tree; | |
320 | entry.flags = CAnchorsCacheEntry::DIRTY; | |
9f25631d | 321 | |
43a03e3b | 322 | cachedCoinsUsage += entry.tree.DynamicMemoryUsage(); |
9f25631d SB |
323 | } else { |
324 | if (parent_it->second.entered != child_it->second.entered) { | |
325 | // The parent may have removed the entry. | |
326 | parent_it->second.entered = child_it->second.entered; | |
327 | parent_it->second.flags |= CAnchorsCacheEntry::DIRTY; | |
328 | } | |
329 | } | |
330 | } | |
331 | ||
332 | CAnchorsMap::iterator itOld = child_it++; | |
333 | mapAnchors.erase(itOld); | |
334 | } | |
45d6bee9 | 335 | |
bb64be52 | 336 | for (CNullifiersMap::iterator child_it = mapNullifiers.begin(); child_it != mapNullifiers.end();) |
45d6bee9 | 337 | { |
9e511dbb | 338 | if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization). |
1d184d53 | 339 | CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first); |
45d6bee9 | 340 | |
1d184d53 | 341 | if (parent_it == cacheNullifiers.end()) { |
f398a947 SB |
342 | CNullifiersCacheEntry& entry = cacheNullifiers[child_it->first]; |
343 | entry.entered = child_it->second.entered; | |
344 | entry.flags = CNullifiersCacheEntry::DIRTY; | |
45d6bee9 SB |
345 | } else { |
346 | if (parent_it->second.entered != child_it->second.entered) { | |
347 | parent_it->second.entered = child_it->second.entered; | |
9e511dbb | 348 | parent_it->second.flags |= CNullifiersCacheEntry::DIRTY; |
45d6bee9 SB |
349 | } |
350 | } | |
351 | } | |
d889a287 | 352 | CNullifiersMap::iterator itOld = child_it++; |
bb64be52 | 353 | mapNullifiers.erase(itOld); |
45d6bee9 SB |
354 | } |
355 | ||
9f25631d | 356 | hashAnchor = hashAnchorIn; |
a0fa20a1 PW |
357 | hashBlock = hashBlockIn; |
358 | return true; | |
359 | } | |
360 | ||
361 | bool CCoinsViewCache::Flush() { | |
1d184d53 | 362 | bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashAnchor, cacheAnchors, cacheNullifiers); |
b0875eb3 | 363 | cacheCoins.clear(); |
9f25631d | 364 | cacheAnchors.clear(); |
1d184d53 | 365 | cacheNullifiers.clear(); |
046392dc | 366 | cachedCoinsUsage = 0; |
a0fa20a1 PW |
367 | return fOk; |
368 | } | |
369 | ||
a3dc587a | 370 | unsigned int CCoinsViewCache::GetCacheSize() const { |
a0fa20a1 PW |
371 | return cacheCoins.size(); |
372 | } | |
373 | ||
a3dc587a | 374 | const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) const |
a0fa20a1 | 375 | { |
629d75fa PW |
376 | const CCoins* coins = AccessCoins(input.prevout.hash); |
377 | assert(coins && coins->IsAvailable(input.prevout.n)); | |
378 | return coins->vout[input.prevout.n]; | |
a0fa20a1 PW |
379 | } |
380 | ||
a372168e | 381 | CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const |
a0fa20a1 PW |
382 | { |
383 | if (tx.IsCoinBase()) | |
384 | return 0; | |
385 | ||
a372168e | 386 | CAmount nResult = 0; |
a0fa20a1 PW |
387 | for (unsigned int i = 0; i < tx.vin.size(); i++) |
388 | nResult += GetOutputFor(tx.vin[i]).nValue; | |
389 | ||
942bc467 | 390 | nResult += tx.GetJoinSplitValueIn(); |
f512cf7c | 391 | |
a0fa20a1 PW |
392 | return nResult; |
393 | } | |
394 | ||
ee964faf | 395 | bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const |
a8ac403d | 396 | { |
6c59778a SB |
397 | boost::unordered_map<uint256, ZCIncrementalMerkleTree, CCoinsKeyHasher> intermediates; |
398 | ||
b7e4abd6 | 399 | BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) |
a8ac403d | 400 | { |
9e511dbb | 401 | BOOST_FOREACH(const uint256& nullifier, joinsplit.nullifiers) |
d66877af | 402 | { |
9e511dbb SB |
403 | if (GetNullifier(nullifier)) { |
404 | // If the nullifier is set, this transaction | |
d66877af SB |
405 | // double-spends! |
406 | return false; | |
407 | } | |
408 | } | |
409 | ||
434f3284 | 410 | ZCIncrementalMerkleTree tree; |
b7e4abd6 | 411 | auto it = intermediates.find(joinsplit.anchor); |
6c59778a SB |
412 | if (it != intermediates.end()) { |
413 | tree = it->second; | |
b7e4abd6 | 414 | } else if (!GetAnchorAt(joinsplit.anchor, tree)) { |
a8ac403d SB |
415 | return false; |
416 | } | |
6c59778a | 417 | |
b7e4abd6 | 418 | BOOST_FOREACH(const uint256& commitment, joinsplit.commitments) |
6c59778a SB |
419 | { |
420 | tree.append(commitment); | |
421 | } | |
422 | ||
423 | intermediates.insert(std::make_pair(tree.root(), tree)); | |
a8ac403d SB |
424 | } |
425 | ||
426 | return true; | |
427 | } | |
428 | ||
a3dc587a | 429 | bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const |
a0fa20a1 PW |
430 | { |
431 | if (!tx.IsCoinBase()) { | |
a0fa20a1 PW |
432 | for (unsigned int i = 0; i < tx.vin.size(); i++) { |
433 | const COutPoint &prevout = tx.vin[i].prevout; | |
629d75fa PW |
434 | const CCoins* coins = AccessCoins(prevout.hash); |
435 | if (!coins || !coins->IsAvailable(prevout.n)) { | |
a0fa20a1 | 436 | return false; |
629d75fa | 437 | } |
a0fa20a1 PW |
438 | } |
439 | } | |
440 | return true; | |
441 | } | |
4d707d51 | 442 | |
a3dc587a | 443 | double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const |
4d707d51 GA |
444 | { |
445 | if (tx.IsCoinBase()) | |
446 | return 0.0; | |
ec19e8e2 DH |
447 | |
448 | // Joinsplits do not reveal any information about the value or age of a note, so we | |
449 | // cannot apply the priority algorithm used for transparent utxos. Instead, we just | |
450 | // use the maximum priority whenever a transaction contains any JoinSplits. | |
451 | // (Note that coinbase transactions cannot contain JoinSplits.) | |
452 | // FIXME: this logic is partially duplicated between here and CreateNewBlock in miner.cpp. | |
453 | ||
454 | if (tx.vjoinsplit.size() > 0) { | |
455 | return MAX_PRIORITY; | |
456 | } | |
457 | ||
4d707d51 GA |
458 | double dResult = 0.0; |
459 | BOOST_FOREACH(const CTxIn& txin, tx.vin) | |
460 | { | |
629d75fa PW |
461 | const CCoins* coins = AccessCoins(txin.prevout.hash); |
462 | assert(coins); | |
463 | if (!coins->IsAvailable(txin.prevout.n)) continue; | |
464 | if (coins->nHeight < nHeight) { | |
465 | dResult += coins->vout[txin.prevout.n].nValue * (nHeight-coins->nHeight); | |
4d707d51 GA |
466 | } |
467 | } | |
520ced14 | 468 | |
4d707d51 GA |
469 | return tx.ComputePriority(dResult); |
470 | } | |
f28aec01 | 471 | |
046392dc | 472 | CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_, size_t usage) : cache(cache_), it(it_), cachedCoinUsage(usage) { |
02bced16 PW |
473 | assert(!cache.hasModifier); |
474 | cache.hasModifier = true; | |
475 | } | |
f28aec01 | 476 | |
058b08c1 PW |
477 | CCoinsModifier::~CCoinsModifier() |
478 | { | |
f28aec01 PW |
479 | assert(cache.hasModifier); |
480 | cache.hasModifier = false; | |
058b08c1 | 481 | it->second.coins.Cleanup(); |
046392dc | 482 | cache.cachedCoinsUsage -= cachedCoinUsage; // Subtract the old usage |
058b08c1 PW |
483 | if ((it->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) { |
484 | cache.cacheCoins.erase(it); | |
046392dc PW |
485 | } else { |
486 | // If the coin still exists after the modification, add the new usage | |
6bd1d60c | 487 | cache.cachedCoinsUsage += it->second.coins.DynamicMemoryUsage(); |
058b08c1 | 488 | } |
f28aec01 | 489 | } |