Skip to content

Commit 264ca9d

Browse files
committed
Merge bitcoin/bitcoin#29619: refactor: consolidate MempoolAcceptResult processing
07cd510 [refactor] consolidate invalid MempoolAcceptResult processing (glozow) 9353aa4 [refactor] consolidate valid MempoolAcceptResult processing (glozow) Pull request description: Every time we try to `ProcessTransaction` (i.e. submit a tx to mempool), we use the result to update a few net processing data structures. For example, after a failure, the {wtxid, txid, both, neither} (depending on reason) should be cached in `m_recent_rejects` so we don't try to download/validate it again. There are 2 current places and at least 1 future place where we need to process `MempoolAcceptResult`: - In the `ProcessMessage` logic after receiving and validating a tx - In `ProcessOrphanTx` where we retry orphans - With #28970, after processing a package of transactions, we should do these updates for each tx in the package. Consolidate this code so it isn't repeated in 2 places and so we can reuse it in a future PR. ACKs for top commit: instagibbs: ACK 07cd510 achow101: ACK 07cd510 dergoegge: Code review ACK 07cd510 TheCharlatan: ACK 07cd510 Tree-SHA512: c4e74cb65e4f52882fca52e6682efa5dcf1562d98418454e09be256ffd026caae642a90aa5b9cccaae214be240d6f4be9d87b516953b2ee69a655f16ea569ed9
2 parents 0ed2c13 + 07cd510 commit 264ca9d

File tree

1 file changed

+115
-114
lines changed

1 file changed

+115
-114
lines changed

src/net_processing.cpp

Lines changed: 115 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,20 @@ class PeerManagerImpl final : public PeerManager
582582
*/
583583
bool MaybeDiscourageAndDisconnect(CNode& pnode, Peer& peer);
584584

585+
/** Handle a transaction whose result was not MempoolAcceptResult::ResultType::VALID.
586+
* @param[in] maybe_add_extra_compact_tx Whether this tx should be added to vExtraTxnForCompact.
587+
* Set to false if the tx has already been rejected before,
588+
* e.g. is an orphan, to avoid adding duplicate entries.
589+
* Updates m_txrequest, m_recent_rejects, m_orphanage, and vExtraTxnForCompact. */
590+
void ProcessInvalidTx(NodeId nodeid, const CTransactionRef& tx, const TxValidationState& result,
591+
bool maybe_add_extra_compact_tx)
592+
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, cs_main);
593+
594+
/** Handle a transaction whose result was MempoolAcceptResult::ResultType::VALID.
595+
* Updates m_txrequest, m_orphanage, and vExtraTxnForCompact. Also queues the tx for relay. */
596+
void ProcessValidTx(NodeId nodeid, const CTransactionRef& tx, const std::list<CTransactionRef>& replaced_transactions)
597+
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, g_msgproc_mutex, cs_main);
598+
585599
/**
586600
* Reconsider orphan transactions after a parent has been accepted to the mempool.
587601
*
@@ -3054,6 +3068,91 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
30543068
return;
30553069
}
30563070

3071+
void PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx, const TxValidationState& state,
3072+
bool maybe_add_extra_compact_tx)
3073+
{
3074+
AssertLockNotHeld(m_peer_mutex);
3075+
AssertLockHeld(g_msgproc_mutex);
3076+
AssertLockHeld(cs_main);
3077+
3078+
LogDebug(BCLog::MEMPOOLREJ, "%s (wtxid=%s) from peer=%d was not accepted: %s\n",
3079+
ptx->GetHash().ToString(),
3080+
ptx->GetWitnessHash().ToString(),
3081+
nodeid,
3082+
state.ToString());
3083+
3084+
if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
3085+
return;
3086+
} else if (state.GetResult() != TxValidationResult::TX_WITNESS_STRIPPED) {
3087+
// We can add the wtxid of this transaction to our reject filter.
3088+
// Do not add txids of witness transactions or witness-stripped
3089+
// transactions to the filter, as they can have been malleated;
3090+
// adding such txids to the reject filter would potentially
3091+
// interfere with relay of valid transactions from peers that
3092+
// do not support wtxid-based relay. See
3093+
// https://github.com/bitcoin/bitcoin/issues/8279 for details.
3094+
// We can remove this restriction (and always add wtxids to
3095+
// the filter even for witness stripped transactions) once
3096+
// wtxid-based relay is broadly deployed.
3097+
// See also comments in https://github.com/bitcoin/bitcoin/pull/18044#discussion_r443419034
3098+
// for concerns around weakening security of unupgraded nodes
3099+
// if we start doing this too early.
3100+
m_recent_rejects.insert(ptx->GetWitnessHash().ToUint256());
3101+
m_txrequest.ForgetTxHash(ptx->GetWitnessHash());
3102+
// If the transaction failed for TX_INPUTS_NOT_STANDARD,
3103+
// then we know that the witness was irrelevant to the policy
3104+
// failure, since this check depends only on the txid
3105+
// (the scriptPubKey being spent is covered by the txid).
3106+
// Add the txid to the reject filter to prevent repeated
3107+
// processing of this transaction in the event that child
3108+
// transactions are later received (resulting in
3109+
// parent-fetching by txid via the orphan-handling logic).
3110+
if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && ptx->HasWitness()) {
3111+
m_recent_rejects.insert(ptx->GetHash().ToUint256());
3112+
m_txrequest.ForgetTxHash(ptx->GetHash());
3113+
}
3114+
if (maybe_add_extra_compact_tx && RecursiveDynamicUsage(*ptx) < 100000) {
3115+
AddToCompactExtraTransactions(ptx);
3116+
}
3117+
}
3118+
3119+
MaybePunishNodeForTx(nodeid, state);
3120+
3121+
// If the tx failed in ProcessOrphanTx, it should be removed from the orphanage unless the
3122+
// tx was still missing inputs. If the tx was not in the orphanage, EraseTx does nothing and returns 0.
3123+
if (Assume(state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) && m_orphanage.EraseTx(ptx->GetHash()) > 0) {
3124+
LogDebug(BCLog::TXPACKAGES, " removed orphan tx %s (wtxid=%s)\n", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString());
3125+
}
3126+
}
3127+
3128+
void PeerManagerImpl::ProcessValidTx(NodeId nodeid, const CTransactionRef& tx, const std::list<CTransactionRef>& replaced_transactions)
3129+
{
3130+
AssertLockNotHeld(m_peer_mutex);
3131+
AssertLockHeld(g_msgproc_mutex);
3132+
AssertLockHeld(cs_main);
3133+
3134+
// As this version of the transaction was acceptable, we can forget about any requests for it.
3135+
// No-op if the tx is not in txrequest.
3136+
m_txrequest.ForgetTxHash(tx->GetHash());
3137+
m_txrequest.ForgetTxHash(tx->GetWitnessHash());
3138+
3139+
m_orphanage.AddChildrenToWorkSet(*tx);
3140+
// If it came from the orphanage, remove it. No-op if the tx is not in txorphanage.
3141+
m_orphanage.EraseTx(tx->GetHash());
3142+
3143+
LogDebug(BCLog::MEMPOOL, "AcceptToMemoryPool: peer=%d: accepted %s (wtxid=%s) (poolsz %u txn, %u kB)\n",
3144+
nodeid,
3145+
tx->GetHash().ToString(),
3146+
tx->GetWitnessHash().ToString(),
3147+
m_mempool.size(), m_mempool.DynamicMemoryUsage() / 1000);
3148+
3149+
RelayTransaction(tx->GetHash(), tx->GetWitnessHash());
3150+
3151+
for (const CTransactionRef& removedTx : replaced_transactions) {
3152+
AddToCompactExtraTransactions(removedTx);
3153+
}
3154+
}
3155+
30573156
bool PeerManagerImpl::ProcessOrphanTx(Peer& peer)
30583157
{
30593158
AssertLockHeld(g_msgproc_mutex);
@@ -3069,66 +3168,23 @@ bool PeerManagerImpl::ProcessOrphanTx(Peer& peer)
30693168

30703169
if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
30713170
LogPrint(BCLog::TXPACKAGES, " accepted orphan tx %s (wtxid=%s)\n", orphanHash.ToString(), orphan_wtxid.ToString());
3072-
LogPrint(BCLog::MEMPOOL, "AcceptToMemoryPool: peer=%d: accepted %s (wtxid=%s) (poolsz %u txn, %u kB)\n",
3073-
peer.m_id,
3074-
orphanHash.ToString(),
3075-
orphan_wtxid.ToString(),
3076-
m_mempool.size(), m_mempool.DynamicMemoryUsage() / 1000);
3077-
RelayTransaction(orphanHash, porphanTx->GetWitnessHash());
3078-
m_orphanage.AddChildrenToWorkSet(*porphanTx);
3079-
m_orphanage.EraseTx(orphanHash);
3080-
for (const CTransactionRef& removedTx : result.m_replaced_transactions.value()) {
3081-
AddToCompactExtraTransactions(removedTx);
3082-
}
3171+
Assume(result.m_replaced_transactions.has_value());
3172+
std::list<CTransactionRef> empty_replacement_list;
3173+
ProcessValidTx(peer.m_id, porphanTx, result.m_replaced_transactions.value_or(empty_replacement_list));
30833174
return true;
30843175
} else if (state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) {
3085-
if (state.IsInvalid()) {
3086-
LogPrint(BCLog::TXPACKAGES, " invalid orphan tx %s (wtxid=%s) from peer=%d. %s\n",
3087-
orphanHash.ToString(),
3088-
orphan_wtxid.ToString(),
3089-
peer.m_id,
3090-
state.ToString());
3091-
LogPrint(BCLog::MEMPOOLREJ, "%s (wtxid=%s) from peer=%d was not accepted: %s\n",
3092-
orphanHash.ToString(),
3093-
orphan_wtxid.ToString(),
3094-
peer.m_id,
3095-
state.ToString());
3096-
// Maybe punish peer that gave us an invalid orphan tx
3097-
MaybePunishNodeForTx(peer.m_id, state);
3098-
}
3099-
// Has inputs but not accepted to mempool
3100-
// Probably non-standard or insufficient fee
3101-
LogPrint(BCLog::TXPACKAGES, " removed orphan tx %s (wtxid=%s)\n", orphanHash.ToString(), orphan_wtxid.ToString());
3102-
if (state.GetResult() != TxValidationResult::TX_WITNESS_STRIPPED) {
3103-
// We can add the wtxid of this transaction to our reject filter.
3104-
// Do not add txids of witness transactions or witness-stripped
3105-
// transactions to the filter, as they can have been malleated;
3106-
// adding such txids to the reject filter would potentially
3107-
// interfere with relay of valid transactions from peers that
3108-
// do not support wtxid-based relay. See
3109-
// https://github.com/bitcoin/bitcoin/issues/8279 for details.
3110-
// We can remove this restriction (and always add wtxids to
3111-
// the filter even for witness stripped transactions) once
3112-
// wtxid-based relay is broadly deployed.
3113-
// See also comments in https://github.com/bitcoin/bitcoin/pull/18044#discussion_r443419034
3114-
// for concerns around weakening security of unupgraded nodes
3115-
// if we start doing this too early.
3116-
m_recent_rejects.insert(porphanTx->GetWitnessHash().ToUint256());
3117-
// If the transaction failed for TX_INPUTS_NOT_STANDARD,
3118-
// then we know that the witness was irrelevant to the policy
3119-
// failure, since this check depends only on the txid
3120-
// (the scriptPubKey being spent is covered by the txid).
3121-
// Add the txid to the reject filter to prevent repeated
3122-
// processing of this transaction in the event that child
3123-
// transactions are later received (resulting in
3124-
// parent-fetching by txid via the orphan-handling logic).
3125-
if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && porphanTx->HasWitness()) {
3126-
// We only add the txid if it differs from the wtxid, to
3127-
// avoid wasting entries in the rolling bloom filter.
3128-
m_recent_rejects.insert(porphanTx->GetHash().ToUint256());
3129-
}
3176+
LogPrint(BCLog::TXPACKAGES, " invalid orphan tx %s (wtxid=%s) from peer=%d. %s\n",
3177+
orphanHash.ToString(),
3178+
orphan_wtxid.ToString(),
3179+
peer.m_id,
3180+
state.ToString());
3181+
3182+
if (Assume(state.IsInvalid() &&
3183+
state.GetResult() != TxValidationResult::TX_UNKNOWN &&
3184+
state.GetResult() != TxValidationResult::TX_NO_MEMPOOL &&
3185+
state.GetResult() != TxValidationResult::TX_RESULT_UNSET)) {
3186+
ProcessInvalidTx(peer.m_id, porphanTx, state, /*maybe_add_extra_compact_tx=*/false);
31303187
}
3131-
m_orphanage.EraseTx(orphanHash);
31323188
return true;
31333189
}
31343190
}
@@ -4298,24 +4354,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
42984354
const TxValidationState& state = result.m_state;
42994355

43004356
if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
4301-
// As this version of the transaction was acceptable, we can forget about any
4302-
// requests for it.
4303-
m_txrequest.ForgetTxHash(tx.GetHash());
4304-
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
4305-
RelayTransaction(tx.GetHash(), tx.GetWitnessHash());
4306-
m_orphanage.AddChildrenToWorkSet(tx);
4307-
4357+
ProcessValidTx(pfrom.GetId(), ptx, result.m_replaced_transactions.value());
43084358
pfrom.m_last_tx_time = GetTime<std::chrono::seconds>();
4309-
4310-
LogPrint(BCLog::MEMPOOL, "AcceptToMemoryPool: peer=%d: accepted %s (wtxid=%s) (poolsz %u txn, %u kB)\n",
4311-
pfrom.GetId(),
4312-
tx.GetHash().ToString(),
4313-
tx.GetWitnessHash().ToString(),
4314-
m_mempool.size(), m_mempool.DynamicMemoryUsage() / 1000);
4315-
4316-
for (const CTransactionRef& removedTx : result.m_replaced_transactions.value()) {
4317-
AddToCompactExtraTransactions(removedTx);
4318-
}
43194359
}
43204360
else if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS)
43214361
{
@@ -4376,48 +4416,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
43764416
m_txrequest.ForgetTxHash(tx.GetHash());
43774417
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
43784418
}
4379-
} else {
4380-
if (state.GetResult() != TxValidationResult::TX_WITNESS_STRIPPED) {
4381-
// We can add the wtxid of this transaction to our reject filter.
4382-
// Do not add txids of witness transactions or witness-stripped
4383-
// transactions to the filter, as they can have been malleated;
4384-
// adding such txids to the reject filter would potentially
4385-
// interfere with relay of valid transactions from peers that
4386-
// do not support wtxid-based relay. See
4387-
// https://github.com/bitcoin/bitcoin/issues/8279 for details.
4388-
// We can remove this restriction (and always add wtxids to
4389-
// the filter even for witness stripped transactions) once
4390-
// wtxid-based relay is broadly deployed.
4391-
// See also comments in https://github.com/bitcoin/bitcoin/pull/18044#discussion_r443419034
4392-
// for concerns around weakening security of unupgraded nodes
4393-
// if we start doing this too early.
4394-
m_recent_rejects.insert(tx.GetWitnessHash().ToUint256());
4395-
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
4396-
// If the transaction failed for TX_INPUTS_NOT_STANDARD,
4397-
// then we know that the witness was irrelevant to the policy
4398-
// failure, since this check depends only on the txid
4399-
// (the scriptPubKey being spent is covered by the txid).
4400-
// Add the txid to the reject filter to prevent repeated
4401-
// processing of this transaction in the event that child
4402-
// transactions are later received (resulting in
4403-
// parent-fetching by txid via the orphan-handling logic).
4404-
if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && tx.HasWitness()) {
4405-
m_recent_rejects.insert(tx.GetHash().ToUint256());
4406-
m_txrequest.ForgetTxHash(tx.GetHash());
4407-
}
4408-
if (RecursiveDynamicUsage(*ptx) < 100000) {
4409-
AddToCompactExtraTransactions(ptx);
4410-
}
4411-
}
44124419
}
4413-
44144420
if (state.IsInvalid()) {
4415-
LogPrint(BCLog::MEMPOOLREJ, "%s (wtxid=%s) from peer=%d was not accepted: %s\n",
4416-
tx.GetHash().ToString(),
4417-
tx.GetWitnessHash().ToString(),
4418-
pfrom.GetId(),
4419-
state.ToString());
4420-
MaybePunishNodeForTx(pfrom.GetId(), state);
4421+
ProcessInvalidTx(pfrom.GetId(), ptx, state, /*maybe_add_extra_compact_tx=*/true);
44214422
}
44224423
return;
44234424
}

0 commit comments

Comments
 (0)