net_processing: stop private broadcast of a transaction after round-trip

Remove the transaction from the list of transactions to broadcast after
we receive it from the network.

Only remove the transaction if it is the same as the one we sent: has
the same wtxid (and it follows the same txid). Don't remove transactions
that have the same txid and different wtxid. Such transactions show that
some of the private broadcast recipients malleated the witness and the
transaction made it back to us. The witness could be either:
* invalid, in which case the transaction will not be accepted in
  anybody's pool; or
* valid, in which case either the original or the malleated transaction
  will make it to nodes' mempools and eventually be mined. Our response
  is to keep broadcasting the original. If the malleated transaction
  wins then we will eventually stop broadcasting the original when it
  gets stale and gets removed from the "to broadcast" storage cause it
  is not acceptable in our mempool.
This commit is contained in:
Vasil Dimov
2024-01-30 18:51:23 +01:00
parent 2de53eee74
commit 37b79f9c39
3 changed files with 34 additions and 0 deletions

View File

@@ -4425,6 +4425,17 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
const uint256& hash = peer->m_wtxid_relay ? wtxid.ToUint256() : txid.ToUint256();
AddKnownTx(*peer, hash);
if (const auto num_broadcasted{m_tx_for_private_broadcast.Remove(ptx)}) {
LogInfo("[privatebroadcast] Received our privately broadcast transaction (txid=%s) from the "
"network from peer=%d%s; stopping private broadcast attempts",
txid.ToString(), pfrom.GetId(), pfrom.LogIP(fLogIPs));
if (NUM_PRIVATE_BROADCAST_PER_TX > num_broadcasted.value()) {
// Not all of the initial NUM_PRIVATE_BROADCAST_PER_TX connections were needed.
// Tell CConnman it does not need to start the remaining ones.
m_connman.m_private_broadcast.NumToOpenSub(NUM_PRIVATE_BROADCAST_PER_TX - num_broadcasted.value());
}
}
LOCK2(cs_main, m_tx_download_mutex);
const auto& [should_validate, package_to_validate] = m_txdownloadman.ReceivedTx(pfrom.GetId(), ptx);