X-Git-Url: https://repo.jachan.dev/VerusCoin.git/blobdiff_plain/75c34b749447b312e1b64571f958d77c3389636c..88d014d0157f227aaa45c66be47aef4b09bd3530:/src/txmempool.cpp diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 0f588324a..1d980a86e 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// file COPYING or https://www.opensource.org/licenses/mit-license.php . #include "txmempool.h" @@ -14,14 +14,16 @@ #include "timedata.h" #include "util.h" #include "utilmoneystr.h" +#include "validationinterface.h" #include "version.h" +#include "pbaas/pbaas.h" #define _COINBASE_MATURITY 100 using namespace std; CTxMemPoolEntry::CTxMemPoolEntry(): nFee(0), nTxSize(0), nModSize(0), nUsageSize(0), nTime(0), dPriority(0.0), - hadNoDependencies(false), spendsCoinbase(false) + hadNoDependencies(false), spendsCoinbase(false), hasReserve(false) { nHeight = MEMPOOL_HEIGHT; } @@ -29,9 +31,9 @@ CTxMemPoolEntry::CTxMemPoolEntry(): CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, int64_t _nTime, double _dPriority, unsigned int _nHeight, bool poolHasNoInputsOf, - bool _spendsCoinbase, uint32_t _nBranchId): + bool _spendsCoinbase, uint32_t _nBranchId, bool hasreserve): tx(_tx), nFee(_nFee), nTime(_nTime), dPriority(_dPriority), nHeight(_nHeight), - hadNoDependencies(poolHasNoInputsOf), + hadNoDependencies(poolHasNoInputsOf), hasReserve(hasreserve), spendsCoinbase(_spendsCoinbase), nBranchId(_nBranchId) { nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); @@ -49,6 +51,12 @@ double CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const { CAmount nValueIn = tx.GetValueOut()+nFee; + CCurrencyState currencyState; + unsigned int lastHeight = currentHeight < 1 ? 0 : currentHeight - 1; + if (hasReserve && (currencyState = ConnectedChains.GetCurrencyState(currentHeight - 1)).IsValid()) + { + nValueIn += currencyState.ReserveToNative(tx.GetReserveValueOut()); + } double deltaPriority = ((double)(currentHeight-nHeight)*nValueIn)/nModSize; double dResult = dPriority + deltaPriority; return dResult; @@ -104,11 +112,13 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, LOCK(cs); mapTx.insert(entry); const CTransaction& tx = mapTx.find(hash)->GetTx(); + mapRecentlyAddedTx[tx.GetHash()] = &tx; + nRecentlyAddedSequence += 1; if (!tx.IsCoinImport()) { for (unsigned int i = 0; i < tx.vin.size(); i++) mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); } - BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { + BOOST_FOREACH(const JSDescription &joinsplit, tx.vJoinSplit) { BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) { mapSproutNullifiers[nf] = &tx; } @@ -131,78 +141,39 @@ void CTxMemPool::addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewC std::vector inserted; uint256 txhash = tx.GetHash(); - for (unsigned int j = 0; j < tx.vin.size(); j++) { - const CTxIn input = tx.vin[j]; - const CTxOut &prevout = view.GetOutputFor(input); - if (prevout.scriptPubKey.IsPayToScriptHash()) { - vector hashBytes(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22); - CMempoolAddressDeltaKey key(2, uint160(hashBytes), txhash, j, 1); - CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n); - mapAddress.insert(make_pair(key, delta)); - inserted.push_back(key); - } - else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) { - vector hashBytes(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23); - CMempoolAddressDeltaKey key(1, uint160(hashBytes), txhash, j, 1); - CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n); - mapAddress.insert(make_pair(key, delta)); - inserted.push_back(key); - } - else if (prevout.scriptPubKey.IsPayToPublicKey()) { - vector hashBytes(prevout.scriptPubKey.begin()+1, prevout.scriptPubKey.begin()+34); - CMempoolAddressDeltaKey key(1, Hash160(hashBytes), txhash, j, 1); - CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n); - mapAddress.insert(make_pair(key, delta)); - inserted.push_back(key); - } - else if (prevout.scriptPubKey.IsPayToCryptoCondition()) { - vector hashBytes(prevout.scriptPubKey.begin(), prevout.scriptPubKey.end()); - CMempoolAddressDeltaKey key(1, Hash160(hashBytes), txhash, j, 1); + if (!tx.IsCoinBase()) + { + for (unsigned int j = 0; j < tx.vin.size(); j++) { + const CTxIn input = tx.vin[j]; + const CTxOut &prevout = view.GetOutputFor(input); + CScript::ScriptType type = prevout.scriptPubKey.GetType(); + if (type == CScript::UNKNOWN) + continue; + CMempoolAddressDeltaKey key(type, prevout.scriptPubKey.AddressHash(), txhash, j, 1); CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n); mapAddress.insert(make_pair(key, delta)); inserted.push_back(key); - } } - - for (unsigned int k = 0; k < tx.vout.size(); k++) { - const CTxOut &out = tx.vout[k]; - if (out.scriptPubKey.IsPayToScriptHash()) { - vector hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22); - CMempoolAddressDeltaKey key(2, uint160(hashBytes), txhash, k, 0); - mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue))); - inserted.push_back(key); - } - else if (out.scriptPubKey.IsPayToPublicKeyHash()) { - vector hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23); - std::pair ret; - CMempoolAddressDeltaKey key(1, uint160(hashBytes), txhash, k, 0); - mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue))); - inserted.push_back(key); - } - else if (out.scriptPubKey.IsPayToPublicKey()) { - vector hashBytes(out.scriptPubKey.begin()+1, out.scriptPubKey.begin()+34); - std::pair ret; - CMempoolAddressDeltaKey key(1, Hash160(hashBytes), txhash, k, 0); - mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue))); - inserted.push_back(key); - } - else if (out.scriptPubKey.IsPayToCryptoCondition()) { - vector hashBytes(out.scriptPubKey.begin(), out.scriptPubKey.end()); - std::pair ret; - CMempoolAddressDeltaKey key(1, Hash160(hashBytes), txhash, k, 0); - mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue))); - inserted.push_back(key); } } + for (unsigned int j = 0; j < tx.vout.size(); j++) { + const CTxOut &out = tx.vout[j]; + CScript::ScriptType type = out.scriptPubKey.GetType(); + if (type == CScript::UNKNOWN) + continue; + CMempoolAddressDeltaKey key(type, out.scriptPubKey.AddressHash(), txhash, j, 0); + mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue))); + inserted.push_back(key); + } + mapAddressInserted.insert(make_pair(txhash, inserted)); } -bool CTxMemPool::getAddressIndex(std::vector > &addresses, - std::vector > &results) +bool CTxMemPool::getAddressIndex(const std::vector > &addresses, std::vector > &results) { LOCK(cs); - for (std::vector >::iterator it = addresses.begin(); it != addresses.end(); it++) { - addressDeltaMap::iterator ait = mapAddress.lower_bound(CMempoolAddressDeltaKey((*it).second, (*it).first)); + for (std::vector >::const_iterator it = addresses.begin(); it != addresses.end(); it++) { + auto ait = mapAddress.lower_bound(CMempoolAddressDeltaKey((*it).second, (*it).first)); while (ait != mapAddress.end() && (*ait).first.addressBytes == (*it).first && (*ait).first.type == (*it).second) { results.push_back(*ait); ait++; @@ -214,7 +185,7 @@ bool CTxMemPool::getAddressIndex(std::vector > &addresse bool CTxMemPool::removeAddressIndex(const uint256 txhash) { LOCK(cs); - addressDeltaMapInserted::iterator it = mapAddressInserted.find(txhash); + auto it = mapAddressInserted.find(txhash); if (it != mapAddressInserted.end()) { std::vector keys = (*it).second; @@ -230,55 +201,27 @@ bool CTxMemPool::removeAddressIndex(const uint256 txhash) void CTxMemPool::addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view) { LOCK(cs); - const CTransaction& tx = entry.GetTx(); + uint256 txhash = tx.GetHash(); std::vector inserted; - uint256 txhash = tx.GetHash(); for (unsigned int j = 0; j < tx.vin.size(); j++) { const CTxIn input = tx.vin[j]; const CTxOut &prevout = view.GetOutputFor(input); - uint160 addressHash; - int addressType; - - if (prevout.scriptPubKey.IsPayToScriptHash()) { - addressHash = uint160(vector (prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22)); - addressType = 2; - } - else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) { - addressHash = uint160(vector (prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23)); - addressType = 1; - } - else if (prevout.scriptPubKey.IsPayToPublicKey()) { - addressHash = Hash160(vector (prevout.scriptPubKey.begin()+1, prevout.scriptPubKey.begin()+34)); - addressType = 1; - } - else if (prevout.scriptPubKey.IsPayToCryptoCondition()) { - addressHash = Hash160(vector (prevout.scriptPubKey.begin(), prevout.scriptPubKey.end())); - addressType = 1; - } - else { - addressHash.SetNull(); - addressType = 0; - } - CSpentIndexKey key = CSpentIndexKey(input.prevout.hash, input.prevout.n); - CSpentIndexValue value = CSpentIndexValue(txhash, j, -1, prevout.nValue, addressType, addressHash); - + CSpentIndexValue value = CSpentIndexValue(txhash, j, -1, prevout.nValue, + prevout.scriptPubKey.GetType(), + prevout.scriptPubKey.AddressHash()); mapSpent.insert(make_pair(key, value)); inserted.push_back(key); - } - mapSpentInserted.insert(make_pair(txhash, inserted)); } -bool CTxMemPool::getSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value) +bool CTxMemPool::getSpentIndex(const CSpentIndexKey &key, CSpentIndexValue &value) { LOCK(cs); - mapSpentIndex::iterator it; - - it = mapSpent.find(key); + std::map::iterator it = mapSpent.find(key); if (it != mapSpent.end()) { value = it->second; return true; @@ -289,7 +232,7 @@ bool CTxMemPool::getSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value) bool CTxMemPool::removeSpentIndex(const uint256 txhash) { LOCK(cs); - mapSpentIndexInserted::iterator it = mapSpentInserted.find(txhash); + auto it = mapSpentInserted.find(txhash); if (it != mapSpentInserted.end()) { std::vector keys = (*it).second; @@ -336,9 +279,10 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem txToRemove.push_back(it->second.ptx->GetHash()); } } + mapRecentlyAddedTx.erase(hash); BOOST_FOREACH(const CTxIn& txin, tx.vin) mapNextTx.erase(txin.prevout); - BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit) { + BOOST_FOREACH(const JSDescription& joinsplit, tx.vJoinSplit) { BOOST_FOREACH(const uint256& nf, joinsplit.nullifiers) { mapSproutNullifiers.erase(nf); } @@ -352,8 +296,11 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list& rem mapTx.erase(hash); nTransactionsUpdated++; minerPolicyEstimator->removeTx(hash); - removeAddressIndex(hash); - removeSpentIndex(hash); + if (fAddressIndex) + removeAddressIndex(hash); + if (fSpentIndex) + removeSpentIndex(hash); + ClearPrioritisation(tx.GetHash()); } } } @@ -365,8 +312,10 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem { // Remove transactions spending a coinbase which are now immature extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; + if ( ASSETCHAINS_SYMBOL[0] == 0 ) COINBASE_MATURITY = _COINBASE_MATURITY; + // Remove transactions spending a coinbase which are now immature and no-longer-final transactions LOCK(cs); list transactionsToRemove; @@ -381,9 +330,11 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem continue; const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash); if (nCheckFrequency != 0) assert(coins); - if (!coins || (coins->IsCoinBase() && (((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY) && - ((signed long)nMemPoolHeight < komodo_block_unlocktime(coins->nHeight) && - coins->IsAvailable(0) && coins->vout[0].nValue >= ASSETCHAINS_TIMELOCKGTE))) { + + if (!coins || (coins->IsCoinBase() && + (((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY) || + ((signed long)nMemPoolHeight < komodo_block_unlocktime(coins->nHeight) && + coins->IsAvailable(0) && coins->vout[0].nValue >= ASSETCHAINS_TIMELOCKGTE))) { transactionsToRemove.push_back(tx); break; } @@ -410,7 +361,7 @@ void CTxMemPool::removeWithAnchor(const uint256 &invalidRoot, ShieldedType type) const CTransaction& tx = it->GetTx(); switch (type) { case SPROUT: - BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit) { + BOOST_FOREACH(const JSDescription& joinsplit, tx.vJoinSplit) { if (joinsplit.anchor == invalidRoot) { transactionsToRemove.push_back(tx); break; @@ -453,7 +404,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list } } - BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { + BOOST_FOREACH(const JSDescription &joinsplit, tx.vJoinSplit) { BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) { std::map::iterator it = mapSproutNullifiers.find(nf); if (it != mapSproutNullifiers.end()) { @@ -604,7 +555,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const boost::unordered_map intermediates; - BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { + BOOST_FOREACH(const JSDescription &joinsplit, tx.vJoinSplit) { BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) { assert(!pcoins->GetNullifier(nf, SPROUT)); } @@ -761,7 +712,7 @@ CTxMemPool::ReadFeeEstimates(CAutoFile& filein) return true; } -void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash, double dPriorityDelta, const CAmount& nFeeDelta) +void CTxMemPool::PrioritiseTransaction(const uint256 &hash, const string strHash, double dPriorityDelta, const CAmount& nFeeDelta) { { LOCK(cs); @@ -787,6 +738,45 @@ void CTxMemPool::ClearPrioritisation(const uint256 hash) { LOCK(cs); mapDeltas.erase(hash); + mapReserveTransactions.erase(hash); +} + +bool CTxMemPool::PrioritiseReserveTransaction(const CReserveTransactionDescriptor &txDesc, const CCurrencyState ¤cyState) +{ + LOCK(cs); + uint256 hash = txDesc.ptx->GetHash(); + auto it = mapReserveTransactions.find(hash); + if (txDesc.IsValid()) + { + mapReserveTransactions[hash] = txDesc; + CAmount feeDelta = currencyState.ReserveToNative(txDesc.ReserveFees() + txDesc.reserveConversionFees) + txDesc.nativeConversionFees; + PrioritiseTransaction(hash, hash.GetHex().c_str(), (double)feeDelta * 100.0, feeDelta); + return true; + } + return false; +} + +bool CTxMemPool::IsKnownReserveTransaction(const uint256 &hash, CReserveTransactionDescriptor &txDesc) +{ + LOCK(cs); + auto it = mapReserveTransactions.find(hash); + if (it != mapReserveTransactions.end() && it->second.IsValid()) + { + // refresh transaction from mempool or delete it if not found (we may not need this at all) + indexed_transaction_set::const_iterator i = mapTx.find(hash); + if (i == mapTx.end()) + { + ClearPrioritisation(hash); + } + else + { + it->second.ptx = &(i->GetTx()); + + txDesc = it->second; + return true; + } + } + return false; } bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const @@ -809,6 +799,49 @@ bool CTxMemPool::nullifierExists(const uint256& nullifier, ShieldedType type) co } } +void CTxMemPool::NotifyRecentlyAdded() +{ + uint64_t recentlyAddedSequence; + std::vector txs; + { + LOCK(cs); + recentlyAddedSequence = nRecentlyAddedSequence; + for (const auto& kv : mapRecentlyAddedTx) { + txs.push_back(*(kv.second)); + } + mapRecentlyAddedTx.clear(); + } + + // A race condition can occur here between these SyncWithWallets calls, and + // the ones triggered by block logic (in ConnectTip and DisconnectTip). It + // is harmless because calling SyncWithWallets(_, NULL) does not alter the + // wallet transaction's block information. + for (auto tx : txs) { + try { + SyncWithWallets(tx, NULL); + } catch (const boost::thread_interrupted&) { + throw; + } catch (const std::exception& e) { + PrintExceptionContinue(&e, "CTxMemPool::NotifyRecentlyAdded()"); + } catch (...) { + PrintExceptionContinue(NULL, "CTxMemPool::NotifyRecentlyAdded()"); + } + } + + // Update the notified sequence number. We only need this in regtest mode, + // and should not lock on cs after calling SyncWithWallets otherwise. + if (Params().NetworkIDString() == "regtest") { + LOCK(cs); + nNotifiedSequence = recentlyAddedSequence; + } +} + +bool CTxMemPool::IsFullyNotified() { + assert(Params().NetworkIDString() == "regtest"); + LOCK(cs); + return nRecentlyAddedSequence == nNotifiedSequence; +} + CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { } bool CCoinsViewMemPool::GetNullifier(const uint256 &nf, ShieldedType type) const @@ -835,5 +868,5 @@ bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const { size_t CTxMemPool::DynamicMemoryUsage() const { LOCK(cs); // Estimate the overhead of mapTx to be 6 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented. - return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 6 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + cachedInnerUsage; + return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 6 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapDeltas) + cachedInnerUsage; }