12
12
13
13
#include < cassert>
14
14
15
- namespace node {
16
- bool TxOrphanage::AddTx (const CTransactionRef& tx, NodeId peer)
15
+ namespace node {
16
+
17
+ class TxOrphanageImpl final : public TxOrphanage {
18
+ private:
19
+ struct OrphanTx : public OrphanTxBase {
20
+ NodeSeconds nTimeExpire;
21
+ size_t list_pos;
22
+ };
23
+
24
+ /* * Total usage (weight) of all entries in m_orphans. */
25
+ int64_t m_total_orphan_usage{0 };
26
+
27
+ /* * Total number of <peer, tx> pairs. Can be larger than m_orphans.size() because multiple peers
28
+ * may have announced the same orphan. */
29
+ unsigned int m_total_announcements{0 };
30
+
31
+ /* * Map from wtxid to orphan transaction record. Limited by
32
+ * DEFAULT_MAX_ORPHAN_TRANSACTIONS */
33
+ std::map<Wtxid, OrphanTx> m_orphans;
34
+
35
+ struct PeerOrphanInfo {
36
+ /* * List of transactions that should be reconsidered: added to in AddChildrenToWorkSet,
37
+ * removed from one-by-one with each call to GetTxToReconsider. The wtxids may refer to
38
+ * transactions that are no longer present in orphanage; these are lazily removed in
39
+ * GetTxToReconsider. */
40
+ std::set<Wtxid> m_work_set;
41
+
42
+ /* * Total weight of orphans for which this peer is an announcer.
43
+ * If orphans are provided by different peers, its weight will be accounted for in each
44
+ * PeerOrphanInfo, so the total of all peers' m_total_usage may be larger than
45
+ * m_total_orphan_size. If a peer is removed as an announcer, even if the orphan still
46
+ * remains in the orphanage, this number will be decremented. */
47
+ int64_t m_total_usage{0 };
48
+ };
49
+ std::map<NodeId, PeerOrphanInfo> m_peer_orphanage_info;
50
+
51
+ using OrphanMap = decltype (m_orphans);
52
+
53
+ struct IteratorComparator
54
+ {
55
+ template <typename I>
56
+ bool operator ()(const I& a, const I& b) const
57
+ {
58
+ return a->first < b->first ;
59
+ }
60
+ };
61
+
62
+ /* * Index from the parents' COutPoint into the m_orphans. Used
63
+ * to remove orphan transactions from the m_orphans */
64
+ std::map<COutPoint, std::set<OrphanMap::iterator, IteratorComparator>> m_outpoint_to_orphan_it;
65
+
66
+ /* * Orphan transactions in vector for quick random eviction */
67
+ std::vector<OrphanMap::iterator> m_orphan_list;
68
+
69
+ /* * Timestamp for the next scheduled sweep of expired orphans */
70
+ NodeSeconds m_next_sweep{0s};
71
+
72
+ public:
73
+ bool AddTx (const CTransactionRef& tx, NodeId peer) override ;
74
+ bool AddAnnouncer (const Wtxid& wtxid, NodeId peer) override ;
75
+ CTransactionRef GetTx (const Wtxid& wtxid) const override ;
76
+ bool HaveTx (const Wtxid& wtxid) const override ;
77
+ bool HaveTxFromPeer (const Wtxid& wtxid, NodeId peer) const override ;
78
+ CTransactionRef GetTxToReconsider (NodeId peer) override ;
79
+ int EraseTx (const Wtxid& wtxid) override ;
80
+ void EraseForPeer (NodeId peer) override ;
81
+ void EraseForBlock (const CBlock& block) override ;
82
+ void LimitOrphans (FastRandomContext& rng) override ;
83
+ void AddChildrenToWorkSet (const CTransaction& tx, FastRandomContext& rng) override ;
84
+ bool HaveTxToReconsider (NodeId peer) override ;
85
+ std::vector<CTransactionRef> GetChildrenFromSamePeer (const CTransactionRef& parent, NodeId nodeid) const override ;
86
+ size_t Size () const override { return m_orphans.size (); }
87
+ std::vector<OrphanTxBase> GetOrphanTransactions () const override ;
88
+ int64_t TotalOrphanUsage () const override { return m_total_orphan_usage; }
89
+ int64_t UsageByPeer (NodeId peer) const override ;
90
+ void SanityCheck () const override ;
91
+ };
92
+
93
+ bool TxOrphanageImpl::AddTx (const CTransactionRef& tx, NodeId peer)
17
94
{
18
95
const Txid& hash = tx->GetHash ();
19
96
const Wtxid& wtxid = tx->GetWitnessHash ();
@@ -53,7 +130,7 @@ bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer)
53
130
return true ;
54
131
}
55
132
56
- bool TxOrphanage ::AddAnnouncer (const Wtxid& wtxid, NodeId peer)
133
+ bool TxOrphanageImpl ::AddAnnouncer (const Wtxid& wtxid, NodeId peer)
57
134
{
58
135
const auto it = m_orphans.find (wtxid);
59
136
if (it != m_orphans.end ()) {
@@ -70,7 +147,7 @@ bool TxOrphanage::AddAnnouncer(const Wtxid& wtxid, NodeId peer)
70
147
return false ;
71
148
}
72
149
73
- int TxOrphanage ::EraseTx (const Wtxid& wtxid)
150
+ int TxOrphanageImpl ::EraseTx (const Wtxid& wtxid)
74
151
{
75
152
std::map<Wtxid, OrphanTx>::iterator it = m_orphans.find (wtxid);
76
153
if (it == m_orphans.end ())
@@ -116,7 +193,7 @@ int TxOrphanage::EraseTx(const Wtxid& wtxid)
116
193
return 1 ;
117
194
}
118
195
119
- void TxOrphanage ::EraseForPeer (NodeId peer)
196
+ void TxOrphanageImpl ::EraseForPeer (NodeId peer)
120
197
{
121
198
// Zeroes out this peer's m_total_usage.
122
199
m_peer_orphanage_info.erase (peer);
@@ -141,7 +218,7 @@ void TxOrphanage::EraseForPeer(NodeId peer)
141
218
if (nErased > 0 ) LogDebug (BCLog::TXPACKAGES, " Erased %d orphan transaction(s) from peer=%d\n " , nErased, peer);
142
219
}
143
220
144
- void TxOrphanage ::LimitOrphans (FastRandomContext& rng)
221
+ void TxOrphanageImpl ::LimitOrphans (FastRandomContext& rng)
145
222
{
146
223
unsigned int nEvicted = 0 ;
147
224
auto nNow{Now<NodeSeconds>()};
@@ -173,7 +250,7 @@ void TxOrphanage::LimitOrphans(FastRandomContext& rng)
173
250
if (nEvicted > 0 ) LogDebug (BCLog::TXPACKAGES, " orphanage overflow, removed %u tx\n " , nEvicted);
174
251
}
175
252
176
- void TxOrphanage ::AddChildrenToWorkSet (const CTransaction& tx, FastRandomContext& rng)
253
+ void TxOrphanageImpl ::AddChildrenToWorkSet (const CTransaction& tx, FastRandomContext& rng)
177
254
{
178
255
for (unsigned int i = 0 ; i < tx.vout .size (); i++) {
179
256
const auto it_by_prev = m_outpoint_to_orphan_it.find (COutPoint (tx.GetHash (), i));
@@ -201,24 +278,25 @@ void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx, FastRandomContext
201
278
}
202
279
}
203
280
204
- bool TxOrphanage ::HaveTx (const Wtxid& wtxid) const
281
+ bool TxOrphanageImpl ::HaveTx (const Wtxid& wtxid) const
205
282
{
206
283
return m_orphans.count (wtxid);
207
284
}
208
285
209
- CTransactionRef TxOrphanage ::GetTx (const Wtxid& wtxid) const
286
+ CTransactionRef TxOrphanageImpl ::GetTx (const Wtxid& wtxid) const
210
287
{
211
288
auto it = m_orphans.find (wtxid);
212
289
return it != m_orphans.end () ? it->second .tx : nullptr ;
213
290
}
214
291
215
- bool TxOrphanage::HaveTxFromPeer (const Wtxid& wtxid, NodeId peer) const
292
+
293
+ bool TxOrphanageImpl::HaveTxFromPeer (const Wtxid& wtxid, NodeId peer) const
216
294
{
217
295
auto it = m_orphans.find (wtxid);
218
296
return (it != m_orphans.end () && it->second .announcers .contains (peer));
219
297
}
220
298
221
- CTransactionRef TxOrphanage ::GetTxToReconsider (NodeId peer)
299
+ CTransactionRef TxOrphanageImpl ::GetTxToReconsider (NodeId peer)
222
300
{
223
301
auto peer_it = m_peer_orphanage_info.find (peer);
224
302
if (peer_it == m_peer_orphanage_info.end ()) return nullptr ;
@@ -236,7 +314,7 @@ CTransactionRef TxOrphanage::GetTxToReconsider(NodeId peer)
236
314
return nullptr ;
237
315
}
238
316
239
- bool TxOrphanage ::HaveTxToReconsider (NodeId peer)
317
+ bool TxOrphanageImpl ::HaveTxToReconsider (NodeId peer)
240
318
{
241
319
auto peer_it = m_peer_orphanage_info.find (peer);
242
320
if (peer_it == m_peer_orphanage_info.end ()) return false ;
@@ -245,7 +323,7 @@ bool TxOrphanage::HaveTxToReconsider(NodeId peer)
245
323
return !work_set.empty ();
246
324
}
247
325
248
- void TxOrphanage ::EraseForBlock (const CBlock& block)
326
+ void TxOrphanageImpl ::EraseForBlock (const CBlock& block)
249
327
{
250
328
std::vector<Wtxid> vOrphanErase;
251
329
@@ -273,7 +351,7 @@ void TxOrphanage::EraseForBlock(const CBlock& block)
273
351
}
274
352
}
275
353
276
- std::vector<CTransactionRef> TxOrphanage ::GetChildrenFromSamePeer (const CTransactionRef& parent, NodeId nodeid) const
354
+ std::vector<CTransactionRef> TxOrphanageImpl ::GetChildrenFromSamePeer (const CTransactionRef& parent, NodeId nodeid) const
277
355
{
278
356
// First construct a vector of iterators to ensure we do not return duplicates of the same tx
279
357
// and so we can sort by nTimeExpire.
@@ -313,7 +391,7 @@ std::vector<CTransactionRef> TxOrphanage::GetChildrenFromSamePeer(const CTransac
313
391
return children_found;
314
392
}
315
393
316
- std::vector<TxOrphanage::OrphanTxBase> TxOrphanage ::GetOrphanTransactions () const
394
+ std::vector<TxOrphanage::OrphanTxBase> TxOrphanageImpl ::GetOrphanTransactions () const
317
395
{
318
396
std::vector<OrphanTxBase> ret;
319
397
ret.reserve (m_orphans.size ());
@@ -323,7 +401,13 @@ std::vector<TxOrphanage::OrphanTxBase> TxOrphanage::GetOrphanTransactions() cons
323
401
return ret;
324
402
}
325
403
326
- void TxOrphanage::SanityCheck () const
404
+ int64_t TxOrphanageImpl::UsageByPeer (NodeId peer) const
405
+ {
406
+ auto peer_it = m_peer_orphanage_info.find (peer);
407
+ return peer_it == m_peer_orphanage_info.end () ? 0 : peer_it->second .m_total_usage ;
408
+ }
409
+
410
+ void TxOrphanageImpl::SanityCheck () const
327
411
{
328
412
// Check that cached m_total_announcements is correct
329
413
unsigned int counted_total_announcements{0 };
@@ -362,4 +446,10 @@ void TxOrphanage::SanityCheck() const
362
446
}
363
447
}
364
448
}
449
+
450
+ std::unique_ptr<TxOrphanage> MakeTxOrphanage () noexcept
451
+ {
452
+ return std::make_unique<TxOrphanageImpl>();
453
+ }
454
+
365
455
} // namespace node
0 commit comments