@@ -584,7 +584,7 @@ class PeerManagerImpl final : public PeerManager
584584 * @param[in] maybe_add_extra_compact_tx Whether this tx should be added to vExtraTxnForCompact.
585585 * Set to false if the tx has already been rejected before,
586586 * e.g. is an orphan, to avoid adding duplicate entries.
587- * Updates m_txrequest, m_recent_rejects, m_recent_rejects_reconsiderable , m_orphanage, and vExtraTxnForCompact. */
587+ * Updates m_txrequest, m_lazy_recent_rejects, m_lazy_recent_rejects_reconsiderable , m_orphanage, and vExtraTxnForCompact. */
588588 void ProcessInvalidTx (NodeId nodeid, const CTransactionRef& tx, const TxValidationState& result,
589589 bool maybe_add_extra_compact_tx)
590590 EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, m_tx_download_mutex);
@@ -776,9 +776,9 @@ class PeerManagerImpl final : public PeerManager
776776 /* * Synchronizes tx download including TxRequestTracker, rejection filters, and TxOrphanage.
777777 * Lock invariants:
778778 * - A txhash (txid or wtxid) in m_txrequest is not also in m_orphanage.
779- * - A txhash (txid or wtxid) in m_txrequest is not also in m_recent_rejects .
780- * - A txhash (txid or wtxid) in m_txrequest is not also in m_recent_rejects_reconsiderable .
781- * - A txhash (txid or wtxid) in m_txrequest is not also in m_recent_confirmed_transactions .
779+ * - A txhash (txid or wtxid) in m_txrequest is not also in m_lazy_recent_rejects .
780+ * - A txhash (txid or wtxid) in m_txrequest is not also in m_lazy_recent_rejects_reconsiderable .
781+ * - A txhash (txid or wtxid) in m_txrequest is not also in m_lazy_recent_confirmed_transactions .
782782 * - Each data structure's limits hold (m_orphanage max size, m_txrequest per-peer limits, etc).
783783 */
784784 Mutex m_tx_download_mutex ACQUIRED_BEFORE (m_mempool.cs);
@@ -856,9 +856,9 @@ class PeerManagerImpl final : public PeerManager
856856 /* * Check whether we already have this gtxid in:
857857 * - mempool
858858 * - orphanage
859- * - m_recent_rejects
860- * - m_recent_rejects_reconsiderable (if include_reconsiderable = true)
861- * - m_recent_confirmed_transactions
859+ * - m_lazy_recent_rejects
860+ * - m_lazy_recent_rejects_reconsiderable (if include_reconsiderable = true)
861+ * - m_lazy_recent_confirmed_transactions
862862 * */
863863 bool AlreadyHaveTx (const GenTxid& gtxid, bool include_reconsiderable)
864864 EXCLUSIVE_LOCKS_REQUIRED(m_tx_download_mutex);
@@ -897,15 +897,26 @@ class PeerManagerImpl final : public PeerManager
897897 *
898898 * Memory used: 1.3 MB
899899 */
900- CRollingBloomFilter m_recent_rejects GUARDED_BY (m_tx_download_mutex){120'000 , 0.000'001 };
900+ std::unique_ptr<CRollingBloomFilter> m_lazy_recent_rejects GUARDED_BY (m_tx_download_mutex){nullptr };
901+
902+ CRollingBloomFilter& RecentRejectsFilter () EXCLUSIVE_LOCKS_REQUIRED(m_tx_download_mutex)
903+ {
904+ AssertLockHeld (m_tx_download_mutex);
905+
906+ if (!m_lazy_recent_rejects) {
907+ m_lazy_recent_rejects = std::make_unique<CRollingBloomFilter>(120'000 , 0.000'001 );
908+ }
909+
910+ return *m_lazy_recent_rejects;
911+ }
901912
902913 /* *
903914 * Filter for:
904915 * (1) wtxids of transactions that were recently rejected by the mempool but are
905916 * eligible for reconsideration if submitted with other transactions.
906917 * (2) packages (see GetPackageHash) we have already rejected before and should not retry.
907918 *
908- * Similar to m_recent_rejects , this filter is used to save bandwidth when e.g. all of our peers
919+ * Similar to m_lazy_recent_rejects , this filter is used to save bandwidth when e.g. all of our peers
909920 * have larger mempools and thus lower minimum feerates than us.
910921 *
911922 * When a transaction's error is TxValidationResult::TX_RECONSIDERABLE (in a package or by
@@ -917,9 +928,20 @@ class PeerManagerImpl final : public PeerManager
917928 *
918929 * Reset this filter when the chain tip changes.
919930 *
920- * Parameters are picked to be the same as m_recent_rejects , with the same rationale.
931+ * Parameters are picked to be the same as m_lazy_recent_rejects , with the same rationale.
921932 */
922- CRollingBloomFilter m_recent_rejects_reconsiderable GUARDED_BY (m_tx_download_mutex){120'000 , 0.000'001 };
933+ std::unique_ptr<CRollingBloomFilter> m_lazy_recent_rejects_reconsiderable GUARDED_BY (m_tx_download_mutex){nullptr };
934+
935+ CRollingBloomFilter& RecentRejectsReconsiderableFilter () EXCLUSIVE_LOCKS_REQUIRED(m_tx_download_mutex)
936+ {
937+ AssertLockHeld (m_tx_download_mutex);
938+
939+ if (!m_lazy_recent_rejects_reconsiderable) {
940+ m_lazy_recent_rejects_reconsiderable = std::make_unique<CRollingBloomFilter>(120'000 , 0.000'001 );
941+ }
942+
943+ return *m_lazy_recent_rejects_reconsiderable;
944+ }
923945
924946 /*
925947 * Filter for transactions that have been recently confirmed.
@@ -936,7 +958,18 @@ class PeerManagerImpl final : public PeerManager
936958 * transaction per day that would be inadvertently ignored (which is the
937959 * same probability that we have in the reject filter).
938960 */
939- CRollingBloomFilter m_recent_confirmed_transactions GUARDED_BY (m_tx_download_mutex){48'000 , 0.000'001 };
961+ std::unique_ptr<CRollingBloomFilter> m_lazy_recent_confirmed_transactions GUARDED_BY (m_tx_download_mutex){nullptr };
962+
963+ CRollingBloomFilter& RecentConfirmedTransactionsFilter () EXCLUSIVE_LOCKS_REQUIRED(m_tx_download_mutex)
964+ {
965+ AssertLockHeld (m_tx_download_mutex);
966+
967+ if (!m_lazy_recent_confirmed_transactions) {
968+ m_lazy_recent_confirmed_transactions = std::make_unique<CRollingBloomFilter>(48'000 , 0.000'001 );
969+ }
970+
971+ return *m_lazy_recent_confirmed_transactions;
972+ }
940973
941974 /* *
942975 * For sending `inv`s to inbound peers, we use a single (exponentially
@@ -2080,8 +2113,8 @@ void PeerManagerImpl::ActiveTipChange(const CBlockIndex& new_tip, bool is_ibd)
20802113 // If the chain tip has changed, previously rejected transactions might now be valid, e.g. due
20812114 // to a timelock. Reset the rejection filters to give those transactions another chance if we
20822115 // see them again.
2083- m_recent_rejects .reset ();
2084- m_recent_rejects_reconsiderable .reset ();
2116+ RecentRejectsFilter () .reset ();
2117+ RecentRejectsReconsiderableFilter () .reset ();
20852118 }
20862119}
20872120
@@ -2119,9 +2152,9 @@ void PeerManagerImpl::BlockConnected(
21192152 m_orphanage.EraseForBlock (*pblock);
21202153
21212154 for (const auto & ptx : pblock->vtx ) {
2122- m_recent_confirmed_transactions .insert (ptx->GetHash ().ToUint256 ());
2155+ RecentConfirmedTransactionsFilter () .insert (ptx->GetHash ().ToUint256 ());
21232156 if (ptx->HasWitness ()) {
2124- m_recent_confirmed_transactions .insert (ptx->GetWitnessHash ().ToUint256 ());
2157+ RecentConfirmedTransactionsFilter () .insert (ptx->GetWitnessHash ().ToUint256 ());
21252158 }
21262159 m_txrequest.ForgetTxHash (ptx->GetHash ());
21272160 m_txrequest.ForgetTxHash (ptx->GetWitnessHash ());
@@ -2139,7 +2172,7 @@ void PeerManagerImpl::BlockDisconnected(const std::shared_ptr<const CBlock> &blo
21392172 // presumably the most common case of relaying a confirmed transaction
21402173 // should be just after a new block containing it is found.
21412174 LOCK (m_tx_download_mutex);
2142- m_recent_confirmed_transactions .reset ();
2175+ RecentConfirmedTransactionsFilter () .reset ();
21432176}
21442177
21452178/* *
@@ -2300,11 +2333,11 @@ bool PeerManagerImpl::AlreadyHaveTx(const GenTxid& gtxid, bool include_reconside
23002333 if (m_orphanage.HaveTx (Wtxid::FromUint256 (hash))) return true ;
23012334 }
23022335
2303- if (include_reconsiderable && m_recent_rejects_reconsiderable .contains (hash)) return true ;
2336+ if (include_reconsiderable && RecentRejectsReconsiderableFilter () .contains (hash)) return true ;
23042337
2305- if (m_recent_confirmed_transactions .contains (hash)) return true ;
2338+ if (RecentConfirmedTransactionsFilter () .contains (hash)) return true ;
23062339
2307- return m_recent_rejects .contains (hash) || m_mempool.exists (gtxid);
2340+ return RecentRejectsFilter () .contains (hash) || m_mempool.exists (gtxid);
23082341}
23092342
23102343bool PeerManagerImpl::AlreadyHaveBlock (const uint256& block_hash)
@@ -3192,12 +3225,12 @@ void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx
31923225 // for concerns around weakening security of unupgraded nodes
31933226 // if we start doing this too early.
31943227 if (state.GetResult () == TxValidationResult::TX_RECONSIDERABLE) {
3195- // If the result is TX_RECONSIDERABLE, add it to m_recent_rejects_reconsiderable
3228+ // If the result is TX_RECONSIDERABLE, add it to m_lazy_recent_rejects_reconsiderable
31963229 // because we should not download or submit this transaction by itself again, but may
31973230 // submit it as part of a package later.
3198- m_recent_rejects_reconsiderable .insert (ptx->GetWitnessHash ().ToUint256 ());
3231+ RecentRejectsReconsiderableFilter () .insert (ptx->GetWitnessHash ().ToUint256 ());
31993232 } else {
3200- m_recent_rejects .insert (ptx->GetWitnessHash ().ToUint256 ());
3233+ RecentRejectsFilter () .insert (ptx->GetWitnessHash ().ToUint256 ());
32013234 }
32023235 m_txrequest.ForgetTxHash (ptx->GetWitnessHash ());
32033236 // If the transaction failed for TX_INPUTS_NOT_STANDARD,
@@ -3211,7 +3244,7 @@ void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx
32113244 // We only add the txid if it differs from the wtxid, to avoid wasting entries in the
32123245 // rolling bloom filter.
32133246 if (state.GetResult () == TxValidationResult::TX_INPUTS_NOT_STANDARD && ptx->HasWitness ()) {
3214- m_recent_rejects .insert (ptx->GetHash ().ToUint256 ());
3247+ RecentRejectsFilter () .insert (ptx->GetHash ().ToUint256 ());
32153248 m_txrequest.ForgetTxHash (ptx->GetHash ());
32163249 }
32173250 if (maybe_add_extra_compact_tx && RecursiveDynamicUsage (*ptx) < 100000 ) {
@@ -3266,7 +3299,7 @@ void PeerManagerImpl::ProcessPackageResult(const PackageToValidate& package_to_v
32663299 const auto & senders = package_to_validate.m_senders ;
32673300
32683301 if (package_result.m_state .IsInvalid ()) {
3269- m_recent_rejects_reconsiderable .insert (GetPackageHash (package));
3302+ RecentRejectsReconsiderableFilter () .insert (GetPackageHash (package));
32703303 }
32713304 // We currently only expect to process 1-parent-1-child packages. Remove if this changes.
32723305 if (!Assume (package.size () == 2 )) return ;
@@ -3320,7 +3353,7 @@ std::optional<PeerManagerImpl::PackageToValidate> PeerManagerImpl::Find1P1CPacka
33203353
33213354 const auto & parent_wtxid{ptx->GetWitnessHash ()};
33223355
3323- Assume (m_recent_rejects_reconsiderable .contains (parent_wtxid.ToUint256 ()));
3356+ Assume (RecentRejectsReconsiderableFilter () .contains (parent_wtxid.ToUint256 ()));
33243357
33253358 // Prefer children from this peer. This helps prevent censorship attempts in which an attacker
33263359 // sends lots of fake children for the parent, and we (unluckily) keep selecting the fake
@@ -3332,7 +3365,7 @@ std::optional<PeerManagerImpl::PackageToValidate> PeerManagerImpl::Find1P1CPacka
33323365 // most recent) one efficiently.
33333366 for (const auto & child : cpfp_candidates_same_peer) {
33343367 Package maybe_cpfp_package{ptx, child};
3335- if (!m_recent_rejects_reconsiderable .contains (GetPackageHash (maybe_cpfp_package))) {
3368+ if (!RecentRejectsReconsiderableFilter () .contains (GetPackageHash (maybe_cpfp_package))) {
33363369 return PeerManagerImpl::PackageToValidate{ptx, child, nodeid, nodeid};
33373370 }
33383371 }
@@ -3356,10 +3389,10 @@ std::optional<PeerManagerImpl::PackageToValidate> PeerManagerImpl::Find1P1CPacka
33563389
33573390 for (const auto index : tx_indices) {
33583391 // If we already tried a package and failed for any reason, the combined hash was
3359- // cached in m_recent_rejects_reconsiderable .
3392+ // cached in m_lazy_recent_rejects_reconsiderable .
33603393 const auto [child_tx, child_sender] = cpfp_candidates_different_peer.at (index);
33613394 Package maybe_cpfp_package{ptx, child_tx};
3362- if (!m_recent_rejects_reconsiderable .contains (GetPackageHash (maybe_cpfp_package))) {
3395+ if (!RecentRejectsReconsiderableFilter () .contains (GetPackageHash (maybe_cpfp_package))) {
33633396 return PeerManagerImpl::PackageToValidate{ptx, child_tx, nodeid, child_sender};
33643397 }
33653398 }
@@ -4551,8 +4584,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
45514584 }
45524585 }
45534586
4554- if (m_recent_rejects_reconsiderable .contains (wtxid)) {
4555- // When a transaction is already in m_recent_rejects_reconsiderable , we shouldn't submit
4587+ if (RecentRejectsReconsiderableFilter () .contains (wtxid)) {
4588+ // When a transaction is already in m_lazy_recent_rejects_reconsiderable , we shouldn't submit
45564589 // it by itself again. However, look for a matching child in the orphanage, as it is
45574590 // possible that they succeed as a package.
45584591 LogPrint (BCLog::TXPACKAGES, " found tx %s (wtxid=%s) in reconsiderable rejects, looking for child in orphanage\n " ,
@@ -4564,20 +4597,20 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
45644597 ProcessPackageResult (package_to_validate.value (), package_result);
45654598 }
45664599 }
4567- // If a tx is detected by m_recent_rejects it is ignored. Because we haven't
4600+ // If a tx is detected by m_lazy_recent_rejects it is ignored. Because we haven't
45684601 // submitted the tx to our mempool, we won't have computed a DoS
45694602 // score for it or determined exactly why we consider it invalid.
45704603 //
45714604 // This means we won't penalize any peer subsequently relaying a DoSy
45724605 // tx (even if we penalized the first peer who gave it to us) because
4573- // we have to account for m_recent_rejects showing false positives. In
4606+ // we have to account for m_lazy_recent_rejects showing false positives. In
45744607 // other words, we shouldn't penalize a peer if we aren't *sure* they
45754608 // submitted a DoSy tx.
45764609 //
4577- // Note that m_recent_rejects doesn't just record DoSy or invalid
4610+ // Note that m_lazy_recent_rejects doesn't just record DoSy or invalid
45784611 // transactions, but any tx not accepted by the mempool, which may be
45794612 // due to node policy (vs. consensus). So we can't blanket penalize a
4580- // peer simply for relaying a tx that our m_recent_rejects has caught,
4613+ // peer simply for relaying a tx that our m_lazy_recent_rejects has caught,
45814614 // regardless of false positives.
45824615 return ;
45834616 }
@@ -4604,16 +4637,16 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
46044637 std::sort (unique_parents.begin (), unique_parents.end ());
46054638 unique_parents.erase (std::unique (unique_parents.begin (), unique_parents.end ()), unique_parents.end ());
46064639
4607- // Distinguish between parents in m_recent_rejects and m_recent_rejects_reconsiderable .
4608- // We can tolerate having up to 1 parent in m_recent_rejects_reconsiderable since we
4609- // submit 1p1c packages. However, fail immediately if any are in m_recent_rejects .
4640+ // Distinguish between parents in m_lazy_recent_rejects and m_lazy_recent_rejects_reconsiderable .
4641+ // We can tolerate having up to 1 parent in m_lazy_recent_rejects_reconsiderable since we
4642+ // submit 1p1c packages. However, fail immediately if any are in m_lazy_recent_rejects .
46104643 std::optional<uint256> rejected_parent_reconsiderable;
46114644 for (const uint256& parent_txid : unique_parents) {
4612- if (m_recent_rejects .contains (parent_txid)) {
4645+ if (RecentRejectsFilter () .contains (parent_txid)) {
46134646 fRejectedParents = true ;
46144647 break ;
4615- } else if (m_recent_rejects_reconsiderable .contains (parent_txid) && !m_mempool.exists (GenTxid::Txid (parent_txid))) {
4616- // More than 1 parent in m_recent_rejects_reconsiderable : 1p1c will not be
4648+ } else if (RecentRejectsReconsiderableFilter () .contains (parent_txid) && !m_mempool.exists (GenTxid::Txid (parent_txid))) {
4649+ // More than 1 parent in m_lazy_recent_rejects_reconsiderable : 1p1c will not be
46174650 // sufficient to accept this package, so just give up here.
46184651 if (rejected_parent_reconsiderable.has_value ()) {
46194652 fRejectedParents = true ;
@@ -4633,7 +4666,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
46334666 // protocol for getting all unconfirmed parents.
46344667 const auto gtxid{GenTxid::Txid (parent_txid)};
46354668 AddKnownTx (*peer, parent_txid);
4636- // Exclude m_recent_rejects_reconsiderable : the missing parent may have been
4669+ // Exclude m_lazy_recent_rejects_reconsiderable : the missing parent may have been
46374670 // previously rejected for being too low feerate. This orphan might CPFP it.
46384671 if (!AlreadyHaveTx (gtxid, /* include_reconsiderable=*/ false )) AddTxAnnouncement (pfrom, gtxid, current_time);
46394672 }
@@ -4658,8 +4691,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
46584691 // regardless of what witness is provided, we will not accept
46594692 // this, so we don't need to allow for redownload of this txid
46604693 // from any of our non-wtxidrelay peers.
4661- m_recent_rejects .insert (tx.GetHash ().ToUint256 ());
4662- m_recent_rejects .insert (tx.GetWitnessHash ().ToUint256 ());
4694+ RecentRejectsFilter () .insert (tx.GetHash ().ToUint256 ());
4695+ RecentRejectsFilter () .insert (tx.GetWitnessHash ().ToUint256 ());
46634696 m_txrequest.ForgetTxHash (tx.GetHash ());
46644697 m_txrequest.ForgetTxHash (tx.GetWitnessHash ());
46654698 }
@@ -6306,7 +6339,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
63066339 entry.second .GetHash ().ToString (), entry.first );
63076340 }
63086341 for (const GenTxid& gtxid : requestable) {
6309- // Exclude m_recent_rejects_reconsiderable : we may be requesting a missing parent
6342+ // Exclude m_lazy_recent_rejects_reconsiderable : we may be requesting a missing parent
63106343 // that was previously rejected for being too low feerate.
63116344 if (!AlreadyHaveTx (gtxid, /* include_reconsiderable=*/ false )) {
63126345 LogPrint (BCLog::NET, " Requesting %s %s peer=%d\n " , gtxid.IsWtxid () ? " wtx" : " tx" ,
0 commit comments