Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show All 40 Lines | |||||
#include <memory> | #include <memory> | ||||
#include <typeinfo> | #include <typeinfo> | ||||
/** Expiration time for orphan transactions in seconds */ | /** Expiration time for orphan transactions in seconds */ | ||||
static constexpr int64_t ORPHAN_TX_EXPIRE_TIME = 20 * 60; | static constexpr int64_t ORPHAN_TX_EXPIRE_TIME = 20 * 60; | ||||
/** Minimum time between orphan transactions expire time checks in seconds */ | /** Minimum time between orphan transactions expire time checks in seconds */ | ||||
static constexpr int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60; | static constexpr int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60; | ||||
/** How long to cache transactions in mapRelay for normal relay */ | /** How long to cache transactions in mapRelay for normal relay */ | ||||
static constexpr std::chrono::seconds RELAY_TX_CACHE_TIME{15 * 60}; | static constexpr std::chrono::seconds RELAY_TX_CACHE_TIME = | ||||
std::chrono::minutes{15}; | |||||
/** How long a transaction has to be in the mempool before it can | |||||
* unconditionally be relayed (even when not in mapRelay). */ | |||||
static constexpr std::chrono::seconds UNCONDITIONAL_RELAY_DELAY = | |||||
std::chrono::minutes{2}; | |||||
/** | /** | ||||
* Headers download timeout expressed in microseconds. | * Headers download timeout expressed in microseconds. | ||||
* Timeout = base + per_header * (expected number of headers) | * Timeout = base + per_header * (expected number of headers) | ||||
*/ | */ | ||||
// 15 minutes | // 15 minutes | ||||
static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_BASE = 15 * 60 * 1000000; | static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_BASE = 15 * 60 * 1000000; | ||||
// 1ms/header | // 1ms/header | ||||
static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1000; | static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1000; | ||||
▲ Show 20 Lines • Show All 1,913 Lines • ▼ Show 20 Lines | if (send && pindex->nStatus.hasData()) { | ||||
connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::INV, vInv)); | connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::INV, vInv)); | ||||
pfrom.hashContinue = BlockHash(); | pfrom.hashContinue = BlockHash(); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
//! Determine whether or not a peer can request a transaction, and return it (or | //! Determine whether or not a peer can request a transaction, and return it (or | ||||
//! nullptr if not found or not allowed). | //! nullptr if not found or not allowed). | ||||
CTransactionRef static FindTxForGetData( | CTransactionRef static FindTxForGetData(const CNode &peer, const TxId &txid, | ||||
const CNode &peer, const TxId &txid, const std::chrono::seconds mempool_req, | const std::chrono::seconds mempool_req, | ||||
const std::chrono::seconds longlived_mempool_time) LOCKS_EXCLUDED(cs_main) { | const std::chrono::seconds now) | ||||
LOCKS_EXCLUDED(cs_main) { | |||||
// Check if the requested transaction is so recent that we're just | // Check if the requested transaction is so recent that we're just | ||||
// about to announce it to the peer; if so, they certainly shouldn't | // about to announce it to the peer; if so, they certainly shouldn't | ||||
// know we already have it. | // know we already have it. | ||||
{ | { | ||||
LOCK(peer.m_tx_relay->cs_tx_inventory); | LOCK(peer.m_tx_relay->cs_tx_inventory); | ||||
if (peer.m_tx_relay->setInventoryTxToSend.count(txid)) { | if (peer.m_tx_relay->setInventoryTxToSend.count(txid)) { | ||||
return {}; | return {}; | ||||
} | } | ||||
} | } | ||||
auto txinfo = g_mempool.info(txid); | auto txinfo = g_mempool.info(txid); | ||||
if (txinfo.tx) { | if (txinfo.tx) { | ||||
// 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, | ||||
// or when it's too recent to have expired from mapRelay. | // and it's more recent than UNCONDITIONAL_RELAY_DELAY. | ||||
if ((mempool_req.count() && txinfo.m_time <= mempool_req) || | if ((mempool_req.count() && txinfo.m_time <= mempool_req) || | ||||
txinfo.m_time <= longlived_mempool_time) { | txinfo.m_time <= now - UNCONDITIONAL_RELAY_DELAY) { | ||||
return txinfo.tx; | return txinfo.tx; | ||||
} | } | ||||
} | } | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
// Look up transaction in relay pool | // Look up transaction in relay pool | ||||
auto mi = mapRelay.find(txid); | auto mi = mapRelay.find(txid); | ||||
Show All 10 Lines | static void ProcessGetData(const Config &config, CNode &pfrom, | ||||
const std::atomic<bool> &interruptMsgProc) | const std::atomic<bool> &interruptMsgProc) | ||||
LOCKS_EXCLUDED(cs_main) { | LOCKS_EXCLUDED(cs_main) { | ||||
AssertLockNotHeld(cs_main); | AssertLockNotHeld(cs_main); | ||||
std::deque<CInv>::iterator it = pfrom.vRecvGetData.begin(); | std::deque<CInv>::iterator it = pfrom.vRecvGetData.begin(); | ||||
std::vector<CInv> vNotFound; | std::vector<CInv> vNotFound; | ||||
const CNetMsgMaker msgMaker(pfrom.GetCommonVersion()); | const CNetMsgMaker msgMaker(pfrom.GetCommonVersion()); | ||||
// mempool entries added before this time have likely expired from mapRelay | const std::chrono::seconds now = GetTime<std::chrono::seconds>(); | ||||
const std::chrono::seconds longlived_mempool_time = | |||||
GetTime<std::chrono::seconds>() - RELAY_TX_CACHE_TIME; | |||||
// Get last mempool request time | // Get last mempool request time | ||||
const std::chrono::seconds mempool_req = | const std::chrono::seconds mempool_req = | ||||
pfrom.m_tx_relay != nullptr | pfrom.m_tx_relay != nullptr | ||||
? pfrom.m_tx_relay->m_last_mempool_req.load() | ? pfrom.m_tx_relay->m_last_mempool_req.load() | ||||
: std::chrono::seconds::min(); | : std::chrono::seconds::min(); | ||||
// Process as many TX items from the front of the getdata queue as | // Process as many TX items from the front of the getdata queue as | ||||
// possible, since they're common and it's efficient to batch process | // possible, since they're common and it's efficient to batch process | ||||
Show All 11 Lines | while (it != pfrom.vRecvGetData.end() && it->type == MSG_TX) { | ||||
const CInv &inv = *it++; | const CInv &inv = *it++; | ||||
if (pfrom.m_tx_relay == nullptr) { | if (pfrom.m_tx_relay == nullptr) { | ||||
// Ignore GETDATA requests for transactions from blocks-only | // Ignore GETDATA requests for transactions from blocks-only | ||||
// peers. | // peers. | ||||
continue; | continue; | ||||
} | } | ||||
CTransactionRef tx = FindTxForGetData( | CTransactionRef tx = | ||||
pfrom, TxId{inv.hash}, mempool_req, longlived_mempool_time); | FindTxForGetData(pfrom, TxId{inv.hash}, mempool_req, now); | ||||
if (tx) { | if (tx) { | ||||
int nSendFlags = 0; | int nSendFlags = 0; | ||||
connman.PushMessage(&pfrom, | connman.PushMessage(&pfrom, | ||||
msgMaker.Make(nSendFlags, NetMsgType::TX, *tx)); | msgMaker.Make(nSendFlags, NetMsgType::TX, *tx)); | ||||
mempool.RemoveUnbroadcastTx(TxId(inv.hash)); | mempool.RemoveUnbroadcastTx(TxId(inv.hash)); | ||||
} else { | } else { | ||||
vNotFound.push_back(inv); | vNotFound.push_back(inv); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 3,527 Lines • Show Last 20 Lines |