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.cpp297
1 files changed, 170 insertions, 127 deletions
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 59cd83e493..1df47fe3dd 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -41,6 +41,7 @@
#include <algorithm>
#include <atomic>
#include <chrono>
+#include <future>
#include <memory>
#include <optional>
#include <typeinfo>
@@ -232,6 +233,39 @@ struct Peer {
/** Whether a ping has been requested by the user */
std::atomic<bool> m_ping_queued{false};
+ /** Whether this peer relays txs via wtxid */
+ std::atomic<bool> m_wtxid_relay{false};
+
+ struct TxRelay {
+ mutable RecursiveMutex m_bloom_filter_mutex;
+ // We use m_relay_txs for two purposes -
+ // a) it allows us to not relay tx invs before receiving the peer's version message
+ // b) the peer may tell us in its version message that we should not relay tx invs
+ // unless it loads a bloom filter.
+ bool m_relay_txs GUARDED_BY(m_bloom_filter_mutex){false};
+ std::unique_ptr<CBloomFilter> m_bloom_filter PT_GUARDED_BY(m_bloom_filter_mutex) GUARDED_BY(m_bloom_filter_mutex){nullptr};
+
+ mutable RecursiveMutex m_tx_inventory_mutex;
+ CRollingBloomFilter m_tx_inventory_known_filter GUARDED_BY(m_tx_inventory_mutex){50000, 0.000001};
+ // Set of transaction ids we still have to announce.
+ // They are sorted by the mempool before relay, so the order is not important.
+ std::set<uint256> m_tx_inventory_to_send;
+ // Used for BIP35 mempool sending
+ bool m_send_mempool GUARDED_BY(m_tx_inventory_mutex){false};
+ // Last time a "MEMPOOL" request was serviced.
+ std::atomic<std::chrono::seconds> m_last_mempool_req{0s};
+ std::chrono::microseconds m_next_inv_send_time{0};
+
+ /** Minimum fee rate with which to filter inv's to this node */
+ std::atomic<CAmount> m_fee_filter_received{0};
+ CAmount m_fee_filter_sent{0};
+ std::chrono::microseconds m_next_send_feefilter{0};
+ };
+
+ /** Transaction relay data. Will be a nullptr if we're not relaying
+ * transactions with this peer (e.g. if it's a block-relay-only peer) */
+ std::unique_ptr<TxRelay> m_tx_relay;
+
/** A vector of addresses to send to the peer, limited to MAX_ADDR_TO_SEND. */
std::vector<CAddress> m_addrs_to_send;
/** Probabilistic filter to track recent addr messages relayed with this
@@ -290,8 +324,9 @@ struct Peer {
/** Work queue of items requested by this peer **/
std::deque<CInv> m_getdata_requests GUARDED_BY(m_getdata_requests_mutex);
- explicit Peer(NodeId id)
+ explicit Peer(NodeId id, bool tx_relay)
: m_id(id)
+ , m_tx_relay(tx_relay ? std::make_unique<TxRelay>() : nullptr)
{}
};
@@ -331,9 +366,6 @@ public:
const std::chrono::microseconds time_received, const std::atomic<bool>& interruptMsgProc) override;
private:
- void _RelayTransaction(const uint256& txid, const uint256& wtxid)
- EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
/** Consider evicting an outbound peer based on the amount of time they've been behind our tip */
void ConsiderEviction(CNode& pto, std::chrono::seconds time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -394,7 +426,7 @@ private:
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
/** Send a version message to a peer */
- void PushNodeVersion(CNode& pnode);
+ void PushNodeVersion(CNode& pnode, Peer& peer);
/** Send a ping message every PING_INTERVAL or if requested via RPC. May
* mark the peer to be disconnected if a ping has timed out.
@@ -415,7 +447,7 @@ private:
void RelayAddress(NodeId originator, const CAddress& addr, bool fReachable);
/** Send `feefilter` message. */
- void MaybeSendFeefilter(CNode& node, std::chrono::microseconds current_time);
+ void MaybeSendFeefilter(CNode& node, Peer& peer, std::chrono::microseconds current_time);
const CChainParams& m_chainparams;
CConnman& m_connman;
@@ -464,7 +496,7 @@ private:
std::map<uint256, std::pair<NodeId, bool>> mapBlockSource GUARDED_BY(cs_main);
/** Number of peers with wtxid relay. */
- int m_wtxid_relay_peers GUARDED_BY(cs_main) = 0;
+ std::atomic<int> m_wtxid_relay_peers{0};
/** Number of outbound peers with m_chain_sync.m_protect. */
int m_outbound_peers_with_protect_from_disconnect GUARDED_BY(cs_main) = 0;
@@ -779,9 +811,6 @@ struct CNodeState {
//! A rolling bloom filter of all announced tx CInvs to this peer.
CRollingBloomFilter m_recently_announced_invs = CRollingBloomFilter{INVENTORY_MAX_RECENT_RELAY, 0.000001};
- //! Whether this peer relays txs via wtxid
- bool m_wtxid_relay{false};
-
CNodeState(bool is_inbound) : m_is_inbound(is_inbound) {}
};
@@ -826,6 +855,14 @@ static void PushAddress(Peer& peer, const CAddress& addr, FastRandomContext& ins
}
}
+static void AddKnownTx(Peer& peer, const uint256& hash)
+{
+ if (peer.m_tx_relay != nullptr) {
+ LOCK(peer.m_tx_relay->m_tx_inventory_mutex);
+ peer.m_tx_relay->m_tx_inventory_known_filter.insert(hash);
+ }
+}
+
static void UpdatePreferredDownload(const CNode& node, CNodeState* state) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
nPreferredDownload -= state->fPreferredDownload;
@@ -1121,7 +1158,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
} // namespace
-void PeerManagerImpl::PushNodeVersion(CNode& pnode)
+void PeerManagerImpl::PushNodeVersion(CNode& pnode, Peer& peer)
{
// Note that pnode->GetLocalServices() is a reflection of the local
// services we were offering when the CNode object was created for this
@@ -1136,7 +1173,7 @@ void PeerManagerImpl::PushNodeVersion(CNode& pnode)
CService addr_you = addr.IsRoutable() && !IsProxy(addr) && addr.IsAddrV1Compatible() ? addr : CService();
uint64_t your_services{addr.nServices};
- const bool tx_relay = !m_ignore_incoming_txs && pnode.m_tx_relay != nullptr && !pnode.IsFeelerConn();
+ const bool tx_relay = !m_ignore_incoming_txs && peer.m_tx_relay != nullptr && !pnode.IsFeelerConn();
m_connman.PushMessage(&pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, my_services, nTime,
your_services, addr_you, // Together the pre-version-31402 serialization of CAddress "addrYou" (without nTime)
my_services, CService(), // Together the pre-version-31402 serialization of CAddress "addrMe" (without nTime)
@@ -1193,13 +1230,13 @@ void PeerManagerImpl::InitializeNode(CNode *pnode)
mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(pnode->IsInboundConn()));
assert(m_txrequest.Count(nodeid) == 0);
}
+ PeerRef peer = std::make_shared<Peer>(nodeid, /*tx_relay=*/ !pnode->IsBlockOnlyConn());
{
- PeerRef peer = std::make_shared<Peer>(nodeid);
LOCK(m_peer_mutex);
- m_peer_map.emplace_hint(m_peer_map.end(), nodeid, std::move(peer));
+ m_peer_map.emplace_hint(m_peer_map.end(), nodeid, peer);
}
if (!pnode->IsInboundConn()) {
- PushNodeVersion(*pnode);
+ PushNodeVersion(*pnode, *peer);
}
}
@@ -1211,8 +1248,7 @@ void PeerManagerImpl::ReattemptInitialBroadcast(CScheduler& scheduler)
CTransactionRef tx = m_mempool.get(txid);
if (tx != nullptr) {
- LOCK(cs_main);
- _RelayTransaction(txid, tx->GetWitnessHash());
+ RelayTransaction(txid, tx->GetWitnessHash());
} else {
m_mempool.RemoveUnbroadcastTx(txid, true);
}
@@ -1239,6 +1275,8 @@ void PeerManagerImpl::FinalizeNode(const CNode& node)
PeerRef peer = RemovePeer(nodeid);
assert(peer != nullptr);
misbehavior = WITH_LOCK(peer->m_misbehavior_mutex, return peer->m_misbehavior_score);
+ m_wtxid_relay_peers -= peer->m_wtxid_relay;
+ assert(m_wtxid_relay_peers >= 0);
}
CNodeState *state = State(nodeid);
assert(state != nullptr);
@@ -1256,8 +1294,6 @@ void PeerManagerImpl::FinalizeNode(const CNode& node)
assert(m_peers_downloading_from >= 0);
m_outbound_peers_with_protect_from_disconnect -= state->m_chain_sync.m_protect;
assert(m_outbound_peers_with_protect_from_disconnect >= 0);
- m_wtxid_relay_peers -= state->m_wtxid_relay;
- assert(m_wtxid_relay_peers >= 0);
mapNodeState.erase(nodeid);
@@ -1330,6 +1366,14 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) c
ping_wait = GetTime<std::chrono::microseconds>() - peer->m_ping_start.load();
}
+ if (peer->m_tx_relay != nullptr) {
+ stats.m_relay_txs = WITH_LOCK(peer->m_tx_relay->m_bloom_filter_mutex, return peer->m_tx_relay->m_relay_txs);
+ stats.m_fee_filter_received = peer->m_tx_relay->m_fee_filter_received.load();
+ } else {
+ stats.m_relay_txs = false;
+ stats.m_fee_filter_received = 0;
+ }
+
stats.m_ping_wait = ping_wait;
stats.m_addr_processed = peer->m_addr_processed.load();
stats.m_addr_rate_limited = peer->m_addr_rate_limited.load();
@@ -1596,6 +1640,8 @@ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::sha
bool fWitnessEnabled = DeploymentActiveAt(*pindex, m_chainparams.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT);
uint256 hashBlock(pblock->GetHash());
+ const std::shared_future<CSerializedNetMsg> lazy_ser{
+ std::async(std::launch::deferred, [&] { return msgMaker.Make(NetMsgType::CMPCTBLOCK, *pcmpctblock); })};
{
LOCK(cs_most_recent_block);
@@ -1605,10 +1651,9 @@ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::sha
fWitnessesPresentInMostRecentCompactBlock = fWitnessEnabled;
}
- m_connman.ForEachNode([this, &pcmpctblock, pindex, &msgMaker, fWitnessEnabled, &hashBlock](CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
+ m_connman.ForEachNode([this, pindex, fWitnessEnabled, &lazy_ser, &hashBlock](CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
AssertLockHeld(::cs_main);
- // TODO: Avoid the repeated-serialization here
if (pnode->GetCommonVersion() < INVALID_CB_NO_BAN_VERSION || pnode->fDisconnect)
return;
ProcessBlockAvailability(pnode->GetId());
@@ -1620,7 +1665,9 @@ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::sha
LogPrint(BCLog::NET, "%s sending header-and-ids %s to peer=%d\n", "PeerManager::NewPoWValidBlock",
hashBlock.ToString(), pnode->GetId());
- m_connman.PushMessage(pnode, msgMaker.Make(NetMsgType::CMPCTBLOCK, *pcmpctblock));
+
+ const CSerializedNetMsg& ser_cmpctblock{lazy_ser.get()};
+ m_connman.PushMessage(pnode, ser_cmpctblock.Copy());
state.pindexBestHeaderSent = pindex;
}
});
@@ -1742,22 +1789,17 @@ void PeerManagerImpl::SendPings()
void PeerManagerImpl::RelayTransaction(const uint256& txid, const uint256& wtxid)
{
- WITH_LOCK(cs_main, _RelayTransaction(txid, wtxid););
-}
-
-void PeerManagerImpl::_RelayTransaction(const uint256& txid, const uint256& wtxid)
-{
- m_connman.ForEachNode([&txid, &wtxid](CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
- AssertLockHeld(::cs_main);
+ LOCK(m_peer_mutex);
+ for(auto& it : m_peer_map) {
+ Peer& peer = *it.second;
+ if (!peer.m_tx_relay) continue;
- CNodeState* state = State(pnode->GetId());
- if (state == nullptr) return;
- if (state->m_wtxid_relay) {
- pnode->PushTxInventory(wtxid);
- } else {
- pnode->PushTxInventory(txid);
+ const uint256& hash{peer.m_wtxid_relay ? wtxid : txid};
+ LOCK(peer.m_tx_relay->m_tx_inventory_mutex);
+ if (!peer.m_tx_relay->m_tx_inventory_known_filter.contains(hash)) {
+ peer.m_tx_relay->m_tx_inventory_to_send.insert(hash);
}
- });
+ };
}
void PeerManagerImpl::RelayAddress(NodeId originator,
@@ -1903,11 +1945,11 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
} else if (inv.IsMsgFilteredBlk()) {
bool sendMerkleBlock = false;
CMerkleBlock merkleBlock;
- if (pfrom.m_tx_relay != nullptr) {
- LOCK(pfrom.m_tx_relay->cs_filter);
- if (pfrom.m_tx_relay->pfilter) {
+ if (peer.m_tx_relay != nullptr) {
+ LOCK(peer.m_tx_relay->m_bloom_filter_mutex);
+ if (peer.m_tx_relay->m_bloom_filter) {
sendMerkleBlock = true;
- merkleBlock = CMerkleBlock(*pblock, *pfrom.m_tx_relay->pfilter);
+ merkleBlock = CMerkleBlock(*pblock, *peer.m_tx_relay->m_bloom_filter);
}
}
if (sendMerkleBlock) {
@@ -1996,7 +2038,7 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic
const auto now{GetTime<std::chrono::seconds>()};
// Get last mempool request time
- const auto mempool_req = pfrom.m_tx_relay != nullptr ? pfrom.m_tx_relay->m_last_mempool_req.load() : std::chrono::seconds::min();
+ const auto mempool_req = peer.m_tx_relay != nullptr ? peer.m_tx_relay->m_last_mempool_req.load() : std::chrono::seconds::min();
// 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
@@ -2009,7 +2051,7 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic
const CInv &inv = *it++;
- if (pfrom.m_tx_relay == nullptr) {
+ if (peer.m_tx_relay == nullptr) {
// Ignore GETDATA requests for transactions from blocks-only peers.
continue;
}
@@ -2037,7 +2079,7 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic
}
for (const uint256& parent_txid : parent_ids_to_add) {
// Relaying a transaction with a recent but unconfirmed parent.
- if (WITH_LOCK(pfrom.m_tx_relay->cs_tx_inventory, return !pfrom.m_tx_relay->filterInventoryKnown.contains(parent_txid))) {
+ if (WITH_LOCK(peer.m_tx_relay->m_tx_inventory_mutex, return !peer.m_tx_relay->m_tx_inventory_known_filter.contains(parent_txid))) {
LOCK(cs_main);
State(pfrom.GetId())->m_recently_announced_invs.insert(parent_txid);
}
@@ -2317,7 +2359,7 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
- _RelayTransaction(orphanHash, porphanTx->GetWitnessHash());
+ RelayTransaction(orphanHash, porphanTx->GetWitnessHash());
m_orphanage.AddChildrenToWorkSet(*porphanTx, orphan_work_set);
m_orphanage.EraseTx(orphanHash);
for (const CTransactionRef& removedTx : result.m_replaced_transactions.value()) {
@@ -2633,7 +2675,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Inbound peers send us their version message when they connect.
// We send our version message in response.
if (pfrom.IsInboundConn()) {
- PushNodeVersion(pfrom);
+ PushNodeVersion(pfrom, *peer);
}
// Change version
@@ -2672,9 +2714,10 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// set nodes not capable of serving the complete blockchain history as "limited nodes"
pfrom.m_limited_node = (!(nServices & NODE_NETWORK) && (nServices & NODE_NETWORK_LIMITED));
- if (pfrom.m_tx_relay != nullptr) {
- LOCK(pfrom.m_tx_relay->cs_filter);
- pfrom.m_tx_relay->fRelayTxes = fRelay; // set to true after we get the first filter* message
+ if (peer->m_tx_relay != nullptr) {
+ LOCK(peer->m_tx_relay->m_bloom_filter_mutex);
+ peer->m_tx_relay->m_relay_txs = fRelay; // set to true after we get the first filter* message
+ if (fRelay) pfrom.m_relays_txs = true;
}
if((nServices & NODE_WITNESS))
@@ -2863,9 +2906,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
return;
}
if (pfrom.GetCommonVersion() >= WTXID_RELAY_VERSION) {
- LOCK(cs_main);
- if (!State(pfrom.GetId())->m_wtxid_relay) {
- State(pfrom.GetId())->m_wtxid_relay = true;
+ if (!peer->m_wtxid_relay) {
+ peer->m_wtxid_relay = true;
m_wtxid_relay_peers++;
} else {
LogPrint(BCLog::NET, "ignoring duplicate wtxidrelay from peer=%d\n", pfrom.GetId());
@@ -3001,7 +3043,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Reject tx INVs when the -blocksonly setting is enabled, or this is a
// block-relay-only peer
- bool reject_tx_invs{m_ignore_incoming_txs || (pfrom.m_tx_relay == nullptr)};
+ bool reject_tx_invs{m_ignore_incoming_txs || (peer->m_tx_relay == nullptr)};
// Allow peers with relay permission to send data other than blocks in blocks only mode
if (pfrom.HasPermission(NetPermissionFlags::Relay)) {
@@ -3019,7 +3061,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Ignore INVs that don't match wtxidrelay setting.
// Note that orphan parent fetching always uses MSG_TX GETDATAs regardless of the wtxidrelay setting.
// This is fine as no INV messages are involved in that process.
- if (State(pfrom.GetId())->m_wtxid_relay) {
+ if (peer->m_wtxid_relay) {
if (inv.IsMsgTx()) continue;
} else {
if (inv.IsMsgWtx()) continue;
@@ -3048,7 +3090,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
const bool fAlreadyHave = AlreadyHaveTx(gtxid);
LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());
- pfrom.AddKnownTx(inv.hash);
+ AddKnownTx(*peer, inv.hash);
if (!fAlreadyHave && !m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
AddTxAnnouncement(pfrom, gtxid, current_time);
}
@@ -3278,8 +3320,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Stop processing the transaction early if
// 1) We are in blocks only mode and peer has no relay permission
// 2) This peer is a block-relay-only peer
- if ((m_ignore_incoming_txs && !pfrom.HasPermission(NetPermissionFlags::Relay)) || (pfrom.m_tx_relay == nullptr))
- {
+ if ((m_ignore_incoming_txs && !pfrom.HasPermission(NetPermissionFlags::Relay)) || (peer->m_tx_relay == nullptr)) {
LogPrint(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom.GetId());
pfrom.fDisconnect = true;
return;
@@ -3297,21 +3338,19 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
const uint256& txid = ptx->GetHash();
const uint256& wtxid = ptx->GetWitnessHash();
- LOCK2(cs_main, g_cs_orphans);
-
- CNodeState* nodestate = State(pfrom.GetId());
-
- const uint256& hash = nodestate->m_wtxid_relay ? wtxid : txid;
- pfrom.AddKnownTx(hash);
- if (nodestate->m_wtxid_relay && txid != wtxid) {
- // Insert txid into filterInventoryKnown, even for
+ const uint256& hash = peer->m_wtxid_relay ? wtxid : txid;
+ AddKnownTx(*peer, hash);
+ if (peer->m_wtxid_relay && txid != wtxid) {
+ // Insert txid into m_tx_inventory_known_filter, even for
// wtxidrelay peers. This prevents re-adding of
// unconfirmed parents to the recently_announced
// filter, when a child tx is requested. See
// ProcessGetData().
- pfrom.AddKnownTx(txid);
+ AddKnownTx(*peer, txid);
}
+ LOCK2(cs_main, g_cs_orphans);
+
m_txrequest.ReceivedResponse(pfrom.GetId(), txid);
if (tx.HasWitness()) m_txrequest.ReceivedResponse(pfrom.GetId(), wtxid);
@@ -3336,7 +3375,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
LogPrintf("Not relaying non-mempool transaction %s from forcerelay peer=%d\n", tx.GetHash().ToString(), pfrom.GetId());
} else {
LogPrintf("Force relaying tx %s from peer=%d\n", tx.GetHash().ToString(), pfrom.GetId());
- _RelayTransaction(tx.GetHash(), tx.GetWitnessHash());
+ RelayTransaction(tx.GetHash(), tx.GetWitnessHash());
}
}
return;
@@ -3350,7 +3389,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// requests for it.
m_txrequest.ForgetTxHash(tx.GetHash());
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
- _RelayTransaction(tx.GetHash(), tx.GetWitnessHash());
+ RelayTransaction(tx.GetHash(), tx.GetWitnessHash());
m_orphanage.AddChildrenToWorkSet(tx, peer->m_orphan_work_set);
pfrom.m_last_tx_time = GetTime<std::chrono::seconds>();
@@ -3397,7 +3436,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Eventually we should replace this with an improved
// protocol for getting all unconfirmed parents.
const auto gtxid{GenTxid::Txid(parent_txid)};
- pfrom.AddKnownTx(parent_txid);
+ AddKnownTx(*peer, parent_txid);
if (!AlreadyHaveTx(gtxid)) AddTxAnnouncement(pfrom, gtxid, current_time);
}
@@ -3893,9 +3932,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
return;
}
- if (pfrom.m_tx_relay != nullptr) {
- LOCK(pfrom.m_tx_relay->cs_tx_inventory);
- pfrom.m_tx_relay->fSendMempool = true;
+ if (peer->m_tx_relay != nullptr) {
+ LOCK(peer->m_tx_relay->m_tx_inventory_mutex);
+ peer->m_tx_relay->m_send_mempool = true;
}
return;
}
@@ -3989,11 +4028,13 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// There is no excuse for sending a too-large filter
Misbehaving(pfrom.GetId(), 100, "too-large bloom filter");
}
- else if (pfrom.m_tx_relay != nullptr)
+ else if (peer->m_tx_relay != nullptr)
{
- LOCK(pfrom.m_tx_relay->cs_filter);
- pfrom.m_tx_relay->pfilter.reset(new CBloomFilter(filter));
- pfrom.m_tx_relay->fRelayTxes = true;
+ LOCK(peer->m_tx_relay->m_bloom_filter_mutex);
+ peer->m_tx_relay->m_bloom_filter.reset(new CBloomFilter(filter));
+ pfrom.m_bloom_filter_loaded = true;
+ peer->m_tx_relay->m_relay_txs = true;
+ pfrom.m_relays_txs = true;
}
return;
}
@@ -4012,10 +4053,10 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
bool bad = false;
if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) {
bad = true;
- } else if (pfrom.m_tx_relay != nullptr) {
- LOCK(pfrom.m_tx_relay->cs_filter);
- if (pfrom.m_tx_relay->pfilter) {
- pfrom.m_tx_relay->pfilter->insert(vData);
+ } else if (peer->m_tx_relay != nullptr) {
+ LOCK(peer->m_tx_relay->m_bloom_filter_mutex);
+ if (peer->m_tx_relay->m_bloom_filter) {
+ peer->m_tx_relay->m_bloom_filter->insert(vData);
} else {
bad = true;
}
@@ -4032,12 +4073,14 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
pfrom.fDisconnect = true;
return;
}
- if (pfrom.m_tx_relay == nullptr) {
+ if (peer->m_tx_relay == nullptr) {
return;
}
- LOCK(pfrom.m_tx_relay->cs_filter);
- pfrom.m_tx_relay->pfilter = nullptr;
- pfrom.m_tx_relay->fRelayTxes = true;
+ LOCK(peer->m_tx_relay->m_bloom_filter_mutex);
+ peer->m_tx_relay->m_bloom_filter = nullptr;
+ pfrom.m_bloom_filter_loaded = false;
+ peer->m_tx_relay->m_relay_txs = true;
+ pfrom.m_relays_txs = true;
return;
}
@@ -4045,8 +4088,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
CAmount newFeeFilter = 0;
vRecv >> newFeeFilter;
if (MoneyRange(newFeeFilter)) {
- if (pfrom.m_tx_relay != nullptr) {
- pfrom.m_tx_relay->minFeeFilter = newFeeFilter;
+ if (peer->m_tx_relay != nullptr) {
+ peer->m_tx_relay->m_fee_filter_received = newFeeFilter;
}
LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom.GetId());
}
@@ -4504,10 +4547,10 @@ void PeerManagerImpl::MaybeSendAddr(CNode& node, Peer& peer, std::chrono::micros
}
}
-void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, std::chrono::microseconds current_time)
+void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, Peer& peer, std::chrono::microseconds current_time)
{
if (m_ignore_incoming_txs) return;
- if (!pto.m_tx_relay) return;
+ if (!peer.m_tx_relay) return;
if (pto.GetCommonVersion() < FEEFILTER_VERSION) return;
// peers with the forcerelay permission should not filter txs to us
if (pto.HasPermission(NetPermissionFlags::ForceRelay)) return;
@@ -4521,27 +4564,27 @@ void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, std::chrono::microseconds c
currentFilter = MAX_MONEY;
} else {
static const CAmount MAX_FILTER{g_filter_rounder.round(MAX_MONEY)};
- if (pto.m_tx_relay->lastSentFeeFilter == MAX_FILTER) {
+ if (peer.m_tx_relay->m_fee_filter_sent == MAX_FILTER) {
// Send the current filter if we sent MAX_FILTER previously
// and made it out of IBD.
- pto.m_tx_relay->m_next_send_feefilter = 0us;
+ peer.m_tx_relay->m_next_send_feefilter = 0us;
}
}
- if (current_time > pto.m_tx_relay->m_next_send_feefilter) {
+ if (current_time > peer.m_tx_relay->m_next_send_feefilter) {
CAmount filterToSend = g_filter_rounder.round(currentFilter);
// We always have a fee filter of at least minRelayTxFee
filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK());
- if (filterToSend != pto.m_tx_relay->lastSentFeeFilter) {
+ if (filterToSend != peer.m_tx_relay->m_fee_filter_sent) {
m_connman.PushMessage(&pto, CNetMsgMaker(pto.GetCommonVersion()).Make(NetMsgType::FEEFILTER, filterToSend));
- pto.m_tx_relay->lastSentFeeFilter = filterToSend;
+ peer.m_tx_relay->m_fee_filter_sent = filterToSend;
}
- pto.m_tx_relay->m_next_send_feefilter = GetExponentialRand(current_time, AVG_FEEFILTER_BROADCAST_INTERVAL);
+ peer.m_tx_relay->m_next_send_feefilter = GetExponentialRand(current_time, AVG_FEEFILTER_BROADCAST_INTERVAL);
}
// If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY
// until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY.
- else if (current_time + MAX_FEEFILTER_CHANGE_DELAY < pto.m_tx_relay->m_next_send_feefilter &&
- (currentFilter < 3 * pto.m_tx_relay->lastSentFeeFilter / 4 || currentFilter > 4 * pto.m_tx_relay->lastSentFeeFilter / 3)) {
- pto.m_tx_relay->m_next_send_feefilter = current_time + GetRandomDuration<std::chrono::microseconds>(MAX_FEEFILTER_CHANGE_DELAY);
+ else if (current_time + MAX_FEEFILTER_CHANGE_DELAY < peer.m_tx_relay->m_next_send_feefilter &&
+ (currentFilter < 3 * peer.m_tx_relay->m_fee_filter_sent / 4 || currentFilter > 4 * peer.m_tx_relay->m_fee_filter_sent / 3)) {
+ peer.m_tx_relay->m_next_send_feefilter = current_time + GetRandomDuration<std::chrono::microseconds>(MAX_FEEFILTER_CHANGE_DELAY);
}
}
@@ -4808,45 +4851,45 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
peer->m_blocks_for_inv_relay.clear();
}
- if (pto->m_tx_relay != nullptr) {
- LOCK(pto->m_tx_relay->cs_tx_inventory);
+ if (peer->m_tx_relay != nullptr) {
+ LOCK(peer->m_tx_relay->m_tx_inventory_mutex);
// Check whether periodic sends should happen
bool fSendTrickle = pto->HasPermission(NetPermissionFlags::NoBan);
- if (pto->m_tx_relay->nNextInvSend < current_time) {
+ if (peer->m_tx_relay->m_next_inv_send_time < current_time) {
fSendTrickle = true;
if (pto->IsInboundConn()) {
- pto->m_tx_relay->nNextInvSend = NextInvToInbounds(current_time, INBOUND_INVENTORY_BROADCAST_INTERVAL);
+ peer->m_tx_relay->m_next_inv_send_time = NextInvToInbounds(current_time, INBOUND_INVENTORY_BROADCAST_INTERVAL);
} else {
- pto->m_tx_relay->nNextInvSend = GetExponentialRand(current_time, OUTBOUND_INVENTORY_BROADCAST_INTERVAL);
+ peer->m_tx_relay->m_next_inv_send_time = GetExponentialRand(current_time, OUTBOUND_INVENTORY_BROADCAST_INTERVAL);
}
}
// Time to send but the peer has requested we not relay transactions.
if (fSendTrickle) {
- LOCK(pto->m_tx_relay->cs_filter);
- if (!pto->m_tx_relay->fRelayTxes) pto->m_tx_relay->setInventoryTxToSend.clear();
+ LOCK(peer->m_tx_relay->m_bloom_filter_mutex);
+ if (!peer->m_tx_relay->m_relay_txs) peer->m_tx_relay->m_tx_inventory_to_send.clear();
}
// Respond to BIP35 mempool requests
- if (fSendTrickle && pto->m_tx_relay->fSendMempool) {
+ if (fSendTrickle && peer->m_tx_relay->m_send_mempool) {
auto vtxinfo = m_mempool.infoAll();
- pto->m_tx_relay->fSendMempool = false;
- const CFeeRate filterrate{pto->m_tx_relay->minFeeFilter.load()};
+ peer->m_tx_relay->m_send_mempool = false;
+ const CFeeRate filterrate{peer->m_tx_relay->m_fee_filter_received.load()};
- LOCK(pto->m_tx_relay->cs_filter);
+ LOCK(peer->m_tx_relay->m_bloom_filter_mutex);
for (const auto& txinfo : vtxinfo) {
- const uint256& hash = state.m_wtxid_relay ? txinfo.tx->GetWitnessHash() : txinfo.tx->GetHash();
- CInv inv(state.m_wtxid_relay ? MSG_WTX : MSG_TX, hash);
- pto->m_tx_relay->setInventoryTxToSend.erase(hash);
+ const uint256& hash = peer->m_wtxid_relay ? txinfo.tx->GetWitnessHash() : txinfo.tx->GetHash();
+ CInv inv(peer->m_wtxid_relay ? MSG_WTX : MSG_TX, hash);
+ peer->m_tx_relay->m_tx_inventory_to_send.erase(hash);
// Don't send transactions that peers will not put into their mempool
if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
continue;
}
- if (pto->m_tx_relay->pfilter) {
- if (!pto->m_tx_relay->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
+ if (peer->m_tx_relay->m_bloom_filter) {
+ if (!peer->m_tx_relay->m_bloom_filter->IsRelevantAndUpdate(*txinfo.tx)) continue;
}
- pto->m_tx_relay->filterInventoryKnown.insert(hash);
+ peer->m_tx_relay->m_tx_inventory_known_filter.insert(hash);
// Responses to MEMPOOL requests bypass the m_recently_announced_invs filter.
vInv.push_back(inv);
if (vInv.size() == MAX_INV_SZ) {
@@ -4854,37 +4897,37 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
vInv.clear();
}
}
- pto->m_tx_relay->m_last_mempool_req = std::chrono::duration_cast<std::chrono::seconds>(current_time);
+ peer->m_tx_relay->m_last_mempool_req = std::chrono::duration_cast<std::chrono::seconds>(current_time);
}
// Determine transactions to relay
if (fSendTrickle) {
// Produce a vector with all candidates for sending
std::vector<std::set<uint256>::iterator> vInvTx;
- vInvTx.reserve(pto->m_tx_relay->setInventoryTxToSend.size());
- for (std::set<uint256>::iterator it = pto->m_tx_relay->setInventoryTxToSend.begin(); it != pto->m_tx_relay->setInventoryTxToSend.end(); it++) {
+ vInvTx.reserve(peer->m_tx_relay->m_tx_inventory_to_send.size());
+ for (std::set<uint256>::iterator it = peer->m_tx_relay->m_tx_inventory_to_send.begin(); it != peer->m_tx_relay->m_tx_inventory_to_send.end(); it++) {
vInvTx.push_back(it);
}
- const CFeeRate filterrate{pto->m_tx_relay->minFeeFilter.load()};
+ const CFeeRate filterrate{peer->m_tx_relay->m_fee_filter_received.load()};
// Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
// A heap is used so that not all items need sorting if only a few are being sent.
- CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool, state.m_wtxid_relay);
+ CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool, peer->m_wtxid_relay);
std::make_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
// No reason to drain out at many times the network's capacity,
// especially since we have many peers and some will draw much shorter delays.
unsigned int nRelayedTransactions = 0;
- LOCK(pto->m_tx_relay->cs_filter);
+ LOCK(peer->m_tx_relay->m_bloom_filter_mutex);
while (!vInvTx.empty() && nRelayedTransactions < INVENTORY_BROADCAST_MAX) {
// Fetch the top element from the heap
std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
std::set<uint256>::iterator it = vInvTx.back();
vInvTx.pop_back();
uint256 hash = *it;
- CInv inv(state.m_wtxid_relay ? MSG_WTX : MSG_TX, hash);
+ CInv inv(peer->m_wtxid_relay ? MSG_WTX : MSG_TX, hash);
// Remove it from the to-be-sent set
- pto->m_tx_relay->setInventoryTxToSend.erase(it);
+ peer->m_tx_relay->m_tx_inventory_to_send.erase(it);
// Check if not in the filter already
- if (pto->m_tx_relay->filterInventoryKnown.contains(hash)) {
+ if (peer->m_tx_relay->m_tx_inventory_known_filter.contains(hash)) {
continue;
}
// Not in the mempool anymore? don't bother sending it.
@@ -4898,7 +4941,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
continue;
}
- if (pto->m_tx_relay->pfilter && !pto->m_tx_relay->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
+ if (peer->m_tx_relay->m_bloom_filter && !peer->m_tx_relay->m_bloom_filter->IsRelevantAndUpdate(*txinfo.tx)) continue;
// Send
State(pto->GetId())->m_recently_announced_invs.insert(hash);
vInv.push_back(inv);
@@ -4925,14 +4968,14 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
vInv.clear();
}
- pto->m_tx_relay->filterInventoryKnown.insert(hash);
+ peer->m_tx_relay->m_tx_inventory_known_filter.insert(hash);
if (hash != txid) {
- // Insert txid into filterInventoryKnown, even for
+ // Insert txid into m_tx_inventory_known_filter, even for
// wtxidrelay peers. This prevents re-adding of
// unconfirmed parents to the recently_announced
// filter, when a child tx is requested. See
// ProcessGetData().
- pto->m_tx_relay->filterInventoryKnown.insert(txid);
+ peer->m_tx_relay->m_tx_inventory_known_filter.insert(txid);
}
}
}
@@ -5053,6 +5096,6 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
if (!vGetData.empty())
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
} // release cs_main
- MaybeSendFeefilter(*pto, current_time);
+ MaybeSendFeefilter(*pto, *peer, current_time);
return true;
}