Skip to content

Commit 6c51e1d

Browse files
committed
[p2p] add separate rejections cache for reconsiderable txns
1 parent 410ebd6 commit 6c51e1d

File tree

1 file changed

+51
-8
lines changed

1 file changed

+51
-8
lines changed

src/net_processing.cpp

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ class PeerManagerImpl final : public PeerManager
586586
* @param[in] maybe_add_extra_compact_tx Whether this tx should be added to vExtraTxnForCompact.
587587
* Set to false if the tx has already been rejected before,
588588
* 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. */
590590
void ProcessInvalidTx(NodeId nodeid, const CTransactionRef& tx, const TxValidationState& result,
591591
bool maybe_add_extra_compact_tx)
592592
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, cs_main);
@@ -806,7 +806,16 @@ class PeerManagerImpl final : public PeerManager
806806
/** Stalling timeout for blocks in IBD */
807807
std::atomic<std::chrono::seconds> m_block_stalling_timeout{BLOCK_STALLING_TIMEOUT_DEFAULT};
808808

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)
810819
EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_recent_confirmed_transactions_mutex);
811820

812821
/**
@@ -844,8 +853,32 @@ class PeerManagerImpl final : public PeerManager
844853
* Memory used: 1.3 MB
845854
*/
846855
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. */
847858
uint256 hashRecentRejectsChainTip GUARDED_BY(cs_main);
848859

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+
849882
/*
850883
* Filter for transactions that have been recently confirmed.
851884
* We use this to avoid requesting transactions that have already been
@@ -2194,7 +2227,7 @@ void PeerManagerImpl::BlockChecked(const CBlock& block, const BlockValidationSta
21942227
//
21952228

21962229

2197-
bool PeerManagerImpl::AlreadyHaveTx(const GenTxid& gtxid)
2230+
bool PeerManagerImpl::AlreadyHaveTx(const GenTxid& gtxid, bool include_reconsiderable)
21982231
{
21992232
if (m_chainman.ActiveChain().Tip()->GetBlockHash() != hashRecentRejectsChainTip) {
22002233
// If the chain tip has changed previously rejected transactions
@@ -2203,12 +2236,15 @@ bool PeerManagerImpl::AlreadyHaveTx(const GenTxid& gtxid)
22032236
// txs a second chance.
22042237
hashRecentRejectsChainTip = m_chainman.ActiveChain().Tip()->GetBlockHash();
22052238
m_recent_rejects.reset();
2239+
m_recent_rejects_reconsiderable.reset();
22062240
}
22072241

22082242
const uint256& hash = gtxid.GetHash();
22092243

22102244
if (m_orphanage.HaveTx(gtxid)) return true;
22112245

2246+
if (include_reconsiderable && m_recent_rejects_reconsiderable.contains(hash)) return true;
2247+
22122248
{
22132249
LOCK(m_recent_confirmed_transactions_mutex);
22142250
if (m_recent_confirmed_transactions.contains(hash)) return true;
@@ -3097,7 +3133,14 @@ void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx
30973133
// See also comments in https://github.com/bitcoin/bitcoin/pull/18044#discussion_r443419034
30983134
// for concerns around weakening security of unupgraded nodes
30993135
// 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+
}
31013144
m_txrequest.ForgetTxHash(ptx->GetWitnessHash());
31023145
// If the transaction failed for TX_INPUTS_NOT_STANDARD,
31033146
// 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,
40154058
return;
40164059
}
40174060
const GenTxid gtxid = ToGenTxid(inv);
4018-
const bool fAlreadyHave = AlreadyHaveTx(gtxid);
4061+
const bool fAlreadyHave = AlreadyHaveTx(gtxid, /*include_reconsiderable=*/true);
40194062
LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());
40204063

40214064
AddKnownTx(*peer, inv.hash);
@@ -4320,7 +4363,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
43204363
// already; and an adversary can already relay us old transactions
43214364
// (older than our recency filter) if trying to DoS us, without any need
43224365
// for witness malleation.
4323-
if (AlreadyHaveTx(GenTxid::Wtxid(wtxid))) {
4366+
if (AlreadyHaveTx(GenTxid::Wtxid(wtxid), /*include_reconsiderable=*/true)) {
43244367
if (pfrom.HasPermission(NetPermissionFlags::ForceRelay)) {
43254368
// Always relay transactions received from peers with forcerelay
43264369
// permission, even if they were already in the mempool, allowing
@@ -4392,7 +4435,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
43924435
// protocol for getting all unconfirmed parents.
43934436
const auto gtxid{GenTxid::Txid(parent_txid)};
43944437
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);
43964439
}
43974440

43984441
if (m_orphanage.AddTx(ptx, pfrom.GetId())) {
@@ -6033,7 +6076,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
60336076
entry.second.GetHash().ToString(), entry.first);
60346077
}
60356078
for (const GenTxid& gtxid : requestable) {
6036-
if (!AlreadyHaveTx(gtxid)) {
6079+
if (!AlreadyHaveTx(gtxid, /*include_reconsiderable=*/true)) {
60376080
LogPrint(BCLog::NET, "Requesting %s %s peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx",
60386081
gtxid.GetHash().ToString(), pto->GetId());
60396082
vGetData.emplace_back(gtxid.IsWtxid() ? MSG_WTX : (MSG_TX | GetFetchFlags(*peer)), gtxid.GetHash());

0 commit comments

Comments
 (0)