@@ -1713,6 +1713,67 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
1713
1713
return true ;
1714
1714
}
1715
1715
1716
+ void static ProcessOrphanTx (CConnman* connman, std::set<uint256>& orphan_work_set, std::list<CTransactionRef>& removed_txn) EXCLUSIVE_LOCKS_REQUIRED(cs_main, g_cs_orphans)
1717
+ {
1718
+ AssertLockHeld (cs_main);
1719
+ AssertLockHeld (g_cs_orphans);
1720
+ std::set<NodeId> setMisbehaving;
1721
+ bool done = false ;
1722
+ while (!done && !orphan_work_set.empty ()) {
1723
+ const uint256 orphanHash = *orphan_work_set.begin ();
1724
+ orphan_work_set.erase (orphan_work_set.begin ());
1725
+
1726
+ auto orphan_it = mapOrphanTransactions.find (orphanHash);
1727
+ if (orphan_it == mapOrphanTransactions.end ()) continue ;
1728
+
1729
+ const CTransactionRef porphanTx = orphan_it->second .tx ;
1730
+ const CTransaction& orphanTx = *porphanTx;
1731
+ NodeId fromPeer = orphan_it->second .fromPeer ;
1732
+ bool fMissingInputs2 = false ;
1733
+ // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan
1734
+ // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get
1735
+ // anyone relaying LegitTxX banned)
1736
+ CValidationState stateDummy;
1737
+
1738
+ if (setMisbehaving.count (fromPeer)) continue ;
1739
+ if (AcceptToMemoryPool (mempool, stateDummy, porphanTx, &fMissingInputs2 , &removed_txn, false /* bypass_limits */ , 0 /* nAbsurdFee */ )) {
1740
+ LogPrint (BCLog::MEMPOOL, " accepted orphan tx %s\n " , orphanHash.ToString ());
1741
+ RelayTransaction (orphanTx, connman);
1742
+ for (unsigned int i = 0 ; i < orphanTx.vout .size (); i++) {
1743
+ auto it_by_prev = mapOrphanTransactionsByPrev.find (COutPoint (orphanHash, i));
1744
+ if (it_by_prev != mapOrphanTransactionsByPrev.end ()) {
1745
+ for (const auto & elem : it_by_prev->second ) {
1746
+ orphan_work_set.insert (elem->first );
1747
+ }
1748
+ }
1749
+ }
1750
+ EraseOrphanTx (orphanHash);
1751
+ done = true ;
1752
+ } else if (!fMissingInputs2 ) {
1753
+ int nDos = 0 ;
1754
+ if (stateDummy.IsInvalid (nDos) && nDos > 0 ) {
1755
+ // Punish peer that gave us an invalid orphan tx
1756
+ Misbehaving (fromPeer, nDos);
1757
+ setMisbehaving.insert (fromPeer);
1758
+ LogPrint (BCLog::MEMPOOL, " invalid orphan tx %s\n " , orphanHash.ToString ());
1759
+ }
1760
+ // Has inputs but not accepted to mempool
1761
+ // Probably non-standard or insufficient fee
1762
+ LogPrint (BCLog::MEMPOOL, " removed orphan tx %s\n " , orphanHash.ToString ());
1763
+ if (!orphanTx.HasWitness () && !stateDummy.CorruptionPossible ()) {
1764
+ // Do not use rejection cache for witness transactions or
1765
+ // witness-stripped transactions, as they can have been malleated.
1766
+ // See https://github.com/bitcoin/bitcoin/issues/8279 for details.
1767
+ assert (recentRejects);
1768
+ recentRejects->insert (orphanHash);
1769
+ }
1770
+ EraseOrphanTx (orphanHash);
1771
+ done = true ;
1772
+ }
1773
+ mempool.check (pcoinsTip.get ());
1774
+ }
1775
+ }
1776
+
1716
1777
bool static ProcessMessage (CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool >& interruptMsgProc, bool enable_bip61)
1717
1778
{
1718
1779
LogPrint (BCLog::NET, " received: %s (%u bytes) peer=%d\n " , SanitizeString (strCommand), vRecv.size (), pfrom->GetId ());
@@ -2342,8 +2403,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
2342
2403
return true ;
2343
2404
}
2344
2405
2345
- std::deque<COutPoint> vWorkQueue;
2346
- std::vector<uint256> vEraseQueue;
2347
2406
CTransactionRef ptx;
2348
2407
vRecv >> ptx;
2349
2408
const CTransaction& tx = *ptx;
@@ -2368,7 +2427,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
2368
2427
mempool.check (pcoinsTip.get ());
2369
2428
RelayTransaction (tx, connman);
2370
2429
for (unsigned int i = 0 ; i < tx.vout .size (); i++) {
2371
- vWorkQueue.emplace_back (inv.hash , i);
2430
+ auto it_by_prev = mapOrphanTransactionsByPrev.find (COutPoint (inv.hash , i));
2431
+ if (it_by_prev != mapOrphanTransactionsByPrev.end ()) {
2432
+ for (const auto & elem : it_by_prev->second ) {
2433
+ pfrom->orphan_work_set .insert (elem->first );
2434
+ }
2435
+ }
2372
2436
}
2373
2437
2374
2438
pfrom->nLastTXTime = GetTime ();
@@ -2379,65 +2443,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
2379
2443
mempool.size (), mempool.DynamicMemoryUsage () / 1000 );
2380
2444
2381
2445
// Recursively process any orphan transactions that depended on this one
2382
- std::set<NodeId> setMisbehaving;
2383
- while (!vWorkQueue.empty ()) {
2384
- auto itByPrev = mapOrphanTransactionsByPrev.find (vWorkQueue.front ());
2385
- vWorkQueue.pop_front ();
2386
- if (itByPrev == mapOrphanTransactionsByPrev.end ())
2387
- continue ;
2388
- for (auto mi = itByPrev->second .begin ();
2389
- mi != itByPrev->second .end ();
2390
- ++mi)
2391
- {
2392
- const CTransactionRef& porphanTx = (*mi)->second .tx ;
2393
- const CTransaction& orphanTx = *porphanTx;
2394
- const uint256& orphanHash = orphanTx.GetHash ();
2395
- NodeId fromPeer = (*mi)->second .fromPeer ;
2396
- bool fMissingInputs2 = false ;
2397
- // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan
2398
- // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get
2399
- // anyone relaying LegitTxX banned)
2400
- CValidationState stateDummy;
2401
-
2402
-
2403
- if (setMisbehaving.count (fromPeer))
2404
- continue ;
2405
- if (AcceptToMemoryPool (mempool, stateDummy, porphanTx, &fMissingInputs2 , &lRemovedTxn, false /* bypass_limits */ , 0 /* nAbsurdFee */ )) {
2406
- LogPrint (BCLog::MEMPOOL, " accepted orphan tx %s\n " , orphanHash.ToString ());
2407
- RelayTransaction (orphanTx, connman);
2408
- for (unsigned int i = 0 ; i < orphanTx.vout .size (); i++) {
2409
- vWorkQueue.emplace_back (orphanHash, i);
2410
- }
2411
- vEraseQueue.push_back (orphanHash);
2412
- }
2413
- else if (!fMissingInputs2 )
2414
- {
2415
- int nDos = 0 ;
2416
- if (stateDummy.IsInvalid (nDos) && nDos > 0 )
2417
- {
2418
- // Punish peer that gave us an invalid orphan tx
2419
- Misbehaving (fromPeer, nDos);
2420
- setMisbehaving.insert (fromPeer);
2421
- LogPrint (BCLog::MEMPOOL, " invalid orphan tx %s\n " , orphanHash.ToString ());
2422
- }
2423
- // Has inputs but not accepted to mempool
2424
- // Probably non-standard or insufficient fee
2425
- LogPrint (BCLog::MEMPOOL, " removed orphan tx %s\n " , orphanHash.ToString ());
2426
- vEraseQueue.push_back (orphanHash);
2427
- if (!orphanTx.HasWitness () && !stateDummy.CorruptionPossible ()) {
2428
- // Do not use rejection cache for witness transactions or
2429
- // witness-stripped transactions, as they can have been malleated.
2430
- // See https://github.com/bitcoin/bitcoin/issues/8279 for details.
2431
- assert (recentRejects);
2432
- recentRejects->insert (orphanHash);
2433
- }
2434
- }
2435
- mempool.check (pcoinsTip.get ());
2436
- }
2437
- }
2438
-
2439
- for (const uint256& hash : vEraseQueue)
2440
- EraseOrphanTx (hash);
2446
+ ProcessOrphanTx (connman, pfrom->orphan_work_set , lRemovedTxn);
2441
2447
}
2442
2448
else if (fMissingInputs )
2443
2449
{
@@ -3169,11 +3175,21 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
3169
3175
if (!pfrom->vRecvGetData .empty ())
3170
3176
ProcessGetData (pfrom, chainparams, connman, interruptMsgProc);
3171
3177
3178
+ if (!pfrom->orphan_work_set .empty ()) {
3179
+ std::list<CTransactionRef> removed_txn;
3180
+ LOCK2 (cs_main, g_cs_orphans);
3181
+ ProcessOrphanTx (connman, pfrom->orphan_work_set , removed_txn);
3182
+ for (const CTransactionRef& removedTx : removed_txn) {
3183
+ AddToCompactExtraTransactions (removedTx);
3184
+ }
3185
+ }
3186
+
3172
3187
if (pfrom->fDisconnect )
3173
3188
return false ;
3174
3189
3175
3190
// this maintains the order of responses
3176
3191
if (!pfrom->vRecvGetData .empty ()) return true ;
3192
+ if (!pfrom->orphan_work_set .empty ()) return true ;
3177
3193
3178
3194
// Don't bother if send buffer is too full to respond anyway
3179
3195
if (pfrom->fPauseSend )
0 commit comments