@@ -586,7 +586,7 @@ class PeerManagerImpl final : public PeerManager
586
586
* @param[in] maybe_add_extra_compact_tx Whether this tx should be added to vExtraTxnForCompact.
587
587
* Set to false if the tx has already been rejected before,
588
588
* e.g. is an orphan, to avoid adding duplicate entries.
589
- * Updates m_txrequest, m_recent_rejects, m_orphanage, and vExtraTxnForCompact. */
589
+ * Updates m_txrequest, m_recent_rejects, m_recent_rejects_reconsiderable, m_orphanage, and vExtraTxnForCompact. */
590
590
void ProcessInvalidTx (NodeId nodeid, const CTransactionRef& tx, const TxValidationState& result,
591
591
bool maybe_add_extra_compact_tx)
592
592
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, cs_main);
@@ -806,7 +806,16 @@ class PeerManagerImpl final : public PeerManager
806
806
/* * Stalling timeout for blocks in IBD */
807
807
std::atomic<std::chrono::seconds> m_block_stalling_timeout{BLOCK_STALLING_TIMEOUT_DEFAULT};
808
808
809
- bool AlreadyHaveTx (const GenTxid& gtxid)
809
+ /* * Check whether we already have this gtxid in:
810
+ * - mempool
811
+ * - orphanage
812
+ * - m_recent_rejects
813
+ * - m_recent_rejects_reconsiderable (if include_reconsiderable = true)
814
+ * - m_recent_confirmed_transactions
815
+ * Also responsible for resetting m_recent_rejects and m_recent_rejects_reconsiderable if the
816
+ * chain tip has changed.
817
+ * */
818
+ bool AlreadyHaveTx (const GenTxid& gtxid, bool include_reconsiderable)
810
819
EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_recent_confirmed_transactions_mutex);
811
820
812
821
/* *
@@ -844,8 +853,32 @@ class PeerManagerImpl final : public PeerManager
844
853
* Memory used: 1.3 MB
845
854
*/
846
855
CRollingBloomFilter m_recent_rejects GUARDED_BY (::cs_main){120'000 , 0.000'001 };
856
+ /* * Block hash of chain tip the last time we reset m_recent_rejects and
857
+ * m_recent_rejects_reconsiderable. */
847
858
uint256 hashRecentRejectsChainTip GUARDED_BY (cs_main);
848
859
860
+ /* *
861
+ * Filter for:
862
+ * (1) wtxids of transactions that were recently rejected by the mempool but are
863
+ * eligible for reconsideration if submitted with other transactions.
864
+ * (2) packages (see GetPackageHash) we have already rejected before and should not retry.
865
+ *
866
+ * Similar to m_recent_rejects, this filter is used to save bandwidth when e.g. all of our peers
867
+ * have larger mempools and thus lower minimum feerates than us.
868
+ *
869
+ * When a transaction's error is TxValidationResult::TX_RECONSIDERABLE (in a package or by
870
+ * itself), add its wtxid to this filter. When a package fails for any reason, add the combined
871
+ * hash to this filter.
872
+ *
873
+ * Upon receiving an announcement for a transaction, if it exists in this filter, do not
874
+ * download the txdata. When considering packages, if it exists in this filter, drop it.
875
+ *
876
+ * Reset this filter when the chain tip changes.
877
+ *
878
+ * Parameters are picked to be the same as m_recent_rejects, with the same rationale.
879
+ */
880
+ CRollingBloomFilter m_recent_rejects_reconsiderable GUARDED_BY (::cs_main){120'000 , 0.000'001 };
881
+
849
882
/*
850
883
* Filter for transactions that have been recently confirmed.
851
884
* We use this to avoid requesting transactions that have already been
@@ -2194,7 +2227,7 @@ void PeerManagerImpl::BlockChecked(const CBlock& block, const BlockValidationSta
2194
2227
//
2195
2228
2196
2229
2197
- bool PeerManagerImpl::AlreadyHaveTx (const GenTxid& gtxid)
2230
+ bool PeerManagerImpl::AlreadyHaveTx (const GenTxid& gtxid, bool include_reconsiderable )
2198
2231
{
2199
2232
if (m_chainman.ActiveChain ().Tip ()->GetBlockHash () != hashRecentRejectsChainTip) {
2200
2233
// If the chain tip has changed previously rejected transactions
@@ -2203,12 +2236,15 @@ bool PeerManagerImpl::AlreadyHaveTx(const GenTxid& gtxid)
2203
2236
// txs a second chance.
2204
2237
hashRecentRejectsChainTip = m_chainman.ActiveChain ().Tip ()->GetBlockHash ();
2205
2238
m_recent_rejects.reset ();
2239
+ m_recent_rejects_reconsiderable.reset ();
2206
2240
}
2207
2241
2208
2242
const uint256& hash = gtxid.GetHash ();
2209
2243
2210
2244
if (m_orphanage.HaveTx (gtxid)) return true ;
2211
2245
2246
+ if (include_reconsiderable && m_recent_rejects_reconsiderable.contains (hash)) return true ;
2247
+
2212
2248
{
2213
2249
LOCK (m_recent_confirmed_transactions_mutex);
2214
2250
if (m_recent_confirmed_transactions.contains (hash)) return true ;
@@ -3097,7 +3133,14 @@ void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx
3097
3133
// See also comments in https://github.com/bitcoin/bitcoin/pull/18044#discussion_r443419034
3098
3134
// for concerns around weakening security of unupgraded nodes
3099
3135
// if we start doing this too early.
3100
- m_recent_rejects.insert (ptx->GetWitnessHash ().ToUint256 ());
3136
+ if (state.GetResult () == TxValidationResult::TX_RECONSIDERABLE) {
3137
+ // If the result is TX_RECONSIDERABLE, add it to m_recent_rejects_reconsiderable
3138
+ // because we should not download or submit this transaction by itself again, but may
3139
+ // submit it as part of a package later.
3140
+ m_recent_rejects_reconsiderable.insert (ptx->GetWitnessHash ().ToUint256 ());
3141
+ } else {
3142
+ m_recent_rejects.insert (ptx->GetWitnessHash ().ToUint256 ());
3143
+ }
3101
3144
m_txrequest.ForgetTxHash (ptx->GetWitnessHash ());
3102
3145
// If the transaction failed for TX_INPUTS_NOT_STANDARD,
3103
3146
// then we know that the witness was irrelevant to the policy
@@ -4015,7 +4058,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
4015
4058
return ;
4016
4059
}
4017
4060
const GenTxid gtxid = ToGenTxid (inv);
4018
- const bool fAlreadyHave = AlreadyHaveTx (gtxid);
4061
+ const bool fAlreadyHave = AlreadyHaveTx (gtxid, /* include_reconsiderable= */ true );
4019
4062
LogPrint (BCLog::NET, " got inv: %s %s peer=%d\n " , inv.ToString (), fAlreadyHave ? " have" : " new" , pfrom.GetId ());
4020
4063
4021
4064
AddKnownTx (*peer, inv.hash );
@@ -4320,7 +4363,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
4320
4363
// already; and an adversary can already relay us old transactions
4321
4364
// (older than our recency filter) if trying to DoS us, without any need
4322
4365
// for witness malleation.
4323
- if (AlreadyHaveTx (GenTxid::Wtxid (wtxid))) {
4366
+ if (AlreadyHaveTx (GenTxid::Wtxid (wtxid), /* include_reconsiderable= */ true )) {
4324
4367
if (pfrom.HasPermission (NetPermissionFlags::ForceRelay)) {
4325
4368
// Always relay transactions received from peers with forcerelay
4326
4369
// permission, even if they were already in the mempool, allowing
@@ -4392,7 +4435,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
4392
4435
// protocol for getting all unconfirmed parents.
4393
4436
const auto gtxid{GenTxid::Txid (parent_txid)};
4394
4437
AddKnownTx (*peer, parent_txid);
4395
- if (!AlreadyHaveTx (gtxid)) AddTxAnnouncement (pfrom, gtxid, current_time);
4438
+ if (!AlreadyHaveTx (gtxid, /* include_reconsiderable= */ true )) AddTxAnnouncement (pfrom, gtxid, current_time);
4396
4439
}
4397
4440
4398
4441
if (m_orphanage.AddTx (ptx, pfrom.GetId ())) {
@@ -6033,7 +6076,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
6033
6076
entry.second .GetHash ().ToString (), entry.first );
6034
6077
}
6035
6078
for (const GenTxid& gtxid : requestable) {
6036
- if (!AlreadyHaveTx (gtxid)) {
6079
+ if (!AlreadyHaveTx (gtxid, /* include_reconsiderable= */ true )) {
6037
6080
LogPrint (BCLog::NET, " Requesting %s %s peer=%d\n " , gtxid.IsWtxid () ? " wtx" : " tx" ,
6038
6081
gtxid.GetHash ().ToString (), pto->GetId ());
6039
6082
vGetData.emplace_back (gtxid.IsWtxid () ? MSG_WTX : (MSG_TX | GetFetchFlags (*peer)), gtxid.GetHash ());
0 commit comments