@@ -153,8 +153,14 @@ struct COrphanTx {
153
153
int64_t nTimeExpire;
154
154
size_t list_pos;
155
155
};
156
+
157
+ /* * Guards orphan transactions and extra txs for compact blocks */
156
158
RecursiveMutex g_cs_orphans;
159
+ /* * Map from txid to orphan transaction record. Limited by
160
+ * -maxorphantx/DEFAULT_MAX_ORPHAN_TRANSACTIONS */
157
161
std::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY (g_cs_orphans);
162
+ /* * Index from wtxid into the mapOrphanTransactions to lookup orphan
163
+ * transactions using their witness ids. */
158
164
std::map<uint256, std::map<uint256, COrphanTx>::iterator> g_orphans_by_wtxid GUARDED_BY (g_cs_orphans);
159
165
160
166
void EraseOrphansFor (NodeId peer);
@@ -258,12 +264,19 @@ namespace {
258
264
return &(*a) < &(*b);
259
265
}
260
266
};
261
- std::map<COutPoint, std::set<std::map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY (g_cs_orphans);
262
267
263
- std::vector<std::map<uint256, COrphanTx>::iterator> g_orphan_list GUARDED_BY (g_cs_orphans); // ! For random eviction
268
+ /* * Index from the parents' COutPoint into the mapOrphanTransactions. Used
269
+ * to remove orphan transactions from the mapOrphanTransactions */
270
+ std::map<COutPoint, std::set<std::map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY (g_cs_orphans);
271
+ /* * Orphan transactions in vector for quick random eviction */
272
+ std::vector<std::map<uint256, COrphanTx>::iterator> g_orphan_list GUARDED_BY (g_cs_orphans);
264
273
265
- static size_t vExtraTxnForCompactIt GUARDED_BY (g_cs_orphans) = 0;
274
+ /* * Orphan/conflicted/etc transactions that are kept for compact block reconstruction.
275
+ * The last -blockreconstructionextratxn/DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN of
276
+ * these are kept in a ring buffer */
266
277
static std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUARDED_BY (g_cs_orphans);
278
+ /* * Offset into vExtraTxnForCompact to insert the next tx */
279
+ static size_t vExtraTxnForCompactIt GUARDED_BY (g_cs_orphans) = 0;
267
280
} // namespace
268
281
269
282
namespace {
@@ -2021,32 +2034,34 @@ void PeerManager::ProcessHeadersMessage(CNode& pfrom, const std::vector<CBlockHe
2021
2034
return ;
2022
2035
}
2023
2036
2024
- void PeerManager::ProcessOrphanTx (std::set<uint256>& orphan_work_set, std::list<CTransactionRef>& removed_txn)
2037
+ /* *
2038
+ * Reconsider orphan transactions after a parent has been accepted to the mempool.
2039
+ *
2040
+ * @param[in/out] orphan_work_set The set of orphan transactions to reconsider. Generally only one
2041
+ * orphan will be reconsidered on each call of this function. This set
2042
+ * may be added to if accepting an orphan causes its children to be
2043
+ * reconsidered.
2044
+ */
2045
+ void PeerManager::ProcessOrphanTx (std::set<uint256>& orphan_work_set)
2025
2046
{
2026
2047
AssertLockHeld (cs_main);
2027
2048
AssertLockHeld (g_cs_orphans);
2028
- std::set<NodeId> setMisbehaving;
2029
- bool done = false ;
2030
- while (!done && !orphan_work_set.empty ()) {
2049
+
2050
+ while (!orphan_work_set.empty ()) {
2031
2051
const uint256 orphanHash = *orphan_work_set.begin ();
2032
2052
orphan_work_set.erase (orphan_work_set.begin ());
2033
2053
2034
2054
auto orphan_it = mapOrphanTransactions.find (orphanHash);
2035
2055
if (orphan_it == mapOrphanTransactions.end ()) continue ;
2036
2056
2037
2057
const CTransactionRef porphanTx = orphan_it->second .tx ;
2038
- const CTransaction& orphanTx = *porphanTx;
2039
- NodeId fromPeer = orphan_it->second .fromPeer ;
2040
- // Use a new TxValidationState because orphans come from different peers (and we call
2041
- // MaybePunishNodeForTx based on the source peer from the orphan map, not based on the peer
2042
- // that relayed the previous transaction).
2043
- TxValidationState orphan_state;
2044
-
2045
- if (setMisbehaving.count (fromPeer)) continue ;
2046
- if (AcceptToMemoryPool (m_mempool, orphan_state, porphanTx, &removed_txn, false /* bypass_limits */ , 0 /* nAbsurdFee */ )) {
2058
+ TxValidationState state;
2059
+ std::list<CTransactionRef> removed_txn;
2060
+
2061
+ if (AcceptToMemoryPool (m_mempool, state, porphanTx, &removed_txn, false /* bypass_limits */ , 0 /* nAbsurdFee */ )) {
2047
2062
LogPrint (BCLog::MEMPOOL, " accepted orphan tx %s\n " , orphanHash.ToString ());
2048
2063
RelayTransaction (orphanHash, porphanTx->GetWitnessHash (), m_connman);
2049
- for (unsigned int i = 0 ; i < orphanTx. vout .size (); i++) {
2064
+ for (unsigned int i = 0 ; i < porphanTx-> vout .size (); i++) {
2050
2065
auto it_by_prev = mapOrphanTransactionsByPrev.find (COutPoint (orphanHash, i));
2051
2066
if (it_by_prev != mapOrphanTransactionsByPrev.end ()) {
2052
2067
for (const auto & elem : it_by_prev->second ) {
@@ -2055,22 +2070,23 @@ void PeerManager::ProcessOrphanTx(std::set<uint256>& orphan_work_set, std::list<
2055
2070
}
2056
2071
}
2057
2072
EraseOrphanTx (orphanHash);
2058
- done = true ;
2059
- } else if (orphan_state.GetResult () != TxValidationResult::TX_MISSING_INPUTS) {
2060
- if (orphan_state.IsInvalid ()) {
2061
- // Punish peer that gave us an invalid orphan tx
2062
- if (MaybePunishNodeForTx (fromPeer, orphan_state)) {
2063
- setMisbehaving.insert (fromPeer);
2064
- }
2073
+ for (const CTransactionRef& removedTx : removed_txn) {
2074
+ AddToCompactExtraTransactions (removedTx);
2075
+ }
2076
+ break ;
2077
+ } else if (state.GetResult () != TxValidationResult::TX_MISSING_INPUTS) {
2078
+ if (state.IsInvalid ()) {
2065
2079
LogPrint (BCLog::MEMPOOL, " invalid orphan tx %s from peer=%d. %s\n " ,
2066
2080
orphanHash.ToString (),
2067
- fromPeer,
2068
- orphan_state.ToString ());
2081
+ orphan_it->second .fromPeer ,
2082
+ state.ToString ());
2083
+ // Maybe punish peer that gave us an invalid orphan tx
2084
+ MaybePunishNodeForTx (orphan_it->second .fromPeer , state);
2069
2085
}
2070
2086
// Has inputs but not accepted to mempool
2071
2087
// Probably non-standard or insufficient fee
2072
2088
LogPrint (BCLog::MEMPOOL, " removed orphan tx %s\n " , orphanHash.ToString ());
2073
- if (orphan_state .GetResult () != TxValidationResult::TX_WITNESS_STRIPPED) {
2089
+ if (state .GetResult () != TxValidationResult::TX_WITNESS_STRIPPED) {
2074
2090
// We can add the wtxid of this transaction to our reject filter.
2075
2091
// Do not add txids of witness transactions or witness-stripped
2076
2092
// transactions to the filter, as they can have been malleated;
@@ -2085,7 +2101,7 @@ void PeerManager::ProcessOrphanTx(std::set<uint256>& orphan_work_set, std::list<
2085
2101
// for concerns around weakening security of unupgraded nodes
2086
2102
// if we start doing this too early.
2087
2103
assert (recentRejects);
2088
- recentRejects->insert (orphanTx. GetWitnessHash ());
2104
+ recentRejects->insert (porphanTx-> GetWitnessHash ());
2089
2105
// If the transaction failed for TX_INPUTS_NOT_STANDARD,
2090
2106
// then we know that the witness was irrelevant to the policy
2091
2107
// failure, since this check depends only on the txid
@@ -2094,17 +2110,17 @@ void PeerManager::ProcessOrphanTx(std::set<uint256>& orphan_work_set, std::list<
2094
2110
// processing of this transaction in the event that child
2095
2111
// transactions are later received (resulting in
2096
2112
// parent-fetching by txid via the orphan-handling logic).
2097
- if (orphan_state .GetResult () == TxValidationResult::TX_INPUTS_NOT_STANDARD && orphanTx. GetWitnessHash () != orphanTx. GetHash ()) {
2113
+ if (state .GetResult () == TxValidationResult::TX_INPUTS_NOT_STANDARD && porphanTx-> GetWitnessHash () != porphanTx-> GetHash ()) {
2098
2114
// We only add the txid if it differs from the wtxid, to
2099
2115
// avoid wasting entries in the rolling bloom filter.
2100
- recentRejects->insert (orphanTx. GetHash ());
2116
+ recentRejects->insert (porphanTx-> GetHash ());
2101
2117
}
2102
2118
}
2103
2119
EraseOrphanTx (orphanHash);
2104
- done = true ;
2120
+ break ;
2105
2121
}
2106
- m_mempool.check (&::ChainstateActive ().CoinsTip ());
2107
2122
}
2123
+ m_mempool.check (&::ChainstateActive ().CoinsTip ());
2108
2124
}
2109
2125
2110
2126
/* *
@@ -3017,8 +3033,12 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
3017
3033
tx.GetHash ().ToString (),
3018
3034
m_mempool.size (), m_mempool.DynamicMemoryUsage () / 1000 );
3019
3035
3036
+ for (const CTransactionRef& removedTx : lRemovedTxn) {
3037
+ AddToCompactExtraTransactions (removedTx);
3038
+ }
3039
+
3020
3040
// Recursively process any orphan transactions that depended on this one
3021
- ProcessOrphanTx (pfrom.orphan_work_set , lRemovedTxn );
3041
+ ProcessOrphanTx (pfrom.orphan_work_set );
3022
3042
}
3023
3043
else if (state.GetResult () == TxValidationResult::TX_MISSING_INPUTS)
3024
3044
{
@@ -3119,9 +3139,6 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
3119
3139
}
3120
3140
}
3121
3141
3122
- for (const CTransactionRef& removedTx : lRemovedTxn)
3123
- AddToCompactExtraTransactions (removedTx);
3124
-
3125
3142
// If a tx has been detected by recentRejects, we will have reached
3126
3143
// this point and the tx will have been ignored. Because we haven't run
3127
3144
// the tx through AcceptToMemoryPool, we won't have computed a DoS
@@ -3821,12 +3838,8 @@ bool PeerManager::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgP
3821
3838
ProcessGetData (*pfrom, m_chainparams, m_connman, m_mempool, interruptMsgProc);
3822
3839
3823
3840
if (!pfrom->orphan_work_set .empty ()) {
3824
- std::list<CTransactionRef> removed_txn;
3825
3841
LOCK2 (cs_main, g_cs_orphans);
3826
- ProcessOrphanTx (pfrom->orphan_work_set , removed_txn);
3827
- for (const CTransactionRef& removedTx : removed_txn) {
3828
- AddToCompactExtraTransactions (removedTx);
3829
- }
3842
+ ProcessOrphanTx (pfrom->orphan_work_set );
3830
3843
}
3831
3844
3832
3845
if (pfrom->fDisconnect )
0 commit comments