@@ -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+
30573156bool 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