@@ -121,9 +121,18 @@ static constexpr std::chrono::seconds AVG_ADDRESS_BROADCAST_INTERVAL{30};
121
121
/* * Average delay between trickled inventory transmissions in seconds.
122
122
* Blocks and whitelisted receivers bypass this, outbound peers get half this delay. */
123
123
static 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 .
125
125
* 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" );
127
136
/* * Average delay between feefilter broadcasts in seconds. */
128
137
static constexpr unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60 ;
129
138
/* * Maximum feefilter broadcast delay after significant change. */
@@ -397,6 +406,9 @@ struct CNodeState {
397
406
// ! Whether this peer is a manual connection
398
407
bool m_is_manual_connection;
399
408
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
+
400
412
CNodeState (CAddress addrIn, std::string addrNameIn, bool is_inbound, bool is_manual) :
401
413
address (addrIn), name(std::move(addrNameIn)), m_is_inbound(is_inbound),
402
414
m_is_manual_connection (is_manual)
@@ -424,6 +436,7 @@ struct CNodeState {
424
436
fSupportsDesiredCmpctVersion = false ;
425
437
m_chain_sync = { 0 , nullptr , false , false };
426
438
m_last_block_announcement = 0 ;
439
+ m_recently_announced_invs.reset ();
427
440
}
428
441
};
429
442
@@ -1631,19 +1644,25 @@ CTransactionRef static FindTxForGetData(const CNode& peer, const uint256& txid,
1631
1644
1632
1645
auto txinfo = mempool.info (txid);
1633
1646
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 .
1637
1650
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 ) ;
1639
1652
}
1640
1653
}
1641
1654
1642
1655
{
1643
1656
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
+ }
1647
1666
}
1648
1667
1649
1668
return {};
@@ -4155,6 +4174,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
4155
4174
if (!pto->m_tx_relay ->pfilter ->IsRelevantAndUpdate (*txinfo.tx )) continue ;
4156
4175
}
4157
4176
pto->m_tx_relay ->filterInventoryKnown .insert (hash);
4177
+ // Responses to MEMPOOL requests bypass the m_recently_announced_invs filter.
4158
4178
vInv.push_back (inv);
4159
4179
if (vInv.size () == MAX_INV_SZ) {
4160
4180
connman->PushMessage (pto, msgMaker.Make (NetMsgType::INV, vInv));
@@ -4208,6 +4228,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
4208
4228
}
4209
4229
if (pto->m_tx_relay ->pfilter && !pto->m_tx_relay ->pfilter ->IsRelevantAndUpdate (*txinfo.tx )) continue ;
4210
4230
// Send
4231
+ State (pto->GetId ())->m_recently_announced_invs .insert (hash);
4211
4232
vInv.push_back (CInv (MSG_TX, hash));
4212
4233
nRelayedTransactions++;
4213
4234
{
0 commit comments