Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 196 Lines • ▼ Show 20 Lines | |||||
static const std::chrono::seconds AVG_ADDRESS_BROADCAST_INTERVAL{30}; | static const std::chrono::seconds AVG_ADDRESS_BROADCAST_INTERVAL{30}; | ||||
/** | /** | ||||
* Average delay between trickled inventory transmissions in seconds. | * Average delay between trickled inventory transmissions in seconds. | ||||
* Blocks and whitelisted receivers bypass this, outbound peers get half this | * Blocks and whitelisted receivers bypass this, outbound peers get half this | ||||
* delay. | * delay. | ||||
*/ | */ | ||||
static const unsigned int INVENTORY_BROADCAST_INTERVAL = 5; | static const unsigned int INVENTORY_BROADCAST_INTERVAL = 5; | ||||
/** | /** | ||||
* Maximum number of inventory items to send per transmission. | * Maximum rate of inventory items to send per second. | ||||
* Limits the impact of low-fee transaction floods. | * Limits the impact of low-fee transaction floods. | ||||
*/ | */ | ||||
static constexpr unsigned int INVENTORY_BROADCAST_PER_SECOND = 7; | |||||
/** Maximum number of inventory items to send per transmission. */ | |||||
static constexpr unsigned int INVENTORY_BROADCAST_MAX_PER_MB = | static constexpr unsigned int INVENTORY_BROADCAST_MAX_PER_MB = | ||||
7 * INVENTORY_BROADCAST_INTERVAL; | INVENTORY_BROADCAST_PER_SECOND * INVENTORY_BROADCAST_INTERVAL; | ||||
/** The number of most recently announced transactions a peer can request. */ | |||||
static constexpr unsigned int INVENTORY_MAX_RECENT_RELAY = 3500; | |||||
/** | |||||
* Verify that INVENTORY_MAX_RECENT_RELAY is enough to cache everything | |||||
* typically relayed before unconditional relay from the mempool kicks in. This | |||||
* is only a lower bound, and it should be larger to account for higher inv rate | |||||
* to outbound peers, and random variations in the broadcast mechanism. | |||||
*/ | |||||
static_assert(INVENTORY_MAX_RECENT_RELAY >= INVENTORY_BROADCAST_PER_SECOND * | |||||
UNCONDITIONAL_RELAY_DELAY / | |||||
std::chrono::seconds{1}, | |||||
"INVENTORY_RELAY_MAX too low"); | |||||
/** | /** | ||||
* Average delay between feefilter broadcasts in seconds. | * Average delay between feefilter broadcasts in seconds. | ||||
*/ | */ | ||||
static constexpr unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60; | static constexpr unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60; | ||||
/** | /** | ||||
* Maximum feefilter broadcast delay after significant change. | * Maximum feefilter broadcast delay after significant change. | ||||
*/ | */ | ||||
static constexpr unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60; | static constexpr unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60; | ||||
▲ Show 20 Lines • Show All 285 Lines • ▼ Show 20 Lines | struct CNodeState { | ||||
AvalancheState m_avalanche_state; | AvalancheState m_avalanche_state; | ||||
//! Whether this peer is an inbound connection | //! Whether this peer is an inbound connection | ||||
bool m_is_inbound; | bool m_is_inbound; | ||||
//! Whether this peer is a manual connection | //! Whether this peer is a manual connection | ||||
bool m_is_manual_connection; | bool m_is_manual_connection; | ||||
//! A rolling bloom filter of all announced tx CInvs to this peer. | |||||
CRollingBloomFilter m_recently_announced_invs = | |||||
CRollingBloomFilter{INVENTORY_MAX_RECENT_RELAY, 0.000001}; | |||||
CNodeState(CAddress addrIn, bool is_inbound, bool is_manual) | CNodeState(CAddress addrIn, bool is_inbound, bool is_manual) | ||||
: address(addrIn), m_is_inbound(is_inbound), | : address(addrIn), m_is_inbound(is_inbound), | ||||
m_is_manual_connection(is_manual) { | m_is_manual_connection(is_manual) { | ||||
fCurrentlyConnected = false; | fCurrentlyConnected = false; | ||||
pindexBestKnownBlock = nullptr; | pindexBestKnownBlock = nullptr; | ||||
hashLastUnknownBlock = BlockHash(); | hashLastUnknownBlock = BlockHash(); | ||||
pindexLastCommonBlock = nullptr; | pindexLastCommonBlock = nullptr; | ||||
pindexBestHeaderSent = nullptr; | pindexBestHeaderSent = nullptr; | ||||
nUnconnectingHeaders = 0; | nUnconnectingHeaders = 0; | ||||
fSyncStarted = false; | fSyncStarted = false; | ||||
nHeadersSyncTimeout = 0; | nHeadersSyncTimeout = 0; | ||||
nStallingSince = 0; | nStallingSince = 0; | ||||
nDownloadingSince = 0; | nDownloadingSince = 0; | ||||
nBlocksInFlight = 0; | nBlocksInFlight = 0; | ||||
nBlocksInFlightValidHeaders = 0; | nBlocksInFlightValidHeaders = 0; | ||||
fPreferredDownload = false; | fPreferredDownload = false; | ||||
fPreferHeaders = false; | fPreferHeaders = false; | ||||
fPreferHeaderAndIDs = false; | fPreferHeaderAndIDs = false; | ||||
fProvidesHeaderAndIDs = false; | fProvidesHeaderAndIDs = false; | ||||
fSupportsDesiredCmpctVersion = false; | fSupportsDesiredCmpctVersion = false; | ||||
m_chain_sync = {0, nullptr, false, false}; | m_chain_sync = {0, nullptr, false, false}; | ||||
m_last_block_announcement = 0; | m_last_block_announcement = 0; | ||||
m_recently_announced_invs.reset(); | |||||
} | } | ||||
}; | }; | ||||
// Keeps track of the time (in microseconds) when transactions were requested | // Keeps track of the time (in microseconds) when transactions were requested | ||||
// last time | // last time | ||||
limitedmap<TxId, std::chrono::microseconds> | limitedmap<TxId, std::chrono::microseconds> | ||||
g_already_asked_for GUARDED_BY(cs_main)(MAX_INV_SZ); | g_already_asked_for GUARDED_BY(cs_main)(MAX_INV_SZ); | ||||
▲ Show 20 Lines • Show All 1,450 Lines • ▼ Show 20 Lines | // 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 | // If a TX could have been INVed in reply to a MEMPOOL request, | ||||
// that TX couldn't have been INVed in reply to a MEMPOOL request, | // or is older than UNCONDITIONAL_RELAY_DELAY, permit the request | ||||
// and it's more recent than UNCONDITIONAL_RELAY_DELAY. | // unconditionally. | ||||
if ((mempool_req.count() && txinfo.m_time <= mempool_req) || | if ((mempool_req.count() && txinfo.m_time <= mempool_req) || | ||||
txinfo.m_time <= now - UNCONDITIONAL_RELAY_DELAY) { | txinfo.m_time <= now - UNCONDITIONAL_RELAY_DELAY) { | ||||
return txinfo.tx; | return std::move(txinfo.tx); | ||||
} | } | ||||
} | } | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
// Look up transaction in relay pool | |||||
// Otherwise, the transaction must have been announced recently. | |||||
if (State(peer.GetId())->m_recently_announced_invs.contains(txid)) { | |||||
// If it was, it can be relayed from either the mempool... | |||||
if (txinfo.tx) { | |||||
return std::move(txinfo.tx); | |||||
} | |||||
// ... or the relay pool. | |||||
auto mi = mapRelay.find(txid); | auto mi = mapRelay.find(txid); | ||||
if (mi != mapRelay.end()) { | if (mi != mapRelay.end()) { | ||||
return mi->second; | return mi->second; | ||||
} | } | ||||
} | } | ||||
} | |||||
return {}; | return {}; | ||||
} | } | ||||
static void ProcessGetData(const Config &config, CNode &pfrom, | static void ProcessGetData(const Config &config, CNode &pfrom, | ||||
CConnman &connman, CTxMemPool &mempool, | CConnman &connman, CTxMemPool &mempool, | ||||
const std::atomic<bool> &interruptMsgProc) | const std::atomic<bool> &interruptMsgProc) | ||||
LOCKS_EXCLUDED(cs_main) { | LOCKS_EXCLUDED(cs_main) { | ||||
▲ Show 20 Lines • Show All 3,192 Lines • ▼ Show 20 Lines | if (pingSend) { | ||||
continue; | continue; | ||||
} | } | ||||
if (pto->m_tx_relay->pfilter && | if (pto->m_tx_relay->pfilter && | ||||
!pto->m_tx_relay->pfilter->IsRelevantAndUpdate( | !pto->m_tx_relay->pfilter->IsRelevantAndUpdate( | ||||
*txinfo.tx)) { | *txinfo.tx)) { | ||||
continue; | continue; | ||||
} | } | ||||
pto->m_tx_relay->filterInventoryKnown.insert(txid); | pto->m_tx_relay->filterInventoryKnown.insert(txid); | ||||
// Responses to MEMPOOL requests bypass the | |||||
// m_recently_announced_invs filter. | |||||
vInv.push_back(inv); | vInv.push_back(inv); | ||||
if (vInv.size() == MAX_INV_SZ) { | if (vInv.size() == MAX_INV_SZ) { | ||||
m_connman.PushMessage( | m_connman.PushMessage( | ||||
pto, msgMaker.Make(NetMsgType::INV, vInv)); | pto, msgMaker.Make(NetMsgType::INV, vInv)); | ||||
vInv.clear(); | vInv.clear(); | ||||
} | } | ||||
} | } | ||||
pto->m_tx_relay->m_last_mempool_req = | pto->m_tx_relay->m_last_mempool_req = | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | if (pingSend) { | ||||
continue; | continue; | ||||
} | } | ||||
if (pto->m_tx_relay->pfilter && | if (pto->m_tx_relay->pfilter && | ||||
!pto->m_tx_relay->pfilter->IsRelevantAndUpdate( | !pto->m_tx_relay->pfilter->IsRelevantAndUpdate( | ||||
*txinfo.tx)) { | *txinfo.tx)) { | ||||
continue; | continue; | ||||
} | } | ||||
// Send | // Send | ||||
State(pto->GetId()) | |||||
->m_recently_announced_invs.insert(txid); | |||||
vInv.push_back(CInv(MSG_TX, txid)); | 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(); | ||||
▲ Show 20 Lines • Show All 290 Lines • Show Last 20 Lines |