@ -37,13 +37,13 @@
# include <typeinfo>
/** How long to cache transactions in mapRelay for normal relay */
static constexpr std : : chrono : : seconds RELAY_TX_CACHE_TIME = std : : chrono : : minutes { 15 } ;
static constexpr auto RELAY_TX_CACHE_TIME = 15 min ;
/** 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
static constexpr auto UNCONDITIONAL_RELAY_DELAY = 2 min ;
/** Headers download timeout .
* Timeout = base + per_header * ( expected number of headers ) */
static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_BASE = 15 * 60 * 1000000 ; // 15 minutes
static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1000 ; // 1ms/header
static constexpr auto HEADERS_DOWNLOAD_TIMEOUT_BASE = 15 min ;
static constexpr auto HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1 ms ;
/** Protect at least this many outbound peers from disconnection due to slow/
* behind headers chain .
*/
@ -90,8 +90,8 @@ static constexpr std::chrono::microseconds GETDATA_TX_INTERVAL{std::chrono::seco
static const unsigned int MAX_GETDATA_SZ = 1000 ;
/** Number of blocks that can be requested at any given time from a single peer. */
static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16 ;
/** Time out in seconds during which a peer must stall block download progress before being disconnected. */
static const unsigned int BLOCK_STALLING_TIMEOUT = 2 ;
/** Time during which a peer must stall block download progress before being disconnected. */
static const expr auto BLOCK_STALLING_TIMEOUT = 2 s ;
/** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends
* less than this number , we reached its tip . Changing this value is a protocol upgrade . */
static const unsigned int MAX_HEADERS_RESULTS = 2000 ;
@ -105,10 +105,10 @@ static const int MAX_BLOCKTXN_DEPTH = 10;
* degree of disordering of blocks on disk ( which make reindexing and pruning harder ) . We ' ll probably
* want to make this a per - peer adaptive value at some point . */
static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024 ;
/** Block download timeout base, expressed in m illionth s of the block interval (i.e. 10 min) */
static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 1 000000 ;
/** Block download timeout base, expressed in m ultiple s of the block interval (i.e. 10 min) */
static const expr double BLOCK_DOWNLOAD_TIMEOUT_BASE = 1 ;
/** Additional block download timeout per parallel downloading peer (i.e. 5 min) */
static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 500000 ;
static const expr double BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 0.5 ;
/** Maximum number of headers to announce when relaying blocks with headers message.*/
static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8 ;
/** Maximum number of unconnecting headers announcements before DoS score */
@ -116,17 +116,21 @@ static const int MAX_UNCONNECTING_HEADERS = 10;
/** Minimum blocks required to signal NODE_NETWORK_LIMITED */
static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288 ;
/** Average delay between local address broadcasts */
static constexpr std : : chrono : : hours AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL { 24 } ;
static constexpr auto AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24 h ;
/** Average delay between peer address broadcasts */
static constexpr std : : chrono : : seconds AVG_ADDRESS_BROADCAST_INTERVAL { 30 } ;
/** Average delay between trickled inventory transmissions in seconds.
* Blocks and peers with noban permission bypass this , outbound peers get half this delay . */
static const unsigned int INVENTORY_BROADCAST_INTERVAL = 5 ;
static constexpr auto AVG_ADDRESS_BROADCAST_INTERVAL = 30 s ;
/** Average delay between trickled inventory transmissions for inbound peers.
* Blocks and peers with noban permission bypass this . */
static constexpr auto INBOUND_INVENTORY_BROADCAST_INTERVAL = 5 s ;
/** Average delay between trickled inventory transmissions for outbound peers.
* Use a smaller delay as there is less privacy concern for them .
* Blocks and peers with noban permission bypass this . */
static constexpr auto OUTBOUND_INVENTORY_BROADCAST_INTERVAL = 2 s ;
/** Maximum rate of inventory items to send per second.
* 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 = INVENTORY_BROADCAST_PER_SECOND * INVENTORY_BROADCAST_INTERVAL;
static constexpr unsigned int INVENTORY_BROADCAST_MAX = INVENTORY_BROADCAST_PER_SECOND * count_seconds( INBOUND_ 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
@ -135,9 +139,9 @@ static constexpr unsigned int INVENTORY_MAX_RECENT_RELAY = 3500;
* 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. */
static constexpr unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60 ;
static constexpr auto AVG_FEEFILTER_BROADCAST_INTERVAL = 10 min ;
/** Maximum feefilter broadcast delay after significant change. */
static constexpr unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60 ;
static constexpr auto MAX_FEEFILTER_CHANGE_DELAY = 5 min ;
/** Maximum number of compact filters that may be requested with one getcfilters. See BIP 157. */
static constexpr uint32_t MAX_GETCFILTERS_SIZE = 1000 ;
/** Maximum number of cf hashes that may be requested with one getcfheaders. See BIP 157. */
@ -441,7 +445,7 @@ private:
typedef std : : map < uint256 , CTransactionRef > MapRelay ;
MapRelay mapRelay GUARDED_BY ( cs_main ) ;
/** Expiration-time ordered list of (expire time, relay map entry) pairs. */
std : : deque < std : : pair < int64_t , MapRelay : : iterator > > vRelayE xpiration GUARDED_BY ( cs_main ) ;
std : : deque < std : : pair < std : : chrono : : microseconds , MapRelay : : iterator > > g_relay_e xpiration GUARDED_BY ( cs_main ) ;
/**
* When a peer sends us a valid block , instruct it to announce blocks to us
@ -499,12 +503,12 @@ struct CNodeState {
//! Whether we've started headers synchronization with this peer.
bool fSyncStarted ;
//! When to potentially disconnect peer for stalling headers download
int64_t nHeadersSyncTimeout ;
std : : chrono : : microseconds m_headers_sync_timeout { 0u s } ;
//! Since when we're stalling block download progress (in microseconds), or 0.
int64_t nStallingSince ;
std : : chrono : : microseconds m_stalling_since { 0u s } ;
std : : list < QueuedBlock > vBlocksInFlight ;
//! When the first entry in vBlocksInFlight started downloading. Don't care when vBlocksInFlight is empty.
int64_t nDownloadingSince ;
std : : chrono : : microseconds m_downloading_since { 0u s } ;
int nBlocksInFlight ;
int nBlocksInFlightValidHeaders ;
//! Whether we consider this a preferred download peer.
@ -587,9 +591,6 @@ struct CNodeState {
pindexBestHeaderSent = nullptr ;
nUnconnectingHeaders = 0 ;
fSyncStarted = false ;
nHeadersSyncTimeout = 0 ;
nStallingSince = 0 ;
nDownloadingSince = 0 ;
nBlocksInFlight = 0 ;
nBlocksInFlightValidHeaders = 0 ;
fPreferredDownload = false ;
@ -638,11 +639,11 @@ bool PeerManagerImpl::MarkBlockAsReceived(const uint256& hash)
}
if ( state - > vBlocksInFlight . begin ( ) = = itInFlight - > second . second ) {
// First block on the queue was received, update the start download time for the next one
state - > nDownloadingS ince = std : : max ( state - > nDownloadingSince, count_microseconds ( GetTime < std : : chrono : : microseconds > ( ) ) ) ;
state - > m_downloading_s ince = std : : max ( state - > m_downloading_since, GetTime < std : : chrono : : microseconds > ( ) ) ;
}
state - > vBlocksInFlight . erase ( itInFlight - > second . second ) ;
state - > nBlocksInFlight - - ;
state - > nStallingSince = 0 ;
state - > m_stalling_since = 0u s ;
mapBlocksInFlight . erase ( itInFlight ) ;
return true ;
}
@ -672,7 +673,7 @@ bool PeerManagerImpl::MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, co
state - > nBlocksInFlightValidHeaders + = it - > fValidatedHeaders ;
if ( state - > nBlocksInFlight = = 1 ) {
// We're starting a block download (batch) from this peer.
state - > nDownloadingS ince = GetTime < std : : chrono : : microseconds > ( ) . count ( ) ;
state - > m_downloading_s ince = GetTime < std : : chrono : : microseconds > ( ) ;
}
if ( state - > nBlocksInFlightValidHeaders = = 1 & & pindex ! = nullptr ) {
nPeersWithValidatedDownloads + + ;
@ -1078,7 +1079,7 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats)
ping_wait = GetTime < std : : chrono : : microseconds > ( ) - peer - > m_ping_start . load ( ) ;
}
stats . m_ping_wait _usec = count_microseconds( ping_wait) ;
stats . m_ping_wait = ping_wait;
return true ;
}
@ -4279,7 +4280,13 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// Only actively request headers from a single peer, unless we're close to today.
if ( ( nSyncStarted = = 0 & & fFetch ) | | pindexBestHeader - > GetBlockTime ( ) > GetAdjustedTime ( ) - 24 * 60 * 60 ) {
state . fSyncStarted = true ;
state . nHeadersSyncTimeout = count_microseconds ( current_time ) + HEADERS_DOWNLOAD_TIMEOUT_BASE + HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER * ( GetAdjustedTime ( ) - pindexBestHeader - > GetBlockTime ( ) ) / ( consensusParams . nPowTargetSpacing ) ;
state . m_headers_sync_timeout = current_time + HEADERS_DOWNLOAD_TIMEOUT_BASE +
(
// Convert HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER to microseconds before scaling
// to maintain precision
std : : chrono : : microseconds { HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER } *
( GetAdjustedTime ( ) - pindexBestHeader - > GetBlockTime ( ) ) / consensusParams . nPowTargetSpacing
) ;
nSyncStarted + + ;
const CBlockIndex * pindexStart = pindexBestHeader ;
/* If possible, start at the block preceding the currently
@ -4460,10 +4467,9 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
if ( pto - > m_tx_relay - > nNextInvSend < current_time ) {
fSendTrickle = true ;
if ( pto - > IsInboundConn ( ) ) {
pto - > m_tx_relay - > nNextInvSend = std: : chrono : : microseconds { m_connman. PoissonNextSendInbound ( c ount_microseconds( c urrent_time) , INVENTORY_BROADCAST_INTERVAL) } ;
pto - > m_tx_relay - > nNextInvSend = m_connman. PoissonNextSendInbound ( c urrent_time, INBOUND_ INVENTORY_BROADCAST_INTERVAL) ;
} else {
// Use half the delay for outbound peers, as there is less privacy concern for them.
pto - > m_tx_relay - > nNextInvSend = PoissonNextSend ( current_time , std : : chrono : : seconds { INVENTORY_BROADCAST_INTERVAL > > 1 } ) ;
pto - > m_tx_relay - > nNextInvSend = PoissonNextSend ( current_time , OUTBOUND_INVENTORY_BROADCAST_INTERVAL ) ;
}
}
@ -4551,20 +4557,20 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
nRelayedTransactions + + ;
{
// Expire old relay messages
while ( ! vRelayExpiration. empty ( ) & & vRelayE xpiration. front ( ) . first < c ount_microseconds( c urrent_time) )
while ( ! g_relay_expiration. empty ( ) & & g_relay_e xpiration. front ( ) . first < c urrent_time)
{
mapRelay . erase ( vRelayE xpiration. front ( ) . second ) ;
vRelayE xpiration. pop_front ( ) ;
mapRelay . erase ( g_relay_e xpiration. front ( ) . second ) ;
g_relay_e xpiration. pop_front ( ) ;
}
auto ret = mapRelay . emplace ( txid , std : : move ( txinfo . tx ) ) ;
if ( ret . second ) {
vRelayE xpiration. emplace_back ( c ount_microseconds( c urrent_time + std: : chrono : : microseconds { RELAY_TX_CACHE_TIME} ) , ret . first ) ;
g_relay_e xpiration. emplace_back ( c urrent_time + RELAY_TX_CACHE_TIME, ret . first ) ;
}
// Add wtxid-based lookup into mapRelay as well, so that peers can request by wtxid
auto ret2 = mapRelay . emplace ( wtxid , ret . first - > second ) ;
if ( ret2 . second ) {
vRelayE xpiration. emplace_back ( c ount_microseconds( c urrent_time + std: : chrono : : microseconds { RELAY_TX_CACHE_TIME} ) , ret2 . first ) ;
g_relay_e xpiration. emplace_back ( c urrent_time + RELAY_TX_CACHE_TIME, ret2 . first ) ;
}
}
if ( vInv . size ( ) = = MAX_INV_SZ ) {
@ -4589,7 +4595,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// Detect whether we're stalling
current_time = GetTime < std : : chrono : : microseconds > ( ) ;
if ( state . nStallingSince & & state . nStallingSince < count_microseconds ( current_time ) - 1000000 * BLOCK_STALLING_TIMEOUT ) {
if ( state . m_stalling_since. count ( ) & & state . m_stalling_since < current_time - BLOCK_STALLING_TIMEOUT ) {
// Stalling only triggers when the block download window cannot move. During normal steady state,
// the download window should be much larger than the to-be-downloaded set of blocks, so disconnection
// should only happen during initial block download.
@ -4597,7 +4603,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
pto - > fDisconnect = true ;
return true ;
}
// In case there is a block that has been in flight from this peer for 2 + 0.5 * N times the block interval
// In case there is a block that has been in flight from this peer for block_interval * (1 + 0.5 * N)
// (with N the number of peers from which we're downloading validated blocks), disconnect due to timeout.
// We compensate for other peers to prevent killing off peers due to our own downstream link
// being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes
@ -4605,17 +4611,17 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
if ( state . vBlocksInFlight . size ( ) > 0 ) {
QueuedBlock & queuedBlock = state . vBlocksInFlight . front ( ) ;
int nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - ( state . nBlocksInFlightValidHeaders > 0 ) ;
if ( c ount_microseconds( current_time ) > state . nDownloadingSince + consensusParams . nPowTargetSpacing * ( BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads ) ) {
if ( c urrent_time > state . m_downloading_since + std : : chrono : : seconds { consensusParams . nPowTargetSpacing } * ( BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads ) ) {
LogPrintf ( " Timeout downloading block %s from peer=%d, disconnecting \n " , queuedBlock . hash . ToString ( ) , pto - > GetId ( ) ) ;
pto - > fDisconnect = true ;
return true ;
}
}
// Check for headers sync timeouts
if ( state . fSyncStarted & & state . nHeadersSyncTimeout < std : : numeric_limits < int64_t > : : max ( ) ) {
if ( state . fSyncStarted & & state . m_headers_sync_timeout < std : : chrono : : microseconds : : max ( ) ) {
// Detect whether this is a stalling initial-headers-sync peer
if ( pindexBestHeader - > GetBlockTime ( ) < = GetAdjustedTime ( ) - 24 * 60 * 60 ) {
if ( c ount_microseconds( current_time ) > state . nHeadersSyncT imeout & & nSyncStarted = = 1 & & ( nPreferredDownload - state . fPreferredDownload > = 1 ) ) {
if ( c urrent_time > state . m_headers_sync_t imeout & & nSyncStarted = = 1 & & ( nPreferredDownload - state . fPreferredDownload > = 1 ) ) {
// Disconnect a peer (without the noban permission) if it is our only sync peer,
// and we have others we could be using instead.
// Note: If all our peers are inbound, then we won't
@ -4634,13 +4640,13 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// this peer (eventually).
state . fSyncStarted = false ;
nSyncStarted - - ;
state . nHeadersSyncTimeout = 0 ;
state . m_headers_sync_timeout = 0u s ;
}
}
} else {
// After we've caught up once, reset the timeout so we can't trigger
// disconnect later.
state . nHeadersSyncTimeout = std : : numeric_limits < int64_t > : : max ( ) ;
state . m_headers_sync_timeout = std : : chrono : : microseconds : : max ( ) ;
}
}
@ -4664,8 +4670,8 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
pindex - > nHeight , pto - > GetId ( ) ) ;
}
if ( state . nBlocksInFlight = = 0 & & staller ! = - 1 ) {
if ( State ( staller ) - > nStallingSince = = 0 ) {
State ( staller ) - > nStallingSince = count_microseconds ( current_time ) ;
if ( State ( staller ) - > m_stalling_since = = 0u s ) {
State ( staller ) - > m_stalling_since = current_time ;
LogPrint ( BCLog : : NET , " Stall started peer=%d \n " , staller ) ;
}
}
@ -4718,10 +4724,10 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
if ( pto - > m_tx_relay - > lastSentFeeFilter = = MAX_FILTER ) {
// Send the current filter if we sent MAX_FILTER previously
// and made it out of IBD.
pto - > m_tx_relay - > nextSendTimeFeeFilter = count_microseconds ( current_time ) - 1 ;
pto - > m_tx_relay - > m_next_send_feefilter = 0u s ;
}
}
if ( c ount_microseconds( c urrent_time) > pto - > m_tx_relay - > nextSendTimeFeeF ilter) {
if ( c urrent_time > pto - > m_tx_relay - > m_next_send_feef ilter) {
CAmount filterToSend = g_filter_rounder . round ( currentFilter ) ;
// We always have a fee filter of at least minRelayTxFee
filterToSend = std : : max ( filterToSend , : : minRelayTxFee . GetFeePerK ( ) ) ;
@ -4729,13 +4735,13 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
m_connman . PushMessage ( pto , msgMaker . Make ( NetMsgType : : FEEFILTER , filterToSend ) ) ;
pto - > m_tx_relay - > lastSentFeeFilter = filterToSend ;
}
pto - > m_tx_relay - > nextSendTimeFeeF ilter = PoissonNextSend ( c ount_microseconds( c urrent_time) , AVG_FEEFILTER_BROADCAST_INTERVAL ) ;
pto - > m_tx_relay - > m_next_send_feef ilter = PoissonNextSend ( c urrent_time, AVG_FEEFILTER_BROADCAST_INTERVAL ) ;
}
// If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY
// until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY.
else if ( c ount_microseconds( c urrent_time) + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto - > m_tx_relay - > nextSendTimeFeeF ilter & &
else if ( c urrent_time + MAX_FEEFILTER_CHANGE_DELAY < pto - > m_tx_relay - > m_next_send_feef ilter & &
( currentFilter < 3 * pto - > m_tx_relay - > lastSentFeeFilter / 4 | | currentFilter > 4 * pto - > m_tx_relay - > lastSentFeeFilter / 3 ) ) {
pto - > m_tx_relay - > nextSendTimeFeeFilter = count_microseconds ( current_time ) + GetRandInt ( MAX_FEEFILTER_CHANGE_DELAY ) * 1000000 ;
pto - > m_tx_relay - > m_next_send_feefilter = current_time + GetRandomDuration < std : : chrono : : microseconds > ( MAX_FEEFILTER_CHANGE_DELAY ) ;
}
}
} // release cs_main