diff --git a/src/net_processing.cpp b/src/net_processing.cpp --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1974,7 +1974,7 @@ } static void ProcessGetData(const Config &config, CNode &pfrom, - CConnman &connman, const CTxMemPool &mempool, + CConnman &connman, CTxMemPool &mempool, const std::atomic &interruptMsgProc) LOCKS_EXCLUDED(cs_main) { AssertLockNotHeld(cs_main); @@ -2032,7 +2032,13 @@ push = true; } } - if (!push) { + + if (push) { + // We interpret fulfilling a GETDATA for a transaction as a + // successful initial broadcast and remove it from our + // unbroadcast set. + mempool.RemoveUnbroadcastTx(TxId(inv.hash)); + } else { vNotFound.push_back(inv); } } diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp --- a/src/node/transaction.cpp +++ b/src/node/transaction.cpp @@ -88,6 +88,10 @@ } if (relay) { + // the mempool tracks locally submitted transactions to make a + // best-effort of initial broadcast + node.mempool->AddUnbroadcastTx(txid); + RelayTransaction(txid, *node.connman); } diff --git a/src/txmempool.h b/src/txmempool.h --- a/src/txmempool.h +++ b/src/txmempool.h @@ -580,6 +580,12 @@ std::vector GetSortedDepthAndScore() const EXCLUSIVE_LOCKS_REQUIRED(cs); + /** + * Track locally submitted transactions to periodically retry initial + * broadcast + */ + std::set m_unbroadcast_txids GUARDED_BY(cs); + public: indirectmap mapNextTx GUARDED_BY(cs); std::map mapDeltas; @@ -777,6 +783,21 @@ size_t DynamicMemoryUsage() const; + /** Adds a transaction to the unbroadcast set */ + void AddUnbroadcastTx(const TxId &txid) { + LOCK(cs); + m_unbroadcast_txids.insert(txid); + } + + /** Removes a transaction from the unbroadcast set */ + void RemoveUnbroadcastTx(const TxId &txid, const bool unchecked = false); + + /** Returns transactions in unbroadcast set */ + const std::set GetUnbroadcastTxs() const { + LOCK(cs); + return m_unbroadcast_txids; + } + private: /** * UpdateForDescendants is used by UpdateTransactionsFromBlock to update the diff --git a/src/txmempool.cpp b/src/txmempool.cpp --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -476,6 +476,9 @@ mapNextTx.erase(txin.prevout); } + /* add logging because unchecked */ + RemoveUnbroadcastTx(it->GetTx().GetId(), true); + if (vTxHashes.size() > 1) { vTxHashes[it->vTxHashesIdx] = std::move(vTxHashes.back()); vTxHashes[it->vTxHashesIdx].second->vTxHashesIdx = it->vTxHashesIdx; @@ -1065,6 +1068,17 @@ memusage::DynamicUsage(vTxHashes) + cachedInnerUsage; } +void CTxMemPool::RemoveUnbroadcastTx(const TxId &txid, const bool unchecked) { + LOCK(cs); + + if (m_unbroadcast_txids.erase(txid)) { + LogPrint( + BCLog::MEMPOOL, "Removed %i from set of unbroadcast txns%s\n", + txid.GetHex(), + (unchecked ? " before confirmation that txn was sent out" : "")); + } +} + void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants, MemPoolRemovalReason reason) { AssertLockHeld(cs);