Skip to content

Commit 6ec1809

Browse files
committed
net_processing: drop m_recently_announced_invs bloom filter
Rather than using a bloom filter to track announced invs, simply allow a peer to request any tx that entered the mempool prior to the last INV message we sent them. This also obsoletes the UNCONDITIONAL_RELAY_DELAY.
1 parent a70beaf commit 6ec1809

File tree

3 files changed

+30
-59
lines changed

3 files changed

+30
-59
lines changed

src/net_processing.cpp

Lines changed: 15 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@
5151
#include <optional>
5252
#include <typeinfo>
5353

54-
/** How long a transaction has to be in the mempool before it can unconditionally be relayed. */
55-
static constexpr auto UNCONDITIONAL_RELAY_DELAY = 2min;
5654
/** Headers download timeout.
5755
* Timeout = base + per_header * (expected number of headers) */
5856
static constexpr auto HEADERS_DOWNLOAD_TIMEOUT_BASE = 15min;
@@ -151,13 +149,6 @@ static constexpr auto OUTBOUND_INVENTORY_BROADCAST_INTERVAL{2s};
151149
static constexpr unsigned int INVENTORY_BROADCAST_PER_SECOND = 7;
152150
/** Maximum number of inventory items to send per transmission. */
153151
static constexpr unsigned int INVENTORY_BROADCAST_MAX = INVENTORY_BROADCAST_PER_SECOND * count_seconds(INBOUND_INVENTORY_BROADCAST_INTERVAL);
154-
/** The number of most recently announced transactions a peer can request. */
155-
static constexpr unsigned int INVENTORY_MAX_RECENT_RELAY = 3500;
156-
/** Verify that INVENTORY_MAX_RECENT_RELAY is enough to cache everything typically
157-
* relayed before unconditional relay from the mempool kicks in. This is only a
158-
* lower bound, and it should be larger to account for higher inv rate to outbound
159-
* peers, and random variations in the broadcast mechanism. */
160-
static_assert(INVENTORY_MAX_RECENT_RELAY >= INVENTORY_BROADCAST_PER_SECOND * UNCONDITIONAL_RELAY_DELAY / std::chrono::seconds{1}, "INVENTORY_RELAY_MAX too low");
161152
/** Average delay between feefilter broadcasts in seconds. */
162153
static constexpr auto AVG_FEEFILTER_BROADCAST_INTERVAL{10min};
163154
/** Maximum feefilter broadcast delay after significant change. */
@@ -273,9 +264,6 @@ struct Peer {
273264
/** A bloom filter for which transactions to announce to the peer. See BIP37. */
274265
std::unique_ptr<CBloomFilter> m_bloom_filter PT_GUARDED_BY(m_bloom_filter_mutex) GUARDED_BY(m_bloom_filter_mutex){nullptr};
275266

276-
/** A rolling bloom filter of all announced tx CInvs to this peer */
277-
CRollingBloomFilter m_recently_announced_invs GUARDED_BY(NetEventsInterface::g_msgproc_mutex){INVENTORY_MAX_RECENT_RELAY, 0.000001};
278-
279267
mutable RecursiveMutex m_tx_inventory_mutex;
280268
/** A filter of all the txids and wtxids that the peer has announced to
281269
* us or we have announced to the peer. We use this to avoid announcing
@@ -290,11 +278,12 @@ struct Peer {
290278
* permitted if the peer has NetPermissionFlags::Mempool or we advertise
291279
* NODE_BLOOM. See BIP35. */
292280
bool m_send_mempool GUARDED_BY(m_tx_inventory_mutex){false};
293-
/** The last time a BIP35 `mempool` request was serviced. */
294-
std::atomic<std::chrono::seconds> m_last_mempool_req{0s};
295281
/** The next time after which we will send an `inv` message containing
296282
* transaction announcements to this peer. */
297283
std::chrono::microseconds m_next_inv_send_time GUARDED_BY(m_tx_inventory_mutex){0};
284+
/** The mempool sequence num at which we sent the last `inv` message to this peer.
285+
* Can relay txs with lower sequence numbers than this (see CTxMempool::info_for_relay). */
286+
uint64_t m_last_inv_sequence GUARDED_BY(NetEventsInterface::g_msgproc_mutex){1};
298287

299288
/** Minimum fee rate with which to filter transaction announcements to this node. See BIP133. */
300289
std::atomic<CAmount> m_fee_filter_received{0};
@@ -908,7 +897,7 @@ class PeerManagerImpl final : public PeerManager
908897
std::atomic<std::chrono::seconds> m_last_tip_update{0s};
909898

910899
/** Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed). */
911-
CTransactionRef FindTxForGetData(const Peer::TxRelay& tx_relay, const GenTxid& gtxid, const std::chrono::seconds mempool_req, const std::chrono::seconds now)
900+
CTransactionRef FindTxForGetData(const Peer::TxRelay& tx_relay, const GenTxid& gtxid)
912901
EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex, NetEventsInterface::g_msgproc_mutex);
913902

914903
void ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic<bool>& interruptMsgProc)
@@ -2290,22 +2279,14 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
22902279
}
22912280
}
22922281

2293-
CTransactionRef PeerManagerImpl::FindTxForGetData(const Peer::TxRelay& tx_relay, const GenTxid& gtxid, const std::chrono::seconds mempool_req, const std::chrono::seconds now)
2282+
CTransactionRef PeerManagerImpl::FindTxForGetData(const Peer::TxRelay& tx_relay, const GenTxid& gtxid)
22942283
{
2295-
auto txinfo = m_mempool.info(gtxid);
2284+
// If a tx was in the mempool prior to the last INV for this peer, permit the request.
2285+
auto txinfo = m_mempool.info_for_relay(gtxid, tx_relay.m_last_inv_sequence);
22962286
if (txinfo.tx) {
2297-
// If a TX could have been INVed in reply to a MEMPOOL request,
2298-
// or is older than UNCONDITIONAL_RELAY_DELAY, permit the request
2299-
// unconditionally.
2300-
if ((mempool_req.count() && txinfo.m_time <= mempool_req) || txinfo.m_time <= now - UNCONDITIONAL_RELAY_DELAY) {
2301-
return std::move(txinfo.tx);
2302-
}
2287+
return std::move(txinfo.tx);
23032288
}
23042289

2305-
// Otherwise, the transaction might have been announced recently.
2306-
bool recent = tx_relay.m_recently_announced_invs.contains(gtxid.GetHash());
2307-
if (recent && txinfo.tx) return std::move(txinfo.tx);
2308-
23092290
// Or it might be from the most recent block
23102291
{
23112292
LOCK(m_most_recent_block_mutex);
@@ -2328,10 +2309,6 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic
23282309
std::vector<CInv> vNotFound;
23292310
const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
23302311

2331-
const auto now{GetTime<std::chrono::seconds>()};
2332-
// Get last mempool request time
2333-
const auto mempool_req = tx_relay != nullptr ? tx_relay->m_last_mempool_req.load() : std::chrono::seconds::min();
2334-
23352312
// Process as many TX items from the front of the getdata queue as
23362313
// possible, since they're common and it's efficient to batch process
23372314
// them.
@@ -2349,33 +2326,12 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic
23492326
continue;
23502327
}
23512328

2352-
CTransactionRef tx = FindTxForGetData(*tx_relay, ToGenTxid(inv), mempool_req, now);
2329+
CTransactionRef tx = FindTxForGetData(*tx_relay, ToGenTxid(inv));
23532330
if (tx) {
23542331
// WTX and WITNESS_TX imply we serialize with witness
23552332
int nSendFlags = (inv.IsMsgTx() ? SERIALIZE_TRANSACTION_NO_WITNESS : 0);
23562333
m_connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *tx));
23572334
m_mempool.RemoveUnbroadcastTx(tx->GetHash());
2358-
// As we're going to send tx, make sure its unconfirmed parents are made requestable.
2359-
std::vector<uint256> parent_ids_to_add;
2360-
{
2361-
LOCK(m_mempool.cs);
2362-
auto tx_iter = m_mempool.GetIter(tx->GetHash());
2363-
if (tx_iter) {
2364-
const CTxMemPoolEntry::Parents& parents = (*tx_iter)->GetMemPoolParentsConst();
2365-
parent_ids_to_add.reserve(parents.size());
2366-
for (const CTxMemPoolEntry& parent : parents) {
2367-
if (parent.GetTime() > now - UNCONDITIONAL_RELAY_DELAY) {
2368-
parent_ids_to_add.push_back(parent.GetTx().GetHash());
2369-
}
2370-
}
2371-
}
2372-
}
2373-
for (const uint256& parent_txid : parent_ids_to_add) {
2374-
// Relaying a transaction with a recent but unconfirmed parent.
2375-
if (WITH_LOCK(tx_relay->m_tx_inventory_mutex, return !tx_relay->m_tx_inventory_known_filter.contains(parent_txid))) {
2376-
tx_relay->m_recently_announced_invs.insert(parent_txid);
2377-
}
2378-
}
23792335
} else {
23802336
vNotFound.push_back(inv);
23812337
}
@@ -5734,14 +5690,12 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
57345690
if (!tx_relay->m_bloom_filter->IsRelevantAndUpdate(*txinfo.tx)) continue;
57355691
}
57365692
tx_relay->m_tx_inventory_known_filter.insert(hash);
5737-
// Responses to MEMPOOL requests bypass the m_recently_announced_invs filter.
57385693
vInv.push_back(inv);
57395694
if (vInv.size() == MAX_INV_SZ) {
57405695
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
57415696
vInv.clear();
57425697
}
57435698
}
5744-
tx_relay->m_last_mempool_req = std::chrono::duration_cast<std::chrono::seconds>(current_time);
57455699
}
57465700

57475701
// Determine transactions to relay
@@ -5781,30 +5735,32 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
57815735
if (!txinfo.tx) {
57825736
continue;
57835737
}
5784-
auto txid = txinfo.tx->GetHash();
57855738
// Peer told you to not send transactions at that feerate? Don't bother sending it.
57865739
if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
57875740
continue;
57885741
}
57895742
if (tx_relay->m_bloom_filter && !tx_relay->m_bloom_filter->IsRelevantAndUpdate(*txinfo.tx)) continue;
57905743
// Send
5791-
tx_relay->m_recently_announced_invs.insert(hash);
57925744
vInv.push_back(inv);
57935745
nRelayedTransactions++;
57945746
if (vInv.size() == MAX_INV_SZ) {
57955747
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
57965748
vInv.clear();
57975749
}
57985750
tx_relay->m_tx_inventory_known_filter.insert(hash);
5799-
if (hash != txid) {
5751+
if (peer->m_wtxid_relay && hash != txinfo.tx->GetHash()) {
58005752
// Insert txid into m_tx_inventory_known_filter, even for
58015753
// wtxidrelay peers. This prevents re-adding of
58025754
// unconfirmed parents to the recently_announced
58035755
// filter, when a child tx is requested. See
58045756
// ProcessGetData().
5805-
tx_relay->m_tx_inventory_known_filter.insert(txid);
5757+
tx_relay->m_tx_inventory_known_filter.insert(txinfo.tx->GetHash());
58065758
}
58075759
}
5760+
5761+
// Ensure we'll respond to GETDATA requests for anything we've just announced
5762+
LOCK(m_mempool.cs);
5763+
tx_relay->m_last_inv_sequence = m_mempool.GetSequence();
58085764
}
58095765
}
58105766
if (!vInv.empty())

src/txmempool.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,17 @@ TxMempoolInfo CTxMemPool::info(const GenTxid& gtxid) const
853853
return GetInfo(i);
854854
}
855855

856+
TxMempoolInfo CTxMemPool::info_for_relay(const GenTxid& gtxid, uint64_t last_sequence) const
857+
{
858+
LOCK(cs);
859+
indexed_transaction_set::const_iterator i = (gtxid.IsWtxid() ? get_iter_from_wtxid(gtxid.GetHash()) : mapTx.find(gtxid.GetHash()));
860+
if (i != mapTx.end() && i->GetSequence() < last_sequence) {
861+
return GetInfo(i);
862+
} else {
863+
return TxMempoolInfo();
864+
}
865+
}
866+
856867
void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta)
857868
{
858869
{

src/txmempool.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,10 @@ class CTxMemPool
708708
return mapTx.project<0>(mapTx.get<index_by_wtxid>().find(wtxid));
709709
}
710710
TxMempoolInfo info(const GenTxid& gtxid) const;
711+
712+
/** Returns info for a transaction if its entry_sequence < last_sequence */
713+
TxMempoolInfo info_for_relay(const GenTxid& gtxid, uint64_t last_sequence) const;
714+
711715
std::vector<TxMempoolInfo> infoAll() const;
712716

713717
size_t DynamicMemoryUsage() const;

0 commit comments

Comments
 (0)