Remove work limit in UpdateForDescendants()
The work limit served to prevent the descendant walking algorithm from doing too much work by marking the parent transaction as dirty. However to implement ancestor tracking, it's not possible to similarly mark those descendant transactions as dirty without having to calculate them to begin with. This commit removes the work limit altogether. With appropriate chain limits (-limitdescendantcount) the concern about doing too much work inside this function should be mitigated.
This commit is contained in:
parent
5de2baa138
commit
76a76321d2
3 changed files with 12 additions and 80 deletions
14
src/main.cpp
14
src/main.cpp
|
@ -1194,20 +1194,6 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
|||
// Save these to avoid repeated lookups
|
||||
setIterConflicting.insert(mi);
|
||||
|
||||
// If this entry is "dirty", then we don't have descendant
|
||||
// state for this transaction, which means we probably have
|
||||
// lots of in-mempool descendants.
|
||||
// Don't allow replacements of dirty transactions, to ensure
|
||||
// that we don't spend too much time walking descendants.
|
||||
// This should be rare.
|
||||
if (mi->IsDirty()) {
|
||||
return state.DoS(0, false,
|
||||
REJECT_NONSTANDARD, "too many potential replacements", false,
|
||||
strprintf("too many potential replacements: rejecting replacement %s; cannot replace tx %s with untracked descendants",
|
||||
hash.ToString(),
|
||||
mi->GetTx().GetHash().ToString()));
|
||||
}
|
||||
|
||||
// Don't allow the replacement to reduce the feerate of the
|
||||
// mempool.
|
||||
//
|
||||
|
|
|
@ -64,21 +64,13 @@ void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta)
|
|||
// Update the given tx for any in-mempool descendants.
|
||||
// Assumes that setMemPoolChildren is correct for the given tx and all
|
||||
// descendants.
|
||||
bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit, cacheMap &cachedDescendants, const std::set<uint256> &setExclude)
|
||||
void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendants, const std::set<uint256> &setExclude)
|
||||
{
|
||||
// Track the number of entries (outside setExclude) that we'd need to visit
|
||||
// (will bail out if it exceeds maxDescendantsToVisit)
|
||||
int nChildrenToVisit = 0;
|
||||
|
||||
setEntries stageEntries, setAllDescendants;
|
||||
stageEntries = GetMemPoolChildren(updateIt);
|
||||
|
||||
while (!stageEntries.empty()) {
|
||||
const txiter cit = *stageEntries.begin();
|
||||
if (cit->IsDirty()) {
|
||||
// Don't consider any more children if any descendant is dirty
|
||||
return false;
|
||||
}
|
||||
setAllDescendants.insert(cit);
|
||||
stageEntries.erase(cit);
|
||||
const setEntries &setChildren = GetMemPoolChildren(cit);
|
||||
|
@ -88,22 +80,11 @@ bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit
|
|||
// We've already calculated this one, just add the entries for this set
|
||||
// but don't traverse again.
|
||||
BOOST_FOREACH(const txiter cacheEntry, cacheIt->second) {
|
||||
// update visit count only for new child transactions
|
||||
// (outside of setExclude and stageEntries)
|
||||
if (setAllDescendants.insert(cacheEntry).second &&
|
||||
!setExclude.count(cacheEntry->GetTx().GetHash()) &&
|
||||
!stageEntries.count(cacheEntry)) {
|
||||
nChildrenToVisit++;
|
||||
}
|
||||
setAllDescendants.insert(cacheEntry);
|
||||
}
|
||||
} else if (!setAllDescendants.count(childEntry)) {
|
||||
// Schedule for later processing and update our visit count
|
||||
if (stageEntries.insert(childEntry).second && !setExclude.count(childEntry->GetTx().GetHash())) {
|
||||
nChildrenToVisit++;
|
||||
}
|
||||
}
|
||||
if (nChildrenToVisit > maxDescendantsToVisit) {
|
||||
return false;
|
||||
// Schedule for later processing
|
||||
stageEntries.insert(childEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +102,6 @@ bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit
|
|||
}
|
||||
}
|
||||
mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount));
|
||||
return true;
|
||||
}
|
||||
|
||||
// vHashesToUpdate is the set of transaction hashes from a disconnected block
|
||||
|
@ -167,10 +147,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashes
|
|||
UpdateParent(childIter, it, true);
|
||||
}
|
||||
}
|
||||
if (!UpdateForDescendants(it, 100, mapMemPoolDescendantsToUpdate, setAlreadyIncluded)) {
|
||||
// Mark as dirty if we can't do the calculation.
|
||||
mapTx.modify(it, set_dirty());
|
||||
}
|
||||
UpdateForDescendants(it, mapMemPoolDescendantsToUpdate, setAlreadyIncluded);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,22 +278,13 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove)
|
|||
}
|
||||
}
|
||||
|
||||
void CTxMemPoolEntry::SetDirty()
|
||||
{
|
||||
nCountWithDescendants = 0;
|
||||
nSizeWithDescendants = nTxSize;
|
||||
nModFeesWithDescendants = GetModifiedFee();
|
||||
}
|
||||
|
||||
void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount)
|
||||
{
|
||||
if (!IsDirty()) {
|
||||
nSizeWithDescendants += modifySize;
|
||||
assert(int64_t(nSizeWithDescendants) > 0);
|
||||
nModFeesWithDescendants += modifyFee;
|
||||
nCountWithDescendants += modifyCount;
|
||||
assert(int64_t(nCountWithDescendants) > 0);
|
||||
}
|
||||
nSizeWithDescendants += modifySize;
|
||||
assert(int64_t(nSizeWithDescendants) > 0);
|
||||
nModFeesWithDescendants += modifyFee;
|
||||
nCountWithDescendants += modifyCount;
|
||||
assert(int64_t(nCountWithDescendants) > 0);
|
||||
}
|
||||
|
||||
CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) :
|
||||
|
@ -658,12 +626,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
|
|||
assert(setChildrenCheck == GetMemPoolChildren(it));
|
||||
// Also check to make sure size is greater than sum with immediate children.
|
||||
// just a sanity check, not definitive that this calc is correct...
|
||||
if (!it->IsDirty()) {
|
||||
assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize());
|
||||
} else {
|
||||
assert(it->GetSizeWithDescendants() == it->GetTxSize());
|
||||
assert(it->GetModFeesWithDescendants() == it->GetModifiedFee());
|
||||
}
|
||||
assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize());
|
||||
|
||||
if (fDependsWait)
|
||||
waitingOnDependants.push_back(&(*it));
|
||||
|
|
|
@ -108,13 +108,6 @@ public:
|
|||
// modified fees with descendants.
|
||||
void UpdateFeeDelta(int64_t feeDelta);
|
||||
|
||||
/** We can set the entry to be dirty if doing the full calculation of in-
|
||||
* mempool descendants will be too expensive, which can potentially happen
|
||||
* when re-adding transactions from a block back to the mempool.
|
||||
*/
|
||||
void SetDirty();
|
||||
bool IsDirty() const { return nCountWithDescendants == 0; }
|
||||
|
||||
uint64_t GetCountWithDescendants() const { return nCountWithDescendants; }
|
||||
uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }
|
||||
CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; }
|
||||
|
@ -138,12 +131,6 @@ struct update_descendant_state
|
|||
int64_t modifyCount;
|
||||
};
|
||||
|
||||
struct set_dirty
|
||||
{
|
||||
void operator() (CTxMemPoolEntry &e)
|
||||
{ e.SetDirty(); }
|
||||
};
|
||||
|
||||
struct update_fee_delta
|
||||
{
|
||||
update_fee_delta(int64_t _feeDelta) : feeDelta(_feeDelta) { }
|
||||
|
@ -555,15 +542,11 @@ private:
|
|||
* updated and hence their state is already reflected in the parent
|
||||
* state).
|
||||
*
|
||||
* If updating an entry requires looking at more than maxDescendantsToVisit
|
||||
* transactions, outside of the ones in setExclude, then give up.
|
||||
*
|
||||
* cachedDescendants will be updated with the descendants of the transaction
|
||||
* being updated, so that future invocations don't need to walk the
|
||||
* same transaction again, if encountered in another transaction chain.
|
||||
*/
|
||||
bool UpdateForDescendants(txiter updateIt,
|
||||
int maxDescendantsToVisit,
|
||||
void UpdateForDescendants(txiter updateIt,
|
||||
cacheMap &cachedDescendants,
|
||||
const std::set<uint256> &setExclude);
|
||||
/** Update ancestors of hash to add/remove it as a descendant transaction. */
|
||||
|
|
Loading…
Reference in a new issue