@@ -444,6 +444,8 @@ class PeerManagerImpl final : public PeerManager
444
444
*/
445
445
std::map<NodeId, PeerRef> m_peer_map GUARDED_BY (m_peer_mutex);
446
446
447
+ std::atomic<std::chrono::microseconds> m_next_send_inv_to_incoming{0us};
448
+
447
449
/* * Number of nodes with fSyncStarted. */
448
450
int nSyncStarted GUARDED_BY (cs_main) = 0;
449
451
@@ -518,6 +520,15 @@ class PeerManagerImpl final : public PeerManager
518
520
Mutex m_recent_confirmed_transactions_mutex;
519
521
CRollingBloomFilter m_recent_confirmed_transactions GUARDED_BY (m_recent_confirmed_transactions_mutex){48'000 , 0.000'001 };
520
522
523
+ /* *
524
+ * For sending `inv`s to inbound peers, we use a single (exponentially
525
+ * distributed) timer for all peers. If we used a separate timer for each
526
+ * peer, a spy node could make multiple inbound connections to us to
527
+ * accurately determine when we received the transaction (and potentially
528
+ * determine the transaction's origin). */
529
+ std::chrono::microseconds PoissonNextSendInbound (std::chrono::microseconds now,
530
+ std::chrono::seconds average_interval);
531
+
521
532
/* * Have we requested this block from a peer */
522
533
bool IsBlockRequested (const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
523
534
@@ -819,6 +830,18 @@ static void UpdatePreferredDownload(const CNode& node, CNodeState* state) EXCLUS
819
830
nPreferredDownload += state->fPreferredDownload ;
820
831
}
821
832
833
+ std::chrono::microseconds PeerManagerImpl::PoissonNextSendInbound (std::chrono::microseconds now,
834
+ std::chrono::seconds average_interval)
835
+ {
836
+ if (m_next_send_inv_to_incoming.load () < now) {
837
+ // If this function were called from multiple threads simultaneously
838
+ // it would possible that both update the next send variable, and return a different result to their caller.
839
+ // This is not possible in practice as only the net processing thread invokes this function.
840
+ m_next_send_inv_to_incoming = GetExponentialRand (now, average_interval);
841
+ }
842
+ return m_next_send_inv_to_incoming;
843
+ }
844
+
822
845
bool PeerManagerImpl::IsBlockRequested (const uint256& hash)
823
846
{
824
847
return mapBlocksInFlight.find (hash) != mapBlocksInFlight.end ();
@@ -4786,7 +4809,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
4786
4809
if (pto->m_tx_relay ->nNextInvSend < current_time) {
4787
4810
fSendTrickle = true ;
4788
4811
if (pto->IsInboundConn ()) {
4789
- pto->m_tx_relay ->nNextInvSend = m_connman. PoissonNextSendInbound (current_time, INBOUND_INVENTORY_BROADCAST_INTERVAL);
4812
+ pto->m_tx_relay ->nNextInvSend = PoissonNextSendInbound (current_time, INBOUND_INVENTORY_BROADCAST_INTERVAL);
4790
4813
} else {
4791
4814
pto->m_tx_relay ->nNextInvSend = GetExponentialRand (current_time, OUTBOUND_INVENTORY_BROADCAST_INTERVAL);
4792
4815
}
0 commit comments