Changeset View
Changeset View
Standalone View
Standalone View
src/txmempool.cpp
Show First 20 Lines • Show All 186 Lines • ▼ Show 20 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.GetTxId()); | boost::optional<txiter> piter = GetIter(in.prevout.GetTxId()); | ||||
if (piter == mapTx.end()) { | if (!piter) { | ||||
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); | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
▲ Show 20 Lines • Show All 206 Lines • ▼ Show 20 Lines | void CTxMemPool::addUnchecked(const TxId &txid, const CTxMemPoolEntry &entry, | ||||
// Add to memory pool without checking anything. | // Add to memory pool without checking anything. | ||||
// Used by AcceptToMemoryPool(), which DOES do all the appropriate checks. | // Used by AcceptToMemoryPool(), which DOES do all the appropriate checks. | ||||
indexed_transaction_set::iterator newit = mapTx.insert(entry).first; | indexed_transaction_set::iterator newit = mapTx.insert(entry).first; | ||||
mapLinks.insert(make_pair(newit, TxLinks())); | mapLinks.insert(make_pair(newit, TxLinks())); | ||||
// Update transaction for any feeDelta created by PrioritiseTransaction | // Update transaction for any feeDelta created by PrioritiseTransaction | ||||
// TODO: refactor so that the fee delta is calculated before inserting into | // TODO: refactor so that the fee delta is calculated before inserting into | ||||
// mapTx. | // mapTx. | ||||
std::map<TxId, TXModifier>::const_iterator pos = mapDeltas.find(txid); | double priorityDelta = 0; | ||||
if (pos != mapDeltas.end()) { | Amount feeDelta = Amount::zero(); | ||||
const TXModifier &deltas = pos->second; | ApplyDeltas(entry.GetTx().GetId(), priorityDelta, feeDelta); | ||||
if (deltas.second != Amount::zero()) { | if (feeDelta != Amount::zero()) { | ||||
mapTx.modify(newit, update_fee_delta(deltas.second)); | mapTx.modify(newit, update_fee_delta(feeDelta)); | ||||
} | |||||
} | } | ||||
// Update cachedInnerUsage to include contained transaction's usage. | // Update cachedInnerUsage to include contained transaction's usage. | ||||
// (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<TxId> setParentTransactions; | std::set<TxId> 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.GetTxId()); | 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. | ||||
// Update ancestors with information about this tx | // Update ancestors with information about this tx | ||||
for (const TxId &phash : setParentTransactions) { | for (const auto &pit : GetIterSet(setParentTransactions)) { | ||||
txiter pit = mapTx.find(phash); | |||||
if (pit != mapTx.end()) { | |||||
UpdateParent(newit, pit, true); | UpdateParent(newit, pit, true); | ||||
} | } | ||||
} | |||||
UpdateAncestorsOf(true, newit, setAncestors); | UpdateAncestorsOf(true, newit, setAncestors); | ||||
UpdateEntryForAncestors(newit, setAncestors); | UpdateEntryForAncestors(newit, setAncestors); | ||||
nTransactionsUpdated++; | nTransactionsUpdated++; | ||||
totalTxSize += entry.GetTxSize(); | totalTxSize += entry.GetTxSize(); | ||||
vTxHashes.emplace_back(tx.GetHash(), newit); | vTxHashes.emplace_back(tx.GetHash(), newit); | ||||
newit->vTxHashesIdx = vTxHashes.size() - 1; | newit->vTxHashesIdx = vTxHashes.size() - 1; | ||||
▲ Show 20 Lines • Show All 520 Lines • ▼ Show 20 Lines | void CTxMemPool::ApplyDeltas(const TxId &txid, double &dPriorityDelta, | ||||
nFeeDelta += deltas.second; | nFeeDelta += deltas.second; | ||||
} | } | ||||
void CTxMemPool::ClearPrioritisation(const TxId &txid) { | void CTxMemPool::ClearPrioritisation(const TxId &txid) { | ||||
LOCK(cs); | LOCK(cs); | ||||
mapDeltas.erase(txid); | mapDeltas.erase(txid); | ||||
} | } | ||||
const CTransaction *CTxMemPool::GetConflictTx(const COutPoint &prevout) const { | |||||
const auto it = mapNextTx.find(prevout); | |||||
return it == mapNextTx.end() ? nullptr : it->second; | |||||
} | |||||
boost::optional<CTxMemPool::txiter> | |||||
CTxMemPool::GetIter(const TxId &txid) const { | |||||
auto it = mapTx.find(txid); | |||||
if (it != mapTx.end()) { | |||||
return it; | |||||
} | |||||
return boost::optional<txiter>{}; | |||||
} | |||||
CTxMemPool::setEntries | |||||
CTxMemPool::GetIterSet(const std::set<TxId> &txids) const { | |||||
CTxMemPool::setEntries ret; | |||||
for (const auto &txid : txids) { | |||||
const auto mi = GetIter(txid); | |||||
if (mi) { | |||||
ret.insert(*mi); | |||||
} | |||||
} | |||||
return ret; | |||||
} | |||||
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.GetTxId())) { | if (exists(in.prevout.GetTxId())) { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
▲ Show 20 Lines • Show All 396 Lines • Show Last 20 Lines |