Skip to content

Commit c4ce0c1

Browse files
committed
[refactor] move invalid tx processing to TxDownload
Move-only. Also delete external RecentRejectsFilter() access since it is no longer necessary.
1 parent c6b2174 commit c4ce0c1

File tree

4 files changed

+175
-153
lines changed

4 files changed

+175
-153
lines changed

src/net_processing.cpp

Lines changed: 2 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -808,12 +808,6 @@ class PeerManagerImpl final : public PeerManager
808808
/** Stalling timeout for blocks in IBD */
809809
std::atomic<std::chrono::seconds> m_block_stalling_timeout{BLOCK_STALLING_TIMEOUT_DEFAULT};
810810

811-
CRollingBloomFilter& RecentRejectsFilter() EXCLUSIVE_LOCKS_REQUIRED(m_tx_download_mutex)
812-
{
813-
AssertLockHeld(m_tx_download_mutex);
814-
return m_txdownloadman.RecentRejectsFilter();
815-
}
816-
817811
CRollingBloomFilter& RecentRejectsReconsiderableFilter() EXCLUSIVE_LOCKS_REQUIRED(m_tx_download_mutex)
818812
{
819813
AssertLockHeld(m_tx_download_mutex);
@@ -1906,7 +1900,7 @@ PeerManagerImpl::PeerManagerImpl(CConnman& connman, AddrMan& addrman,
19061900
m_banman(banman),
19071901
m_chainman(chainman),
19081902
m_mempool(pool),
1909-
m_txdownloadman(node::TxDownloadOptions{pool, m_rng}),
1903+
m_txdownloadman(node::TxDownloadOptions{pool, m_rng, opts.max_orphan_txs}),
19101904
m_warnings{warnings},
19111905
m_opts{opts}
19121906
{
@@ -2984,148 +2978,14 @@ std::optional<node::PackageToValidate> PeerManagerImpl::ProcessInvalidTx(NodeId
29842978

29852979
PeerRef peer{GetPeerRef(nodeid)};
29862980

2987-
auto& m_orphanage = m_txdownloadman.GetOrphanageRef();
2988-
auto& m_txrequest = m_txdownloadman.GetTxRequestRef();
2989-
const CTransaction& tx{*ptx};
2990-
29912981
LogDebug(BCLog::MEMPOOLREJ, "%s (wtxid=%s) from peer=%d was not accepted: %s\n",
29922982
ptx->GetHash().ToString(),
29932983
ptx->GetWitnessHash().ToString(),
29942984
nodeid,
29952985
state.ToString());
29962986

2997-
// Whether we should call AddToCompactExtraTransactions at the end
2998-
bool add_extra_compact_tx{first_time_failure};
2999-
// Hashes to pass to AddKnownTx later
3000-
std::vector<uint256> unique_parents;
3001-
// Populated if failure is reconsiderable and eligible package is found.
3002-
std::optional<node::PackageToValidate> package_to_validate;
3003-
3004-
if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
3005-
// Only process a new orphan if this is a first time failure, as otherwise it must be either
3006-
// already in orphanage or from 1p1c processing.
3007-
if (first_time_failure) {
3008-
bool fRejectedParents = false; // It may be the case that the orphans parents have all been rejected
3009-
3010-
// Deduplicate parent txids, so that we don't have to loop over
3011-
// the same parent txid more than once down below.
3012-
unique_parents.reserve(tx.vin.size());
3013-
for (const CTxIn& txin : tx.vin) {
3014-
// We start with all parents, and then remove duplicates below.
3015-
unique_parents.push_back(txin.prevout.hash);
3016-
}
3017-
std::sort(unique_parents.begin(), unique_parents.end());
3018-
unique_parents.erase(std::unique(unique_parents.begin(), unique_parents.end()), unique_parents.end());
3019-
3020-
// Distinguish between parents in m_lazy_recent_rejects and m_lazy_recent_rejects_reconsiderable.
3021-
// We can tolerate having up to 1 parent in m_lazy_recent_rejects_reconsiderable since we
3022-
// submit 1p1c packages. However, fail immediately if any are in m_lazy_recent_rejects.
3023-
std::optional<uint256> rejected_parent_reconsiderable;
3024-
for (const uint256& parent_txid : unique_parents) {
3025-
if (RecentRejectsFilter().contains(parent_txid)) {
3026-
fRejectedParents = true;
3027-
break;
3028-
} else if (RecentRejectsReconsiderableFilter().contains(parent_txid) && !m_mempool.exists(GenTxid::Txid(parent_txid))) {
3029-
// More than 1 parent in m_lazy_recent_rejects_reconsiderable: 1p1c will not be
3030-
// sufficient to accept this package, so just give up here.
3031-
if (rejected_parent_reconsiderable.has_value()) {
3032-
fRejectedParents = true;
3033-
break;
3034-
}
3035-
rejected_parent_reconsiderable = parent_txid;
3036-
}
3037-
}
3038-
if (!fRejectedParents) {
3039-
const auto current_time{GetTime<std::chrono::microseconds>()};
3040-
3041-
for (const uint256& parent_txid : unique_parents) {
3042-
// Here, we only have the txid (and not wtxid) of the
3043-
// inputs, so we only request in txid mode, even for
3044-
// wtxidrelay peers.
3045-
// Eventually we should replace this with an improved
3046-
// protocol for getting all unconfirmed parents.
3047-
const auto gtxid{GenTxid::Txid(parent_txid)};
3048-
// Exclude m_lazy_recent_rejects_reconsiderable: the missing parent may have been
3049-
// previously rejected for being too low feerate. This orphan might CPFP it.
3050-
if (!m_txdownloadman.AlreadyHaveTx(gtxid, /*include_reconsiderable=*/false)) {
3051-
m_txdownloadman.AddTxAnnouncement(nodeid, gtxid, current_time, /*p2p_inv=*/false);
3052-
}
3053-
}
2987+
const auto& [add_extra_compact_tx, unique_parents, package_to_validate] = m_txdownloadman.MempoolRejectedTx(ptx, state, nodeid, first_time_failure);
30542988

3055-
// Potentially flip add_extra_compact_tx to false if AddTx returns false because the tx was already there
3056-
add_extra_compact_tx &= m_orphanage.AddTx(ptx, nodeid);
3057-
3058-
// Once added to the orphan pool, a tx is considered AlreadyHave, and we shouldn't request it anymore.
3059-
m_txrequest.ForgetTxHash(tx.GetHash());
3060-
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
3061-
3062-
// DoS prevention: do not allow m_orphanage to grow unbounded (see CVE-2012-3789)
3063-
m_orphanage.LimitOrphans(m_opts.max_orphan_txs, m_rng);
3064-
} else {
3065-
unique_parents.clear();
3066-
LogDebug(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s (wtxid=%s)\n",
3067-
tx.GetHash().ToString(),
3068-
tx.GetWitnessHash().ToString());
3069-
// We will continue to reject this tx since it has rejected
3070-
// parents so avoid re-requesting it from other peers.
3071-
// Here we add both the txid and the wtxid, as we know that
3072-
// regardless of what witness is provided, we will not accept
3073-
// this, so we don't need to allow for redownload of this txid
3074-
// from any of our non-wtxidrelay peers.
3075-
RecentRejectsFilter().insert(tx.GetHash().ToUint256());
3076-
RecentRejectsFilter().insert(tx.GetWitnessHash().ToUint256());
3077-
m_txrequest.ForgetTxHash(tx.GetHash());
3078-
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
3079-
}
3080-
}
3081-
} else if (state.GetResult() == TxValidationResult::TX_WITNESS_STRIPPED) {
3082-
add_extra_compact_tx = false;
3083-
} else {
3084-
// We can add the wtxid of this transaction to our reject filter.
3085-
// Do not add txids of witness transactions or witness-stripped
3086-
// transactions to the filter, as they can have been malleated;
3087-
// adding such txids to the reject filter would potentially
3088-
// interfere with relay of valid transactions from peers that
3089-
// do not support wtxid-based relay. See
3090-
// https://github.com/bitcoin/bitcoin/issues/8279 for details.
3091-
// We can remove this restriction (and always add wtxids to
3092-
// the filter even for witness stripped transactions) once
3093-
// wtxid-based relay is broadly deployed.
3094-
// See also comments in https://github.com/bitcoin/bitcoin/pull/18044#discussion_r443419034
3095-
// for concerns around weakening security of unupgraded nodes
3096-
// if we start doing this too early.
3097-
if (state.GetResult() == TxValidationResult::TX_RECONSIDERABLE) {
3098-
// If the result is TX_RECONSIDERABLE, add it to m_lazy_recent_rejects_reconsiderable
3099-
// because we should not download or submit this transaction by itself again, but may
3100-
// submit it as part of a package later.
3101-
RecentRejectsReconsiderableFilter().insert(ptx->GetWitnessHash().ToUint256());
3102-
3103-
if (first_time_failure) {
3104-
// When a transaction fails for TX_RECONSIDERABLE, look for a matching child in the
3105-
// orphanage, as it is possible that they succeed as a package.
3106-
LogDebug(BCLog::TXPACKAGES, "tx %s (wtxid=%s) failed but reconsiderable, looking for child in orphanage\n",
3107-
ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString());
3108-
package_to_validate = m_txdownloadman.Find1P1CPackage(ptx, nodeid);
3109-
}
3110-
} else {
3111-
RecentRejectsFilter().insert(ptx->GetWitnessHash().ToUint256());
3112-
}
3113-
m_txrequest.ForgetTxHash(ptx->GetWitnessHash());
3114-
// If the transaction failed for TX_INPUTS_NOT_STANDARD,
3115-
// then we know that the witness was irrelevant to the policy
3116-
// failure, since this check depends only on the txid
3117-
// (the scriptPubKey being spent is covered by the txid).
3118-
// Add the txid to the reject filter to prevent repeated
3119-
// processing of this transaction in the event that child
3120-
// transactions are later received (resulting in
3121-
// parent-fetching by txid via the orphan-handling logic).
3122-
// We only add the txid if it differs from the wtxid, to avoid wasting entries in the
3123-
// rolling bloom filter.
3124-
if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && ptx->HasWitness()) {
3125-
RecentRejectsFilter().insert(ptx->GetHash().ToUint256());
3126-
m_txrequest.ForgetTxHash(ptx->GetHash());
3127-
}
3128-
}
31292989
if (add_extra_compact_tx && RecursiveDynamicUsage(*ptx) < 100000) {
31302990
AddToCompactExtraTransactions(ptx);
31312991
}
@@ -3135,12 +2995,6 @@ std::optional<node::PackageToValidate> PeerManagerImpl::ProcessInvalidTx(NodeId
31352995

31362996
MaybePunishNodeForTx(nodeid, state);
31372997

3138-
// If the tx failed in ProcessOrphanTx, it should be removed from the orphanage unless the
3139-
// tx was still missing inputs. If the tx was not in the orphanage, EraseTx does nothing and returns 0.
3140-
if (state.GetResult() != TxValidationResult::TX_MISSING_INPUTS && m_orphanage.EraseTx(ptx->GetWitnessHash()) > 0) {
3141-
LogDebug(BCLog::TXPACKAGES, " removed orphan tx %s (wtxid=%s)\n", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString());
3142-
}
3143-
31442998
return package_to_validate;
31452999
}
31463000

src/node/txdownloadman.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ struct TxDownloadOptions {
4141
const CTxMemPool& m_mempool;
4242
/** RNG provided by caller. */
4343
FastRandomContext& m_rng;
44+
/** Maximum number of transactions allowed in orphanage. */
45+
const uint32_t m_max_orphan_txs;
4446
};
4547
struct TxDownloadConnectionInfo {
4648
/** Whether this peer is preferred for transaction download. */
@@ -64,6 +66,8 @@ struct PackageToValidate {
6466

6567
// Move ctor
6668
PackageToValidate(PackageToValidate&& other) : m_txns{std::move(other.m_txns)}, m_senders{std::move(other.m_senders)} {}
69+
// Copy ctor
70+
PackageToValidate(const PackageToValidate& other) = default;
6771

6872
// Move assignment
6973
PackageToValidate& operator=(PackageToValidate&& other) {
@@ -83,6 +87,13 @@ struct PackageToValidate {
8387
m_senders.back());
8488
}
8589
};
90+
struct RejectedTxTodo
91+
{
92+
bool m_should_add_extra_compact_tx;
93+
std::vector<uint256> m_unique_parents;
94+
std::optional<PackageToValidate> m_package_to_validate;
95+
};
96+
8697

8798
/**
8899
* Class responsible for deciding what transactions to request and, once
@@ -114,7 +125,6 @@ class TxDownloadManager {
114125
// temporary and removed later once logic has been moved internally.
115126
TxOrphanage& GetOrphanageRef();
116127
TxRequestTracker& GetTxRequestRef();
117-
CRollingBloomFilter& RecentRejectsFilter();
118128
CRollingBloomFilter& RecentRejectsReconsiderableFilter();
119129

120130
// Responses to chain events. TxDownloadManager is not an actual client of ValidationInterface, these are called through PeerManager.
@@ -155,6 +165,9 @@ class TxDownloadManager {
155165

156166
/** Respond to successful transaction submission to mempool */
157167
void MempoolAcceptedTx(const CTransactionRef& tx);
168+
169+
/** Respond to transaction rejected from mempool */
170+
RejectedTxTodo MempoolRejectedTx(const CTransactionRef& ptx, const TxValidationState& state, NodeId nodeid, bool first_time_failure);
158171
};
159172
} // namespace node
160173
#endif // BITCOIN_NODE_TXDOWNLOADMAN_H

0 commit comments

Comments
 (0)