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