Skip to content

Commit 6bd4963

Browse files
committed
txorphanage: Move functions and data into class
Collects all the orphan handling globals into a single member var in net_processing, and ensures access is encapuslated into the interface functions. Also adds doxygen comments for methods.
1 parent 03257b8 commit 6bd4963

File tree

5 files changed

+106
-96
lines changed

5 files changed

+106
-96
lines changed

src/net_processing.cpp

+15-31
Original file line numberDiff line numberDiff line change
@@ -457,11 +457,12 @@ class PeerManagerImpl final : public PeerManager
457457
/** Number of peers from which we're downloading blocks. */
458458
int nPeersWithValidatedDownloads GUARDED_BY(cs_main) = 0;
459459

460+
/** Storage for orphan information */
461+
TxOrphanage m_orphanage;
460462
};
461463
} // namespace
462464

463465
namespace {
464-
465466
/** Number of preferable block download peers. */
466467
int nPreferredDownload GUARDED_BY(cs_main) = 0;
467468

@@ -1003,7 +1004,7 @@ void PeerManagerImpl::FinalizeNode(const CNode& node, bool& fUpdateConnectionTim
10031004
for (const QueuedBlock& entry : state->vBlocksInFlight) {
10041005
mapBlocksInFlight.erase(entry.hash);
10051006
}
1006-
WITH_LOCK(g_cs_orphans, EraseOrphansFor(nodeid));
1007+
WITH_LOCK(g_cs_orphans, m_orphanage.EraseForPeer(nodeid));
10071008
m_txrequest.DisconnectedPeer(nodeid);
10081009
nPreferredDownload -= state->fPreferredDownload;
10091010
nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0);
@@ -1080,11 +1081,6 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats)
10801081
return true;
10811082
}
10821083

1083-
//////////////////////////////////////////////////////////////////////////////
1084-
//
1085-
// mapOrphanTransactions
1086-
//
1087-
10881084
static void AddToCompactExtraTransactions(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
10891085
{
10901086
size_t max_extra_txn = gArgs.GetArg("-blockreconstructionextratxn", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN);
@@ -1255,13 +1251,13 @@ PeerManagerImpl::PeerManagerImpl(const CChainParams& chainparams, CConnman& conn
12551251
}
12561252

12571253
/**
1258-
* Evict orphan txn pool entries (EraseOrphanTx) based on a newly connected
1254+
* Evict orphan txn pool entries based on a newly connected
12591255
* block, remember the recently confirmed transactions, and delete tracked
12601256
* announcements for them. Also save the time of the last tip update.
12611257
*/
12621258
void PeerManagerImpl::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex)
12631259
{
1264-
EraseOrphansForBlock(*pblock);
1260+
m_orphanage.EraseForBlock(*pblock);
12651261
m_last_tip_update = GetTime();
12661262

12671263
{
@@ -1445,7 +1441,7 @@ bool PeerManagerImpl::AlreadyHaveTx(const GenTxid& gtxid)
14451441

14461442
const uint256& hash = gtxid.GetHash();
14471443

1448-
if (HaveOrphanTx(gtxid)) return true;
1444+
if (m_orphanage.HaveTx(gtxid)) return true;
14491445

14501446
{
14511447
LOCK(m_recent_confirmed_transactions_mutex);
@@ -2040,7 +2036,7 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
20402036
const uint256 orphanHash = *orphan_work_set.begin();
20412037
orphan_work_set.erase(orphan_work_set.begin());
20422038

2043-
const auto [porphanTx, from_peer] = GetOrphanTx(orphanHash);
2039+
const auto [porphanTx, from_peer] = m_orphanage.GetTx(orphanHash);
20442040
if (porphanTx == nullptr) continue;
20452041

20462042
const MempoolAcceptResult result = AcceptToMemoryPool(::ChainstateActive(), m_mempool, porphanTx, false /* bypass_limits */);
@@ -2049,8 +2045,8 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
20492045
if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
20502046
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
20512047
RelayTransaction(orphanHash, porphanTx->GetWitnessHash(), m_connman);
2052-
AddChildrenToWorkSet(*porphanTx, orphan_work_set);
2053-
EraseOrphanTx(orphanHash);
2048+
m_orphanage.AddChildrenToWorkSet(*porphanTx, orphan_work_set);
2049+
m_orphanage.EraseTx(orphanHash);
20542050
for (const CTransactionRef& removedTx : result.m_replaced_transactions.value()) {
20552051
AddToCompactExtraTransactions(removedTx);
20562052
}
@@ -2097,7 +2093,7 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
20972093
recentRejects->insert(porphanTx->GetHash());
20982094
}
20992095
}
2100-
EraseOrphanTx(orphanHash);
2096+
m_orphanage.EraseTx(orphanHash);
21012097
break;
21022098
}
21032099
}
@@ -3068,7 +3064,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
30683064
m_txrequest.ForgetTxHash(tx.GetHash());
30693065
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
30703066
RelayTransaction(tx.GetHash(), tx.GetWitnessHash(), m_connman);
3071-
AddChildrenToWorkSet(tx, peer->m_orphan_work_set);
3067+
m_orphanage.AddChildrenToWorkSet(tx, peer->m_orphan_work_set);
30723068

30733069
pfrom.nLastTXTime = GetTime();
30743070

@@ -3118,19 +3114,19 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
31183114
if (!AlreadyHaveTx(gtxid)) AddTxAnnouncement(pfrom, gtxid, current_time);
31193115
}
31203116

3121-
if (OrphanageAddTx(ptx, pfrom.GetId())) {
3117+
if (m_orphanage.AddTx(ptx, pfrom.GetId())) {
31223118
AddToCompactExtraTransactions(ptx);
31233119
}
31243120

31253121
// Once added to the orphan pool, a tx is considered AlreadyHave, and we shouldn't request it anymore.
31263122
m_txrequest.ForgetTxHash(tx.GetHash());
31273123
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
31283124

3129-
// DoS prevention: do not allow mapOrphanTransactions to grow unbounded (see CVE-2012-3789)
3125+
// DoS prevention: do not allow m_orphanage to grow unbounded (see CVE-2012-3789)
31303126
unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, gArgs.GetArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS));
3131-
unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx);
3127+
unsigned int nEvicted = m_orphanage.LimitOrphans(nMaxOrphanTx);
31323128
if (nEvicted > 0) {
3133-
LogPrint(BCLog::MEMPOOL, "mapOrphan overflow, removed %u tx\n", nEvicted);
3129+
LogPrint(BCLog::MEMPOOL, "orphanage overflow, removed %u tx\n", nEvicted);
31343130
}
31353131
} else {
31363132
LogPrint(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s\n",tx.GetHash().ToString());
@@ -4744,15 +4740,3 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
47444740
return true;
47454741
}
47464742

4747-
class CNetProcessingCleanup
4748-
{
4749-
public:
4750-
CNetProcessingCleanup() {}
4751-
~CNetProcessingCleanup() {
4752-
// orphan transactions
4753-
mapOrphanTransactions.clear();
4754-
mapOrphanTransactionsByPrev.clear();
4755-
g_orphans_by_wtxid.clear();
4756-
}
4757-
};
4758-
static CNetProcessingCleanup instance_of_cnetprocessingcleanup;

src/test/denialofservice_tests.cpp

+31-22
Original file line numberDiff line numberDiff line change
@@ -284,15 +284,23 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
284284
peerLogic->FinalizeNode(dummyNode, dummy);
285285
}
286286

287-
static CTransactionRef RandomOrphan()
287+
class TxOrphanageTest : public TxOrphanage
288288
{
289-
std::map<uint256, COrphanTx>::iterator it;
290-
LOCK2(cs_main, g_cs_orphans);
291-
it = mapOrphanTransactions.lower_bound(InsecureRand256());
292-
if (it == mapOrphanTransactions.end())
293-
it = mapOrphanTransactions.begin();
294-
return it->second.tx;
295-
}
289+
public:
290+
inline size_t CountOrphans() const EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
291+
{
292+
return mapOrphanTransactions.size();
293+
}
294+
295+
CTransactionRef RandomOrphan() EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
296+
{
297+
std::map<uint256, COrphanTx>::iterator it;
298+
it = mapOrphanTransactions.lower_bound(InsecureRand256());
299+
if (it == mapOrphanTransactions.end())
300+
it = mapOrphanTransactions.begin();
301+
return it->second.tx;
302+
}
303+
};
296304

297305
static void MakeNewKeyWithFastRandomContext(CKey& key)
298306
{
@@ -312,6 +320,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
312320
// signature's R and S values have leading zeros.
313321
g_insecure_rand_ctx = FastRandomContext(ArithToUint256(arith_uint256(33)));
314322

323+
TxOrphanageTest orphanage;
315324
CKey key;
316325
MakeNewKeyWithFastRandomContext(key);
317326
FillableSigningProvider keystore;
@@ -331,13 +340,13 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
331340
tx.vout[0].nValue = 1*CENT;
332341
tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
333342

334-
OrphanageAddTx(MakeTransactionRef(tx), i);
343+
orphanage.AddTx(MakeTransactionRef(tx), i);
335344
}
336345

337346
// ... and 50 that depend on other orphans:
338347
for (int i = 0; i < 50; i++)
339348
{
340-
CTransactionRef txPrev = RandomOrphan();
349+
CTransactionRef txPrev = orphanage.RandomOrphan();
341350

342351
CMutableTransaction tx;
343352
tx.vin.resize(1);
@@ -348,13 +357,13 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
348357
tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
349358
BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL));
350359

351-
OrphanageAddTx(MakeTransactionRef(tx), i);
360+
orphanage.AddTx(MakeTransactionRef(tx), i);
352361
}
353362

354363
// This really-big orphan should be ignored:
355364
for (int i = 0; i < 10; i++)
356365
{
357-
CTransactionRef txPrev = RandomOrphan();
366+
CTransactionRef txPrev = orphanage.RandomOrphan();
358367

359368
CMutableTransaction tx;
360369
tx.vout.resize(1);
@@ -372,24 +381,24 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
372381
for (unsigned int j = 1; j < tx.vin.size(); j++)
373382
tx.vin[j].scriptSig = tx.vin[0].scriptSig;
374383

375-
BOOST_CHECK(!OrphanageAddTx(MakeTransactionRef(tx), i));
384+
BOOST_CHECK(!orphanage.AddTx(MakeTransactionRef(tx), i));
376385
}
377386

378387
// Test EraseOrphansFor:
379388
for (NodeId i = 0; i < 3; i++)
380389
{
381-
size_t sizeBefore = mapOrphanTransactions.size();
382-
EraseOrphansFor(i);
383-
BOOST_CHECK(mapOrphanTransactions.size() < sizeBefore);
390+
size_t sizeBefore = orphanage.CountOrphans();
391+
orphanage.EraseForPeer(i);
392+
BOOST_CHECK(orphanage.CountOrphans() < sizeBefore);
384393
}
385394

386395
// Test LimitOrphanTxSize() function:
387-
LimitOrphanTxSize(40);
388-
BOOST_CHECK(mapOrphanTransactions.size() <= 40);
389-
LimitOrphanTxSize(10);
390-
BOOST_CHECK(mapOrphanTransactions.size() <= 10);
391-
LimitOrphanTxSize(0);
392-
BOOST_CHECK(mapOrphanTransactions.empty());
396+
orphanage.LimitOrphans(40);
397+
BOOST_CHECK(orphanage.CountOrphans() <= 40);
398+
orphanage.LimitOrphans(10);
399+
BOOST_CHECK(orphanage.CountOrphans() <= 10);
400+
orphanage.LimitOrphans(0);
401+
BOOST_CHECK(orphanage.CountOrphans() == 0);
393402
}
394403

395404
BOOST_AUTO_TEST_SUITE_END()

src/txorphanage.cpp

+13-19
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,7 @@ static constexpr int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60;
1717

1818
RecursiveMutex g_cs_orphans;
1919

20-
std::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(g_cs_orphans);
21-
std::map<uint256, std::map<uint256, COrphanTx>::iterator> g_orphans_by_wtxid GUARDED_BY(g_cs_orphans);
22-
23-
std::map<COutPoint, std::set<std::map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY(g_cs_orphans);
24-
25-
std::vector<std::map<uint256, COrphanTx>::iterator> g_orphan_list GUARDED_BY(g_cs_orphans);
26-
27-
bool OrphanageAddTx(const CTransactionRef& tx, NodeId peer)
20+
bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer)
2821
{
2922
AssertLockHeld(g_cs_orphans);
3023

@@ -60,8 +53,9 @@ bool OrphanageAddTx(const CTransactionRef& tx, NodeId peer)
6053
return true;
6154
}
6255

63-
int EraseOrphanTx(const uint256& txid)
56+
int TxOrphanage::EraseTx(const uint256& txid)
6457
{
58+
AssertLockHeld(g_cs_orphans);
6559
std::map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(txid);
6660
if (it == mapOrphanTransactions.end())
6761
return 0;
@@ -91,7 +85,7 @@ int EraseOrphanTx(const uint256& txid)
9185
return 1;
9286
}
9387

94-
void EraseOrphansFor(NodeId peer)
88+
void TxOrphanage::EraseForPeer(NodeId peer)
9589
{
9690
AssertLockHeld(g_cs_orphans);
9791

@@ -102,13 +96,13 @@ void EraseOrphansFor(NodeId peer)
10296
std::map<uint256, COrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid
10397
if (maybeErase->second.fromPeer == peer)
10498
{
105-
nErased += EraseOrphanTx(maybeErase->second.tx->GetHash());
99+
nErased += EraseTx(maybeErase->second.tx->GetHash());
106100
}
107101
}
108102
if (nErased > 0) LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx from peer=%d\n", nErased, peer);
109103
}
110104

111-
unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
105+
unsigned int TxOrphanage::LimitOrphans(unsigned int nMaxOrphans)
112106
{
113107
AssertLockHeld(g_cs_orphans);
114108

@@ -124,7 +118,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
124118
{
125119
std::map<uint256, COrphanTx>::iterator maybeErase = iter++;
126120
if (maybeErase->second.nTimeExpire <= nNow) {
127-
nErased += EraseOrphanTx(maybeErase->second.tx->GetHash());
121+
nErased += EraseTx(maybeErase->second.tx->GetHash());
128122
} else {
129123
nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime);
130124
}
@@ -138,13 +132,13 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
138132
{
139133
// Evict a random orphan:
140134
size_t randompos = rng.randrange(g_orphan_list.size());
141-
EraseOrphanTx(g_orphan_list[randompos]->first);
135+
EraseTx(g_orphan_list[randompos]->first);
142136
++nEvicted;
143137
}
144138
return nEvicted;
145139
}
146140

147-
void AddChildrenToWorkSet(const CTransaction& tx, std::set<uint256>& orphan_work_set)
141+
void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx, std::set<uint256>& orphan_work_set) const
148142
{
149143
AssertLockHeld(g_cs_orphans);
150144
for (unsigned int i = 0; i < tx.vout.size(); i++) {
@@ -157,7 +151,7 @@ void AddChildrenToWorkSet(const CTransaction& tx, std::set<uint256>& orphan_work
157151
}
158152
}
159153

160-
bool HaveOrphanTx(const GenTxid& gtxid)
154+
bool TxOrphanage::HaveTx(const GenTxid& gtxid) const
161155
{
162156
LOCK(g_cs_orphans);
163157
if (gtxid.IsWtxid()) {
@@ -167,7 +161,7 @@ bool HaveOrphanTx(const GenTxid& gtxid)
167161
}
168162
}
169163

170-
std::pair<CTransactionRef, NodeId> GetOrphanTx(const uint256& txid)
164+
std::pair<CTransactionRef, NodeId> TxOrphanage::GetTx(const uint256& txid) const
171165
{
172166
AssertLockHeld(g_cs_orphans);
173167

@@ -176,7 +170,7 @@ std::pair<CTransactionRef, NodeId> GetOrphanTx(const uint256& txid)
176170
return {it->second.tx, it->second.fromPeer};
177171
}
178172

179-
void EraseOrphansForBlock(const CBlock& block)
173+
void TxOrphanage::EraseForBlock(const CBlock& block)
180174
{
181175
LOCK(g_cs_orphans);
182176

@@ -201,7 +195,7 @@ void EraseOrphansForBlock(const CBlock& block)
201195
if (vOrphanErase.size()) {
202196
int nErased = 0;
203197
for (const uint256& orphanHash : vOrphanErase) {
204-
nErased += EraseOrphanTx(orphanHash);
198+
nErased += EraseTx(orphanHash);
205199
}
206200
LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx included or conflicted by block\n", nErased);
207201
}

0 commit comments

Comments
 (0)