Changeset View
Changeset View
Standalone View
Standalone View
src/txmempool.cpp
Show All 26 Lines | |||||
CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef &_tx, const Amount _nFee, | CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef &_tx, const Amount _nFee, | ||||
int64_t _nTime, unsigned int _entryHeight, | int64_t _nTime, unsigned int _entryHeight, | ||||
bool _spendsCoinbase, int64_t _sigOpsCount, | bool _spendsCoinbase, int64_t _sigOpsCount, | ||||
LockPoints lp) | LockPoints lp) | ||||
: tx(_tx), nFee(_nFee), nTxSize(tx->GetTotalSize()), | : tx(_tx), nFee(_nFee), nTxSize(tx->GetTotalSize()), | ||||
nUsageSize(RecursiveDynamicUsage(tx)), nTime(_nTime), | nUsageSize(RecursiveDynamicUsage(tx)), nTime(_nTime), | ||||
entryHeight(_entryHeight), spendsCoinbase(_spendsCoinbase), | entryHeight(_entryHeight), spendsCoinbase(_spendsCoinbase), | ||||
sigOpCount(_sigOpsCount), lockPoints(lp) { | sigOpCount(_sigOpsCount), lockPoints(lp), m_epoch(0) { | ||||
nCountWithDescendants = 1; | nCountWithDescendants = 1; | ||||
nSizeWithDescendants = GetTxSize(); | nSizeWithDescendants = GetTxSize(); | ||||
nSigOpCountWithDescendants = sigOpCount; | nSigOpCountWithDescendants = sigOpCount; | ||||
nModFeesWithDescendants = nFee; | nModFeesWithDescendants = nFee; | ||||
feeDelta = Amount::zero(); | feeDelta = Amount::zero(); | ||||
nCountWithAncestors = 1; | nCountWithAncestors = 1; | ||||
▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | std::set<TxId> setAlreadyIncluded(txidsToUpdate.begin(), | ||||
txidsToUpdate.end()); | txidsToUpdate.end()); | ||||
// Iterate in reverse, so that whenever we are looking at a transaction | // Iterate in reverse, so that whenever we are looking at a transaction | ||||
// we are sure that all in-mempool descendants have already been processed. | // we are sure that all in-mempool descendants have already been processed. | ||||
// This maximizes the benefit of the descendant cache and guarantees that | // This maximizes the benefit of the descendant cache and guarantees that | ||||
// setMemPoolChildren will be updated, an assumption made in | // setMemPoolChildren will be updated, an assumption made in | ||||
// UpdateForDescendants. | // UpdateForDescendants. | ||||
for (const TxId &txid : reverse_iterate(txidsToUpdate)) { | for (const TxId &txid : reverse_iterate(txidsToUpdate)) { | ||||
// we cache the in-mempool children to avoid duplicate updates | |||||
setEntries setChildren; | |||||
// calculate children from mapNextTx | // calculate children from mapNextTx | ||||
txiter it = mapTx.find(txid); | txiter it = mapTx.find(txid); | ||||
if (it == mapTx.end()) { | if (it == mapTx.end()) { | ||||
continue; | continue; | ||||
} | } | ||||
auto iter = mapNextTx.lower_bound(COutPoint(txid, 0)); | auto iter = mapNextTx.lower_bound(COutPoint(txid, 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. | ||||
// we cache the in-mempool children to avoid duplicate updates | |||||
{ | |||||
const auto epoch = GetFreshEpoch(); | |||||
for (; iter != mapNextTx.end() && iter->first->GetTxId() == txid; | for (; iter != mapNextTx.end() && iter->first->GetTxId() == txid; | ||||
++iter) { | ++iter) { | ||||
const TxId &childTxId = iter->second->GetId(); | const TxId &childTxId = iter->second->GetId(); | ||||
txiter childIter = mapTx.find(childTxId); | txiter childIter = mapTx.find(childTxId); | ||||
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 | ||||
// in the block (which are already accounted for). | // are in the block (which are already accounted for). | ||||
if (setChildren.insert(childIter).second && | if (!visited(childIter) && | ||||
!setAlreadyIncluded.count(childTxId)) { | !setAlreadyIncluded.count(childTxId)) { | ||||
UpdateChild(it, childIter, true); | UpdateChild(it, childIter, true); | ||||
UpdateParent(childIter, it, true); | UpdateParent(childIter, it, true); | ||||
} | } | ||||
} | } | ||||
} // release epoch guard for UpdateForDescendants | |||||
UpdateForDescendants(it, mapMemPoolDescendantsToUpdate, | UpdateForDescendants(it, mapMemPoolDescendantsToUpdate, | ||||
setAlreadyIncluded); | setAlreadyIncluded); | ||||
} | } | ||||
} | } | ||||
bool CTxMemPool::CalculateMemPoolAncestors( | bool CTxMemPool::CalculateMemPoolAncestors( | ||||
const CTxMemPoolEntry &entry, setEntries &setAncestors, | const CTxMemPoolEntry &entry, setEntries &setAncestors, | ||||
uint64_t limitAncestorCount, uint64_t limitAncestorSize, | uint64_t limitAncestorCount, uint64_t limitAncestorSize, | ||||
▲ Show 20 Lines • Show All 196 Lines • ▼ Show 20 Lines | void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, Amount modifyFee, | ||||
assert(int64_t(nSizeWithAncestors) > 0); | assert(int64_t(nSizeWithAncestors) > 0); | ||||
nModFeesWithAncestors += modifyFee; | nModFeesWithAncestors += modifyFee; | ||||
nCountWithAncestors += modifyCount; | nCountWithAncestors += modifyCount; | ||||
assert(int64_t(nCountWithAncestors) > 0); | assert(int64_t(nCountWithAncestors) > 0); | ||||
nSigOpCountWithAncestors += modifySigOps; | nSigOpCountWithAncestors += modifySigOps; | ||||
assert(int(nSigOpCountWithAncestors) >= 0); | assert(int(nSigOpCountWithAncestors) >= 0); | ||||
} | } | ||||
CTxMemPool::CTxMemPool() : nTransactionsUpdated(0) { | CTxMemPool::CTxMemPool() | ||||
: nTransactionsUpdated(0), m_epoch(0), m_has_epoch_guard(false) { | |||||
// lock free clear | // lock free clear | ||||
_clear(); | _clear(); | ||||
// Sanity checks off by default for performance, because otherwise accepting | // Sanity checks off by default for performance, because otherwise accepting | ||||
// transactions becomes O(N^2) where N is the number of transactions in the | // transactions becomes O(N^2) where N is the number of transactions in the | ||||
// pool | // pool | ||||
nCheckFrequency = 0; | nCheckFrequency = 0; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,020 Lines • ▼ Show 20 Lines | pool.removeForReorg(config, &::ChainstateActive().CoinsTip(), | ||||
STANDARD_LOCKTIME_VERIFY_FLAGS); | STANDARD_LOCKTIME_VERIFY_FLAGS); | ||||
// Re-limit mempool size, in case we added any transactions | // Re-limit mempool size, in case we added any transactions | ||||
pool.LimitSize(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * | pool.LimitSize(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * | ||||
1000000, | 1000000, | ||||
std::chrono::hours{ | std::chrono::hours{ | ||||
gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); | gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); | ||||
} | } | ||||
CTxMemPool::EpochGuard CTxMemPool::GetFreshEpoch() const { | |||||
return EpochGuard(*this); | |||||
} | |||||
CTxMemPool::EpochGuard::EpochGuard(const CTxMemPool &in) : pool(in) { | |||||
assert(!pool.m_has_epoch_guard); | |||||
++pool.m_epoch; | |||||
pool.m_has_epoch_guard = true; | |||||
} | |||||
CTxMemPool::EpochGuard::~EpochGuard() { | |||||
// prevents stale results being used | |||||
++pool.m_epoch; | |||||
pool.m_has_epoch_guard = false; | |||||
} |