Switch CTransaction storage in mempool to std::shared_ptr
This commit is contained in:
parent
1b9e6d3c1a
commit
8d39d7a2cf
3 changed files with 103 additions and 53 deletions
32
src/main.cpp
32
src/main.cpp
|
@ -4519,10 +4519,11 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
|
|||
}
|
||||
}
|
||||
if (!push && inv.type == MSG_TX) {
|
||||
int64_t txtime;
|
||||
auto txinfo = mempool.info(inv.hash);
|
||||
// To protect privacy, do not answer getdata using the mempool when
|
||||
// that TX couldn't have been INVed in reply to a MEMPOOL request.
|
||||
if (mempool.lookup(inv.hash, tx, txtime) && txtime <= pfrom->timeLastMempoolReq) {
|
||||
if (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq) {
|
||||
tx = *txinfo.tx;
|
||||
push = true;
|
||||
}
|
||||
}
|
||||
|
@ -5900,8 +5901,7 @@ bool SendMessages(CNode* pto)
|
|||
|
||||
// Respond to BIP35 mempool requests
|
||||
if (fSendTrickle && pto->fSendMempool) {
|
||||
std::vector<uint256> vtxid;
|
||||
mempool.queryHashes(vtxid);
|
||||
auto vtxinfo = mempool.infoAll();
|
||||
pto->fSendMempool = false;
|
||||
CAmount filterrate = 0;
|
||||
{
|
||||
|
@ -5911,20 +5911,16 @@ bool SendMessages(CNode* pto)
|
|||
|
||||
LOCK(pto->cs_filter);
|
||||
|
||||
BOOST_FOREACH(const uint256& hash, vtxid) {
|
||||
for (const auto& txinfo : vtxinfo) {
|
||||
const uint256& hash = txinfo.tx->GetHash();
|
||||
CInv inv(MSG_TX, hash);
|
||||
pto->setInventoryTxToSend.erase(hash);
|
||||
if (filterrate) {
|
||||
CFeeRate feeRate;
|
||||
mempool.lookupFeeRate(hash, feeRate);
|
||||
if (feeRate.GetFeePerK() < filterrate)
|
||||
if (txinfo.feeRate.GetFeePerK() < filterrate)
|
||||
continue;
|
||||
}
|
||||
if (pto->pfilter) {
|
||||
CTransaction tx;
|
||||
bool fInMemPool = mempool.lookup(hash, tx);
|
||||
if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
|
||||
if (!pto->pfilter->IsRelevantAndUpdate(tx)) continue;
|
||||
if (!pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
|
||||
}
|
||||
pto->filterInventoryKnown.insert(hash);
|
||||
vInv.push_back(inv);
|
||||
|
@ -5970,16 +5966,14 @@ bool SendMessages(CNode* pto)
|
|||
continue;
|
||||
}
|
||||
// Not in the mempool anymore? don't bother sending it.
|
||||
CFeeRate feeRate;
|
||||
if (!mempool.lookupFeeRate(hash, feeRate)) {
|
||||
auto txinfo = mempool.info(hash);
|
||||
if (!txinfo.tx) {
|
||||
continue;
|
||||
}
|
||||
if (filterrate && feeRate.GetFeePerK() < filterrate) {
|
||||
if (filterrate && txinfo.feeRate.GetFeePerK() < filterrate) {
|
||||
continue;
|
||||
}
|
||||
CTransaction tx;
|
||||
if (!mempool.lookup(hash, tx)) continue;
|
||||
if (pto->pfilter && !pto->pfilter->IsRelevantAndUpdate(tx)) continue;
|
||||
if (pto->pfilter && !pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
|
||||
// Send
|
||||
vInv.push_back(CInv(MSG_TX, hash));
|
||||
nRelayedTransactions++;
|
||||
|
@ -5992,7 +5986,7 @@ bool SendMessages(CNode* pto)
|
|||
vRelayExpiration.pop_front();
|
||||
}
|
||||
|
||||
auto ret = mapRelay.insert(std::make_pair(hash, tx));
|
||||
auto ret = mapRelay.insert(std::make_pair(hash, *txinfo.tx));
|
||||
if (ret.second) {
|
||||
vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, hash));
|
||||
}
|
||||
|
|
|
@ -23,18 +23,18 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
|
|||
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
|
||||
bool poolHasNoInputsOf, CAmount _inChainInputValue,
|
||||
bool _spendsCoinbase, unsigned int _sigOps, LockPoints lp):
|
||||
tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight),
|
||||
tx(std::make_shared<CTransaction>(_tx)), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight),
|
||||
hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue),
|
||||
spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps), lockPoints(lp)
|
||||
{
|
||||
nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
|
||||
nModSize = tx.CalculateModifiedSize(nTxSize);
|
||||
nUsageSize = RecursiveDynamicUsage(tx);
|
||||
nTxSize = ::GetSerializeSize(_tx, SER_NETWORK, PROTOCOL_VERSION);
|
||||
nModSize = _tx.CalculateModifiedSize(nTxSize);
|
||||
nUsageSize = RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(tx);
|
||||
|
||||
nCountWithDescendants = 1;
|
||||
nSizeWithDescendants = nTxSize;
|
||||
nModFeesWithDescendants = nFee;
|
||||
CAmount nValueIn = tx.GetValueOut()+nFee;
|
||||
CAmount nValueIn = _tx.GetValueOut()+nFee;
|
||||
assert(inChainInputValue <= nValueIn);
|
||||
|
||||
feeDelta = 0;
|
||||
|
@ -768,50 +768,86 @@ bool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb
|
|||
namespace {
|
||||
class DepthAndScoreComparator
|
||||
{
|
||||
CTxMemPool *mp;
|
||||
public:
|
||||
DepthAndScoreComparator(CTxMemPool *mempool) : mp(mempool) {}
|
||||
bool operator()(const uint256& a, const uint256& b) { return mp->CompareDepthAndScore(a, b); }
|
||||
bool operator()(const CTxMemPool::indexed_transaction_set::const_iterator& a, const CTxMemPool::indexed_transaction_set::const_iterator& b)
|
||||
{
|
||||
uint64_t counta = a->GetCountWithAncestors();
|
||||
uint64_t countb = b->GetCountWithAncestors();
|
||||
if (counta == countb) {
|
||||
return CompareTxMemPoolEntryByScore()(*a, *b);
|
||||
}
|
||||
return counta < countb;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<CTxMemPool::indexed_transaction_set::const_iterator> CTxMemPool::GetSortedDepthAndScore() const
|
||||
{
|
||||
std::vector<indexed_transaction_set::const_iterator> iters;
|
||||
AssertLockHeld(cs);
|
||||
|
||||
iters.reserve(mapTx.size());
|
||||
|
||||
for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) {
|
||||
iters.push_back(mi);
|
||||
}
|
||||
std::sort(iters.begin(), iters.end(), DepthAndScoreComparator());
|
||||
return iters;
|
||||
}
|
||||
|
||||
void CTxMemPool::queryHashes(vector<uint256>& vtxid)
|
||||
{
|
||||
LOCK(cs);
|
||||
auto iters = GetSortedDepthAndScore();
|
||||
|
||||
vtxid.clear();
|
||||
|
||||
LOCK(cs);
|
||||
vtxid.reserve(mapTx.size());
|
||||
for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi)
|
||||
vtxid.push_back(mi->GetTx().GetHash());
|
||||
|
||||
std::sort(vtxid.begin(), vtxid.end(), DepthAndScoreComparator(this));
|
||||
for (auto it : iters) {
|
||||
vtxid.push_back(it->GetTx().GetHash());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CTxMemPool::lookup(uint256 hash, CTransaction& result, int64_t& time) const
|
||||
std::vector<TxMempoolInfo> CTxMemPool::infoAll() const
|
||||
{
|
||||
LOCK(cs);
|
||||
indexed_transaction_set::const_iterator i = mapTx.find(hash);
|
||||
if (i == mapTx.end()) return false;
|
||||
result = i->GetTx();
|
||||
time = i->GetTime();
|
||||
return true;
|
||||
auto iters = GetSortedDepthAndScore();
|
||||
|
||||
std::vector<TxMempoolInfo> ret;
|
||||
ret.reserve(mapTx.size());
|
||||
for (auto it : iters) {
|
||||
ret.push_back(TxMempoolInfo{it->GetSharedTx(), it->GetTime(), CFeeRate(it->GetFee(), it->GetTxSize())});
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
|
||||
{
|
||||
int64_t time;
|
||||
return CTxMemPool::lookup(hash, result, time);
|
||||
}
|
||||
|
||||
bool CTxMemPool::lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const
|
||||
std::shared_ptr<const CTransaction> CTxMemPool::get(const uint256& hash) const
|
||||
{
|
||||
LOCK(cs);
|
||||
indexed_transaction_set::const_iterator i = mapTx.find(hash);
|
||||
if (i == mapTx.end())
|
||||
return false;
|
||||
feeRate = CFeeRate(i->GetFee(), i->GetTxSize());
|
||||
return true;
|
||||
return nullptr;
|
||||
return i->GetSharedTx();
|
||||
}
|
||||
|
||||
bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
|
||||
{
|
||||
auto tx = get(hash);
|
||||
if (tx) {
|
||||
result = *tx;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TxMempoolInfo CTxMemPool::info(const uint256& hash) const
|
||||
{
|
||||
LOCK(cs);
|
||||
indexed_transaction_set::const_iterator i = mapTx.find(hash);
|
||||
if (i == mapTx.end())
|
||||
return TxMempoolInfo();
|
||||
return TxMempoolInfo{i->GetSharedTx(), i->GetTime(), CFeeRate(i->GetFee(), i->GetTxSize())};
|
||||
}
|
||||
|
||||
CFeeRate CTxMemPool::estimateFee(int nBlocks) const
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define BITCOIN_TXMEMPOOL_H
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include "amount.h"
|
||||
|
@ -75,7 +76,7 @@ class CTxMemPool;
|
|||
class CTxMemPoolEntry
|
||||
{
|
||||
private:
|
||||
CTransaction tx;
|
||||
std::shared_ptr<const CTransaction> tx;
|
||||
CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups
|
||||
size_t nTxSize; //!< ... and avoid recomputing tx size
|
||||
size_t nModSize; //!< ... and modified size for priority
|
||||
|
@ -112,7 +113,8 @@ public:
|
|||
unsigned int nSigOps, LockPoints lp);
|
||||
CTxMemPoolEntry(const CTxMemPoolEntry& other);
|
||||
|
||||
const CTransaction& GetTx() const { return this->tx; }
|
||||
const CTransaction& GetTx() const { return *this->tx; }
|
||||
std::shared_ptr<const CTransaction> GetSharedTx() const { return this->tx; }
|
||||
/**
|
||||
* Fast calculation of lower bound of current priority as update
|
||||
* from entry priority. Only inputs that were originally in-chain will age.
|
||||
|
@ -307,6 +309,21 @@ struct ancestor_score {};
|
|||
|
||||
class CBlockPolicyEstimator;
|
||||
|
||||
/**
|
||||
* Information about a mempool transaction.
|
||||
*/
|
||||
struct TxMempoolInfo
|
||||
{
|
||||
/** The transaction itself */
|
||||
std::shared_ptr<const CTransaction> tx;
|
||||
|
||||
/** Time the transaction entered the mempool. */
|
||||
int64_t nTime;
|
||||
|
||||
/** Feerate of the transaction. */
|
||||
CFeeRate feeRate;
|
||||
};
|
||||
|
||||
/**
|
||||
* CTxMemPool stores valid-according-to-the-current-best-chain
|
||||
* transactions that may be included in the next block.
|
||||
|
@ -464,6 +481,8 @@ private:
|
|||
void UpdateParent(txiter entry, txiter parent, bool add);
|
||||
void UpdateChild(txiter entry, txiter child, bool add);
|
||||
|
||||
std::vector<indexed_transaction_set::const_iterator> GetSortedDepthAndScore() const;
|
||||
|
||||
public:
|
||||
indirectmap<COutPoint, const CTransaction*> mapNextTx;
|
||||
std::map<uint256, std::pair<double, CAmount> > mapDeltas;
|
||||
|
@ -589,8 +608,9 @@ public:
|
|||
}
|
||||
|
||||
bool lookup(uint256 hash, CTransaction& result) const;
|
||||
bool lookup(uint256 hash, CTransaction& result, int64_t& time) const;
|
||||
bool lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const;
|
||||
std::shared_ptr<const CTransaction> get(const uint256& hash) const;
|
||||
TxMempoolInfo info(const uint256& hash) const;
|
||||
std::vector<TxMempoolInfo> infoAll() const;
|
||||
|
||||
/** Estimate fee rate needed to get into the next nBlocks
|
||||
* If no answer can be given at nBlocks, return an estimate
|
||||
|
|
Loading…
Reference in a new issue