Merge #13793: tx pool: Use class methods to hide raw map iterator impl details
faa1a74942
tx pool: Use class methods to hide raw map iterator impl details (MarcoFalke)
Pull request description:
ATMP et al would often use map iterator implementation details such as `end()` or `find()`, which is acceptable in current code.
However, this not only makes it impossible to turn the maps into private members in the future but also makes it harder to replace the maps with different data structures.
This is required for and split off of #13804
Tree-SHA512: 4f9017fd1d98d9df49d25bba92655a4a97755eea161fd1cbb565ceb81bbc2b4924129d214f8a29563a77e3d8eef85a67c81245ecdc9a9e5292d419922a93cb88
This commit is contained in:
commit
e0a4f9de7f
3 changed files with 46 additions and 29 deletions
|
@ -156,9 +156,9 @@ bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntr
|
|||
// GetMemPoolParents() is only valid for entries in the mempool, so we
|
||||
// iterate mapTx to find parents.
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
||||
txiter piter = mapTx.find(tx.vin[i].prevout.hash);
|
||||
if (piter != mapTx.end()) {
|
||||
parentHashes.insert(piter);
|
||||
boost::optional<txiter> piter = GetIter(tx.vin[i].prevout.hash);
|
||||
if (piter) {
|
||||
parentHashes.insert(*piter);
|
||||
if (parentHashes.size() + 1 > limitAncestorCount) {
|
||||
errString = strprintf("too many unconfirmed parents [limit: %u]", limitAncestorCount);
|
||||
return false;
|
||||
|
@ -364,12 +364,10 @@ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAnces
|
|||
// Update transaction for any feeDelta created by PrioritiseTransaction
|
||||
// TODO: refactor so that the fee delta is calculated before inserting
|
||||
// into mapTx.
|
||||
std::map<uint256, CAmount>::const_iterator pos = mapDeltas.find(entry.GetTx().GetHash());
|
||||
if (pos != mapDeltas.end()) {
|
||||
const CAmount &delta = pos->second;
|
||||
if (delta) {
|
||||
CAmount delta{0};
|
||||
ApplyDelta(entry.GetTx().GetHash(), delta);
|
||||
if (delta) {
|
||||
mapTx.modify(newit, update_fee_delta(delta));
|
||||
}
|
||||
}
|
||||
|
||||
// Update cachedInnerUsage to include contained transaction's usage.
|
||||
|
@ -391,11 +389,8 @@ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAnces
|
|||
// to clean up the mess we're leaving here.
|
||||
|
||||
// Update ancestors with information about this tx
|
||||
for (const uint256 &phash : setParentTransactions) {
|
||||
txiter pit = mapTx.find(phash);
|
||||
if (pit != mapTx.end()) {
|
||||
for (const auto& pit : GetIterSet(setParentTransactions)) {
|
||||
UpdateParent(newit, pit, true);
|
||||
}
|
||||
}
|
||||
UpdateAncestorsOf(true, newit, setAncestors);
|
||||
UpdateEntryForAncestors(newit, setAncestors);
|
||||
|
@ -864,6 +859,29 @@ void CTxMemPool::ClearPrioritisation(const uint256 hash)
|
|||
mapDeltas.erase(hash);
|
||||
}
|
||||
|
||||
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 uint256& txid) const
|
||||
{
|
||||
auto it = mapTx.find(txid);
|
||||
if (it != mapTx.end()) return it;
|
||||
return boost::optional<txiter>{};
|
||||
}
|
||||
|
||||
CTxMemPool::setEntries CTxMemPool::GetIterSet(const std::set<uint256>& hashes) const
|
||||
{
|
||||
CTxMemPool::setEntries ret;
|
||||
for (const auto& h : hashes) {
|
||||
const auto mi = GetIter(h);
|
||||
if (mi) ret.insert(*mi);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const
|
||||
{
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
|
|
|
@ -566,7 +566,15 @@ public:
|
|||
void ApplyDelta(const uint256 hash, CAmount &nFeeDelta) const;
|
||||
void ClearPrioritisation(const uint256 hash);
|
||||
|
||||
public:
|
||||
/** Get the transaction in the pool that spends the same prevout */
|
||||
const CTransaction* GetConflictTx(const COutPoint& prevout) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
/** Returns an iterator to the given hash, if found */
|
||||
boost::optional<txiter> GetIter(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
/** Translate a set of hashes into a set of pool iterators to avoid repeated lookups */
|
||||
setEntries GetIterSet(const std::set<uint256>& hashes) const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
||||
/** Remove a set of transactions from the mempool.
|
||||
* If a transaction is in this set, then all in-mempool descendants must
|
||||
* also be in the set, unless this transaction is being removed for being
|
||||
|
@ -639,7 +647,7 @@ public:
|
|||
return totalTxSize;
|
||||
}
|
||||
|
||||
bool exists(uint256 hash) const
|
||||
bool exists(const uint256& hash) const
|
||||
{
|
||||
LOCK(cs);
|
||||
return (mapTx.count(hash) != 0);
|
||||
|
|
|
@ -602,10 +602,8 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
|
|||
std::set<uint256> setConflicts;
|
||||
for (const CTxIn &txin : tx.vin)
|
||||
{
|
||||
auto itConflicting = pool.mapNextTx.find(txin.prevout);
|
||||
if (itConflicting != pool.mapNextTx.end())
|
||||
{
|
||||
const CTransaction *ptxConflicting = itConflicting->second;
|
||||
const CTransaction* ptxConflicting = pool.GetConflictTx(txin.prevout);
|
||||
if (ptxConflicting) {
|
||||
if (!setConflicts.count(ptxConflicting->GetHash()))
|
||||
{
|
||||
// Allow opt-out of transaction replacement by setting
|
||||
|
@ -786,16 +784,8 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
|
|||
CFeeRate newFeeRate(nModifiedFees, nSize);
|
||||
std::set<uint256> setConflictsParents;
|
||||
const int maxDescendantsToVisit = 100;
|
||||
CTxMemPool::setEntries setIterConflicting;
|
||||
for (const uint256 &hashConflicting : setConflicts)
|
||||
{
|
||||
CTxMemPool::txiter mi = pool.mapTx.find(hashConflicting);
|
||||
if (mi == pool.mapTx.end())
|
||||
continue;
|
||||
|
||||
// Save these to avoid repeated lookups
|
||||
setIterConflicting.insert(mi);
|
||||
|
||||
const CTxMemPool::setEntries setIterConflicting = pool.GetIterSet(setConflicts);
|
||||
for (const auto& mi : setIterConflicting) {
|
||||
// Don't allow the replacement to reduce the feerate of the
|
||||
// mempool.
|
||||
//
|
||||
|
@ -861,11 +851,12 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
|
|||
// Rather than check the UTXO set - potentially expensive -
|
||||
// it's cheaper to just check if the new input refers to a
|
||||
// tx that's in the mempool.
|
||||
if (pool.mapTx.find(tx.vin[j].prevout.hash) != pool.mapTx.end())
|
||||
if (pool.exists(tx.vin[j].prevout.hash)) {
|
||||
return state.DoS(0, false,
|
||||
REJECT_NONSTANDARD, "replacement-adds-unconfirmed", false,
|
||||
strprintf("replacement %s adds unconfirmed input, idx %d",
|
||||
hash.ToString(), j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue