aboutsummaryrefslogtreecommitdiff
path: root/src/policy/fees.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/policy/fees.cpp')
-rw-r--r--src/policy/fees.cpp84
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)