Merge bitcoin/bitcoin#33005: refactor: GenTxid type safety followups

94b39ce738 refactor: Change `m_tx_inventory_to_send` from `std::set<GenTxid>` to `std::set<Wtxid>` (marcofleon)
a9819b0e9d refactor: Change `FindTxForGetData` to take GenTxid instead of CInv (marcofleon)
d588575ed1 refactor: miscellaneous GenTxid followups (marcofleon)

Pull request description:

  This is a followup to https://github.com/bitcoin/bitcoin/pull/32631.

  Addresses:
  https://github.com/bitcoin/bitcoin/pull/32631#discussion_r2200291621
  https://github.com/bitcoin/bitcoin/pull/32631#discussion_r2199951996
  https://github.com/bitcoin/bitcoin/pull/32631#discussion_r2201874252
  https://github.com/bitcoin/bitcoin/pull/32631#discussion_r2201918072
  https://github.com/bitcoin/bitcoin/pull/32631#issuecomment-3063383775

ACKs for top commit:
  glozow:
    ACK 94b39ce738
  maflcko:
    review ACK 94b39ce738 🎲
  stickies-v:
    ACK 94b39ce738

Tree-SHA512: 3c88656b2e4e676653db87df5b1b694e1b1f40d89d7b825dad068e57c9c9f8add098ba797413274bd992b1c1fdec94c794ab3fd086d2a9561f5de92ae9f6d942
This commit is contained in:
merge-script committed 2025-07-30 14:20:03 -04:00
commit dc78ed2140
6 files changed
+46 -43

No files matched your search

+35 -33
View File
@@ -298,11 +298,11 @@ struct Peer {
* us or we have announced to the peer. We use this to avoid announcing * us or we have announced to the peer. We use this to avoid announcing
* the same (w)txid to a peer that already has the transaction. */ * the same (w)txid to a peer that already has the transaction. */
CRollingBloomFilter m_tx_inventory_known_filter GUARDED_BY(m_tx_inventory_mutex){50000, 0.000001}; CRollingBloomFilter m_tx_inventory_known_filter GUARDED_BY(m_tx_inventory_mutex){50000, 0.000001};
/** Set of transaction ids we still have to announce (txid for /** Set of wtxids we still have to announce. For non-wtxid-relay peers,
* non-wtxid-relay peers, wtxid for wtxid-relay peers). We use the * we retrieve the txid from the corresponding mempool transaction when
* mempool to sort transactions in dependency order before relay, so * constructing the `inv` message. We use the mempool to sort transactions
* this does not have to be sorted. */ * in dependency order before relay, so this does not have to be sorted. */
std::set<GenTxid> m_tx_inventory_to_send GUARDED_BY(m_tx_inventory_mutex); std::set<Wtxid> m_tx_inventory_to_send GUARDED_BY(m_tx_inventory_mutex);
/** Whether the peer has requested us to send our complete mempool. Only /** Whether the peer has requested us to send our complete mempool. Only
* permitted if the peer has NetPermissionFlags::Mempool or we advertise * permitted if the peer has NetPermissionFlags::Mempool or we advertise
* NODE_BLOOM. See BIP35. */ * NODE_BLOOM. See BIP35. */
@@ -947,7 +947,7 @@ private:
std::atomic<std::chrono::seconds> m_last_tip_update{0s}; std::atomic<std::chrono::seconds> m_last_tip_update{0s};
/** Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed). */ /** Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed). */
CTransactionRef FindTxForGetData(const Peer::TxRelay& tx_relay, const CInv& inv) CTransactionRef FindTxForGetData(const Peer::TxRelay& tx_relay, const GenTxid& gtxid)
EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex, NetEventsInterface::g_msgproc_mutex); EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex, NetEventsInterface::g_msgproc_mutex);
void ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic<bool>& interruptMsgProc) void ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic<bool>& interruptMsgProc)
@@ -2166,9 +2166,9 @@ void PeerManagerImpl::RelayTransaction(const Txid& txid, const Wtxid& wtxid)
// in the announcement. // in the announcement.
if (tx_relay->m_next_inv_send_time == 0s) continue; if (tx_relay->m_next_inv_send_time == 0s) continue;
const auto gtxid{peer.m_wtxid_relay ? GenTxid{wtxid} : GenTxid{txid}}; const uint256& hash{peer.m_wtxid_relay ? wtxid.ToUint256() : txid.ToUint256()};
if (!tx_relay->m_tx_inventory_known_filter.contains(gtxid.ToUint256())) { if (!tx_relay->m_tx_inventory_known_filter.contains(hash)) {
tx_relay->m_tx_inventory_to_send.insert(gtxid); tx_relay->m_tx_inventory_to_send.insert(wtxid);
} }
} }
} }
@@ -2391,15 +2391,14 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
} }
} }
CTransactionRef PeerManagerImpl::FindTxForGetData(const Peer::TxRelay& tx_relay, const CInv& inv) CTransactionRef PeerManagerImpl::FindTxForGetData(const Peer::TxRelay& tx_relay, const GenTxid& gtxid)
{ {
auto gtxid{ToGenTxid(inv)};
// If a tx was in the mempool prior to the last INV for this peer, permit the request.
auto txinfo{std::visit( auto txinfo{std::visit(
[&](const auto& id) EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex) { [&](const auto& id) EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex) {
return m_mempool.info_for_relay(id, tx_relay.m_last_inv_sequence); return m_mempool.info_for_relay(id, tx_relay.m_last_inv_sequence);
}, },
gtxid)}; gtxid)};
if (txinfo.tx) { if (txinfo.tx) {
return std::move(txinfo.tx); return std::move(txinfo.tx);
} }
@@ -2442,7 +2441,7 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic
continue; continue;
} }
if (auto tx{FindTxForGetData(*tx_relay, inv)}) { if (auto tx{FindTxForGetData(*tx_relay, ToGenTxid(inv))}) {
// WTX and WITNESS_TX imply we serialize with witness // WTX and WITNESS_TX imply we serialize with witness
const auto maybe_with_witness = (inv.IsMsgTx() ? TX_NO_WITNESS : TX_WITH_WITNESS); const auto maybe_with_witness = (inv.IsMsgTx() ? TX_NO_WITNESS : TX_WITH_WITNESS);
MakeAndPushMessage(pfrom, NetMsgType::TX, maybe_with_witness(*tx)); MakeAndPushMessage(pfrom, NetMsgType::TX, maybe_with_witness(*tx));
@@ -5440,7 +5439,7 @@ class CompareInvMempoolOrder
public: public:
explicit CompareInvMempoolOrder(CTxMemPool* mempool) : m_mempool{mempool} {} explicit CompareInvMempoolOrder(CTxMemPool* mempool) : m_mempool{mempool} {}
bool operator()(std::set<GenTxid>::iterator a, std::set<GenTxid>::iterator b) bool operator()(std::set<Wtxid>::iterator a, std::set<Wtxid>::iterator b)
{ {
/* As std::make_heap produces a max-heap, we want the entries with the /* As std::make_heap produces a max-heap, we want the entries with the
* fewest ancestors/highest fee to sort later. */ * fewest ancestors/highest fee to sort later. */
@@ -5756,13 +5755,12 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
LOCK(tx_relay->m_bloom_filter_mutex); LOCK(tx_relay->m_bloom_filter_mutex);
for (const auto& txinfo : vtxinfo) { for (const auto& txinfo : vtxinfo) {
CInv inv{ const Txid& txid{txinfo.tx->GetHash()};
peer->m_wtxid_relay ? MSG_WTX : MSG_TX, const Wtxid& wtxid{txinfo.tx->GetWitnessHash()};
peer->m_wtxid_relay ? const auto inv = peer->m_wtxid_relay ?
txinfo.tx->GetWitnessHash().ToUint256() : CInv{MSG_WTX, wtxid.ToUint256()} :
txinfo.tx->GetHash().ToUint256(), CInv{MSG_TX, txid.ToUint256()};
}; tx_relay->m_tx_inventory_to_send.erase(wtxid);
tx_relay->m_tx_inventory_to_send.erase(ToGenTxid(inv));
// Don't send transactions that peers will not put into their mempool // Don't send transactions that peers will not put into their mempool
if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) { if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
@@ -5783,9 +5781,9 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// Determine transactions to relay // Determine transactions to relay
if (fSendTrickle) { if (fSendTrickle) {
// Produce a vector with all candidates for sending // Produce a vector with all candidates for sending
std::vector<std::set<GenTxid>::iterator> vInvTx; std::vector<std::set<Wtxid>::iterator> vInvTx;
vInvTx.reserve(tx_relay->m_tx_inventory_to_send.size()); vInvTx.reserve(tx_relay->m_tx_inventory_to_send.size());
for (std::set<GenTxid>::iterator it = tx_relay->m_tx_inventory_to_send.begin(); it != tx_relay->m_tx_inventory_to_send.end(); it++) { for (std::set<Wtxid>::iterator it = tx_relay->m_tx_inventory_to_send.begin(); it != tx_relay->m_tx_inventory_to_send.end(); it++) {
vInvTx.push_back(it); vInvTx.push_back(it);
} }
const CFeeRate filterrate{tx_relay->m_fee_filter_received.load()}; const CFeeRate filterrate{tx_relay->m_fee_filter_received.load()};
@@ -5802,20 +5800,24 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
while (!vInvTx.empty() && nRelayedTransactions < broadcast_max) { while (!vInvTx.empty() && nRelayedTransactions < broadcast_max) {
// Fetch the top element from the heap // Fetch the top element from the heap
std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder); std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
std::set<GenTxid>::iterator it = vInvTx.back(); std::set<Wtxid>::iterator it = vInvTx.back();
vInvTx.pop_back(); vInvTx.pop_back();
GenTxid hash = *it; auto wtxid = *it;
Assume(peer->m_wtxid_relay == hash.IsWtxid());
CInv inv(peer->m_wtxid_relay ? MSG_WTX : MSG_TX, hash.ToUint256());
// Remove it from the to-be-sent set // Remove it from the to-be-sent set
tx_relay->m_tx_inventory_to_send.erase(it); tx_relay->m_tx_inventory_to_send.erase(it);
// Check if not in the filter already // Not in the mempool anymore? don't bother sending it.
if (tx_relay->m_tx_inventory_known_filter.contains(hash.ToUint256())) { auto txinfo = m_mempool.info(wtxid);
if (!txinfo.tx) {
continue; continue;
} }
// Not in the mempool anymore? don't bother sending it. // `TxRelay::m_tx_inventory_known_filter` contains either txids or wtxids
auto txinfo{std::visit([&](const auto& id) { return m_mempool.info(id); }, hash)}; // depending on whether our peer supports wtxid-relay. Therefore, first
if (!txinfo.tx) { // construct the inv and then use its hash for the filter check.
const auto inv = peer->m_wtxid_relay ?
CInv{MSG_WTX, wtxid.ToUint256()} :
CInv{MSG_TX, txinfo.tx->GetHash().ToUint256()};
// Check if not in the filter already
if (tx_relay->m_tx_inventory_known_filter.contains(inv.hash)) {
continue; continue;
} }
// Peer told you to not send transactions at that feerate? Don't bother sending it. // Peer told you to not send transactions at that feerate? Don't bother sending it.
@@ -5830,7 +5832,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
MakeAndPushMessage(*pto, NetMsgType::INV, vInv); MakeAndPushMessage(*pto, NetMsgType::INV, vInv);
vInv.clear(); vInv.clear();
} }
tx_relay->m_tx_inventory_known_filter.insert(hash.ToUint256()); tx_relay->m_tx_inventory_known_filter.insert(inv.hash);
} }
// Ensure we'll respond to GETDATA requests for anything we've just announced // Ensure we'll respond to GETDATA requests for anything we've just announced
+5 -5
View File
@@ -793,7 +793,7 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei
assert(innerUsage == cachedInnerUsage); assert(innerUsage == cachedInnerUsage);
} }
bool CTxMemPool::CompareDepthAndScore(const GenTxid& hasha, const GenTxid& hashb) const bool CTxMemPool::CompareDepthAndScore(const Wtxid& hasha, const Wtxid& hashb) const
{ {
/* Return `true` if hasha should be considered sooner than hashb. Namely when: /* Return `true` if hasha should be considered sooner than hashb. Namely when:
* a is not in the mempool, but b is * a is not in the mempool, but b is
@@ -801,9 +801,9 @@ bool CTxMemPool::CompareDepthAndScore(const GenTxid& hasha, const GenTxid& hashb
* both are in the mempool and a has a higher score than b * both are in the mempool and a has a higher score than b
*/ */
LOCK(cs); LOCK(cs);
auto j{std::visit([&](const auto& id) EXCLUSIVE_LOCKS_REQUIRED(cs) { return GetIter(id); }, hashb)}; auto j{GetIter(hashb)};
if (!j.has_value()) return false; if (!j.has_value()) return false;
auto i{std::visit([&](const auto& id) EXCLUSIVE_LOCKS_REQUIRED(cs) { return GetIter(id); }, hasha)}; auto i{GetIter(hasha)};
if (!i.has_value()) return true; if (!i.has_value()) return true;
uint64_t counta = i.value()->GetCountWithAncestors(); uint64_t counta = i.value()->GetCountWithAncestors();
uint64_t countb = j.value()->GetCountWithAncestors(); uint64_t countb = j.value()->GetCountWithAncestors();
@@ -961,9 +961,9 @@ const CTransaction* CTxMemPool::GetConflictTx(const COutPoint& prevout) const
std::optional<CTxMemPool::txiter> CTxMemPool::GetIter(const Txid& txid) const std::optional<CTxMemPool::txiter> CTxMemPool::GetIter(const Txid& txid) const
{ {
AssertLockHeld(cs);
auto it = mapTx.find(txid.ToUint256()); auto it = mapTx.find(txid.ToUint256());
if (it != mapTx.end()) return it; return it != mapTx.end() ? std::make_optional(it) : std::nullopt;
return std::nullopt;
} }
std::optional<CTxMemPool::txiter> CTxMemPool::GetIter(const Wtxid& wtxid) const std::optional<CTxMemPool::txiter> CTxMemPool::GetIter(const Wtxid& wtxid) const
+1 -1
View File
@@ -448,7 +448,7 @@ public:
void removeConflicts(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(cs); void removeConflicts(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(cs);
void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight) EXCLUSIVE_LOCKS_REQUIRED(cs); void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight) EXCLUSIVE_LOCKS_REQUIRED(cs);
bool CompareDepthAndScore(const GenTxid& hasha, const GenTxid& hashb) const; bool CompareDepthAndScore(const Wtxid& hasha, const Wtxid& hashb) const;
bool isSpent(const COutPoint& outpoint) const; bool isSpent(const COutPoint& outpoint) const;
unsigned int GetTransactionsUpdated() const; unsigned int GetTransactionsUpdated() const;
void AddTransactionsUpdated(unsigned int n); void AddTransactionsUpdated(unsigned int n);
+2 -2
View File
@@ -595,7 +595,7 @@ public:
//! Find the GenTxids to request now from peer. //! Find the GenTxids to request now from peer.
std::vector<GenTxid> GetRequestable(NodeId peer, std::chrono::microseconds now, std::vector<GenTxid> GetRequestable(NodeId peer, std::chrono::microseconds now,
std::vector<std::pair<NodeId, GenTxid>>* expired) std::vector<std::pair<NodeId, GenTxid>>* expired)
{ {
// Move time. // Move time.
SetTimePoint(now, expired); SetTimePoint(now, expired);
@@ -746,7 +746,7 @@ void TxRequestTracker::ReceivedResponse(NodeId peer, const uint256& txhash)
} }
std::vector<GenTxid> TxRequestTracker::GetRequestable(NodeId peer, std::chrono::microseconds now, std::vector<GenTxid> TxRequestTracker::GetRequestable(NodeId peer, std::chrono::microseconds now,
std::vector<std::pair<NodeId, GenTxid>>* expired) std::vector<std::pair<NodeId, GenTxid>>* expired)
{ {
return m_impl->GetRequestable(peer, now, expired); return m_impl->GetRequestable(peer, now, expired);
} }
+1 -1
View File
@@ -164,7 +164,7 @@ public:
* simultaneously by one peer, and end up being requested from them, the requests will happen in announcement order. * simultaneously by one peer, and end up being requested from them, the requests will happen in announcement order.
*/ */
std::vector<GenTxid> GetRequestable(NodeId peer, std::chrono::microseconds now, std::vector<GenTxid> GetRequestable(NodeId peer, std::chrono::microseconds now,
std::vector<std::pair<NodeId, GenTxid>>* expired = nullptr); std::vector<std::pair<NodeId, GenTxid>>* expired = nullptr);
/** Marks a transaction as requested, with a specified expiry. /** Marks a transaction as requested, with a specified expiry.
* *
+2 -1
View File
@@ -98,7 +98,8 @@ public:
friend auto operator<=>(const GenTxid& a, const GenTxid& b) friend auto operator<=>(const GenTxid& a, const GenTxid& b)
{ {
return std::tuple(a.IsWtxid(), a.ToUint256()) <=> std::tuple(b.IsWtxid(), b.ToUint256()); // Use a reference for read-only access to the hash, avoiding a copy that might not be optimized away.
return std::tuple<bool, const uint256&>(a.IsWtxid(), a.ToUint256()) <=> std::tuple<bool, const uint256&>(b.IsWtxid(), b.ToUint256());
} }
}; };