Skip to content

Commit 416fbc9

Browse files
committed
[refactor] move new orphan handling to ProcessInvalidTx
1 parent c8e67b9 commit 416fbc9

File tree

1 file changed

+81
-78
lines changed

1 file changed

+81
-78
lines changed

src/net_processing.cpp

Lines changed: 81 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -3006,8 +3006,11 @@ void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx
30063006
AssertLockHeld(g_msgproc_mutex);
30073007
AssertLockHeld(m_tx_download_mutex);
30083008

3009+
PeerRef peer{GetPeerRef(nodeid)};
3010+
30093011
auto& m_orphanage = m_txdownloadman.GetOrphanageRef();
30103012
auto& m_txrequest = m_txdownloadman.GetTxRequestRef();
3013+
const CTransaction& tx{*ptx};
30113014

30123015
LogDebug(BCLog::MEMPOOLREJ, "%s (wtxid=%s) from peer=%d was not accepted: %s\n",
30133016
ptx->GetHash().ToString(),
@@ -3016,6 +3019,84 @@ void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx
30163019
state.ToString());
30173020

30183021
if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
3022+
// Only process a new orphan if this is a first time failure, as otherwise it must be either
3023+
// already in orphanage or from 1p1c processing.
3024+
if (first_time_failure) {
3025+
bool fRejectedParents = false; // It may be the case that the orphans parents have all been rejected
3026+
3027+
// Deduplicate parent txids, so that we don't have to loop over
3028+
// the same parent txid more than once down below.
3029+
std::vector<uint256> unique_parents;
3030+
unique_parents.reserve(tx.vin.size());
3031+
for (const CTxIn& txin : tx.vin) {
3032+
// We start with all parents, and then remove duplicates below.
3033+
unique_parents.push_back(txin.prevout.hash);
3034+
}
3035+
std::sort(unique_parents.begin(), unique_parents.end());
3036+
unique_parents.erase(std::unique(unique_parents.begin(), unique_parents.end()), unique_parents.end());
3037+
3038+
// Distinguish between parents in m_lazy_recent_rejects and m_lazy_recent_rejects_reconsiderable.
3039+
// We can tolerate having up to 1 parent in m_lazy_recent_rejects_reconsiderable since we
3040+
// submit 1p1c packages. However, fail immediately if any are in m_lazy_recent_rejects.
3041+
std::optional<uint256> rejected_parent_reconsiderable;
3042+
for (const uint256& parent_txid : unique_parents) {
3043+
if (RecentRejectsFilter().contains(parent_txid)) {
3044+
fRejectedParents = true;
3045+
break;
3046+
} else if (RecentRejectsReconsiderableFilter().contains(parent_txid) && !m_mempool.exists(GenTxid::Txid(parent_txid))) {
3047+
// More than 1 parent in m_lazy_recent_rejects_reconsiderable: 1p1c will not be
3048+
// sufficient to accept this package, so just give up here.
3049+
if (rejected_parent_reconsiderable.has_value()) {
3050+
fRejectedParents = true;
3051+
break;
3052+
}
3053+
rejected_parent_reconsiderable = parent_txid;
3054+
}
3055+
}
3056+
if (!fRejectedParents) {
3057+
const auto current_time{GetTime<std::chrono::microseconds>()};
3058+
3059+
for (const uint256& parent_txid : unique_parents) {
3060+
// Here, we only have the txid (and not wtxid) of the
3061+
// inputs, so we only request in txid mode, even for
3062+
// wtxidrelay peers.
3063+
// Eventually we should replace this with an improved
3064+
// protocol for getting all unconfirmed parents.
3065+
const auto gtxid{GenTxid::Txid(parent_txid)};
3066+
if (peer) AddKnownTx(*peer, parent_txid);
3067+
// Exclude m_lazy_recent_rejects_reconsiderable: the missing parent may have been
3068+
// previously rejected for being too low feerate. This orphan might CPFP it.
3069+
if (!m_txdownloadman.AlreadyHaveTx(gtxid, /*include_reconsiderable=*/false)) {
3070+
m_txdownloadman.AddTxAnnouncement(nodeid, gtxid, current_time, /*p2p_inv=*/false);
3071+
}
3072+
}
3073+
3074+
if (m_orphanage.AddTx(ptx, nodeid)) {
3075+
AddToCompactExtraTransactions(ptx);
3076+
}
3077+
3078+
// Once added to the orphan pool, a tx is considered AlreadyHave, and we shouldn't request it anymore.
3079+
m_txrequest.ForgetTxHash(tx.GetHash());
3080+
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
3081+
3082+
// DoS prevention: do not allow m_orphanage to grow unbounded (see CVE-2012-3789)
3083+
m_orphanage.LimitOrphans(m_opts.max_orphan_txs, m_rng);
3084+
} else {
3085+
LogDebug(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s (wtxid=%s)\n",
3086+
tx.GetHash().ToString(),
3087+
tx.GetWitnessHash().ToString());
3088+
// We will continue to reject this tx since it has rejected
3089+
// parents so avoid re-requesting it from other peers.
3090+
// Here we add both the txid and the wtxid, as we know that
3091+
// regardless of what witness is provided, we will not accept
3092+
// this, so we don't need to allow for redownload of this txid
3093+
// from any of our non-wtxidrelay peers.
3094+
RecentRejectsFilter().insert(tx.GetHash().ToUint256());
3095+
RecentRejectsFilter().insert(tx.GetWitnessHash().ToUint256());
3096+
m_txrequest.ForgetTxHash(tx.GetHash());
3097+
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
3098+
}
3099+
}
30193100
return;
30203101
} else if (state.GetResult() != TxValidationResult::TX_WITNESS_STRIPPED) {
30213102
// We can add the wtxid of this transaction to our reject filter.
@@ -4375,7 +4456,6 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
43754456
LOCK2(cs_main, m_tx_download_mutex);
43764457

43774458
auto& m_txrequest = m_txdownloadman.GetTxRequestRef();
4378-
auto& m_orphanage = m_txdownloadman.GetOrphanageRef();
43794459

43804460
m_txrequest.ReceivedResponse(pfrom.GetId(), txid);
43814461
if (tx.HasWitness()) m_txrequest.ReceivedResponse(pfrom.GetId(), wtxid);
@@ -4445,83 +4525,6 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
44454525
ProcessValidTx(pfrom.GetId(), ptx, result.m_replaced_transactions);
44464526
pfrom.m_last_tx_time = GetTime<std::chrono::seconds>();
44474527
}
4448-
else if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS)
4449-
{
4450-
bool fRejectedParents = false; // It may be the case that the orphans parents have all been rejected
4451-
4452-
// Deduplicate parent txids, so that we don't have to loop over
4453-
// the same parent txid more than once down below.
4454-
std::vector<uint256> unique_parents;
4455-
unique_parents.reserve(tx.vin.size());
4456-
for (const CTxIn& txin : tx.vin) {
4457-
// We start with all parents, and then remove duplicates below.
4458-
unique_parents.push_back(txin.prevout.hash);
4459-
}
4460-
std::sort(unique_parents.begin(), unique_parents.end());
4461-
unique_parents.erase(std::unique(unique_parents.begin(), unique_parents.end()), unique_parents.end());
4462-
4463-
// Distinguish between parents in m_lazy_recent_rejects and m_lazy_recent_rejects_reconsiderable.
4464-
// We can tolerate having up to 1 parent in m_lazy_recent_rejects_reconsiderable since we
4465-
// submit 1p1c packages. However, fail immediately if any are in m_lazy_recent_rejects.
4466-
std::optional<uint256> rejected_parent_reconsiderable;
4467-
for (const uint256& parent_txid : unique_parents) {
4468-
if (RecentRejectsFilter().contains(parent_txid)) {
4469-
fRejectedParents = true;
4470-
break;
4471-
} else if (RecentRejectsReconsiderableFilter().contains(parent_txid) && !m_mempool.exists(GenTxid::Txid(parent_txid))) {
4472-
// More than 1 parent in m_lazy_recent_rejects_reconsiderable: 1p1c will not be
4473-
// sufficient to accept this package, so just give up here.
4474-
if (rejected_parent_reconsiderable.has_value()) {
4475-
fRejectedParents = true;
4476-
break;
4477-
}
4478-
rejected_parent_reconsiderable = parent_txid;
4479-
}
4480-
}
4481-
if (!fRejectedParents) {
4482-
const auto current_time{GetTime<std::chrono::microseconds>()};
4483-
4484-
for (const uint256& parent_txid : unique_parents) {
4485-
// Here, we only have the txid (and not wtxid) of the
4486-
// inputs, so we only request in txid mode, even for
4487-
// wtxidrelay peers.
4488-
// Eventually we should replace this with an improved
4489-
// protocol for getting all unconfirmed parents.
4490-
const auto gtxid{GenTxid::Txid(parent_txid)};
4491-
AddKnownTx(*peer, parent_txid);
4492-
// Exclude m_lazy_recent_rejects_reconsiderable: the missing parent may have been
4493-
// previously rejected for being too low feerate. This orphan might CPFP it.
4494-
if (!m_txdownloadman.AlreadyHaveTx(gtxid, /*include_reconsiderable=*/false)) {
4495-
m_txdownloadman.AddTxAnnouncement(pfrom.GetId(), gtxid, current_time, /*p2p_inv=*/false);
4496-
}
4497-
}
4498-
4499-
if (m_orphanage.AddTx(ptx, pfrom.GetId())) {
4500-
AddToCompactExtraTransactions(ptx);
4501-
}
4502-
4503-
// Once added to the orphan pool, a tx is considered AlreadyHave, and we shouldn't request it anymore.
4504-
m_txrequest.ForgetTxHash(tx.GetHash());
4505-
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
4506-
4507-
// DoS prevention: do not allow m_orphanage to grow unbounded (see CVE-2012-3789)
4508-
m_orphanage.LimitOrphans(m_opts.max_orphan_txs, m_rng);
4509-
} else {
4510-
LogDebug(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s (wtxid=%s)\n",
4511-
tx.GetHash().ToString(),
4512-
tx.GetWitnessHash().ToString());
4513-
// We will continue to reject this tx since it has rejected
4514-
// parents so avoid re-requesting it from other peers.
4515-
// Here we add both the txid and the wtxid, as we know that
4516-
// regardless of what witness is provided, we will not accept
4517-
// this, so we don't need to allow for redownload of this txid
4518-
// from any of our non-wtxidrelay peers.
4519-
RecentRejectsFilter().insert(tx.GetHash().ToUint256());
4520-
RecentRejectsFilter().insert(tx.GetWitnessHash().ToUint256());
4521-
m_txrequest.ForgetTxHash(tx.GetHash());
4522-
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
4523-
}
4524-
}
45254528
if (state.IsInvalid()) {
45264529
ProcessInvalidTx(pfrom.GetId(), ptx, state, /*first_time_failure=*/true);
45274530
}

0 commit comments

Comments
 (0)