Changeset View
Changeset View
Standalone View
Standalone View
src/txmempool.cpp
// Copyright (c) 2009-2010 Satoshi Nakamoto | // Copyright (c) 2009-2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include "txmempool.h" | #include "txmempool.h" | ||||
#include "chainparams.h" // for GetConsensus. | #include "chainparams.h" // for GetConsensus. | ||||
#include "clientversion.h" | #include "clientversion.h" | ||||
#include "config.h" | |||||
#include "consensus/consensus.h" | #include "consensus/consensus.h" | ||||
#include "consensus/tx_verify.h" | #include "consensus/tx_verify.h" | ||||
#include "consensus/validation.h" | #include "consensus/validation.h" | ||||
#include "policy/fees.h" | #include "policy/fees.h" | ||||
#include "policy/policy.h" | #include "policy/policy.h" | ||||
#include "streams.h" | #include "streams.h" | ||||
#include "timedata.h" | #include "timedata.h" | ||||
#include "util.h" | #include "util.h" | ||||
▲ Show 20 Lines • Show All 391 Lines • ▼ Show 20 Lines | |||||
CTxMemPool::CTxMemPool() : nTransactionsUpdated(0) { | CTxMemPool::CTxMemPool() : nTransactionsUpdated(0) { | ||||
// 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; | ||||
minerPolicyEstimator = new CBlockPolicyEstimator(); | |||||
} | } | ||||
CTxMemPool::~CTxMemPool() { | CTxMemPool::~CTxMemPool() {} | ||||
delete minerPolicyEstimator; | |||||
} | |||||
bool CTxMemPool::isSpent(const COutPoint &outpoint) { | bool CTxMemPool::isSpent(const COutPoint &outpoint) { | ||||
LOCK(cs); | LOCK(cs); | ||||
return mapNextTx.count(outpoint); | return mapNextTx.count(outpoint); | ||||
} | } | ||||
unsigned int CTxMemPool::GetTransactionsUpdated() const { | unsigned int CTxMemPool::GetTransactionsUpdated() const { | ||||
LOCK(cs); | LOCK(cs); | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | for (const uint256 &phash : setParentTransactions) { | ||||
UpdateParent(newit, pit, true); | UpdateParent(newit, pit, true); | ||||
} | } | ||||
} | } | ||||
UpdateAncestorsOf(true, newit, setAncestors); | UpdateAncestorsOf(true, newit, setAncestors); | ||||
UpdateEntryForAncestors(newit, setAncestors); | UpdateEntryForAncestors(newit, setAncestors); | ||||
nTransactionsUpdated++; | nTransactionsUpdated++; | ||||
totalTxSize += entry.GetTxSize(); | totalTxSize += entry.GetTxSize(); | ||||
minerPolicyEstimator->processTransaction(entry, validFeeEstimate); | |||||
vTxHashes.emplace_back(tx.GetHash(), newit); | vTxHashes.emplace_back(tx.GetHash(), newit); | ||||
newit->vTxHashesIdx = vTxHashes.size() - 1; | newit->vTxHashesIdx = vTxHashes.size() - 1; | ||||
return true; | return true; | ||||
} | } | ||||
void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason) { | void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason) { | ||||
NotifyEntryRemoved(it->GetSharedTx(), reason); | NotifyEntryRemoved(it->GetSharedTx(), reason); | ||||
const uint256 txid = it->GetTx().GetId(); | |||||
for (const CTxIn &txin : it->GetTx().vin) { | for (const CTxIn &txin : it->GetTx().vin) { | ||||
mapNextTx.erase(txin.prevout); | mapNextTx.erase(txin.prevout); | ||||
} | } | ||||
if (vTxHashes.size() > 1) { | if (vTxHashes.size() > 1) { | ||||
vTxHashes[it->vTxHashesIdx] = std::move(vTxHashes.back()); | vTxHashes[it->vTxHashesIdx] = std::move(vTxHashes.back()); | ||||
vTxHashes[it->vTxHashesIdx].second->vTxHashesIdx = it->vTxHashesIdx; | vTxHashes[it->vTxHashesIdx].second->vTxHashesIdx = it->vTxHashesIdx; | ||||
vTxHashes.pop_back(); | vTxHashes.pop_back(); | ||||
if (vTxHashes.size() * 2 < vTxHashes.capacity()) { | if (vTxHashes.size() * 2 < vTxHashes.capacity()) { | ||||
vTxHashes.shrink_to_fit(); | vTxHashes.shrink_to_fit(); | ||||
} | } | ||||
} else { | } else { | ||||
vTxHashes.clear(); | vTxHashes.clear(); | ||||
} | } | ||||
totalTxSize -= it->GetTxSize(); | totalTxSize -= it->GetTxSize(); | ||||
cachedInnerUsage -= it->DynamicMemoryUsage(); | cachedInnerUsage -= it->DynamicMemoryUsage(); | ||||
cachedInnerUsage -= memusage::DynamicUsage(mapLinks[it].parents) + | cachedInnerUsage -= memusage::DynamicUsage(mapLinks[it].parents) + | ||||
memusage::DynamicUsage(mapLinks[it].children); | memusage::DynamicUsage(mapLinks[it].children); | ||||
mapLinks.erase(it); | mapLinks.erase(it); | ||||
mapTx.erase(it); | mapTx.erase(it); | ||||
nTransactionsUpdated++; | nTransactionsUpdated++; | ||||
minerPolicyEstimator->removeTx(txid); | |||||
} | } | ||||
// Calculates descendants of entry that are not already in setDescendants, and | // Calculates descendants of entry that are not already in setDescendants, and | ||||
// adds to setDescendants. Assumes entryit is already a tx in the mempool and | // adds to setDescendants. Assumes entryit is already a tx in the mempool and | ||||
// setMemPoolChildren is correct for tx and all descendants. Also assumes that | // setMemPoolChildren is correct for tx and all descendants. Also assumes that | ||||
// if an entry is in setDescendants already, then all in-mempool descendants of | // if an entry is in setDescendants already, then all in-mempool descendants of | ||||
// it are already in setDescendants as well, so that we can save time by not | // it are already in setDescendants as well, so that we can save time by not | ||||
// iterating over those entries. | // iterating over those entries. | ||||
▲ Show 20 Lines • Show All 139 Lines • ▼ Show 20 Lines | for (const CTransactionRef &tx : boost::adaptors::reverse( | ||||
uint256 txid = tx->GetId(); | uint256 txid = tx->GetId(); | ||||
indexed_transaction_set::iterator i = mapTx.find(txid); | indexed_transaction_set::iterator i = mapTx.find(txid); | ||||
if (i != mapTx.end()) { | if (i != mapTx.end()) { | ||||
entries.push_back(&*i); | entries.push_back(&*i); | ||||
} | } | ||||
} | } | ||||
// Before the txs in the new block have been removed from the mempool, | |||||
// update policy estimates | |||||
minerPolicyEstimator->processBlock(nBlockHeight, entries); | |||||
for (const CTransactionRef &tx : boost::adaptors::reverse( | for (const CTransactionRef &tx : boost::adaptors::reverse( | ||||
disconnectpool.GetQueuedTx().get<insertion_order>())) { | disconnectpool.GetQueuedTx().get<insertion_order>())) { | ||||
txiter it = mapTx.find(tx->GetId()); | txiter it = mapTx.find(tx->GetId()); | ||||
if (it != mapTx.end()) { | if (it != mapTx.end()) { | ||||
setEntries stage; | setEntries stage; | ||||
stage.insert(it); | stage.insert(it); | ||||
RemoveStaged(stage, true, MemPoolRemovalReason::BLOCK); | RemoveStaged(stage, true, MemPoolRemovalReason::BLOCK); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 278 Lines • ▼ Show 20 Lines | CFeeRate CTxMemPool::estimateFee(int nBlocks) const { | ||||
LOCK(cs); | LOCK(cs); | ||||
uint64_t maxMempoolSize = | uint64_t maxMempoolSize = | ||||
gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; | gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; | ||||
// minerPolicy uses recent blocks to figure out a reasonable fee. This | // minerPolicy uses recent blocks to figure out a reasonable fee. This | ||||
// may disagree with the rollingMinimumFeerate under certain scenarios | // may disagree with the rollingMinimumFeerate under certain scenarios | ||||
// where the mempool increases rapidly, or blocks are being mined which | // where the mempool increases rapidly, or blocks are being mined which | ||||
// do not contain propagated transactions. | // do not contain propagated transactions. | ||||
return std::max(minerPolicyEstimator->estimateFee(nBlocks), | return std::max(GetConfig().GetMinFeePerKB(), GetMinFee(maxMempoolSize)); | ||||
GetMinFee(maxMempoolSize)); | |||||
} | } | ||||
CFeeRate CTxMemPool::estimateSmartFee(int nBlocks, | CFeeRate CTxMemPool::estimateSmartFee(int nBlocks, | ||||
int *answerFoundAtBlocks) const { | int *answerFoundAtBlocks) const { | ||||
LOCK(cs); | if (answerFoundAtBlocks != nullptr) { | ||||
*answerFoundAtBlocks = 1; | |||||
} | |||||
// estimateSmartFee already includes the GetMinFee check, this is the | // estimateSmartFee already includes the GetMinFee check, this is the | ||||
// reason it takes `*this`. It does not need std::max as above. | // reason it takes `*this`. It does not need std::max as above. | ||||
return minerPolicyEstimator->estimateSmartFee(nBlocks, answerFoundAtBlocks, | return estimateFee(nBlocks); | ||||
*this); | |||||
} | |||||
bool CTxMemPool::WriteFeeEstimates(CAutoFile &fileout) const { | |||||
try { | |||||
LOCK(cs); | |||||
// version required to read: 0.13.99 or later | |||||
fileout << 139900; | |||||
// version that wrote the file | |||||
fileout << CLIENT_VERSION; | |||||
minerPolicyEstimator->Write(fileout); | |||||
} catch (const std::exception &) { | |||||
LogPrintf("CTxMemPool::WriteFeeEstimates(): unable to write policy " | |||||
"estimator data (non-fatal)\n"); | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
bool CTxMemPool::ReadFeeEstimates(CAutoFile &filein) { | |||||
try { | |||||
int nVersionRequired, nVersionThatWrote; | |||||
filein >> nVersionRequired >> nVersionThatWrote; | |||||
if (nVersionRequired > CLIENT_VERSION) { | |||||
return error("CTxMemPool::ReadFeeEstimates(): up-version (%d) fee " | |||||
"estimate file", | |||||
nVersionRequired); | |||||
} | |||||
LOCK(cs); | |||||
minerPolicyEstimator->Read(filein, nVersionThatWrote); | |||||
} catch (const std::exception &) { | |||||
LogPrintf("CTxMemPool::ReadFeeEstimates(): unable to read policy " | |||||
"estimator data (non-fatal)\n"); | |||||
return false; | |||||
} | |||||
return true; | |||||
} | } | ||||
void CTxMemPool::PrioritiseTransaction(const uint256 hash, | void CTxMemPool::PrioritiseTransaction(const uint256 hash, | ||||
const std::string strHash, | const std::string strHash, | ||||
double dPriorityDelta, | double dPriorityDelta, | ||||
const Amount nFeeDelta) { | const Amount nFeeDelta) { | ||||
{ | { | ||||
LOCK(cs); | LOCK(cs); | ||||
▲ Show 20 Lines • Show All 387 Lines • Show Last 20 Lines |