Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 1,403 Lines • ▼ Show 20 Lines | switch (inv.type) { | ||||
// Use pcoinsTip->HaveCoinInCache as a quick approximation to | // Use pcoinsTip->HaveCoinInCache as a quick approximation to | ||||
// exclude requesting or processing some txs which have already been | // exclude requesting or processing some txs which have already been | ||||
// included in a block. As this is best effort, we only check for | // included in a block. As this is best effort, we only check for | ||||
// output 0 and 1. This works well enough in practice and we get | // output 0 and 1. This works well enough in practice and we get | ||||
// diminishing returns with 2 onward. | // diminishing returns with 2 onward. | ||||
const TxId txid(inv.hash); | const TxId txid(inv.hash); | ||||
return recentRejects->contains(inv.hash) || | return recentRejects->contains(inv.hash) || | ||||
g_mempool.exists(inv.hash) || | g_mempool.exists(txid) || | ||||
pcoinsTip->HaveCoinInCache(COutPoint(txid, 0)) || | pcoinsTip->HaveCoinInCache(COutPoint(txid, 0)) || | ||||
pcoinsTip->HaveCoinInCache(COutPoint(txid, 1)); | pcoinsTip->HaveCoinInCache(COutPoint(txid, 1)); | ||||
} | } | ||||
case MSG_BLOCK: | case MSG_BLOCK: | ||||
return LookupBlockIndex(BlockHash(inv.hash)) != nullptr; | return LookupBlockIndex(BlockHash(inv.hash)) != nullptr; | ||||
} | } | ||||
// Don't know what it is, just say we already got one | // Don't know what it is, just say we already got one | ||||
return true; | return true; | ||||
▲ Show 20 Lines • Show All 248 Lines • ▼ Show 20 Lines | const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); | ||||
auto mi = mapRelay.find(inv.hash); | auto mi = mapRelay.find(inv.hash); | ||||
int nSendFlags = 0; | int nSendFlags = 0; | ||||
if (mi != mapRelay.end()) { | if (mi != mapRelay.end()) { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, | pfrom, | ||||
msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second)); | msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second)); | ||||
push = true; | push = true; | ||||
} else if (pfrom->timeLastMempoolReq) { | } else if (pfrom->timeLastMempoolReq) { | ||||
auto txinfo = g_mempool.info(inv.hash); | auto txinfo = g_mempool.info(TxId(inv.hash)); | ||||
// To protect privacy, do not answer getdata using the mempool | // To protect privacy, do not answer getdata using the mempool | ||||
// when that TX couldn't have been INVed in reply to a MEMPOOL | // when that TX couldn't have been INVed in reply to a MEMPOOL | ||||
// request. | // request. | ||||
if (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq) { | if (txinfo.tx && txinfo.nTime <= pfrom->timeLastMempoolReq) { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, | pfrom, | ||||
msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx)); | msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx)); | ||||
push = true; | push = true; | ||||
▲ Show 20 Lines • Show All 2,325 Lines • ▼ Show 20 Lines | |||||
namespace { | namespace { | ||||
class CompareInvMempoolOrder { | class CompareInvMempoolOrder { | ||||
CTxMemPool *mp; | CTxMemPool *mp; | ||||
public: | public: | ||||
explicit CompareInvMempoolOrder(CTxMemPool *_mempool) { mp = _mempool; } | explicit CompareInvMempoolOrder(CTxMemPool *_mempool) { mp = _mempool; } | ||||
bool operator()(std::set<uint256>::iterator a, | bool operator()(std::set<TxId>::iterator a, std::set<TxId>::iterator b) { | ||||
std::set<uint256>::iterator b) { | /** | ||||
/* As std::make_heap produces a max-heap, we want the entries with the | * As std::make_heap produces a max-heap, we want the entries with the | ||||
* fewest ancestors/highest fee to sort later. */ | * fewest ancestors/highest fee to sort later. | ||||
*/ | |||||
return mp->CompareDepthAndScore(*b, *a); | return mp->CompareDepthAndScore(*b, *a); | ||||
} | } | ||||
}; | }; | ||||
} // namespace | } // namespace | ||||
bool PeerLogicValidation::SendMessages(const Config &config, CNode *pto, | bool PeerLogicValidation::SendMessages(const Config &config, CNode *pto, | ||||
std::atomic<bool> &interruptMsgProc) { | std::atomic<bool> &interruptMsgProc) { | ||||
const Consensus::Params &consensusParams = | const Consensus::Params &consensusParams = | ||||
▲ Show 20 Lines • Show All 343 Lines • ▼ Show 20 Lines | std::vector<CInv> vInv; | ||||
{ | { | ||||
LOCK(pto->cs_feeFilter); | LOCK(pto->cs_feeFilter); | ||||
filterrate = pto->minFeeFilter; | filterrate = pto->minFeeFilter; | ||||
} | } | ||||
LOCK(pto->cs_filter); | LOCK(pto->cs_filter); | ||||
for (const auto &txinfo : vtxinfo) { | for (const auto &txinfo : vtxinfo) { | ||||
const uint256 &txid = txinfo.tx->GetId(); | const TxId &txid = txinfo.tx->GetId(); | ||||
CInv inv(MSG_TX, txid); | CInv inv(MSG_TX, txid); | ||||
pto->setInventoryTxToSend.erase(txid); | pto->setInventoryTxToSend.erase(txid); | ||||
if (filterrate != Amount::zero() && | if (filterrate != Amount::zero() && | ||||
txinfo.feeRate.GetFeePerK() < filterrate) { | txinfo.feeRate.GetFeePerK() < filterrate) { | ||||
continue; | continue; | ||||
} | } | ||||
if (pto->pfilter && | if (pto->pfilter && | ||||
!pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) { | !pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) { | ||||
continue; | continue; | ||||
} | } | ||||
pto->filterInventoryKnown.insert(txid); | pto->filterInventoryKnown.insert(txid); | ||||
vInv.push_back(inv); | vInv.push_back(inv); | ||||
if (vInv.size() == MAX_INV_SZ) { | if (vInv.size() == MAX_INV_SZ) { | ||||
connman->PushMessage(pto, | connman->PushMessage(pto, | ||||
msgMaker.Make(NetMsgType::INV, vInv)); | msgMaker.Make(NetMsgType::INV, vInv)); | ||||
vInv.clear(); | vInv.clear(); | ||||
} | } | ||||
} | } | ||||
pto->timeLastMempoolReq = GetTime(); | pto->timeLastMempoolReq = GetTime(); | ||||
} | } | ||||
// Determine transactions to relay | // Determine transactions to relay | ||||
if (fSendTrickle) { | if (fSendTrickle) { | ||||
// Produce a vector with all candidates for sending | // Produce a vector with all candidates for sending | ||||
std::vector<std::set<uint256>::iterator> vInvTx; | std::vector<std::set<TxId>::iterator> vInvTx; | ||||
vInvTx.reserve(pto->setInventoryTxToSend.size()); | vInvTx.reserve(pto->setInventoryTxToSend.size()); | ||||
for (std::set<uint256>::iterator it = | for (std::set<TxId>::iterator it = | ||||
pto->setInventoryTxToSend.begin(); | pto->setInventoryTxToSend.begin(); | ||||
it != pto->setInventoryTxToSend.end(); it++) { | it != pto->setInventoryTxToSend.end(); it++) { | ||||
vInvTx.push_back(it); | vInvTx.push_back(it); | ||||
} | } | ||||
Amount filterrate = Amount::zero(); | Amount filterrate = Amount::zero(); | ||||
{ | { | ||||
LOCK(pto->cs_feeFilter); | LOCK(pto->cs_feeFilter); | ||||
filterrate = pto->minFeeFilter; | filterrate = pto->minFeeFilter; | ||||
Show All 11 Lines | std::vector<CInv> vInv; | ||||
LOCK(pto->cs_filter); | LOCK(pto->cs_filter); | ||||
while (!vInvTx.empty() && | while (!vInvTx.empty() && | ||||
nRelayedTransactions < INVENTORY_BROADCAST_MAX_PER_MB * | nRelayedTransactions < INVENTORY_BROADCAST_MAX_PER_MB * | ||||
config.GetMaxBlockSize() / | config.GetMaxBlockSize() / | ||||
1000000) { | 1000000) { | ||||
// Fetch the top element from the heap | // Fetch the top element from the heap | ||||
std::pop_heap(vInvTx.begin(), vInvTx.end(), | std::pop_heap(vInvTx.begin(), vInvTx.end(), | ||||
compareInvMempoolOrder); | compareInvMempoolOrder); | ||||
std::set<uint256>::iterator it = vInvTx.back(); | std::set<TxId>::iterator it = vInvTx.back(); | ||||
vInvTx.pop_back(); | vInvTx.pop_back(); | ||||
uint256 hash = *it; | TxId txid = *it; | ||||
// Remove it from the to-be-sent set | // Remove it from the to-be-sent set | ||||
pto->setInventoryTxToSend.erase(it); | pto->setInventoryTxToSend.erase(it); | ||||
// Check if not in the filter already | // Check if not in the filter already | ||||
if (pto->filterInventoryKnown.contains(hash)) { | if (pto->filterInventoryKnown.contains(txid)) { | ||||
continue; | continue; | ||||
} | } | ||||
// Not in the mempool anymore? don't bother sending it. | // Not in the mempool anymore? don't bother sending it. | ||||
auto txinfo = g_mempool.info(hash); | auto txinfo = g_mempool.info(txid); | ||||
if (!txinfo.tx) { | if (!txinfo.tx) { | ||||
continue; | continue; | ||||
} | } | ||||
if (filterrate != Amount::zero() && | if (filterrate != Amount::zero() && | ||||
txinfo.feeRate.GetFeePerK() < filterrate) { | txinfo.feeRate.GetFeePerK() < filterrate) { | ||||
continue; | continue; | ||||
} | } | ||||
if (pto->pfilter && | if (pto->pfilter && | ||||
!pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) { | !pto->pfilter->IsRelevantAndUpdate(*txinfo.tx)) { | ||||
continue; | continue; | ||||
} | } | ||||
// Send | // Send | ||||
vInv.push_back(CInv(MSG_TX, hash)); | vInv.push_back(CInv(MSG_TX, txid)); | ||||
nRelayedTransactions++; | nRelayedTransactions++; | ||||
{ | { | ||||
// Expire old relay messages | // Expire old relay messages | ||||
while (!vRelayExpiration.empty() && | while (!vRelayExpiration.empty() && | ||||
vRelayExpiration.front().first < nNow) { | vRelayExpiration.front().first < nNow) { | ||||
mapRelay.erase(vRelayExpiration.front().second); | mapRelay.erase(vRelayExpiration.front().second); | ||||
vRelayExpiration.pop_front(); | vRelayExpiration.pop_front(); | ||||
} | } | ||||
auto ret = mapRelay.insert( | auto ret = mapRelay.insert( | ||||
std::make_pair(hash, std::move(txinfo.tx))); | std::make_pair(txid, std::move(txinfo.tx))); | ||||
if (ret.second) { | if (ret.second) { | ||||
vRelayExpiration.push_back(std::make_pair( | vRelayExpiration.push_back(std::make_pair( | ||||
nNow + 15 * 60 * 1000000, ret.first)); | nNow + 15 * 60 * 1000000, ret.first)); | ||||
} | } | ||||
} | } | ||||
if (vInv.size() == MAX_INV_SZ) { | if (vInv.size() == MAX_INV_SZ) { | ||||
connman->PushMessage(pto, | connman->PushMessage(pto, | ||||
msgMaker.Make(NetMsgType::INV, vInv)); | msgMaker.Make(NetMsgType::INV, vInv)); | ||||
vInv.clear(); | vInv.clear(); | ||||
} | } | ||||
pto->filterInventoryKnown.insert(hash); | pto->filterInventoryKnown.insert(txid); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (!vInv.empty()) { | if (!vInv.empty()) { | ||||
connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); | connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); | ||||
} | } | ||||
// Detect whether we're stalling | // Detect whether we're stalling | ||||
▲ Show 20 Lines • Show All 237 Lines • Show Last 20 Lines |