| 179 | } |
| 180 | |
| 181 | void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashesToUpdate, uint64_t ancestor_size_limit, uint64_t ancestor_count_limit) |
| 182 | { |
| 183 | AssertLockHeld(cs); |
| 184 | // For each entry in vHashesToUpdate, store the set of in-mempool, but not |
| 185 | // in-vHashesToUpdate transactions, so that we don't have to recalculate |
| 186 | // descendants when we come across a previously seen entry. |
| 187 | cacheMap mapMemPoolDescendantsToUpdate; |
| 188 | |
| 189 | // Use a set for lookups into vHashesToUpdate (these entries are already |
| 190 | // accounted for in the state of their ancestors) |
| 191 | std::set<uint256> setAlreadyIncluded(vHashesToUpdate.begin(), vHashesToUpdate.end()); |
| 192 | |
| 193 | std::set<uint256> descendants_to_remove; |
| 194 | |
| 195 | // Iterate in reverse, so that whenever we are looking at a transaction |
| 196 | // we are sure that all in-mempool descendants have already been processed. |
| 197 | // This maximizes the benefit of the descendant cache and guarantees that |
| 198 | // CTxMemPool::m_children will be updated, an assumption made in |
| 199 | // UpdateForDescendants. |
| 200 | for (const uint256 &hash : reverse_iterate(vHashesToUpdate)) { |
| 201 | // calculate children from mapNextTx |
| 202 | txiter it = mapTx.find(hash); |
| 203 | if (it == mapTx.end()) { |
| 204 | continue; |
| 205 | } |
| 206 | auto iter = mapNextTx.lower_bound(COutPoint(hash, 0)); |
| 207 | // First calculate the children, and update CTxMemPool::m_children to |
| 208 | // include them, and update their CTxMemPoolEntry::m_parents to include this tx. |
| 209 | // we cache the in-mempool children to avoid duplicate updates |
| 210 | { |
| 211 | WITH_FRESH_EPOCH(m_epoch); |
| 212 | for (; iter != mapNextTx.end() && iter->first->hash == hash; ++iter) { |
| 213 | const uint256 &childHash = iter->second->GetHash(); |
| 214 | txiter childIter = mapTx.find(childHash); |
| 215 | assert(childIter != mapTx.end()); |
| 216 | // We can skip updating entries we've encountered before or that |
| 217 | // are in the block (which are already accounted for). |
| 218 | if (!visited(childIter) && !setAlreadyIncluded.count(childHash)) { |
| 219 | UpdateChild(it, childIter, true); |
| 220 | UpdateParent(childIter, it, true); |
| 221 | } |
| 222 | } |
| 223 | } // release epoch guard for UpdateForDescendants |
| 224 | UpdateForDescendants(it, mapMemPoolDescendantsToUpdate, setAlreadyIncluded, descendants_to_remove, ancestor_size_limit, ancestor_count_limit); |
| 225 | } |
| 226 | |
| 227 | for (const auto& txid : descendants_to_remove) { |
| 228 | // This txid may have been removed already in a prior call to removeRecursive. |
| 229 | // Therefore we ensure it is not yet removed already. |
| 230 | if (const std::optional<txiter> txiter = GetIter(txid)) { |
| 231 | removeRecursive((*txiter)->GetTx(), MemPoolRemovalReason::SIZELIMIT); |
| 232 | } |
| 233 | } |
| 234 | } |
| 235 | |
| 236 | bool CTxMemPool::CalculateAncestorsAndCheckLimits(size_t entry_size, |
| 237 | size_t entry_count, |
no test coverage detected