diff options
Diffstat (limited to 'src/policy/fees.cpp')
-rw-r--r-- | src/policy/fees.cpp | 84 |
1 files changed, 44 insertions, 40 deletions
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index a1b785e3e7..5407aefb45 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -281,23 +281,25 @@ void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHe } } -void CBlockPolicyEstimator::removeTx(uint256 hash) +// This function is called from CTxMemPool::removeUnchecked to ensure +// txs removed from the mempool for any reason are no longer +// tracked. Txs that were part of a block have already been removed in +// processBlockTx to ensure they are never double tracked, but it is +// of no harm to try to remove them again. +bool CBlockPolicyEstimator::removeTx(uint256 hash) { std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash); - if (pos == mapMemPoolTxs.end()) { - LogPrint("estimatefee", "Blockpolicy error mempool tx %s not found for removeTx\n", - hash.ToString().c_str()); - return; + if (pos != mapMemPoolTxs.end()) { + feeStats.removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex); + mapMemPoolTxs.erase(hash); + return true; + } else { + return false; } - unsigned int entryHeight = pos->second.blockHeight; - unsigned int bucketIndex = pos->second.bucketIndex; - - feeStats.removeTx(entryHeight, nBestSeenHeight, bucketIndex); - mapMemPoolTxs.erase(hash); } CBlockPolicyEstimator::CBlockPolicyEstimator(const CFeeRate& _minRelayFee) - : nBestSeenHeight(0) + : nBestSeenHeight(0), trackedTxs(0), untrackedTxs(0) { static_assert(MIN_FEERATE > 0, "Min feerate must be nonzero"); minTrackedFee = _minRelayFee < CFeeRate(MIN_FEERATE) ? CFeeRate(MIN_FEERATE) : _minRelayFee; @@ -309,7 +311,7 @@ CBlockPolicyEstimator::CBlockPolicyEstimator(const CFeeRate& _minRelayFee) feeStats.Initialize(vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY); } -void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool fCurrentEstimate) +void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate) { unsigned int txHeight = entry.GetHeight(); uint256 hash = entry.GetTx().GetHash(); @@ -319,23 +321,21 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo return; } - if (txHeight < nBestSeenHeight) { + if (txHeight != nBestSeenHeight) { // Ignore side chains and re-orgs; assuming they are random they don't // affect the estimate. We'll potentially double count transactions in 1-block reorgs. + // Ignore txs if BlockPolicyEstimator is not in sync with chainActive.Tip(). + // It will be synced next time a block is processed. return; } // Only want to be updating estimates when our blockchain is synced, // otherwise we'll miscalculate how many blocks its taking to get included. - if (!fCurrentEstimate) - return; - - if (!entry.WasClearAtEntry()) { - // This transaction depends on other transactions in the mempool to - // be included in a block before it will be able to be included, so - // we shouldn't include it in our calculations + if (!validFeeEstimate) { + untrackedTxs++; return; } + trackedTxs++; // Feerates are stored and reported as BTC-per-kb: CFeeRate feeRate(entry.GetFee(), entry.GetTxSize()); @@ -344,34 +344,33 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo mapMemPoolTxs[hash].bucketIndex = feeStats.NewTx(txHeight, (double)feeRate.GetFeePerK()); } -void CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry& entry) +bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry) { - if (!entry.WasClearAtEntry()) { - // This transaction depended on other transactions in the mempool to - // be included in a block before it was able to be included, so - // we shouldn't include it in our calculations - return; + if (!removeTx(entry->GetTx().GetHash())) { + // This transaction wasn't being tracked for fee estimation + return false; } // How many blocks did it take for miners to include this transaction? // blocksToConfirm is 1-based, so a transaction included in the earliest // possible block has confirmation count of 1 - int blocksToConfirm = nBlockHeight - entry.GetHeight(); + int blocksToConfirm = nBlockHeight - entry->GetHeight(); if (blocksToConfirm <= 0) { // This can't happen because we don't process transactions from a block with a height // lower than our greatest seen height LogPrint("estimatefee", "Blockpolicy error Transaction had negative blocksToConfirm\n"); - return; + return false; } // Feerates are stored and reported as BTC-per-kb: - CFeeRate feeRate(entry.GetFee(), entry.GetTxSize()); + CFeeRate feeRate(entry->GetFee(), entry->GetTxSize()); feeStats.Record(blocksToConfirm, (double)feeRate.GetFeePerK()); + return true; } void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight, - std::vector<CTxMemPoolEntry>& entries, bool fCurrentEstimate) + std::vector<const CTxMemPoolEntry*>& entries) { if (nBlockHeight <= nBestSeenHeight) { // Ignore side chains and re-orgs; assuming they are random @@ -381,25 +380,30 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight, // transaction fees." return; } - nBestSeenHeight = nBlockHeight; - // Only want to be updating estimates when our blockchain is synced, - // otherwise we'll miscalculate how many blocks its taking to get included. - if (!fCurrentEstimate) - return; + // Must update nBestSeenHeight in sync with ClearCurrent so that + // calls to removeTx (via processBlockTx) correctly calculate age + // of unconfirmed txs to remove from tracking. + nBestSeenHeight = nBlockHeight; - // Clear the current block state + // Clear the current block state and update unconfirmed circular buffer feeStats.ClearCurrent(nBlockHeight); + unsigned int countedTxs = 0; // Repopulate the current block states - for (unsigned int i = 0; i < entries.size(); i++) - processBlockTx(nBlockHeight, entries[i]); + for (unsigned int i = 0; i < entries.size(); i++) { + if (processBlockTx(nBlockHeight, entries[i])) + countedTxs++; + } // Update all exponential averages with the current block state feeStats.UpdateMovingAverages(); - LogPrint("estimatefee", "Blockpolicy after updating estimates for %u confirmed entries, new mempool map size %u\n", - entries.size(), mapMemPoolTxs.size()); + LogPrint("estimatefee", "Blockpolicy after updating estimates for %u of %u txs in block, since last block %u of %u tracked, new mempool map size %u\n", + countedTxs, entries.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size()); + + trackedTxs = 0; + untrackedTxs = 0; } CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) |