]>
Commit | Line | Data |
---|---|---|
319b1160 | 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
f914f1a7 | 2 | // Copyright (c) 2009-2014 The Bitcoin Core developers |
7329fdd1 | 3 | // Distributed under the MIT software license, see the accompanying |
bc909a7a | 4 | // file COPYING or https://www.opensource.org/licenses/mit-license.php . |
319b1160 | 5 | |
319b1160 | 6 | #include "txmempool.h" |
611116d4 | 7 | |
71697f97 | 8 | #include "clientversion.h" |
691161d4 | 9 | #include "consensus/consensus.h" |
da29ecbc | 10 | #include "consensus/validation.h" |
b7b4318f | 11 | #include "main.h" |
b649e039 | 12 | #include "policy/fees.h" |
fa736190 | 13 | #include "streams.h" |
f5b35d23 | 14 | #include "timedata.h" |
ad49c256 | 15 | #include "util.h" |
a372168e | 16 | #include "utilmoneystr.h" |
3ff68c50 | 17 | #include "validationinterface.h" |
85c579e3 | 18 | #include "version.h" |
22adf258 | 19 | #include "cc/CCinclude.h" |
41f170fd | 20 | #include "pbaas/pbaas.h" |
22adf258 | 21 | #include "pbaas/identity.h" |
7e2cbee1 | 22 | #define _COINBASE_MATURITY 100 |
319b1160 GA |
23 | |
24 | using namespace std; | |
25 | ||
8bdd2877 | 26 | CTxMemPoolEntry::CTxMemPoolEntry(): |
a4b25180 | 27 | nFee(0), nTxSize(0), nModSize(0), nUsageSize(0), nTime(0), dPriority(0.0), |
41f170fd | 28 | hadNoDependencies(false), spendsCoinbase(false), hasReserve(false) |
4d707d51 GA |
29 | { |
30 | nHeight = MEMPOOL_HEIGHT; | |
31 | } | |
32 | ||
a372168e | 33 | CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, |
4d707d51 | 34 | int64_t _nTime, double _dPriority, |
a4b25180 | 35 | unsigned int _nHeight, bool poolHasNoInputsOf, |
41f170fd | 36 | bool _spendsCoinbase, uint32_t _nBranchId, bool hasreserve): |
b649e039 | 37 | tx(_tx), nFee(_nFee), nTime(_nTime), dPriority(_dPriority), nHeight(_nHeight), |
41f170fd | 38 | hadNoDependencies(poolHasNoInputsOf), hasReserve(hasreserve), |
34a64fe0 | 39 | spendsCoinbase(_spendsCoinbase), nBranchId(_nBranchId) |
4d707d51 GA |
40 | { |
41 | nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); | |
c26649f9 | 42 | nModSize = tx.CalculateModifiedSize(nTxSize); |
6bd1d60c | 43 | nUsageSize = RecursiveDynamicUsage(tx); |
e328fa32 | 44 | feeRate = CFeeRate(nFee, nTxSize); |
4d707d51 GA |
45 | } |
46 | ||
47 | CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) | |
48 | { | |
49 | *this = other; | |
50 | } | |
51 | ||
52 | double | |
53 | CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const | |
54 | { | |
a372168e | 55 | CAmount nValueIn = tx.GetValueOut()+nFee; |
c8c677c9 | 56 | CCurrencyState currencyState; |
1e583775 | 57 | unsigned int lastHeight = currentHeight < 1 ? 0 : currentHeight - 1; |
1fb6db72 | 58 | AssertLockHeld(cs_main); |
1e583775 | 59 | if (hasReserve && (currencyState = ConnectedChains.GetCurrencyState(currentHeight - 1)).IsValid()) |
41f170fd | 60 | { |
1e583775 | 61 | nValueIn += currencyState.ReserveToNative(tx.GetReserveValueOut()); |
41f170fd | 62 | } |
c26649f9 | 63 | double deltaPriority = ((double)(currentHeight-nHeight)*nValueIn)/nModSize; |
4d707d51 GA |
64 | double dResult = dPriority + deltaPriority; |
65 | return dResult; | |
66 | } | |
67 | ||
8bdd2877 | 68 | CTxMemPool::CTxMemPool(const CFeeRate& _minRelayFee) : |
b649e039 | 69 | nTransactionsUpdated(0) |
319b1160 GA |
70 | { |
71 | // Sanity checks off by default for performance, because otherwise | |
72 | // accepting transactions becomes O(N^2) where N is the number | |
73 | // of transactions in the pool | |
934fd197 | 74 | nCheckFrequency = 0; |
171ca774 | 75 | |
b649e039 | 76 | minerPolicyEstimator = new CBlockPolicyEstimator(_minRelayFee); |
171ca774 GA |
77 | } |
78 | ||
79 | CTxMemPool::~CTxMemPool() | |
80 | { | |
81 | delete minerPolicyEstimator; | |
319b1160 GA |
82 | } |
83 | ||
84 | void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins) | |
85 | { | |
86 | LOCK(cs); | |
87 | ||
88 | std::map<COutPoint, CInPoint>::iterator it = mapNextTx.lower_bound(COutPoint(hashTx, 0)); | |
89 | ||
90 | // iterate over all COutPoints in mapNextTx whose hash equals the provided hashTx | |
91 | while (it != mapNextTx.end() && it->first.hash == hashTx) { | |
92 | coins.Spend(it->first.n); // and remove those outputs from coins | |
93 | it++; | |
94 | } | |
95 | } | |
96 | ||
97 | unsigned int CTxMemPool::GetTransactionsUpdated() const | |
98 | { | |
99 | LOCK(cs); | |
100 | return nTransactionsUpdated; | |
101 | } | |
102 | ||
103 | void CTxMemPool::AddTransactionsUpdated(unsigned int n) | |
104 | { | |
105 | LOCK(cs); | |
106 | nTransactionsUpdated += n; | |
107 | } | |
108 | ||
109 | ||
b649e039 | 110 | bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate) |
319b1160 GA |
111 | { |
112 | // Add to memory pool without checking anything. | |
113 | // Used by main.cpp AcceptToMemoryPool(), which DOES do | |
114 | // all the appropriate checks. | |
115 | LOCK(cs); | |
e328fa32 AH |
116 | mapTx.insert(entry); |
117 | const CTransaction& tx = mapTx.find(hash)->GetTx(); | |
3ff68c50 | 118 | mapRecentlyAddedTx[tx.GetHash()] = &tx; |
9d8322a3 | 119 | nRecentlyAddedSequence += 1; |
0cb91a8d SS |
120 | if (!tx.IsCoinImport()) { |
121 | for (unsigned int i = 0; i < tx.vin.size(); i++) | |
122 | mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); | |
123 | } | |
f57f76d7 | 124 | BOOST_FOREACH(const JSDescription &joinsplit, tx.vJoinSplit) { |
22de1602 | 125 | BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) { |
9669920f | 126 | mapSproutNullifiers[nf] = &tx; |
d66877af SB |
127 | } |
128 | } | |
cab341e1 EOW |
129 | for (const SpendDescription &spendDescription : tx.vShieldedSpend) { |
130 | mapSaplingNullifiers[spendDescription.nullifier] = &tx; | |
131 | } | |
b649e039 AM |
132 | nTransactionsUpdated++; |
133 | totalTxSize += entry.GetTxSize(); | |
bde5c8b0 | 134 | cachedInnerUsage += entry.DynamicMemoryUsage(); |
b649e039 AM |
135 | minerPolicyEstimator->processTransaction(entry, fCurrentEstimate); |
136 | ||
319b1160 GA |
137 | return true; |
138 | } | |
139 | ||
8b78a819 T |
140 | void CTxMemPool::addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view) |
141 | { | |
142 | LOCK(cs); | |
143 | const CTransaction& tx = entry.GetTx(); | |
144 | std::vector<CMempoolAddressDeltaKey> inserted; | |
145 | ||
146 | uint256 txhash = tx.GetHash(); | |
1fa4454d MT |
147 | if (!tx.IsCoinBase()) |
148 | { | |
149 | for (unsigned int j = 0; j < tx.vin.size(); j++) { | |
150 | const CTxIn input = tx.vin[j]; | |
151 | const CTxOut &prevout = view.GetOutputFor(input); | |
05cef42a | 152 | COptCCParams p; |
153 | if (prevout.scriptPubKey.IsPayToCryptoCondition(p)) | |
2f537fa1 | 154 | { |
05cef42a | 155 | std::vector<CTxDestination> dests; |
156 | if (p.IsValid()) | |
157 | { | |
158 | dests = p.GetDestinations(); | |
159 | } | |
160 | else | |
161 | { | |
162 | dests = prevout.scriptPubKey.GetDestinations(); | |
163 | } | |
9bd5cb8e | 164 | |
165 | uint32_t nHeight = chainActive.Height(); | |
166 | std::map<uint160, uint32_t> heightOffsets = p.GetIndexHeightOffsets(chainActive.Height()); | |
167 | ||
3d682fc8 | 168 | for (auto dest : dests) |
2f537fa1 | 169 | { |
3d682fc8 | 170 | if (dest.which() != COptCCParams::ADDRTYPE_INVALID) |
2f537fa1 | 171 | { |
9bd5cb8e | 172 | uint160 destID = GetDestinationID(dest); |
173 | if (!(dest.which() == COptCCParams::ADDRTYPE_INDEX && heightOffsets.count(destID) && heightOffsets[destID] != nHeight)) | |
174 | { | |
175 | CMempoolAddressDeltaKey key(AddressTypeFromDest(dest), destID, txhash, j, 1); | |
176 | CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n); | |
177 | mapAddress.insert(make_pair(key, delta)); | |
178 | inserted.push_back(key); | |
179 | } | |
2f537fa1 | 180 | } |
181 | } | |
182 | } | |
183 | else | |
184 | { | |
05cef42a | 185 | CScript::ScriptType type = prevout.scriptPubKey.GetType(); |
186 | if (type == CScript::UNKNOWN) | |
187 | continue; | |
188 | ||
2f537fa1 | 189 | CMempoolAddressDeltaKey key(type, prevout.scriptPubKey.AddressHash(), txhash, j, 1); |
190 | CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n); | |
191 | mapAddress.insert(make_pair(key, delta)); | |
192 | inserted.push_back(key); | |
193 | } | |
7f190223 | 194 | } |
8b78a819 T |
195 | } |
196 | ||
68e174e2 LR |
197 | for (unsigned int j = 0; j < tx.vout.size(); j++) { |
198 | const CTxOut &out = tx.vout[j]; | |
2f537fa1 | 199 | |
05cef42a | 200 | COptCCParams p; |
201 | if (out.scriptPubKey.IsPayToCryptoCondition(p)) | |
2f537fa1 | 202 | { |
05cef42a | 203 | std::vector<CTxDestination> dests; |
204 | if (p.IsValid()) | |
205 | { | |
206 | dests = p.GetDestinations(); | |
207 | } | |
208 | else | |
209 | { | |
210 | dests = out.scriptPubKey.GetDestinations(); | |
211 | } | |
9bd5cb8e | 212 | |
213 | uint32_t nHeight = chainActive.Height(); | |
214 | std::map<uint160, uint32_t> heightOffsets = p.GetIndexHeightOffsets(nHeight); | |
215 | ||
3d682fc8 | 216 | for (auto dest : dests) |
2f537fa1 | 217 | { |
3d682fc8 | 218 | if (dest.which() != COptCCParams::ADDRTYPE_INVALID) |
2f537fa1 | 219 | { |
9bd5cb8e | 220 | uint160 destID = GetDestinationID(dest); |
7c8e5e18 | 221 | if (!(dest.which() == COptCCParams::ADDRTYPE_INDEX && heightOffsets.count(destID) && heightOffsets[destID] > nHeight)) |
9bd5cb8e | 222 | { |
223 | CMempoolAddressDeltaKey key(AddressTypeFromDest(dest), GetDestinationID(dest), txhash, j, 0); | |
224 | mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue))); | |
225 | inserted.push_back(key); | |
226 | } | |
2f537fa1 | 227 | } |
228 | } | |
229 | } | |
230 | else | |
231 | { | |
05cef42a | 232 | CScript::ScriptType type = out.scriptPubKey.GetType(); |
233 | if (type == CScript::UNKNOWN) | |
234 | continue; | |
235 | ||
2f537fa1 | 236 | CMempoolAddressDeltaKey key(type, out.scriptPubKey.AddressHash(), txhash, j, 0); |
237 | mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue))); | |
238 | inserted.push_back(key); | |
239 | } | |
68e174e2 | 240 | } |
8b78a819 T |
241 | mapAddressInserted.insert(make_pair(txhash, inserted)); |
242 | } | |
243 | ||
88d014d0 | 244 | bool CTxMemPool::getAddressIndex(const std::vector<std::pair<uint160, int> > &addresses, std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> > &results) |
8b78a819 T |
245 | { |
246 | LOCK(cs); | |
88d014d0 | 247 | for (std::vector<std::pair<uint160, int> >::const_iterator it = addresses.begin(); it != addresses.end(); it++) { |
248 | auto ait = mapAddress.lower_bound(CMempoolAddressDeltaKey((*it).second, (*it).first)); | |
8b78a819 T |
249 | while (ait != mapAddress.end() && (*ait).first.addressBytes == (*it).first && (*ait).first.type == (*it).second) { |
250 | results.push_back(*ait); | |
251 | ait++; | |
252 | } | |
253 | } | |
254 | return true; | |
255 | } | |
256 | ||
257 | bool CTxMemPool::removeAddressIndex(const uint256 txhash) | |
258 | { | |
259 | LOCK(cs); | |
68e174e2 | 260 | auto it = mapAddressInserted.find(txhash); |
8b78a819 T |
261 | |
262 | if (it != mapAddressInserted.end()) { | |
263 | std::vector<CMempoolAddressDeltaKey> keys = (*it).second; | |
264 | for (std::vector<CMempoolAddressDeltaKey>::iterator mit = keys.begin(); mit != keys.end(); mit++) { | |
265 | mapAddress.erase(*mit); | |
266 | } | |
267 | mapAddressInserted.erase(it); | |
268 | } | |
269 | ||
270 | return true; | |
271 | } | |
272 | ||
273 | void CTxMemPool::addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view) | |
274 | { | |
275 | LOCK(cs); | |
8b78a819 | 276 | const CTransaction& tx = entry.GetTx(); |
86b23f37 | 277 | uint256 txhash = tx.GetHash(); |
8b78a819 T |
278 | std::vector<CSpentIndexKey> inserted; |
279 | ||
8b78a819 T |
280 | for (unsigned int j = 0; j < tx.vin.size(); j++) { |
281 | const CTxIn input = tx.vin[j]; | |
282 | const CTxOut &prevout = view.GetOutputFor(input); | |
8b78a819 | 283 | CSpentIndexKey key = CSpentIndexKey(input.prevout.hash, input.prevout.n); |
86b23f37 LR |
284 | CSpentIndexValue value = CSpentIndexValue(txhash, j, -1, prevout.nValue, |
285 | prevout.scriptPubKey.GetType(), | |
286 | prevout.scriptPubKey.AddressHash()); | |
8b78a819 T |
287 | mapSpent.insert(make_pair(key, value)); |
288 | inserted.push_back(key); | |
8b78a819 | 289 | } |
8b78a819 T |
290 | mapSpentInserted.insert(make_pair(txhash, inserted)); |
291 | } | |
292 | ||
86b23f37 | 293 | bool CTxMemPool::getSpentIndex(const CSpentIndexKey &key, CSpentIndexValue &value) |
8b78a819 T |
294 | { |
295 | LOCK(cs); | |
86b23f37 | 296 | std::map<CSpentIndexKey, CSpentIndexValue, CSpentIndexKeyCompare>::iterator it = mapSpent.find(key); |
8b78a819 T |
297 | if (it != mapSpent.end()) { |
298 | value = it->second; | |
299 | return true; | |
300 | } | |
301 | return false; | |
302 | } | |
303 | ||
304 | bool CTxMemPool::removeSpentIndex(const uint256 txhash) | |
305 | { | |
306 | LOCK(cs); | |
86b23f37 | 307 | auto it = mapSpentInserted.find(txhash); |
8b78a819 T |
308 | |
309 | if (it != mapSpentInserted.end()) { | |
310 | std::vector<CSpentIndexKey> keys = (*it).second; | |
311 | for (std::vector<CSpentIndexKey>::iterator mit = keys.begin(); mit != keys.end(); mit++) { | |
312 | mapSpent.erase(*mit); | |
313 | } | |
314 | mapSpentInserted.erase(it); | |
315 | } | |
316 | ||
317 | return true; | |
318 | } | |
319b1160 | 319 | |
7fd6219a | 320 | void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& removed, bool fRecursive) |
319b1160 GA |
321 | { |
322 | // Remove transaction from memory pool | |
323 | { | |
324 | LOCK(cs); | |
7fd6219a | 325 | std::deque<uint256> txToRemove; |
805344dc S |
326 | txToRemove.push_back(origTx.GetHash()); |
327 | if (fRecursive && !mapTx.count(origTx.GetHash())) { | |
ad9e86dc GA |
328 | // If recursively removing but origTx isn't in the mempool |
329 | // be sure to remove any children that are in the pool. This can | |
330 | // happen during chain re-orgs if origTx isn't re-accepted into | |
331 | // the mempool for any reason. | |
332 | for (unsigned int i = 0; i < origTx.vout.size(); i++) { | |
805344dc | 333 | std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(COutPoint(origTx.GetHash(), i)); |
ad9e86dc GA |
334 | if (it == mapNextTx.end()) |
335 | continue; | |
805344dc | 336 | txToRemove.push_back(it->second.ptx->GetHash()); |
ad9e86dc GA |
337 | } |
338 | } | |
7fd6219a | 339 | while (!txToRemove.empty()) |
319b1160 | 340 | { |
7fd6219a MC |
341 | uint256 hash = txToRemove.front(); |
342 | txToRemove.pop_front(); | |
343 | if (!mapTx.count(hash)) | |
344 | continue; | |
e328fa32 | 345 | const CTransaction& tx = mapTx.find(hash)->GetTx(); |
7fd6219a MC |
346 | if (fRecursive) { |
347 | for (unsigned int i = 0; i < tx.vout.size(); i++) { | |
348 | std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(COutPoint(hash, i)); | |
349 | if (it == mapNextTx.end()) | |
350 | continue; | |
805344dc | 351 | txToRemove.push_back(it->second.ptx->GetHash()); |
7fd6219a MC |
352 | } |
353 | } | |
3ff68c50 | 354 | mapRecentlyAddedTx.erase(hash); |
319b1160 GA |
355 | BOOST_FOREACH(const CTxIn& txin, tx.vin) |
356 | mapNextTx.erase(txin.prevout); | |
f57f76d7 | 357 | BOOST_FOREACH(const JSDescription& joinsplit, tx.vJoinSplit) { |
22de1602 | 358 | BOOST_FOREACH(const uint256& nf, joinsplit.nullifiers) { |
9669920f | 359 | mapSproutNullifiers.erase(nf); |
d66877af SB |
360 | } |
361 | } | |
cab341e1 EOW |
362 | for (const SpendDescription &spendDescription : tx.vShieldedSpend) { |
363 | mapSaplingNullifiers.erase(spendDescription.nullifier); | |
364 | } | |
7fd6219a | 365 | removed.push_back(tx); |
e328fa32 AH |
366 | totalTxSize -= mapTx.find(hash)->GetTxSize(); |
367 | cachedInnerUsage -= mapTx.find(hash)->DynamicMemoryUsage(); | |
319b1160 GA |
368 | mapTx.erase(hash); |
369 | nTransactionsUpdated++; | |
b649e039 | 370 | minerPolicyEstimator->removeTx(hash); |
68e174e2 LR |
371 | if (fAddressIndex) |
372 | removeAddressIndex(hash); | |
86b23f37 LR |
373 | if (fSpentIndex) |
374 | removeSpentIndex(hash); | |
41f170fd | 375 | ClearPrioritisation(tx.GetHash()); |
319b1160 GA |
376 | } |
377 | } | |
319b1160 GA |
378 | } |
379 | ||
0a962eb9 | 380 | extern uint64_t ASSETCHAINS_TIMELOCKGTE; |
e980a26d | 381 | int64_t komodo_block_unlocktime(uint32_t nHeight); |
382 | ||
233c9eb6 | 383 | void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags) |
723d12c0 MC |
384 | { |
385 | // Remove transactions spending a coinbase which are now immature | |
9edf27ec | 386 | extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; |
b2a98c42 | 387 | |
7a90b9dd | 388 | if ( ASSETCHAINS_SYMBOL[0] == 0 ) |
389 | COINBASE_MATURITY = _COINBASE_MATURITY; | |
b2a98c42 | 390 | |
c944d161 | 391 | // Remove transactions spending a coinbase which are now immature and no-longer-final transactions |
723d12c0 MC |
392 | LOCK(cs); |
393 | list<CTransaction> transactionsToRemove; | |
e328fa32 AH |
394 | for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { |
395 | const CTransaction& tx = it->GetTx(); | |
233c9eb6 | 396 | if (!CheckFinalTx(tx, flags)) { |
f5b35d23 | 397 | transactionsToRemove.push_back(tx); |
a4b25180 | 398 | } else if (it->GetSpendsCoinbase()) { |
f5b35d23 MC |
399 | BOOST_FOREACH(const CTxIn& txin, tx.vin) { |
400 | indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); | |
401 | if (it2 != mapTx.end()) | |
402 | continue; | |
403 | const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash); | |
e980a26d | 404 | if (nCheckFrequency != 0) assert(coins); |
b2a98c42 MT |
405 | |
406 | if (!coins || (coins->IsCoinBase() && | |
407 | (((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY) || | |
408 | ((signed long)nMemPoolHeight < komodo_block_unlocktime(coins->nHeight) && | |
409 | coins->IsAvailable(0) && coins->vout[0].nValue >= ASSETCHAINS_TIMELOCKGTE))) { | |
f5b35d23 MC |
410 | transactionsToRemove.push_back(tx); |
411 | break; | |
412 | } | |
723d12c0 MC |
413 | } |
414 | } | |
415 | } | |
416 | BOOST_FOREACH(const CTransaction& tx, transactionsToRemove) { | |
417 | list<CTransaction> removed; | |
418 | remove(tx, removed, true); | |
419 | } | |
420 | } | |
421 | ||
a8ac403d | 422 | |
98d2f090 | 423 | void CTxMemPool::removeWithAnchor(const uint256 &invalidRoot, ShieldedType type) |
a8ac403d SB |
424 | { |
425 | // If a block is disconnected from the tip, and the root changed, | |
426 | // we must invalidate transactions from the mempool which spend | |
427 | // from that root -- almost as though they were spending coinbases | |
428 | // which are no longer valid to spend due to coinbase maturity. | |
429 | LOCK(cs); | |
430 | list<CTransaction> transactionsToRemove; | |
431 | ||
e328fa32 AH |
432 | for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { |
433 | const CTransaction& tx = it->GetTx(); | |
98d2f090 SB |
434 | switch (type) { |
435 | case SPROUT: | |
f57f76d7 | 436 | BOOST_FOREACH(const JSDescription& joinsplit, tx.vJoinSplit) { |
98d2f090 SB |
437 | if (joinsplit.anchor == invalidRoot) { |
438 | transactionsToRemove.push_back(tx); | |
439 | break; | |
440 | } | |
441 | } | |
442 | break; | |
443 | case SAPLING: | |
444 | BOOST_FOREACH(const SpendDescription& spendDescription, tx.vShieldedSpend) { | |
445 | if (spendDescription.anchor == invalidRoot) { | |
446 | transactionsToRemove.push_back(tx); | |
447 | break; | |
448 | } | |
449 | } | |
450 | break; | |
451 | default: | |
8c57bbac | 452 | throw runtime_error("Unknown shielded type"); |
98d2f090 | 453 | break; |
a8ac403d SB |
454 | } |
455 | } | |
456 | ||
457 | BOOST_FOREACH(const CTransaction& tx, transactionsToRemove) { | |
458 | list<CTransaction> removed; | |
459 | remove(tx, removed, true); | |
460 | } | |
461 | } | |
462 | ||
22adf258 | 463 | bool CTxMemPool::checkNameConflicts(const CTransaction &tx, std::list<CTransaction> &conflicting) |
464 | { | |
465 | LOCK(cs); | |
466 | ||
467 | // easy way to check if there are any transactions in the memory pool that define the name specified but are not the same as tx | |
468 | conflicting.clear(); | |
469 | ||
470 | // first, be sure that this is a name definition. if so, it will have both a definition and reservation output. if it is a name definition, | |
471 | // our only concern is whether or not there is a conflicting definition in the mempool. we assume that a check for any conflicting definition | |
472 | // in the blockchain has already taken place. | |
473 | CIdentity identity; | |
474 | CNameReservation reservation; | |
475 | for (auto output : tx.vout) | |
476 | { | |
477 | COptCCParams p; | |
478 | if (output.scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid() && p.version >= p.VERSION_V3) | |
479 | { | |
480 | if (p.evalCode == EVAL_IDENTITY_PRIMARY && p.vData.size() > 1) | |
481 | { | |
482 | if (identity.IsValid()) | |
483 | { | |
484 | identity = CIdentity(); | |
485 | break; | |
486 | } | |
487 | else | |
488 | { | |
489 | identity = CIdentity(p.vData[0]); | |
490 | } | |
491 | } | |
492 | else if (p.evalCode == EVAL_IDENTITY_RESERVATION && p.vData.size() > 1) | |
493 | { | |
494 | if (reservation.IsValid()) | |
495 | { | |
496 | reservation = CNameReservation(); | |
497 | break; | |
498 | } | |
499 | else | |
500 | { | |
501 | reservation = CNameReservation(p.vData[0]); | |
502 | } | |
503 | } | |
504 | } | |
505 | } | |
506 | ||
507 | // it can't conflict if it's not a definition | |
508 | if (!(identity.IsValid() && reservation.IsValid())) | |
509 | { | |
510 | return false; | |
511 | } | |
512 | ||
513 | std::vector<std::pair<uint160, int>> addresses = std::vector<std::pair<uint160, int>>({{identity.GetID(), CScript::P2ID}}); | |
514 | std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta>> results; | |
515 | if (mempool.getAddressIndex(addresses, results) && results.size()) | |
516 | { | |
517 | std::map<uint256, std::pair<CTransaction, int>> txesAndSources; // first hash is transaction of input of prior identity or commitment output in the mempool, second pair is tx and ID output num if identity | |
518 | ||
519 | uint256 txHash = tx.GetHash(); | |
520 | CNameReservation conflictingRes; | |
521 | for (auto r : results) | |
522 | { | |
523 | if (r.first.txhash == txHash) | |
524 | { | |
525 | continue; | |
526 | } | |
527 | CTransaction mpTx; | |
528 | if (lookup(r.first.txhash, mpTx)) | |
529 | { | |
530 | COptCCParams p; | |
531 | if (mpTx.vout[r.first.index].scriptPubKey.IsPayToCryptoCondition(p) && | |
532 | p.IsValid() && | |
533 | p.evalCode == EVAL_IDENTITY_RESERVATION && | |
534 | p.vData.size() > 1 && | |
535 | (conflictingRes = CNameReservation(p.vData[0])).IsValid() && | |
536 | CIdentity(mpTx).IsValid()) | |
537 | { | |
538 | conflicting.push_back(mpTx); | |
539 | } | |
540 | } | |
541 | } | |
542 | } | |
543 | ||
544 | return conflicting.size(); | |
545 | } | |
546 | ||
93a18a36 | 547 | void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed) |
319b1160 | 548 | { |
22adf258 | 549 | LOCK(cs); |
550 | ||
551 | // names are enforced as unique without requiring related spends. | |
552 | // if this is a definition that conflicts with an existing, unrelated name definition, remove the | |
553 | // definition that exists in the mempool | |
554 | std::list<CTransaction> conflicting; | |
555 | if (checkNameConflicts(tx, conflicting)) | |
556 | { | |
557 | for (auto &remTx : conflicting) | |
558 | { | |
559 | remove(remTx, removed, true); | |
560 | } | |
561 | } | |
562 | ||
319b1160 | 563 | // Remove transactions which depend on inputs of tx, recursively |
98e84aae | 564 | list<CTransaction> result; |
319b1160 GA |
565 | BOOST_FOREACH(const CTxIn &txin, tx.vin) { |
566 | std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(txin.prevout); | |
567 | if (it != mapNextTx.end()) { | |
568 | const CTransaction &txConflict = *it->second.ptx; | |
569 | if (txConflict != tx) | |
93a18a36 GA |
570 | { |
571 | remove(txConflict, removed, true); | |
572 | } | |
319b1160 GA |
573 | } |
574 | } | |
d66877af | 575 | |
f57f76d7 | 576 | BOOST_FOREACH(const JSDescription &joinsplit, tx.vJoinSplit) { |
22de1602 | 577 | BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) { |
9669920f EOW |
578 | std::map<uint256, const CTransaction*>::iterator it = mapSproutNullifiers.find(nf); |
579 | if (it != mapSproutNullifiers.end()) { | |
d66877af | 580 | const CTransaction &txConflict = *it->second; |
9669920f | 581 | if (txConflict != tx) { |
d66877af SB |
582 | remove(txConflict, removed, true); |
583 | } | |
584 | } | |
585 | } | |
586 | } | |
cab341e1 EOW |
587 | for (const SpendDescription &spendDescription : tx.vShieldedSpend) { |
588 | std::map<uint256, const CTransaction*>::iterator it = mapSaplingNullifiers.find(spendDescription.nullifier); | |
589 | if (it != mapSaplingNullifiers.end()) { | |
590 | const CTransaction &txConflict = *it->second; | |
9669920f | 591 | if (txConflict != tx) { |
cab341e1 | 592 | remove(txConflict, removed, true); |
9669920f | 593 | } |
cab341e1 EOW |
594 | } |
595 | } | |
319b1160 GA |
596 | } |
597 | ||
f045635e | 598 | int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag); |
f839d3f5 | 599 | extern char ASSETCHAINS_SYMBOL[]; |
f045635e | 600 | |
9bb37bf0 JG |
601 | void CTxMemPool::removeExpired(unsigned int nBlockHeight) |
602 | { | |
f045635e | 603 | CBlockIndex *tipindex; |
2dd22dce | 604 | // Remove expired txs and leftover coinbases from the mempool |
9bb37bf0 JG |
605 | LOCK(cs); |
606 | list<CTransaction> transactionsToRemove; | |
607 | for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) | |
608 | { | |
609 | const CTransaction& tx = it->GetTx(); | |
86131275 | 610 | tipindex = chainActive.LastTip(); |
2dd22dce | 611 | if (tx.IsCoinBase() || IsExpiredTx(tx, nBlockHeight)) |
4825cbeb | 612 | { |
9bb37bf0 JG |
613 | transactionsToRemove.push_back(tx); |
614 | } | |
615 | } | |
616 | for (const CTransaction& tx : transactionsToRemove) { | |
617 | list<CTransaction> removed; | |
618 | remove(tx, removed, true); | |
eb138626 | 619 | LogPrint("mempool", "Removing expired txid: %s\n", tx.GetHash().ToString()); |
9bb37bf0 JG |
620 | } |
621 | } | |
622 | ||
7329fdd1 MF |
623 | /** |
624 | * Called when a block is connected. Removes from mempool and updates the miner fee estimator. | |
625 | */ | |
171ca774 | 626 | void CTxMemPool::removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight, |
b649e039 | 627 | std::list<CTransaction>& conflicts, bool fCurrentEstimate) |
171ca774 GA |
628 | { |
629 | LOCK(cs); | |
630 | std::vector<CTxMemPoolEntry> entries; | |
631 | BOOST_FOREACH(const CTransaction& tx, vtx) | |
632 | { | |
805344dc | 633 | uint256 hash = tx.GetHash(); |
e328fa32 AH |
634 | |
635 | indexed_transaction_set::iterator i = mapTx.find(hash); | |
636 | if (i != mapTx.end()) | |
637 | entries.push_back(*i); | |
171ca774 | 638 | } |
171ca774 GA |
639 | BOOST_FOREACH(const CTransaction& tx, vtx) |
640 | { | |
641 | std::list<CTransaction> dummy; | |
642 | remove(tx, dummy, false); | |
643 | removeConflicts(tx, conflicts); | |
805344dc | 644 | ClearPrioritisation(tx.GetHash()); |
171ca774 | 645 | } |
b649e039 AM |
646 | // After the txs in the new block have been removed from the mempool, update policy estimates |
647 | minerPolicyEstimator->processBlock(nBlockHeight, entries, fCurrentEstimate); | |
171ca774 GA |
648 | } |
649 | ||
34a64fe0 JG |
650 | /** |
651 | * Called whenever the tip changes. Removes transactions which don't commit to | |
652 | * the given branch ID from the mempool. | |
653 | */ | |
654 | void CTxMemPool::removeWithoutBranchId(uint32_t nMemPoolBranchId) | |
655 | { | |
656 | LOCK(cs); | |
657 | std::list<CTransaction> transactionsToRemove; | |
658 | ||
659 | for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { | |
660 | const CTransaction& tx = it->GetTx(); | |
661 | if (it->GetValidatedBranchId() != nMemPoolBranchId) { | |
662 | transactionsToRemove.push_back(tx); | |
663 | } | |
664 | } | |
665 | ||
666 | for (const CTransaction& tx : transactionsToRemove) { | |
667 | std::list<CTransaction> removed; | |
668 | remove(tx, removed, true); | |
669 | } | |
670 | } | |
671 | ||
319b1160 GA |
672 | void CTxMemPool::clear() |
673 | { | |
674 | LOCK(cs); | |
675 | mapTx.clear(); | |
676 | mapNextTx.clear(); | |
6f2c26a4 | 677 | totalTxSize = 0; |
bde5c8b0 | 678 | cachedInnerUsage = 0; |
319b1160 GA |
679 | ++nTransactionsUpdated; |
680 | } | |
681 | ||
d0867acb | 682 | void CTxMemPool::check(const CCoinsViewCache *pcoins) const |
319b1160 | 683 | { |
934fd197 PW |
684 | if (nCheckFrequency == 0) |
685 | return; | |
686 | ||
687 | if (insecure_rand() >= nCheckFrequency) | |
319b1160 GA |
688 | return; |
689 | ||
690 | LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); | |
691 | ||
6f2c26a4 | 692 | uint64_t checkTotal = 0; |
bde5c8b0 | 693 | uint64_t innerUsage = 0; |
6f2c26a4 | 694 | |
b7b4318f | 695 | CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(pcoins)); |
722d811f | 696 | const int64_t nSpendHeight = GetSpendHeight(mempoolDuplicate); |
b7b4318f | 697 | |
319b1160 | 698 | LOCK(cs); |
b7b4318f | 699 | list<const CTxMemPoolEntry*> waitingOnDependants; |
e328fa32 | 700 | for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { |
319b1160 | 701 | unsigned int i = 0; |
e328fa32 AH |
702 | checkTotal += it->GetTxSize(); |
703 | innerUsage += it->DynamicMemoryUsage(); | |
704 | const CTransaction& tx = it->GetTx(); | |
b7b4318f | 705 | bool fDependsWait = false; |
4d707d51 | 706 | BOOST_FOREACH(const CTxIn &txin, tx.vin) { |
319b1160 | 707 | // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. |
e328fa32 | 708 | indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash); |
319b1160 | 709 | if (it2 != mapTx.end()) { |
e328fa32 | 710 | const CTransaction& tx2 = it2->GetTx(); |
4d707d51 | 711 | assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull()); |
b7b4318f | 712 | fDependsWait = true; |
319b1160 | 713 | } else { |
629d75fa PW |
714 | const CCoins* coins = pcoins->AccessCoins(txin.prevout.hash); |
715 | assert(coins && coins->IsAvailable(txin.prevout.n)); | |
319b1160 GA |
716 | } |
717 | // Check whether its inputs are marked in mapNextTx. | |
718 | std::map<COutPoint, CInPoint>::const_iterator it3 = mapNextTx.find(txin.prevout); | |
719 | assert(it3 != mapNextTx.end()); | |
4d707d51 | 720 | assert(it3->second.ptx == &tx); |
319b1160 GA |
721 | assert(it3->second.n == i); |
722 | i++; | |
723 | } | |
a667caec | 724 | |
4fc309f0 | 725 | boost::unordered_map<uint256, SproutMerkleTree, CCoinsKeyHasher> intermediates; |
a667caec | 726 | |
f57f76d7 | 727 | BOOST_FOREACH(const JSDescription &joinsplit, tx.vJoinSplit) { |
22de1602 | 728 | BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) { |
28d20bdb | 729 | assert(!pcoins->GetNullifier(nf, SPROUT)); |
d66877af SB |
730 | } |
731 | ||
4fc309f0 | 732 | SproutMerkleTree tree; |
b7e4abd6 | 733 | auto it = intermediates.find(joinsplit.anchor); |
a667caec SB |
734 | if (it != intermediates.end()) { |
735 | tree = it->second; | |
736 | } else { | |
008f4ee8 | 737 | assert(pcoins->GetSproutAnchorAt(joinsplit.anchor, tree)); |
a667caec SB |
738 | } |
739 | ||
b7e4abd6 | 740 | BOOST_FOREACH(const uint256& commitment, joinsplit.commitments) |
a667caec SB |
741 | { |
742 | tree.append(commitment); | |
743 | } | |
744 | ||
745 | intermediates.insert(std::make_pair(tree.root(), tree)); | |
d66877af | 746 | } |
cab341e1 | 747 | for (const SpendDescription &spendDescription : tx.vShieldedSpend) { |
4fc309f0 | 748 | SaplingMerkleTree tree; |
b4ff7076 SB |
749 | |
750 | assert(pcoins->GetSaplingAnchorAt(spendDescription.anchor, tree)); | |
28d20bdb | 751 | assert(!pcoins->GetNullifier(spendDescription.nullifier, SAPLING)); |
cab341e1 | 752 | } |
b7b4318f | 753 | if (fDependsWait) |
e328fa32 | 754 | waitingOnDependants.push_back(&(*it)); |
b7b4318f | 755 | else { |
d7621ccf | 756 | CValidationState state; |
722d811f JT |
757 | bool fCheckResult = tx.IsCoinBase() || |
758 | Consensus::CheckTxInputs(tx, state, mempoolDuplicate, nSpendHeight, Params().GetConsensus()); | |
759 | assert(fCheckResult); | |
8cb98d91 | 760 | UpdateCoins(tx, mempoolDuplicate, 1000000); |
b7b4318f MC |
761 | } |
762 | } | |
763 | unsigned int stepsSinceLastRemove = 0; | |
764 | while (!waitingOnDependants.empty()) { | |
765 | const CTxMemPoolEntry* entry = waitingOnDependants.front(); | |
766 | waitingOnDependants.pop_front(); | |
767 | CValidationState state; | |
768 | if (!mempoolDuplicate.HaveInputs(entry->GetTx())) { | |
769 | waitingOnDependants.push_back(entry); | |
770 | stepsSinceLastRemove++; | |
771 | assert(stepsSinceLastRemove < waitingOnDependants.size()); | |
772 | } else { | |
722d811f JT |
773 | bool fCheckResult = entry->GetTx().IsCoinBase() || |
774 | Consensus::CheckTxInputs(entry->GetTx(), state, mempoolDuplicate, nSpendHeight, Params().GetConsensus()); | |
775 | assert(fCheckResult); | |
8cb98d91 | 776 | UpdateCoins(entry->GetTx(), mempoolDuplicate, 1000000); |
b7b4318f MC |
777 | stepsSinceLastRemove = 0; |
778 | } | |
319b1160 GA |
779 | } |
780 | for (std::map<COutPoint, CInPoint>::const_iterator it = mapNextTx.begin(); it != mapNextTx.end(); it++) { | |
805344dc | 781 | uint256 hash = it->second.ptx->GetHash(); |
e328fa32 AH |
782 | indexed_transaction_set::const_iterator it2 = mapTx.find(hash); |
783 | const CTransaction& tx = it2->GetTx(); | |
319b1160 | 784 | assert(it2 != mapTx.end()); |
4d707d51 GA |
785 | assert(&tx == it->second.ptx); |
786 | assert(tx.vin.size() > it->second.n); | |
319b1160 GA |
787 | assert(it->first == it->second.ptx->vin[it->second.n].prevout); |
788 | } | |
6f2c26a4 | 789 | |
28d20bdb SB |
790 | checkNullifiers(SPROUT); |
791 | checkNullifiers(SAPLING); | |
d66877af | 792 | |
6f2c26a4 | 793 | assert(totalTxSize == checkTotal); |
bde5c8b0 | 794 | assert(innerUsage == cachedInnerUsage); |
319b1160 GA |
795 | } |
796 | ||
28d20bdb | 797 | void CTxMemPool::checkNullifiers(ShieldedType type) const |
685e936c | 798 | { |
708c87f1 EOW |
799 | const std::map<uint256, const CTransaction*>* mapToUse; |
800 | switch (type) { | |
28d20bdb | 801 | case SPROUT: |
9669920f | 802 | mapToUse = &mapSproutNullifiers; |
708c87f1 | 803 | break; |
28d20bdb | 804 | case SAPLING: |
708c87f1 EOW |
805 | mapToUse = &mapSaplingNullifiers; |
806 | break; | |
807 | default: | |
1f9dfbb9 | 808 | throw runtime_error("Unknown nullifier type"); |
708c87f1 | 809 | } |
685e936c EOW |
810 | for (const auto& entry : *mapToUse) { |
811 | uint256 hash = entry.second->GetHash(); | |
812 | CTxMemPool::indexed_transaction_set::const_iterator findTx = mapTx.find(hash); | |
813 | const CTransaction& tx = findTx->GetTx(); | |
814 | assert(findTx != mapTx.end()); | |
815 | assert(&tx == entry.second); | |
816 | } | |
817 | } | |
818 | ||
4d707d51 | 819 | void CTxMemPool::queryHashes(vector<uint256>& vtxid) |
319b1160 GA |
820 | { |
821 | vtxid.clear(); | |
822 | ||
823 | LOCK(cs); | |
824 | vtxid.reserve(mapTx.size()); | |
e328fa32 AH |
825 | for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) |
826 | vtxid.push_back(mi->GetTx().GetHash()); | |
319b1160 GA |
827 | } |
828 | ||
829 | bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const | |
830 | { | |
831 | LOCK(cs); | |
e328fa32 | 832 | indexed_transaction_set::const_iterator i = mapTx.find(hash); |
319b1160 | 833 | if (i == mapTx.end()) return false; |
e328fa32 | 834 | result = i->GetTx(); |
319b1160 GA |
835 | return true; |
836 | } | |
a0fa20a1 | 837 | |
171ca774 GA |
838 | CFeeRate CTxMemPool::estimateFee(int nBlocks) const |
839 | { | |
840 | LOCK(cs); | |
841 | return minerPolicyEstimator->estimateFee(nBlocks); | |
842 | } | |
843 | double CTxMemPool::estimatePriority(int nBlocks) const | |
844 | { | |
845 | LOCK(cs); | |
846 | return minerPolicyEstimator->estimatePriority(nBlocks); | |
847 | } | |
848 | ||
849 | bool | |
850 | CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const | |
851 | { | |
852 | try { | |
853 | LOCK(cs); | |
b649e039 | 854 | fileout << 109900; // version required to read: 0.10.99 or later |
171ca774 GA |
855 | fileout << CLIENT_VERSION; // version that wrote the file |
856 | minerPolicyEstimator->Write(fileout); | |
857 | } | |
27df4123 | 858 | catch (const std::exception&) { |
7ff9d122 | 859 | LogPrintf("CTxMemPool::WriteFeeEstimates(): unable to write policy estimator data (non-fatal)\n"); |
171ca774 GA |
860 | return false; |
861 | } | |
862 | return true; | |
863 | } | |
864 | ||
865 | bool | |
866 | CTxMemPool::ReadFeeEstimates(CAutoFile& filein) | |
867 | { | |
868 | try { | |
869 | int nVersionRequired, nVersionThatWrote; | |
870 | filein >> nVersionRequired >> nVersionThatWrote; | |
871 | if (nVersionRequired > CLIENT_VERSION) | |
5262fde0 | 872 | return error("CTxMemPool::ReadFeeEstimates(): up-version (%d) fee estimate file", nVersionRequired); |
171ca774 GA |
873 | |
874 | LOCK(cs); | |
b649e039 | 875 | minerPolicyEstimator->Read(filein); |
171ca774 | 876 | } |
27df4123 | 877 | catch (const std::exception&) { |
7ff9d122 | 878 | LogPrintf("CTxMemPool::ReadFeeEstimates(): unable to read policy estimator data (non-fatal)\n"); |
171ca774 GA |
879 | return false; |
880 | } | |
881 | return true; | |
882 | } | |
883 | ||
41f170fd | 884 | void CTxMemPool::PrioritiseTransaction(const uint256 &hash, const string strHash, double dPriorityDelta, const CAmount& nFeeDelta) |
2a72d459 LD |
885 | { |
886 | { | |
887 | LOCK(cs); | |
a372168e | 888 | std::pair<double, CAmount> &deltas = mapDeltas[hash]; |
2a72d459 LD |
889 | deltas.first += dPriorityDelta; |
890 | deltas.second += nFeeDelta; | |
891 | } | |
dd7a9f66 | 892 | if (fDebug) |
893 | { | |
894 | LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, FormatMoney(nFeeDelta)); | |
895 | } | |
2a72d459 LD |
896 | } |
897 | ||
a372168e | 898 | void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) |
2a72d459 LD |
899 | { |
900 | LOCK(cs); | |
a372168e | 901 | std::map<uint256, std::pair<double, CAmount> >::iterator pos = mapDeltas.find(hash); |
2a72d459 LD |
902 | if (pos == mapDeltas.end()) |
903 | return; | |
a372168e | 904 | const std::pair<double, CAmount> &deltas = pos->second; |
2a72d459 LD |
905 | dPriorityDelta += deltas.first; |
906 | nFeeDelta += deltas.second; | |
907 | } | |
908 | ||
909 | void CTxMemPool::ClearPrioritisation(const uint256 hash) | |
910 | { | |
911 | LOCK(cs); | |
912 | mapDeltas.erase(hash); | |
41f170fd MT |
913 | mapReserveTransactions.erase(hash); |
914 | } | |
915 | ||
c8c677c9 | 916 | bool CTxMemPool::PrioritiseReserveTransaction(const CReserveTransactionDescriptor &txDesc, const CCurrencyState ¤cyState) |
41f170fd MT |
917 | { |
918 | LOCK(cs); | |
919 | uint256 hash = txDesc.ptx->GetHash(); | |
920 | auto it = mapReserveTransactions.find(hash); | |
47aecf2f | 921 | if (txDesc.IsValid()) |
41f170fd MT |
922 | { |
923 | mapReserveTransactions[hash] = txDesc; | |
56fe75cb | 924 | CAmount feeDelta = txDesc.AllFeesAsNative(currencyState); |
a1a4dc8b | 925 | PrioritiseTransaction(hash, hash.GetHex().c_str(), (double)feeDelta * 100.0, feeDelta); |
47aecf2f | 926 | return true; |
41f170fd | 927 | } |
47aecf2f | 928 | return false; |
41f170fd MT |
929 | } |
930 | ||
47aecf2f | 931 | bool CTxMemPool::IsKnownReserveTransaction(const uint256 &hash, CReserveTransactionDescriptor &txDesc) |
41f170fd MT |
932 | { |
933 | LOCK(cs); | |
934 | auto it = mapReserveTransactions.find(hash); | |
935 | if (it != mapReserveTransactions.end() && it->second.IsValid()) | |
936 | { | |
1c3499f9 | 937 | // refresh transaction from mempool or delete it if not found (we may not need this at all) |
47aecf2f | 938 | indexed_transaction_set::const_iterator i = mapTx.find(hash); |
939 | if (i == mapTx.end()) | |
940 | { | |
941 | ClearPrioritisation(hash); | |
942 | } | |
943 | else | |
944 | { | |
945 | it->second.ptx = &(i->GetTx()); | |
946 | ||
947 | txDesc = it->second; | |
948 | return true; | |
949 | } | |
41f170fd MT |
950 | } |
951 | return false; | |
2a72d459 LD |
952 | } |
953 | ||
b649e039 AM |
954 | bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const |
955 | { | |
956 | for (unsigned int i = 0; i < tx.vin.size(); i++) | |
957 | if (exists(tx.vin[i].prevout.hash)) | |
958 | return false; | |
959 | return true; | |
960 | } | |
171ca774 | 961 | |
28d20bdb | 962 | bool CTxMemPool::nullifierExists(const uint256& nullifier, ShieldedType type) const |
685e936c | 963 | { |
708c87f1 | 964 | switch (type) { |
28d20bdb | 965 | case SPROUT: |
9669920f | 966 | return mapSproutNullifiers.count(nullifier); |
28d20bdb | 967 | case SAPLING: |
708c87f1 EOW |
968 | return mapSaplingNullifiers.count(nullifier); |
969 | default: | |
1f9dfbb9 | 970 | throw runtime_error("Unknown nullifier type"); |
708c87f1 | 971 | } |
685e936c | 972 | } |
a0fa20a1 | 973 | |
3ff68c50 JG |
974 | void CTxMemPool::NotifyRecentlyAdded() |
975 | { | |
9d8322a3 | 976 | uint64_t recentlyAddedSequence; |
3ff68c50 JG |
977 | std::vector<CTransaction> txs; |
978 | { | |
979 | LOCK(cs); | |
9d8322a3 | 980 | recentlyAddedSequence = nRecentlyAddedSequence; |
3ff68c50 JG |
981 | for (const auto& kv : mapRecentlyAddedTx) { |
982 | txs.push_back(*(kv.second)); | |
983 | } | |
984 | mapRecentlyAddedTx.clear(); | |
985 | } | |
986 | ||
987 | // A race condition can occur here between these SyncWithWallets calls, and | |
988 | // the ones triggered by block logic (in ConnectTip and DisconnectTip). It | |
989 | // is harmless because calling SyncWithWallets(_, NULL) does not alter the | |
990 | // wallet transaction's block information. | |
991 | for (auto tx : txs) { | |
992 | try { | |
993 | SyncWithWallets(tx, NULL); | |
994 | } catch (const boost::thread_interrupted&) { | |
995 | throw; | |
996 | } catch (const std::exception& e) { | |
997 | PrintExceptionContinue(&e, "CTxMemPool::NotifyRecentlyAdded()"); | |
998 | } catch (...) { | |
999 | PrintExceptionContinue(NULL, "CTxMemPool::NotifyRecentlyAdded()"); | |
1000 | } | |
1001 | } | |
9d8322a3 JG |
1002 | |
1003 | // Update the notified sequence number. We only need this in regtest mode, | |
1004 | // and should not lock on cs after calling SyncWithWallets otherwise. | |
1005 | if (Params().NetworkIDString() == "regtest") { | |
1006 | LOCK(cs); | |
1007 | nNotifiedSequence = recentlyAddedSequence; | |
1008 | } | |
1009 | } | |
1010 | ||
1011 | bool CTxMemPool::IsFullyNotified() { | |
1012 | assert(Params().NetworkIDString() == "regtest"); | |
1013 | LOCK(cs); | |
1014 | return nRecentlyAddedSequence == nNotifiedSequence; | |
3ff68c50 JG |
1015 | } |
1016 | ||
685e936c | 1017 | CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { } |
d66877af | 1018 | |
28d20bdb | 1019 | bool CCoinsViewMemPool::GetNullifier(const uint256 &nf, ShieldedType type) const |
685e936c | 1020 | { |
708c87f1 | 1021 | return mempool.nullifierExists(nf, type) || base->GetNullifier(nf, type); |
d66877af SB |
1022 | } |
1023 | ||
a3dc587a | 1024 | bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const { |
ad08d0b9 PW |
1025 | // If an entry in the mempool exists, always return that one, as it's guaranteed to never |
1026 | // conflict with the underlying cache, and it cannot have pruned entries (as it contains full) | |
1027 | // transactions. First checking the underlying cache risks returning a pruned entry instead. | |
a0fa20a1 PW |
1028 | CTransaction tx; |
1029 | if (mempool.lookup(txid, tx)) { | |
1030 | coins = CCoins(tx, MEMPOOL_HEIGHT); | |
1031 | return true; | |
1032 | } | |
ad08d0b9 | 1033 | return (base->GetCoins(txid, coins) && !coins.IsPruned()); |
a0fa20a1 PW |
1034 | } |
1035 | ||
a3dc587a | 1036 | bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const { |
a0fa20a1 PW |
1037 | return mempool.exists(txid) || base->HaveCoins(txid); |
1038 | } | |
bde5c8b0 PW |
1039 | |
1040 | size_t CTxMemPool::DynamicMemoryUsage() const { | |
1041 | LOCK(cs); | |
e328fa32 | 1042 | // Estimate the overhead of mapTx to be 6 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented. |
41f170fd | 1043 | return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 6 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapDeltas) + cachedInnerUsage; |
bde5c8b0 | 1044 | } |