Changeset View
Changeset View
Standalone View
Standalone View
src/txmempool.cpp
Show First 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | while (!stageEntries.empty()) { | ||||
} | } | ||||
} | } | ||||
// setAllDescendants now contains all in-mempool descendants of updateIt. | // setAllDescendants now contains all in-mempool descendants of updateIt. | ||||
// Update and add to cached descendant map | // Update and add to cached descendant map | ||||
int64_t modifySize = 0; | int64_t modifySize = 0; | ||||
Amount modifyFee = 0; | Amount modifyFee = 0; | ||||
int64_t modifyCount = 0; | int64_t modifyCount = 0; | ||||
for (txiter cit : setAllDescendants) { | for (txiter cit : setAllDescendants) { | ||||
if (!setExclude.count(cit->GetTx().GetId())) { | if (!setExclude.count(cit->GetTx().GetHash())) { | ||||
modifySize += cit->GetTxSize(); | modifySize += cit->GetTxSize(); | ||||
modifyFee += cit->GetModifiedFee(); | modifyFee += cit->GetModifiedFee(); | ||||
modifyCount++; | modifyCount++; | ||||
cachedDescendants[updateIt].insert(cit); | cachedDescendants[updateIt].insert(cit); | ||||
// Update ancestor state for each descendant | // Update ancestor state for each descendant | ||||
mapTx.modify(cit, | mapTx.modify(cit, | ||||
update_ancestor_state(updateIt->GetTxSize(), | update_ancestor_state(updateIt->GetTxSize(), | ||||
updateIt->GetModifiedFee(), 1, | updateIt->GetModifiedFee(), 1, | ||||
Show All 34 Lines | for (const uint256 &hash : boost::adaptors::reverse(vHashesToUpdate)) { | ||||
txiter it = mapTx.find(hash); | txiter it = mapTx.find(hash); | ||||
if (it == mapTx.end()) { | if (it == mapTx.end()) { | ||||
continue; | continue; | ||||
} | } | ||||
auto iter = mapNextTx.lower_bound(COutPoint(hash, 0)); | auto iter = mapNextTx.lower_bound(COutPoint(hash, 0)); | ||||
// First calculate the children, and update setMemPoolChildren to | // First calculate the children, and update setMemPoolChildren to | ||||
// include them, and update their setMemPoolParents to include this tx. | // include them, and update their setMemPoolParents to include this tx. | ||||
for (; iter != mapNextTx.end() && iter->first->hash == hash; ++iter) { | for (; iter != mapNextTx.end() && iter->first->hash == hash; ++iter) { | ||||
const uint256 &childHash = iter->second->GetId(); | const uint256 &childHash = iter->second->GetHash(); | ||||
txiter childIter = mapTx.find(childHash); | txiter childIter = mapTx.find(childHash); | ||||
assert(childIter != mapTx.end()); | assert(childIter != mapTx.end()); | ||||
// We can skip updating entries we've encountered before or that are | // We can skip updating entries we've encountered before or that are | ||||
// in the block (which are already accounted for). | // in the block (which are already accounted for). | ||||
if (setChildren.insert(childIter).second && | if (setChildren.insert(childIter).second && | ||||
!setAlreadyIncluded.count(childHash)) { | !setAlreadyIncluded.count(childHash)) { | ||||
UpdateChild(it, childIter, true); | UpdateChild(it, childIter, true); | ||||
UpdateParent(childIter, it, true); | UpdateParent(childIter, it, true); | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | while (!parentHashes.empty()) { | ||||
setAncestors.insert(stageit); | setAncestors.insert(stageit); | ||||
parentHashes.erase(stageit); | parentHashes.erase(stageit); | ||||
totalSizeWithAncestors += stageit->GetTxSize(); | totalSizeWithAncestors += stageit->GetTxSize(); | ||||
if (stageit->GetSizeWithDescendants() + entry.GetTxSize() > | if (stageit->GetSizeWithDescendants() + entry.GetTxSize() > | ||||
limitDescendantSize) { | limitDescendantSize) { | ||||
errString = strprintf( | errString = strprintf( | ||||
"exceeds descendant size limit for tx %s [limit: %u]", | "exceeds descendant size limit for tx %s [limit: %u]", | ||||
stageit->GetTx().GetId().ToString(), limitDescendantSize); | stageit->GetTx().GetHash().ToString(), limitDescendantSize); | ||||
return false; | return false; | ||||
} else if (stageit->GetCountWithDescendants() + 1 > | } else if (stageit->GetCountWithDescendants() + 1 > | ||||
limitDescendantCount) { | limitDescendantCount) { | ||||
errString = strprintf("too many descendants for tx %s [limit: %u]", | errString = strprintf("too many descendants for tx %s [limit: %u]", | ||||
stageit->GetTx().GetId().ToString(), | stageit->GetTx().GetHash().ToString(), | ||||
limitDescendantCount); | limitDescendantCount); | ||||
return false; | return false; | ||||
} else if (totalSizeWithAncestors > limitAncestorSize) { | } else if (totalSizeWithAncestors > limitAncestorSize) { | ||||
errString = strprintf("exceeds ancestor size limit [limit: %u]", | errString = strprintf("exceeds ancestor size limit [limit: %u]", | ||||
limitAncestorSize); | limitAncestorSize); | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 224 Lines • ▼ Show 20 Lines | bool CTxMemPool::addUnchecked(const uint256 &hash, const CTxMemPoolEntry &entry, | ||||
vTxHashes.emplace_back(tx.GetHash(), newit); | vTxHashes.emplace_back(tx.GetHash(), newit); | ||||
newit->vTxHashesIdx = vTxHashes.size() - 1; | newit->vTxHashesIdx = vTxHashes.size() - 1; | ||||
return true; | return true; | ||||
} | } | ||||
void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason) { | void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason) { | ||||
NotifyEntryRemoved(it->GetSharedTx(), reason); | NotifyEntryRemoved(it->GetSharedTx(), reason); | ||||
const uint256 txid = it->GetTx().GetId(); | const uint256 txid = it->GetTx().GetHash(); | ||||
for (const CTxIn &txin : it->GetTx().vin) { | for (const CTxIn &txin : it->GetTx().vin) { | ||||
mapNextTx.erase(txin.prevout); | mapNextTx.erase(txin.prevout); | ||||
} | } | ||||
if (vTxHashes.size() > 1) { | if (vTxHashes.size() > 1) { | ||||
vTxHashes[it->vTxHashesIdx] = std::move(vTxHashes.back()); | vTxHashes[it->vTxHashesIdx] = std::move(vTxHashes.back()); | ||||
vTxHashes[it->vTxHashesIdx].second->vTxHashesIdx = it->vTxHashesIdx; | vTxHashes[it->vTxHashesIdx].second->vTxHashesIdx = it->vTxHashesIdx; | ||||
vTxHashes.pop_back(); | vTxHashes.pop_back(); | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
void CTxMemPool::removeRecursive(const CTransaction &origTx, | void CTxMemPool::removeRecursive(const CTransaction &origTx, | ||||
MemPoolRemovalReason reason) { | MemPoolRemovalReason reason) { | ||||
// Remove transaction from memory pool | // Remove transaction from memory pool | ||||
{ | { | ||||
LOCK(cs); | LOCK(cs); | ||||
setEntries txToRemove; | setEntries txToRemove; | ||||
txiter origit = mapTx.find(origTx.GetId()); | txiter origit = mapTx.find(origTx.GetHash()); | ||||
if (origit != mapTx.end()) { | if (origit != mapTx.end()) { | ||||
txToRemove.insert(origit); | txToRemove.insert(origit); | ||||
} else { | } else { | ||||
// When recursively removing but origTx isn't in the mempool be sure | // When recursively removing but origTx isn't in the mempool be sure | ||||
// to remove any children that are in the pool. This can happen | // to remove any children that are in the pool. This can happen | ||||
// during chain re-orgs if origTx isn't re-accepted into the mempool | // during chain re-orgs if origTx isn't re-accepted into the mempool | ||||
// for any reason. | // for any reason. | ||||
for (unsigned int i = 0; i < origTx.vout.size(); i++) { | for (unsigned int i = 0; i < origTx.vout.size(); i++) { | ||||
auto it = mapNextTx.find(COutPoint(origTx.GetId(), i)); | auto it = mapNextTx.find(COutPoint(origTx.GetHash(), i)); | ||||
if (it == mapNextTx.end()) continue; | if (it == mapNextTx.end()) continue; | ||||
txiter nextit = mapTx.find(it->second->GetId()); | txiter nextit = mapTx.find(it->second->GetHash()); | ||||
assert(nextit != mapTx.end()); | assert(nextit != mapTx.end()); | ||||
txToRemove.insert(nextit); | txToRemove.insert(nextit); | ||||
} | } | ||||
} | } | ||||
setEntries setAllRemoves; | setEntries setAllRemoves; | ||||
for (txiter it : txToRemove) { | for (txiter it : txToRemove) { | ||||
CalculateDescendants(it, setAllRemoves); | CalculateDescendants(it, setAllRemoves); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | |||||
void CTxMemPool::removeConflicts(const CTransaction &tx) { | void CTxMemPool::removeConflicts(const CTransaction &tx) { | ||||
// Remove transactions which depend on inputs of tx, recursively | // Remove transactions which depend on inputs of tx, recursively | ||||
LOCK(cs); | LOCK(cs); | ||||
for (const CTxIn &txin : tx.vin) { | for (const CTxIn &txin : tx.vin) { | ||||
auto it = mapNextTx.find(txin.prevout); | auto it = mapNextTx.find(txin.prevout); | ||||
if (it != mapNextTx.end()) { | if (it != mapNextTx.end()) { | ||||
const CTransaction &txConflict = *it->second; | const CTransaction &txConflict = *it->second; | ||||
if (txConflict != tx) { | if (txConflict != tx) { | ||||
ClearPrioritisation(txConflict.GetId()); | ClearPrioritisation(txConflict.GetHash()); | ||||
removeRecursive(txConflict, MemPoolRemovalReason::CONFLICT); | removeRecursive(txConflict, MemPoolRemovalReason::CONFLICT); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Called when a block is connected. Removes from mempool and updates the miner | * Called when a block is connected. Removes from mempool and updates the miner | ||||
* fee estimator. | * fee estimator. | ||||
*/ | */ | ||||
void CTxMemPool::removeForBlock(const std::vector<CTransactionRef> &vtx, | void CTxMemPool::removeForBlock(const std::vector<CTransactionRef> &vtx, | ||||
unsigned int nBlockHeight) { | unsigned int nBlockHeight) { | ||||
LOCK(cs); | LOCK(cs); | ||||
std::vector<const CTxMemPoolEntry *> entries; | std::vector<const CTxMemPoolEntry *> entries; | ||||
for (const auto &tx : vtx) { | for (const auto &tx : vtx) { | ||||
uint256 txid = tx->GetId(); | uint256 txid = tx->GetHash(); | ||||
indexed_transaction_set::iterator i = mapTx.find(txid); | indexed_transaction_set::iterator i = mapTx.find(txid); | ||||
if (i != mapTx.end()) entries.push_back(&*i); | if (i != mapTx.end()) entries.push_back(&*i); | ||||
} | } | ||||
// Before the txs in the new block have been removed from the mempool, | // Before the txs in the new block have been removed from the mempool, | ||||
// update policy estimates | // update policy estimates | ||||
minerPolicyEstimator->processBlock(nBlockHeight, entries); | minerPolicyEstimator->processBlock(nBlockHeight, entries); | ||||
for (const auto &tx : vtx) { | for (const auto &tx : vtx) { | ||||
txiter it = mapTx.find(tx->GetId()); | txiter it = mapTx.find(tx->GetHash()); | ||||
if (it != mapTx.end()) { | if (it != mapTx.end()) { | ||||
setEntries stage; | setEntries stage; | ||||
stage.insert(it); | stage.insert(it); | ||||
RemoveStaged(stage, true, MemPoolRemovalReason::BLOCK); | RemoveStaged(stage, true, MemPoolRemovalReason::BLOCK); | ||||
} | } | ||||
removeConflicts(*tx); | removeConflicts(*tx); | ||||
ClearPrioritisation(tx->GetId()); | ClearPrioritisation(tx->GetHash()); | ||||
} | } | ||||
lastRollingFeeUpdate = GetTime(); | lastRollingFeeUpdate = GetTime(); | ||||
blockSinceLastRollingFeeBump = true; | blockSinceLastRollingFeeBump = true; | ||||
} | } | ||||
void CTxMemPool::_clear() { | void CTxMemPool::_clear() { | ||||
mapLinks.clear(); | mapLinks.clear(); | ||||
mapTx.clear(); | mapTx.clear(); | ||||
▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | for (indexed_transaction_set::const_iterator it = mapTx.begin(); | ||||
assert(it->GetCountWithAncestors() == nCountCheck); | assert(it->GetCountWithAncestors() == nCountCheck); | ||||
assert(it->GetSizeWithAncestors() == nSizeCheck); | assert(it->GetSizeWithAncestors() == nSizeCheck); | ||||
assert(it->GetSigOpCountWithAncestors() == nSigOpCheck); | assert(it->GetSigOpCountWithAncestors() == nSigOpCheck); | ||||
assert(it->GetModFeesWithAncestors() == nFeesCheck); | assert(it->GetModFeesWithAncestors() == nFeesCheck); | ||||
// Check children against mapNextTx | // Check children against mapNextTx | ||||
CTxMemPool::setEntries setChildrenCheck; | CTxMemPool::setEntries setChildrenCheck; | ||||
auto iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetId(), 0)); | auto iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0)); | ||||
int64_t childSizes = 0; | int64_t childSizes = 0; | ||||
for (; iter != mapNextTx.end() && | for (; iter != mapNextTx.end() && | ||||
iter->first->hash == it->GetTx().GetId(); | iter->first->hash == it->GetTx().GetHash(); | ||||
++iter) { | ++iter) { | ||||
txiter childit = mapTx.find(iter->second->GetId()); | txiter childit = mapTx.find(iter->second->GetHash()); | ||||
assert(childit != | assert(childit != | ||||
mapTx.end()); // mapNextTx points to in-mempool transactions | mapTx.end()); // mapNextTx points to in-mempool transactions | ||||
if (setChildrenCheck.insert(childit).second) { | if (setChildrenCheck.insert(childit).second) { | ||||
childSizes += childit->GetTxSize(); | childSizes += childit->GetTxSize(); | ||||
} | } | ||||
} | } | ||||
assert(setChildrenCheck == GetMemPoolChildren(it)); | assert(setChildrenCheck == GetMemPoolChildren(it)); | ||||
// Also check to make sure size is greater than sum with immediate | // Also check to make sure size is greater than sum with immediate | ||||
Show All 27 Lines | while (!waitingOnDependants.empty()) { | ||||
Consensus::CheckTxInputs(entry->GetTx(), state, | Consensus::CheckTxInputs(entry->GetTx(), state, | ||||
mempoolDuplicate, nSpendHeight); | mempoolDuplicate, nSpendHeight); | ||||
assert(fCheckResult); | assert(fCheckResult); | ||||
UpdateCoins(entry->GetTx(), mempoolDuplicate, 1000000); | UpdateCoins(entry->GetTx(), mempoolDuplicate, 1000000); | ||||
stepsSinceLastRemove = 0; | stepsSinceLastRemove = 0; | ||||
} | } | ||||
} | } | ||||
for (auto it = mapNextTx.cbegin(); it != mapNextTx.cend(); it++) { | for (auto it = mapNextTx.cbegin(); it != mapNextTx.cend(); it++) { | ||||
uint256 txid = it->second->GetId(); | uint256 txid = it->second->GetHash(); | ||||
indexed_transaction_set::const_iterator it2 = mapTx.find(txid); | indexed_transaction_set::const_iterator it2 = mapTx.find(txid); | ||||
const CTransaction &tx = it2->GetTx(); | const CTransaction &tx = it2->GetTx(); | ||||
assert(it2 != mapTx.end()); | assert(it2 != mapTx.end()); | ||||
assert(&tx == it->second); | assert(&tx == it->second); | ||||
} | } | ||||
assert(totalTxSize == checkTotal); | assert(totalTxSize == checkTotal); | ||||
assert(innerUsage == cachedInnerUsage); | assert(innerUsage == cachedInnerUsage); | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | |||||
void CTxMemPool::queryHashes(std::vector<uint256> &vtxid) { | void CTxMemPool::queryHashes(std::vector<uint256> &vtxid) { | ||||
LOCK(cs); | LOCK(cs); | ||||
auto iters = GetSortedDepthAndScore(); | auto iters = GetSortedDepthAndScore(); | ||||
vtxid.clear(); | vtxid.clear(); | ||||
vtxid.reserve(mapTx.size()); | vtxid.reserve(mapTx.size()); | ||||
for (auto it : iters) { | for (auto it : iters) { | ||||
vtxid.push_back(it->GetTx().GetId()); | vtxid.push_back(it->GetTx().GetHash()); | ||||
} | } | ||||
} | } | ||||
static TxMempoolInfo | static TxMempoolInfo | ||||
GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it) { | GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it) { | ||||
return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), | return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), | ||||
CFeeRate(it->GetFee(), it->GetTxSize()), | CFeeRate(it->GetFee(), it->GetTxSize()), | ||||
it->GetModifiedFee() - it->GetFee()}; | it->GetModifiedFee() - it->GetFee()}; | ||||
▲ Show 20 Lines • Show All 351 Lines • Show Last 20 Lines |