aboutsummaryrefslogtreecommitdiff
path: root/src/net_processing.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net_processing.cpp')
-rw-r--r--src/net_processing.cpp102
1 files changed, 53 insertions, 49 deletions
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 7e9bb2f27c..018541a597 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1608,6 +1608,37 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
}
}
+//! Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed).
+CTransactionRef static FindTxForGetData(CNode* peer, const uint256& txid, const std::chrono::seconds mempool_req, const std::chrono::seconds longlived_mempool_time) LOCKS_EXCLUDED(cs_main)
+{
+ // Check if the requested transaction is so recent that we're just
+ // about to announce it to the peer; if so, they certainly shouldn't
+ // know we already have it.
+ {
+ LOCK(peer->m_tx_relay->cs_tx_inventory);
+ if (peer->m_tx_relay->setInventoryTxToSend.count(txid)) return {};
+ }
+
+ {
+ LOCK(cs_main);
+ // Look up transaction in relay pool
+ auto mi = mapRelay.find(txid);
+ if (mi != mapRelay.end()) return mi->second;
+ }
+
+ auto txinfo = mempool.info(txid);
+ if (txinfo.tx) {
+ // To protect privacy, do not answer getdata using the mempool when
+ // that TX couldn't have been INVed in reply to a MEMPOOL request,
+ // or when it's too recent to have expired from mapRelay.
+ if ((mempool_req.count() && txinfo.m_time <= mempool_req) || txinfo.m_time <= longlived_mempool_time) {
+ return txinfo.tx;
+ }
+ }
+
+ return {};
+}
+
void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnman* connman, CTxMemPool& mempool, const std::atomic<bool>& interruptMsgProc) LOCKS_EXCLUDED(cs_main)
{
AssertLockNotHeld(cs_main);
@@ -1622,58 +1653,31 @@ void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnm
const std::chrono::seconds mempool_req = pfrom->m_tx_relay != nullptr ? pfrom->m_tx_relay->m_last_mempool_req.load()
: std::chrono::seconds::min();
- {
- LOCK(cs_main);
+ // Process as many TX items from the front of the getdata queue as
+ // possible, since they're common and it's efficient to batch process
+ // them.
+ while (it != pfrom->vRecvGetData.end() && (it->type == MSG_TX || it->type == MSG_WITNESS_TX)) {
+ if (interruptMsgProc) return;
+ // The send buffer provides backpressure. If there's no space in
+ // the buffer, pause processing until the next call.
+ if (pfrom->fPauseSend) break;
- // Process as many TX items from the front of the getdata queue as
- // possible, since they're common and it's efficient to batch process
- // them.
- while (it != pfrom->vRecvGetData.end() && (it->type == MSG_TX || it->type == MSG_WITNESS_TX)) {
- if (interruptMsgProc)
- return;
- // The send buffer provides backpressure. If there's no space in
- // the buffer, pause processing until the next call.
- if (pfrom->fPauseSend)
- break;
-
- const CInv &inv = *it++;
+ const CInv &inv = *it++;
- if (pfrom->m_tx_relay == nullptr) {
- // Ignore GETDATA requests for transactions from blocks-only peers.
- continue;
- }
+ if (pfrom->m_tx_relay == nullptr) {
+ // Ignore GETDATA requests for transactions from blocks-only peers.
+ continue;
+ }
- // Send stream from relay memory
- bool push = false;
- auto mi = mapRelay.find(inv.hash);
+ CTransactionRef tx = FindTxForGetData(pfrom, inv.hash, mempool_req, longlived_mempool_time);
+ if (tx) {
int nSendFlags = (inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0);
- if (mi != mapRelay.end()) {
- connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second));
- push = true;
- } else {
- auto txinfo = mempool.info(inv.hash);
- // To protect privacy, do not answer getdata using the mempool when
- // that TX couldn't have been INVed in reply to a MEMPOOL request,
- // or when it's too recent to have expired from mapRelay.
- if (txinfo.tx && (
- (mempool_req.count() && txinfo.m_time <= mempool_req)
- || (txinfo.m_time <= longlived_mempool_time)))
- {
- connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx));
- push = true;
- }
- }
-
- if (push) {
- // We interpret fulfilling a GETDATA for a transaction as a
- // successful initial broadcast and remove it from our
- // unbroadcast set.
- mempool.RemoveUnbroadcastTx(inv.hash);
- } else {
- vNotFound.push_back(inv);
- }
+ connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *tx));
+ mempool.RemoveUnbroadcastTx(inv.hash);
+ } else {
+ vNotFound.push_back(inv);
}
- } // release cs_main
+ }
// Only process one BLOCK item per call, since they're uncommon and can be
// expensive to process.
@@ -2671,8 +2675,8 @@ bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRec
if (msg_type == NetMsgType::TX) {
// Stop processing the transaction early if
- // We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off
- // or if this peer is supposed to be a block-relay-only peer
+ // 1) We are in blocks only mode and peer has no relay permission
+ // 2) This peer is a block-relay-only peer
if ((!g_relay_txes && !pfrom->HasPermission(PF_RELAY)) || (pfrom->m_tx_relay == nullptr))
{
LogPrint(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom->GetId());