@@ -121,9 +121,18 @@ static constexpr std::chrono::seconds AVG_ADDRESS_BROADCAST_INTERVAL{30};
121121/* * Average delay between trickled inventory transmissions in seconds.
122122 * Blocks and whitelisted receivers bypass this, outbound peers get half this delay. */
123123static const unsigned int INVENTORY_BROADCAST_INTERVAL = 5 ;
124- /* * Maximum number of inventory items to send per transmission .
124+ /* * Maximum rate of inventory items to send per second .
125125 * Limits the impact of low-fee transaction floods. */
126- static constexpr unsigned int INVENTORY_BROADCAST_MAX = 7 * INVENTORY_BROADCAST_INTERVAL;
126+ static constexpr unsigned int INVENTORY_BROADCAST_PER_SECOND = 7 ;
127+ /* * Maximum number of inventory items to send per transmission. */
128+ static constexpr unsigned int INVENTORY_BROADCAST_MAX = INVENTORY_BROADCAST_PER_SECOND * INVENTORY_BROADCAST_INTERVAL;
129+ /* * The number of most recently announced transactions a peer can request. */
130+ static constexpr unsigned int INVENTORY_MAX_RECENT_RELAY = 3500 ;
131+ /* * Verify that INVENTORY_MAX_RECENT_RELAY is enough to cache everything typically
132+ * relayed before unconditional relay from the mempool kicks in. This is only a
133+ * lower bound, and it should be larger to account for higher inv rate to outbound
134+ * peers, and random variations in the broadcast mechanism. */
135+ static_assert (INVENTORY_MAX_RECENT_RELAY >= INVENTORY_BROADCAST_PER_SECOND * UNCONDITIONAL_RELAY_DELAY / std::chrono::seconds{1 }, " INVENTORY_RELAY_MAX too low" );
127136/* * Average delay between feefilter broadcasts in seconds. */
128137static constexpr unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60 ;
129138/* * Maximum feefilter broadcast delay after significant change. */
@@ -397,6 +406,9 @@ struct CNodeState {
397406 // ! Whether this peer is a manual connection
398407 bool m_is_manual_connection;
399408
409+ // ! A rolling bloom filter of all announced tx CInvs to this peer.
410+ CRollingBloomFilter m_recently_announced_invs = CRollingBloomFilter{INVENTORY_MAX_RECENT_RELAY, 0.000001 };
411+
400412 CNodeState (CAddress addrIn, std::string addrNameIn, bool is_inbound, bool is_manual) :
401413 address (addrIn), name(std::move(addrNameIn)), m_is_inbound(is_inbound),
402414 m_is_manual_connection (is_manual)
@@ -424,6 +436,7 @@ struct CNodeState {
424436 fSupportsDesiredCmpctVersion = false ;
425437 m_chain_sync = { 0 , nullptr , false , false };
426438 m_last_block_announcement = 0 ;
439+ m_recently_announced_invs.reset ();
427440 }
428441};
429442
@@ -1631,19 +1644,25 @@ CTransactionRef static FindTxForGetData(const CNode& peer, const uint256& txid,
16311644
16321645 auto txinfo = mempool.info (txid);
16331646 if (txinfo.tx ) {
1634- // To protect privacy, do not answer getdata using the mempool when
1635- // that TX couldn't have been INVed in reply to a MEMPOOL request,
1636- // and it's more recent than UNCONDITIONAL_RELAY_DELAY .
1647+ // If a TX could have been INVed in reply to a MEMPOOL request,
1648+ // or is older than UNCONDITIONAL_RELAY_DELAY, permit the request
1649+ // unconditionally .
16371650 if ((mempool_req.count () && txinfo.m_time <= mempool_req) || txinfo.m_time <= now - UNCONDITIONAL_RELAY_DELAY) {
1638- return txinfo.tx ;
1651+ return std::move ( txinfo.tx ) ;
16391652 }
16401653 }
16411654
16421655 {
16431656 LOCK (cs_main);
1644- // Look up transaction in relay pool
1645- auto mi = mapRelay.find (txid);
1646- if (mi != mapRelay.end ()) return mi->second ;
1657+
1658+ // Otherwise, the transaction must have been announced recently.
1659+ if (State (peer.GetId ())->m_recently_announced_invs .contains (txid)) {
1660+ // If it was, it can be relayed from either the mempool...
1661+ if (txinfo.tx ) return std::move (txinfo.tx );
1662+ // ... or the relay pool.
1663+ auto mi = mapRelay.find (txid);
1664+ if (mi != mapRelay.end ()) return mi->second ;
1665+ }
16471666 }
16481667
16491668 return {};
@@ -4155,6 +4174,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
41554174 if (!pto->m_tx_relay ->pfilter ->IsRelevantAndUpdate (*txinfo.tx )) continue ;
41564175 }
41574176 pto->m_tx_relay ->filterInventoryKnown .insert (hash);
4177+ // Responses to MEMPOOL requests bypass the m_recently_announced_invs filter.
41584178 vInv.push_back (inv);
41594179 if (vInv.size () == MAX_INV_SZ) {
41604180 connman->PushMessage (pto, msgMaker.Make (NetMsgType::INV, vInv));
@@ -4208,6 +4228,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
42084228 }
42094229 if (pto->m_tx_relay ->pfilter && !pto->m_tx_relay ->pfilter ->IsRelevantAndUpdate (*txinfo.tx )) continue ;
42104230 // Send
4231+ State (pto->GetId ())->m_recently_announced_invs .insert (hash);
42114232 vInv.push_back (CInv (MSG_TX, hash));
42124233 nRelayedTransactions++;
42134234 {
0 commit comments