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