Changeset View
Changeset View
Standalone View
Standalone View
src/txmempool.cpp
Show First 20 Lines • Show All 153 Lines • ▼ Show 20 Lines | for (const uint256 &hash : boost::adaptors::reverse(vHashesToUpdate)) { | ||||
// calculate children from mapNextTx | // calculate children from mapNextTx | ||||
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->GetTxId() == hash; | ||||
++iter) { | |||||
const uint256 &childHash = iter->second->GetId(); | const uint256 &childHash = iter->second->GetId(); | ||||
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); | ||||
Show All 15 Lines | bool CTxMemPool::CalculateMemPoolAncestors( | ||||
setEntries parentHashes; | setEntries parentHashes; | ||||
const CTransaction &tx = entry.GetTx(); | const CTransaction &tx = entry.GetTx(); | ||||
if (fSearchForParents) { | if (fSearchForParents) { | ||||
// Get parents of this transaction that are in the mempool | // Get parents of this transaction that are in the mempool | ||||
// GetMemPoolParents() is only valid for entries in the mempool, so we | // GetMemPoolParents() is only valid for entries in the mempool, so we | ||||
// iterate mapTx to find parents. | // iterate mapTx to find parents. | ||||
for (const CTxIn &in : tx.vin) { | for (const CTxIn &in : tx.vin) { | ||||
txiter piter = mapTx.find(in.prevout.hash); | txiter piter = mapTx.find(in.prevout.GetTxId()); | ||||
if (piter == mapTx.end()) { | if (piter == mapTx.end()) { | ||||
continue; | continue; | ||||
} | } | ||||
parentHashes.insert(piter); | parentHashes.insert(piter); | ||||
if (parentHashes.size() + 1 > limitAncestorCount) { | if (parentHashes.size() + 1 > limitAncestorCount) { | ||||
errString = | errString = | ||||
strprintf("too many unconfirmed parents [limit: %u]", | strprintf("too many unconfirmed parents [limit: %u]", | ||||
limitAncestorCount); | limitAncestorCount); | ||||
▲ Show 20 Lines • Show All 232 Lines • ▼ Show 20 Lines | bool CTxMemPool::addUnchecked(const uint256 &hash, const CTxMemPoolEntry &entry, | ||||
// (When we update the entry for in-mempool parents, memory usage will be | // (When we update the entry for in-mempool parents, memory usage will be | ||||
// further updated.) | // further updated.) | ||||
cachedInnerUsage += entry.DynamicMemoryUsage(); | cachedInnerUsage += entry.DynamicMemoryUsage(); | ||||
const CTransaction &tx = newit->GetTx(); | const CTransaction &tx = newit->GetTx(); | ||||
std::set<uint256> setParentTransactions; | std::set<uint256> setParentTransactions; | ||||
for (const CTxIn &in : tx.vin) { | for (const CTxIn &in : tx.vin) { | ||||
mapNextTx.insert(std::make_pair(&in.prevout, &tx)); | mapNextTx.insert(std::make_pair(&in.prevout, &tx)); | ||||
setParentTransactions.insert(in.prevout.hash); | setParentTransactions.insert(in.prevout.GetTxId()); | ||||
} | } | ||||
// Don't bother worrying about child transactions of this one. Normal case | // Don't bother worrying about child transactions of this one. Normal case | ||||
// of a new transaction arriving is that there can't be any children, | // of a new transaction arriving is that there can't be any children, | ||||
// because such children would be orphans. An exception to that is if a | // because such children would be orphans. An exception to that is if a | ||||
// transaction enters that used to be in a block. In that case, our | // transaction enters that used to be in a block. In that case, our | ||||
// disconnect block logic will call UpdateTransactionsFromBlock to clean up | // disconnect block logic will call UpdateTransactionsFromBlock to clean up | ||||
// the mess we're leaving here. | // the mess we're leaving here. | ||||
▲ Show 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | for (indexed_transaction_set::const_iterator it = mapTx.begin(); | ||||
!CheckSequenceLocks(tx, flags, &lp, validLP)) { | !CheckSequenceLocks(tx, flags, &lp, validLP)) { | ||||
// Note if CheckSequenceLocks fails the LockPoints may still be | // Note if CheckSequenceLocks fails the LockPoints may still be | ||||
// invalid. So it's critical that we remove the tx and not depend on | // invalid. So it's critical that we remove the tx and not depend on | ||||
// the LockPoints. | // the LockPoints. | ||||
txToRemove.insert(it); | txToRemove.insert(it); | ||||
} else if (it->GetSpendsCoinbase()) { | } else if (it->GetSpendsCoinbase()) { | ||||
for (const CTxIn &txin : tx.vin) { | for (const CTxIn &txin : tx.vin) { | ||||
indexed_transaction_set::const_iterator it2 = | indexed_transaction_set::const_iterator it2 = | ||||
mapTx.find(txin.prevout.hash); | mapTx.find(txin.prevout.GetTxId()); | ||||
if (it2 != mapTx.end()) { | if (it2 != mapTx.end()) { | ||||
continue; | continue; | ||||
} | } | ||||
const Coin &coin = pcoins->AccessCoin(txin.prevout); | const Coin &coin = pcoins->AccessCoin(txin.prevout); | ||||
if (nCheckFrequency != 0) { | if (nCheckFrequency != 0) { | ||||
assert(!coin.IsSpent()); | assert(!coin.IsSpent()); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 121 Lines • ▼ Show 20 Lines | for (indexed_transaction_set::const_iterator it = mapTx.begin(); | ||||
bool fDependsWait = false; | bool fDependsWait = false; | ||||
setEntries setParentCheck; | setEntries setParentCheck; | ||||
int64_t parentSizes = 0; | int64_t parentSizes = 0; | ||||
int64_t parentSigOpCount = 0; | int64_t parentSigOpCount = 0; | ||||
for (const CTxIn &txin : tx.vin) { | for (const CTxIn &txin : tx.vin) { | ||||
// Check that every mempool transaction's inputs refer to available | // Check that every mempool transaction's inputs refer to available | ||||
// coins, or other mempool tx's. | // coins, or other mempool tx's. | ||||
indexed_transaction_set::const_iterator it2 = | indexed_transaction_set::const_iterator it2 = | ||||
mapTx.find(txin.prevout.hash); | mapTx.find(txin.prevout.GetTxId()); | ||||
if (it2 != mapTx.end()) { | if (it2 != mapTx.end()) { | ||||
const CTransaction &tx2 = it2->GetTx(); | const CTransaction &tx2 = it2->GetTx(); | ||||
assert(tx2.vout.size() > txin.prevout.n && | assert(tx2.vout.size() > txin.prevout.GetN() && | ||||
!tx2.vout[txin.prevout.n].IsNull()); | !tx2.vout[txin.prevout.GetN()].IsNull()); | ||||
fDependsWait = true; | fDependsWait = true; | ||||
if (setParentCheck.insert(it2).second) { | if (setParentCheck.insert(it2).second) { | ||||
parentSizes += it2->GetTxSize(); | parentSizes += it2->GetTxSize(); | ||||
parentSigOpCount += it2->GetSigOpCount(); | parentSigOpCount += it2->GetSigOpCount(); | ||||
} | } | ||||
} else { | } else { | ||||
assert(pcoins->HaveCoin(txin.prevout)); | assert(pcoins->HaveCoin(txin.prevout)); | ||||
} | } | ||||
Show All 27 Lines | for (indexed_transaction_set::const_iterator it = mapTx.begin(); | ||||
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().GetId(), 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->GetTxId() == it->GetTx().GetId(); | ||||
++iter) { | ++iter) { | ||||
txiter childit = mapTx.find(iter->second->GetId()); | txiter childit = mapTx.find(iter->second->GetId()); | ||||
// mapNextTx points to in-mempool transactions | // mapNextTx points to in-mempool transactions | ||||
assert(childit != mapTx.end()); | assert(childit != mapTx.end()); | ||||
if (setChildrenCheck.insert(childit).second) { | if (setChildrenCheck.insert(childit).second) { | ||||
childSizes += childit->GetTxSize(); | childSizes += childit->GetTxSize(); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 255 Lines • ▼ Show 20 Lines | |||||
void CTxMemPool::ClearPrioritisation(const uint256 hash) { | void CTxMemPool::ClearPrioritisation(const uint256 hash) { | ||||
LOCK(cs); | LOCK(cs); | ||||
mapDeltas.erase(hash); | mapDeltas.erase(hash); | ||||
} | } | ||||
bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const { | bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const { | ||||
for (const CTxIn &in : tx.vin) { | for (const CTxIn &in : tx.vin) { | ||||
if (exists(in.prevout.hash)) { | if (exists(in.prevout.GetTxId())) { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView *baseIn, | CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView *baseIn, | ||||
const CTxMemPool &mempoolIn) | const CTxMemPool &mempoolIn) | ||||
: CCoinsViewBacked(baseIn), mempool(mempoolIn) {} | : CCoinsViewBacked(baseIn), mempool(mempoolIn) {} | ||||
bool CCoinsViewMemPool::GetCoin(const COutPoint &outpoint, Coin &coin) const { | bool CCoinsViewMemPool::GetCoin(const COutPoint &outpoint, Coin &coin) const { | ||||
// If an entry in the mempool exists, always return that one, as it's | // If an entry in the mempool exists, always return that one, as it's | ||||
// guaranteed to never conflict with the underlying cache, and it cannot | // guaranteed to never conflict with the underlying cache, and it cannot | ||||
// have pruned entries (as it contains full) transactions. First checking | // have pruned entries (as it contains full) transactions. First checking | ||||
// the underlying cache risks returning a pruned entry instead. | // the underlying cache risks returning a pruned entry instead. | ||||
CTransactionRef ptx = mempool.get(outpoint.hash); | CTransactionRef ptx = mempool.get(outpoint.GetTxId()); | ||||
if (ptx) { | if (ptx) { | ||||
if (outpoint.n < ptx->vout.size()) { | if (outpoint.GetN() < ptx->vout.size()) { | ||||
coin = Coin(ptx->vout[outpoint.n], MEMPOOL_HEIGHT, false); | coin = Coin(ptx->vout[outpoint.GetN()], MEMPOOL_HEIGHT, false); | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
return base->GetCoin(outpoint, coin) && !coin.IsSpent(); | return base->GetCoin(outpoint, coin) && !coin.IsSpent(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 156 Lines • ▼ Show 20 Lines | while (!mapTx.empty() && DynamicMemoryUsage() > sizelimit) { | ||||
for (txiter iter : stage) { | for (txiter iter : stage) { | ||||
txn.push_back(iter->GetTx()); | txn.push_back(iter->GetTx()); | ||||
} | } | ||||
} | } | ||||
RemoveStaged(stage, false, MemPoolRemovalReason::SIZELIMIT); | RemoveStaged(stage, false, MemPoolRemovalReason::SIZELIMIT); | ||||
if (pvNoSpendsRemaining) { | if (pvNoSpendsRemaining) { | ||||
for (const CTransaction &tx : txn) { | for (const CTransaction &tx : txn) { | ||||
for (const CTxIn &txin : tx.vin) { | for (const CTxIn &txin : tx.vin) { | ||||
if (exists(txin.prevout.hash)) { | if (exists(txin.prevout.GetTxId())) { | ||||
continue; | continue; | ||||
} | } | ||||
if (!mapNextTx.count(txin.prevout)) { | if (!mapNextTx.count(txin.prevout)) { | ||||
pvNoSpendsRemaining->push_back(txin.prevout); | pvNoSpendsRemaining->push_back(txin.prevout); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
Show All 20 Lines |