@@ -477,6 +477,9 @@ class PeerManagerImpl final : public PeerManager
477
477
/* * When our tip was last updated. */
478
478
std::atomic<int64_t > m_last_tip_update{0 };
479
479
480
+ /* * Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed). */
481
+ CTransactionRef FindTxForGetData (CNode* peer, const uint256& txid, const std::chrono::seconds mempool_req, const std::chrono::seconds longlived_mempool_time) LOCKS_EXCLUDED(cs_main);
482
+
480
483
void ProcessGetData (CNode& pfrom, Peer& peer, const std::atomic<bool >& interruptMsgProc) LOCKS_EXCLUDED(cs_main) EXCLUSIVE_LOCKS_REQUIRED(peer.m_getdata_requests_mutex);
481
484
482
485
void ProcessBlock (CNode& pfrom, const std::shared_ptr<const CBlock>& pblock, bool fForceProcessing );
@@ -2079,6 +2082,37 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, const CChainParams& chai
2079
2082
}
2080
2083
}
2081
2084
2085
+ // ! Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed).
2086
+ CTransactionRef PeerManagerImpl::FindTxForGetData (CNode* peer, const uint256& txid, const std::chrono::seconds mempool_req, const std::chrono::seconds longlived_mempool_time) LOCKS_EXCLUDED(cs_main)
2087
+ {
2088
+ // Check if the requested transaction is so recent that we're just
2089
+ // about to announce it to the peer; if so, they certainly shouldn't
2090
+ // know we already have it.
2091
+ {
2092
+ LOCK (peer->m_tx_relay ->cs_tx_inventory );
2093
+ if (peer->m_tx_relay ->setInventoryTxToSend .count (txid)) return {};
2094
+ }
2095
+
2096
+ {
2097
+ LOCK (cs_main);
2098
+ // Look up transaction in relay pool
2099
+ auto mi = mapRelay.find (txid);
2100
+ if (mi != mapRelay.end ()) return mi->second ;
2101
+ }
2102
+
2103
+ auto txinfo = m_mempool.info (txid);
2104
+ if (txinfo.tx ) {
2105
+ // To protect privacy, do not answer getdata using the mempool when
2106
+ // that TX couldn't have been INVed in reply to a MEMPOOL request,
2107
+ // or when it's too recent to have expired from mapRelay.
2108
+ if ((mempool_req.count () && txinfo.m_time <= mempool_req) || txinfo.m_time <= longlived_mempool_time) {
2109
+ return txinfo.tx ;
2110
+ }
2111
+ }
2112
+
2113
+ return {};
2114
+ }
2115
+
2082
2116
void PeerManagerImpl::ProcessGetData (CNode& pfrom, Peer& peer, const std::atomic<bool >& interruptMsgProc)
2083
2117
{
2084
2118
AssertLockNotHeld (cs_main);
@@ -2093,182 +2127,155 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic
2093
2127
const std::chrono::seconds mempool_req = !pfrom.IsAddrRelayPeer () ? pfrom.m_tx_relay ->m_last_mempool_req .load ()
2094
2128
: std::chrono::seconds::min ();
2095
2129
2096
- {
2097
- LOCK (cs_main);
2098
-
2099
- // Process as many TX items from the front of the getdata queue as
2100
- // possible, since they're common and it's efficient to batch process
2101
- // them.
2102
- while (it != peer.m_getdata_requests .end () && it->IsKnownType ()) {
2103
- if (interruptMsgProc)
2104
- return ;
2105
- // The send buffer provides backpressure. If there's no space in
2106
- // the buffer, pause processing until the next call.
2107
- if (pfrom.fPauseSend )
2108
- break ;
2130
+ // Process as many TX items from the front of the getdata queue as
2131
+ // possible, since they're common and it's efficient to batch process
2132
+ // them.
2133
+ while (it != peer.m_getdata_requests .end () && it->IsKnownType ()) {
2134
+ if (interruptMsgProc)
2135
+ return ;
2136
+ // The send buffer provides backpressure. If there's no space in
2137
+ // the buffer, pause processing until the next call.
2138
+ if (pfrom.fPauseSend )
2139
+ break ;
2109
2140
2110
- const CInv &inv = *it;
2141
+ const CInv &inv = *it;
2111
2142
2112
- if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK) {
2113
- break ;
2114
- }
2115
- ++it;
2143
+ if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK) {
2144
+ break ;
2145
+ }
2146
+ ++it;
2116
2147
2117
- if (!pfrom.IsAddrRelayPeer () && NetMessageViolatesBlocksOnly (inv.GetCommand ())) {
2118
- // Note that if we receive a getdata for non-block messages
2119
- // from a block-relay-only outbound peer that violate the policy,
2120
- // we skip such getdata messages from this peer
2121
- continue ;
2122
- }
2148
+ if (!pfrom.IsAddrRelayPeer () && NetMessageViolatesBlocksOnly (inv.GetCommand ())) {
2149
+ // Note that if we receive a getdata for non-block messages
2150
+ // from a block-relay-only outbound peer that violate the policy,
2151
+ // we skip such getdata messages from this peer
2152
+ continue ;
2153
+ }
2123
2154
2124
- // Send stream from relay memory
2125
- bool push = false ;
2126
- if (inv.type == MSG_TX || inv.type == MSG_DSTX) {
2155
+ bool push = false ;
2156
+ if (inv.type == MSG_TX || inv.type == MSG_DSTX) {
2157
+ CTransactionRef tx = FindTxForGetData (&pfrom, inv.hash , mempool_req, longlived_mempool_time);
2158
+ if (tx) {
2127
2159
CCoinJoinBroadcastTx dstx;
2128
2160
if (inv.type == MSG_DSTX) {
2129
2161
dstx = CCoinJoin::GetDSTX (inv.hash );
2130
2162
}
2131
- auto mi = mapRelay.find (inv.hash );
2132
- if (mi != mapRelay.end ()) {
2133
- if (dstx) {
2134
- m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::DSTX, dstx));
2135
- } else {
2136
- m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::TX, *mi->second ));
2137
- }
2138
- push = true ;
2163
+ if (dstx) {
2164
+ m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::DSTX, dstx));
2139
2165
} else {
2140
- auto txinfo = m_mempool.info (inv.hash );
2141
- // To protect privacy, do not answer getdata using the mempool when
2142
- // that TX couldn't have been INVed in reply to a MEMPOOL request,
2143
- // or when it's too recent to have expired from mapRelay.
2144
- if (txinfo.tx && (
2145
- (mempool_req.count () && txinfo.m_time <= mempool_req)
2146
- || (txinfo.m_time <= longlived_mempool_time)))
2147
- {
2148
- if (dstx) {
2149
- m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::DSTX, dstx));
2150
- } else {
2151
- m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::TX, *txinfo.tx ));
2152
- }
2153
- push = true ;
2154
- }
2166
+ m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::TX, *tx));
2155
2167
}
2156
- }
2157
-
2158
- if (push) {
2159
- // We interpret fulfilling a GETDATA for a transaction as a
2160
- // successful initial broadcast and remove it from our
2161
- // unbroadcast set.
2162
2168
m_mempool.RemoveUnbroadcastTx (inv.hash );
2169
+ push = true ;
2163
2170
}
2171
+ }
2164
2172
2165
- if (!push && inv.type == MSG_SPORK) {
2166
- if (auto opt_spork = sporkManager->GetSporkByHash (inv.hash )) {
2167
- m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::SPORK, *opt_spork));
2168
- push = true ;
2169
- }
2173
+ if (!push && inv.type == MSG_SPORK) {
2174
+ if (auto opt_spork = sporkManager->GetSporkByHash (inv.hash )) {
2175
+ m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::SPORK, *opt_spork));
2176
+ push = true ;
2170
2177
}
2178
+ }
2171
2179
2172
- if (!push && inv.type == MSG_GOVERNANCE_OBJECT) {
2173
- CDataStream ss (SER_NETWORK, pfrom.GetSendVersion ());
2174
- bool topush = false ;
2175
- if (m_govman.HaveObjectForHash (inv.hash )) {
2176
- ss.reserve (1000 );
2177
- if (m_govman.SerializeObjectForHash (inv.hash , ss)) {
2178
- topush = true ;
2179
- }
2180
- }
2181
- if (topush) {
2182
- m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::MNGOVERNANCEOBJECT, ss));
2183
- push = true ;
2180
+ if (!push && inv.type == MSG_GOVERNANCE_OBJECT) {
2181
+ CDataStream ss (SER_NETWORK, pfrom.GetSendVersion ());
2182
+ bool topush = false ;
2183
+ if (m_govman.HaveObjectForHash (inv.hash )) {
2184
+ ss.reserve (1000 );
2185
+ if (m_govman.SerializeObjectForHash (inv.hash , ss)) {
2186
+ topush = true ;
2184
2187
}
2185
2188
}
2186
-
2187
- if (!push && inv.type == MSG_GOVERNANCE_OBJECT_VOTE) {
2188
- CDataStream ss (SER_NETWORK, pfrom.GetSendVersion ());
2189
- bool topush = false ;
2190
- if (m_govman.HaveVoteForHash (inv.hash )) {
2191
- ss.reserve (1000 );
2192
- if (m_govman.SerializeVoteForHash (inv.hash , ss)) {
2193
- topush = true ;
2194
- }
2195
- }
2196
- if (topush) {
2197
- m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::MNGOVERNANCEOBJECTVOTE, ss));
2198
- push = true ;
2199
- }
2189
+ if (topush) {
2190
+ m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::MNGOVERNANCEOBJECT, ss));
2191
+ push = true ;
2200
2192
}
2193
+ }
2201
2194
2202
- if (!push && (inv.type == MSG_QUORUM_FINAL_COMMITMENT)) {
2203
- llmq::CFinalCommitment o;
2204
- if (m_llmq_ctx->quorum_block_processor ->GetMineableCommitmentByHash (
2205
- inv.hash , o)) {
2206
- m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::QFCOMMITMENT, o));
2207
- push = true ;
2195
+ if (!push && inv.type == MSG_GOVERNANCE_OBJECT_VOTE) {
2196
+ CDataStream ss (SER_NETWORK, pfrom.GetSendVersion ());
2197
+ bool topush = false ;
2198
+ if (m_govman.HaveVoteForHash (inv.hash )) {
2199
+ ss.reserve (1000 );
2200
+ if (m_govman.SerializeVoteForHash (inv.hash , ss)) {
2201
+ topush = true ;
2208
2202
}
2209
2203
}
2204
+ if (topush) {
2205
+ m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::MNGOVERNANCEOBJECTVOTE, ss));
2206
+ push = true ;
2207
+ }
2208
+ }
2210
2209
2211
- if (!push && (inv.type == MSG_QUORUM_CONTRIB )) {
2212
- llmq::CDKGContribution o;
2213
- if (m_llmq_ctx->qdkgsman -> GetContribution (inv. hash , o)) {
2214
- m_connman. PushMessage (&pfrom, msgMaker. Make (NetMsgType::QCONTRIB, o));
2215
- push = true ;
2216
- }
2210
+ if (!push && (inv.type == MSG_QUORUM_FINAL_COMMITMENT )) {
2211
+ llmq::CFinalCommitment o;
2212
+ if (m_llmq_ctx->quorum_block_processor -> GetMineableCommitmentByHash (
2213
+ inv. hash , o)) {
2214
+ m_connman. PushMessage (&pfrom, msgMaker. Make (NetMsgType::QFCOMMITMENT, o)) ;
2215
+ push = true ;
2217
2216
}
2217
+ }
2218
2218
2219
- if (!push && (inv.type == MSG_QUORUM_COMPLAINT)) {
2220
- llmq::CDKGComplaint o;
2221
- if (m_llmq_ctx->qdkgsman ->GetComplaint (inv.hash , o)) {
2222
- m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::QCOMPLAINT, o));
2223
- push = true ;
2224
- }
2219
+ if (!push && (inv.type == MSG_QUORUM_CONTRIB)) {
2220
+ llmq::CDKGContribution o;
2221
+ if (m_llmq_ctx->qdkgsman ->GetContribution (inv.hash , o)) {
2222
+ m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::QCONTRIB, o));
2223
+ push = true ;
2225
2224
}
2225
+ }
2226
2226
2227
- if (!push && (inv.type == MSG_QUORUM_JUSTIFICATION)) {
2228
- llmq::CDKGJustification o;
2229
- if (m_llmq_ctx->qdkgsman ->GetJustification (inv.hash , o)) {
2230
- m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::QJUSTIFICATION, o));
2231
- push = true ;
2232
- }
2227
+ if (!push && (inv.type == MSG_QUORUM_COMPLAINT)) {
2228
+ llmq::CDKGComplaint o;
2229
+ if (m_llmq_ctx->qdkgsman ->GetComplaint (inv.hash , o)) {
2230
+ m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::QCOMPLAINT, o));
2231
+ push = true ;
2233
2232
}
2233
+ }
2234
2234
2235
- if (!push && (inv.type == MSG_QUORUM_PREMATURE_COMMITMENT)) {
2236
- llmq::CDKGPrematureCommitment o;
2237
- if (m_llmq_ctx->qdkgsman ->GetPrematureCommitment (inv.hash , o)) {
2238
- m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::QPCOMMITMENT, o));
2239
- push = true ;
2240
- }
2235
+ if (!push && (inv.type == MSG_QUORUM_JUSTIFICATION)) {
2236
+ llmq::CDKGJustification o;
2237
+ if (m_llmq_ctx->qdkgsman ->GetJustification (inv.hash , o)) {
2238
+ m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::QJUSTIFICATION, o));
2239
+ push = true ;
2241
2240
}
2241
+ }
2242
2242
2243
- if (!push && (inv.type == MSG_QUORUM_RECOVERED_SIG)) {
2244
- llmq::CRecoveredSig o;
2245
- if (m_llmq_ctx->sigman ->GetRecoveredSigForGetData (inv.hash , o)) {
2246
- m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::QSIGREC, o));
2247
- push = true ;
2248
- }
2243
+ if (!push && (inv.type == MSG_QUORUM_PREMATURE_COMMITMENT)) {
2244
+ llmq::CDKGPrematureCommitment o;
2245
+ if (m_llmq_ctx->qdkgsman ->GetPrematureCommitment (inv.hash , o)) {
2246
+ m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::QPCOMMITMENT, o));
2247
+ push = true ;
2249
2248
}
2249
+ }
2250
2250
2251
- if (!push && (inv.type == MSG_CLSIG)) {
2252
- llmq::CChainLockSig o;
2253
- if (m_llmq_ctx->clhandler ->GetChainLockByHash (inv.hash , o)) {
2254
- m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::CLSIG, o));
2255
- push = true ;
2256
- }
2251
+ if (!push && (inv.type == MSG_QUORUM_RECOVERED_SIG)) {
2252
+ llmq::CRecoveredSig o;
2253
+ if (m_llmq_ctx->sigman ->GetRecoveredSigForGetData (inv.hash , o)) {
2254
+ m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::QSIGREC, o));
2255
+ push = true ;
2257
2256
}
2257
+ }
2258
2258
2259
- if (!push && inv.type == MSG_ISDLOCK) {
2260
- llmq::CInstantSendLock o;
2261
- if (m_llmq_ctx->isman ->GetInstantSendLockByHash (inv.hash , o)) {
2262
- m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::ISDLOCK, o));
2263
- push = true ;
2264
- }
2259
+ if (!push && (inv.type == MSG_CLSIG)) {
2260
+ llmq::CChainLockSig o;
2261
+ if (m_llmq_ctx->clhandler ->GetChainLockByHash (inv.hash , o)) {
2262
+ m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::CLSIG, o));
2263
+ push = true ;
2265
2264
}
2265
+ }
2266
2266
2267
- if (!push) {
2268
- vNotFound.push_back (inv);
2267
+ if (!push && inv.type == MSG_ISDLOCK) {
2268
+ llmq::CInstantSendLock o;
2269
+ if (m_llmq_ctx->isman ->GetInstantSendLockByHash (inv.hash , o)) {
2270
+ m_connman.PushMessage (&pfrom, msgMaker.Make (NetMsgType::ISDLOCK, o));
2271
+ push = true ;
2269
2272
}
2270
2273
}
2271
- } // release cs_main
2274
+
2275
+ if (!push) {
2276
+ vNotFound.push_back (inv);
2277
+ }
2278
+ }
2272
2279
2273
2280
// Only process one BLOCK item per call, since they're uncommon and can be
2274
2281
// expensive to process.
0 commit comments