Switch CTransaction storage in mempool to std::shared_ptr
(cherry picked from commit bitcoin/bitcoin@8d39d7a2cf)
This commit is contained in:
parent
e863fdaebb
commit
e469547f3d
35
src/main.cpp
35
src/main.cpp
|
@ -6148,10 +6148,11 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!push && inv.type == MSG_TX) {
|
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
|
// To protect privacy, do not answer getdata using the mempool when
|
||||||
// that TX couldn't have been INVed in reply to a MEMPOOL request.
|
// that TX couldn't have been INVed in reply to a MEMPOOL request.
|
||||||
if (mempool.lookup(inv.hash, tx, txtime) && txtime <= pfrom->timeLastMempoolReq && !IsExpiringSoonTx(tx, currentHeight + 1)) {
|
if (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq && !IsExpiringSoonTx(*txinfo.tx, currentHeight + 1)) {
|
||||||
|
tx = *txinfo.tx;
|
||||||
push = true;
|
push = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7446,27 +7447,22 @@ bool SendMessages(const Consensus::Params& params, CNode* pto)
|
||||||
if (!pto->fRelayTxes) pto->setInventoryTxToSend.clear();
|
if (!pto->fRelayTxes) pto->setInventoryTxToSend.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int currentHeight = GetHeight();
|
||||||
|
|
||||||
// Respond to BIP35 mempool requests
|
// Respond to BIP35 mempool requests
|
||||||
if (fSendTrickle && pto->fSendMempool) {
|
if (fSendTrickle && pto->fSendMempool) {
|
||||||
std::vector<uint256> vtxid;
|
auto vtxinfo = mempool.infoAll();
|
||||||
mempool.queryHashes(vtxid);
|
|
||||||
pto->fSendMempool = false;
|
pto->fSendMempool = false;
|
||||||
|
|
||||||
LOCK(pto->cs_filter);
|
LOCK(pto->cs_filter);
|
||||||
|
|
||||||
int currentHeight = GetHeight();
|
for (const auto& txinfo : vtxinfo) {
|
||||||
for (const uint256& hash : vtxid) {
|
const uint256& hash = txinfo.tx->GetHash();
|
||||||
CTransaction tx;
|
|
||||||
bool fInMemPool = mempool.lookup(hash, tx);
|
|
||||||
if (fInMemPool && IsExpiringSoonTx(tx, currentHeight + 1)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
CInv inv(MSG_TX, hash);
|
CInv inv(MSG_TX, hash);
|
||||||
pto->setInventoryTxToSend.erase(hash);
|
pto->setInventoryTxToSend.erase(hash);
|
||||||
|
if (IsExpiringSoonTx(*txinfo.tx, currentHeight + 1)) continue;
|
||||||
if (pto->pfilter) {
|
if (pto->pfilter) {
|
||||||
if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
|
if (!pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
|
||||||
if (!pto->pfilter->IsRelevantAndUpdate(tx)) continue;
|
|
||||||
}
|
}
|
||||||
pto->filterInventoryKnown.insert(hash);
|
pto->filterInventoryKnown.insert(hash);
|
||||||
vInv.push_back(inv);
|
vInv.push_back(inv);
|
||||||
|
@ -7507,9 +7503,12 @@ bool SendMessages(const Consensus::Params& params, CNode* pto)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Not in the mempool anymore? don't bother sending it.
|
// Not in the mempool anymore? don't bother sending it.
|
||||||
CTransaction tx;
|
auto txinfo = mempool.info(hash);
|
||||||
if (!mempool.lookup(hash, tx)) continue;
|
if (!txinfo.tx) {
|
||||||
if (pto->pfilter && !pto->pfilter->IsRelevantAndUpdate(tx)) continue;
|
continue;
|
||||||
|
}
|
||||||
|
if (IsExpiringSoonTx(*txinfo.tx, currentHeight + 1)) continue;
|
||||||
|
if (pto->pfilter && !pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
|
||||||
// Send
|
// Send
|
||||||
vInv.push_back(CInv(MSG_TX, hash));
|
vInv.push_back(CInv(MSG_TX, hash));
|
||||||
nRelayedTransactions++;
|
nRelayedTransactions++;
|
||||||
|
@ -7522,7 +7521,7 @@ bool SendMessages(const Consensus::Params& params, CNode* pto)
|
||||||
vRelayExpiration.pop_front();
|
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) {
|
if (ret.second) {
|
||||||
vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, hash));
|
vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, hash));
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,13 +32,13 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
|
||||||
int64_t _nTime, double _dPriority,
|
int64_t _nTime, double _dPriority,
|
||||||
unsigned int _nHeight, bool poolHasNoInputsOf,
|
unsigned int _nHeight, bool poolHasNoInputsOf,
|
||||||
bool _spendsCoinbase, unsigned int _sigOps, uint32_t _nBranchId):
|
bool _spendsCoinbase, unsigned int _sigOps, uint32_t _nBranchId):
|
||||||
tx(_tx), nFee(_nFee), nTime(_nTime), dPriority(_dPriority), nHeight(_nHeight),
|
tx(std::make_shared<CTransaction>(_tx)), nFee(_nFee), nTime(_nTime), dPriority(_dPriority), nHeight(_nHeight),
|
||||||
hadNoDependencies(poolHasNoInputsOf),
|
hadNoDependencies(poolHasNoInputsOf),
|
||||||
spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps), nBranchId(_nBranchId)
|
spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps), nBranchId(_nBranchId)
|
||||||
{
|
{
|
||||||
nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
|
nTxSize = ::GetSerializeSize(_tx, SER_NETWORK, PROTOCOL_VERSION);
|
||||||
nModSize = tx.CalculateModifiedSize(nTxSize);
|
nModSize = _tx.CalculateModifiedSize(nTxSize);
|
||||||
nUsageSize = RecursiveDynamicUsage(tx);
|
nUsageSize = RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(tx);
|
||||||
feeRate = CFeeRate(nFee, nTxSize);
|
feeRate = CFeeRate(nFee, nTxSize);
|
||||||
|
|
||||||
feeDelta = 0;
|
feeDelta = 0;
|
||||||
|
@ -52,7 +52,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
|
||||||
double
|
double
|
||||||
CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
|
CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
|
||||||
{
|
{
|
||||||
CAmount nValueIn = tx.GetValueOut()+nFee;
|
CAmount nValueIn = tx->GetValueOut()+nFee;
|
||||||
double deltaPriority = ((double)(currentHeight-nHeight)*nValueIn)/nModSize;
|
double deltaPriority = ((double)(currentHeight-nHeight)*nValueIn)/nModSize;
|
||||||
double dResult = dPriority + deltaPriority;
|
double dResult = dPriority + deltaPriority;
|
||||||
return dResult;
|
return dResult;
|
||||||
|
@ -692,40 +692,85 @@ bool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb
|
||||||
namespace {
|
namespace {
|
||||||
class DepthAndScoreComparator
|
class DepthAndScoreComparator
|
||||||
{
|
{
|
||||||
CTxMemPool *mp;
|
|
||||||
public:
|
public:
|
||||||
DepthAndScoreComparator(CTxMemPool *mempool) : mp(mempool) {}
|
bool operator()(const CTxMemPool::indexed_transaction_set::const_iterator& a, const CTxMemPool::indexed_transaction_set::const_iterator& b)
|
||||||
bool operator()(const uint256& a, const uint256& b) { return mp->CompareDepthAndScore(a, b); }
|
{
|
||||||
|
// Same logic applies here as to CTxMemPool::CompareDepthAndScore().
|
||||||
|
// As of https://github.com/bitcoin/bitcoin/pull/8126 this comparator
|
||||||
|
// duplicates that function (as it doesn't need to hold a dependency
|
||||||
|
// on the mempool).
|
||||||
|
return CompareTxMemPoolEntryByScore()(*a, *b);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(std::vector<uint256>& vtxid)
|
void CTxMemPool::queryHashes(std::vector<uint256>& vtxid)
|
||||||
{
|
{
|
||||||
vtxid.clear();
|
|
||||||
|
|
||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
vtxid.reserve(mapTx.size());
|
auto iters = GetSortedDepthAndScore();
|
||||||
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));
|
vtxid.clear();
|
||||||
|
vtxid.reserve(mapTx.size());
|
||||||
|
|
||||||
|
for (auto it : iters) {
|
||||||
|
vtxid.push_back(it->GetTx().GetHash());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<TxMempoolInfo> CTxMemPool::infoAll() const
|
||||||
|
{
|
||||||
|
LOCK(cs);
|
||||||
|
auto iters = GetSortedDepthAndScore();
|
||||||
|
|
||||||
bool CTxMemPool::lookup(uint256 hash, CTransaction& result, int64_t& time) const
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const CTransaction> CTxMemPool::get(const uint256& hash) const
|
||||||
{
|
{
|
||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
indexed_transaction_set::const_iterator i = mapTx.find(hash);
|
indexed_transaction_set::const_iterator i = mapTx.find(hash);
|
||||||
if (i == mapTx.end()) return false;
|
if (i == mapTx.end())
|
||||||
result = i->GetTx();
|
return nullptr;
|
||||||
time = i->GetTime();
|
return i->GetSharedTx();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
|
bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
|
||||||
{
|
{
|
||||||
int64_t time;
|
auto tx = get(hash);
|
||||||
return CTxMemPool::lookup(hash, result, time);
|
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
|
CFeeRate CTxMemPool::estimateFee(int nBlocks) const
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#define BITCOIN_TXMEMPOOL_H
|
#define BITCOIN_TXMEMPOOL_H
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "amount.h"
|
#include "amount.h"
|
||||||
#include "coins.h"
|
#include "coins.h"
|
||||||
|
@ -45,7 +46,7 @@ static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF;
|
||||||
class CTxMemPoolEntry
|
class CTxMemPoolEntry
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
CTransaction tx;
|
std::shared_ptr<const CTransaction> tx;
|
||||||
CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups
|
CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups
|
||||||
size_t nTxSize; //!< ... and avoid recomputing tx size
|
size_t nTxSize; //!< ... and avoid recomputing tx size
|
||||||
size_t nModSize; //!< ... and modified size for priority
|
size_t nModSize; //!< ... and modified size for priority
|
||||||
|
@ -68,7 +69,8 @@ public:
|
||||||
CTxMemPoolEntry();
|
CTxMemPoolEntry();
|
||||||
CTxMemPoolEntry(const CTxMemPoolEntry& other);
|
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; }
|
||||||
double GetPriority(unsigned int currentHeight) const;
|
double GetPriority(unsigned int currentHeight) const;
|
||||||
const CAmount& GetFee() const { return nFee; }
|
const CAmount& GetFee() const { return nFee; }
|
||||||
CFeeRate GetFeeRate() const { return feeRate; }
|
CFeeRate GetFeeRate() const { return feeRate; }
|
||||||
|
@ -152,6 +154,21 @@ public:
|
||||||
size_t DynamicMemoryUsage() const { return 0; }
|
size_t DynamicMemoryUsage() const { return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* CTxMemPool stores valid-according-to-the-current-best-chain
|
||||||
* transactions that may be included in the next block.
|
* transactions that may be included in the next block.
|
||||||
|
@ -224,6 +241,8 @@ private:
|
||||||
std::map<CSpentIndexKey, CSpentIndexValue, CSpentIndexKeyCompare> mapSpent;
|
std::map<CSpentIndexKey, CSpentIndexValue, CSpentIndexKeyCompare> mapSpent;
|
||||||
std::map<uint256, std::vector<CSpentIndexKey>> mapSpentInserted;
|
std::map<uint256, std::vector<CSpentIndexKey>> mapSpentInserted;
|
||||||
|
|
||||||
|
std::vector<indexed_transaction_set::const_iterator> GetSortedDepthAndScore() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::map<COutPoint, CInPoint> mapNextTx;
|
std::map<COutPoint, CInPoint> mapNextTx;
|
||||||
std::map<uint256, std::pair<double, CAmount> > mapDeltas;
|
std::map<uint256, std::pair<double, CAmount> > mapDeltas;
|
||||||
|
@ -309,7 +328,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lookup(uint256 hash, CTransaction& result) const;
|
bool lookup(uint256 hash, CTransaction& result) const;
|
||||||
bool lookup(uint256 hash, CTransaction& result, int64_t& time) 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 */
|
/** Estimate fee rate needed to get into the next nBlocks */
|
||||||
CFeeRate estimateFee(int nBlocks) const;
|
CFeeRate estimateFee(int nBlocks) const;
|
||||||
|
|
Loading…
Reference in New Issue