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.cpp367
1 files changed, 220 insertions, 147 deletions
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 2201caf7d2..0b83f756b3 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -25,6 +25,7 @@
#include <reverse_iterator.h>
#include <scheduler.h>
#include <streams.h>
+#include <sync.h>
#include <tinyformat.h>
#include <txmempool.h>
#include <txorphanage.h>
@@ -123,11 +124,11 @@ static constexpr auto AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24h;
/** Average delay between peer address broadcasts */
static constexpr auto AVG_ADDRESS_BROADCAST_INTERVAL = 30s;
/** Average delay between trickled inventory transmissions for inbound peers.
- * Blocks and peers with noban permission bypass this. */
+ * Blocks and peers with NetPermissionFlags::NoBan permission bypass this. */
static constexpr auto INBOUND_INVENTORY_BROADCAST_INTERVAL = 5s;
/** Average delay between trickled inventory transmissions for outbound peers.
* Use a smaller delay as there is less privacy concern for them.
- * Blocks and peers with noban permission bypass this. */
+ * Blocks and peers with NetPermissionFlags::NoBan permission bypass this. */
static constexpr auto OUTBOUND_INVENTORY_BROADCAST_INTERVAL = 2s;
/** Maximum rate of inventory items to send per second.
* Limits the impact of low-fee transaction floods. */
@@ -151,6 +152,8 @@ static constexpr uint32_t MAX_GETCFILTERS_SIZE = 1000;
static constexpr uint32_t MAX_GETCFHEADERS_SIZE = 2000;
/** the maximum percentage of addresses from our addrman to return in response to a getaddr message. */
static constexpr size_t MAX_PCT_ADDR_TO_SEND = 23;
+/** The maximum number of address records permitted in an ADDR message. */
+static constexpr size_t MAX_ADDR_TO_SEND{1000};
// Internal stuff
namespace {
@@ -182,7 +185,7 @@ struct Peer {
Mutex m_misbehavior_mutex;
/** Accumulated misbehavior score for this peer */
int m_misbehavior_score GUARDED_BY(m_misbehavior_mutex){0};
- /** Whether this peer should be disconnected and marked as discouraged (unless it has the noban permission). */
+ /** Whether this peer should be disconnected and marked as discouraged (unless it has NetPermissionFlags::NoBan permission). */
bool m_should_discourage GUARDED_BY(m_misbehavior_mutex){false};
/** Protects block inventory data members */
@@ -211,6 +214,25 @@ struct Peer {
/** Whether a ping has been requested by the user */
std::atomic<bool> m_ping_queued{false};
+ /** A vector of addresses to send to the peer, limited to MAX_ADDR_TO_SEND. */
+ std::vector<CAddress> m_addrs_to_send;
+ /** Probabilistic filter of addresses that this peer already knows.
+ * Used to avoid relaying addresses to this peer more than once. */
+ const std::unique_ptr<CRollingBloomFilter> m_addr_known;
+ /** Whether a getaddr request to this peer is outstanding. */
+ bool m_getaddr_sent{false};
+ /** Guards address sending timers. */
+ mutable Mutex m_addr_send_times_mutex;
+ /** Time point to send the next ADDR message to this peer. */
+ std::chrono::microseconds m_next_addr_send GUARDED_BY(m_addr_send_times_mutex){0};
+ /** Time point to possibly re-announce our local address to this peer. */
+ std::chrono::microseconds m_next_local_addr_send GUARDED_BY(m_addr_send_times_mutex){0};
+ /** Whether the peer has signaled support for receiving ADDRv2 (BIP155)
+ * messages, indicating a preference to receive ADDRv2 instead of ADDR ones. */
+ std::atomic_bool m_wants_addrv2{false};
+ /** Whether this peer has already sent us a getaddr message. */
+ bool m_getaddr_recvd{false};
+
/** Set of txids to reconsider once their parent transactions have been accepted **/
std::set<uint256> m_orphan_work_set GUARDED_BY(g_cs_orphans);
@@ -219,7 +241,10 @@ 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) : m_id(id) {}
+ explicit Peer(NodeId id, bool addr_relay)
+ : m_id(id)
+ , m_addr_known{addr_relay ? std::make_unique<CRollingBloomFilter>(5000, 0.001) : nullptr}
+ {}
};
using PeerRef = std::shared_ptr<Peer>;
@@ -256,6 +281,9 @@ 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, int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -325,7 +353,19 @@ private:
void MaybeSendPing(CNode& node_to, Peer& peer, std::chrono::microseconds now);
/** Send `addr` messages on a regular schedule. */
- void MaybeSendAddr(CNode& node, std::chrono::microseconds current_time);
+ void MaybeSendAddr(CNode& node, Peer& peer, std::chrono::microseconds current_time);
+
+ /** Relay (gossip) an address to a few randomly chosen nodes.
+ *
+ * @param[in] originator The id of the peer that sent us the address. We don't want to relay it back.
+ * @param[in] addr Address to relay.
+ * @param[in] fReachable Whether the address' network is reachable. We relay unreachable
+ * addresses less.
+ */
+ void RelayAddress(NodeId originator, const CAddress& addr, bool fReachable);
+
+ /** Send `feefilter` message. */
+ void MaybeSendFeefilter(CNode& node, std::chrono::microseconds current_time) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
const CChainParams& m_chainparams;
CConnman& m_connman;
@@ -671,12 +711,48 @@ static CNodeState *State(NodeId pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
return &it->second;
}
+static bool RelayAddrsWithPeer(const Peer& peer)
+{
+ return peer.m_addr_known != nullptr;
+}
+
+/**
+ * Whether the peer supports the address. For example, a peer that does not
+ * implement BIP155 cannot receive Tor v3 addresses because it requires
+ * ADDRv2 (BIP155) encoding.
+ */
+static bool IsAddrCompatible(const Peer& peer, const CAddress& addr)
+{
+ return peer.m_wants_addrv2 || addr.IsAddrV1Compatible();
+}
+
+static void AddAddressKnown(Peer& peer, const CAddress& addr)
+{
+ assert(peer.m_addr_known);
+ peer.m_addr_known->insert(addr.GetKey());
+}
+
+static void PushAddress(Peer& peer, const CAddress& addr, FastRandomContext& insecure_rand)
+{
+ // Known checking here is only to save space from duplicates.
+ // Before sending, we'll filter it again for known addresses that were
+ // added after addresses were pushed.
+ assert(peer.m_addr_known);
+ if (addr.IsValid() && !peer.m_addr_known->contains(addr.GetKey()) && IsAddrCompatible(peer, addr)) {
+ if (peer.m_addrs_to_send.size() >= MAX_ADDR_TO_SEND) {
+ peer.m_addrs_to_send[insecure_rand.randrange(peer.m_addrs_to_send.size())] = addr;
+ } else {
+ peer.m_addrs_to_send.push_back(addr);
+ }
+ }
+}
+
static void UpdatePreferredDownload(const CNode& node, CNodeState* state) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
nPreferredDownload -= state->fPreferredDownload;
// Whether this node should be marked as a preferred download node.
- state->fPreferredDownload = (!node.IsInboundConn() || node.HasPermission(PF_NOBAN)) && !node.IsAddrFetchConn() && !node.fClient;
+ state->fPreferredDownload = (!node.IsInboundConn() || node.HasPermission(NetPermissionFlags::NoBan)) && !node.IsAddrFetchConn() && !node.fClient;
nPreferredDownload += state->fPreferredDownload;
}
@@ -956,24 +1032,24 @@ void PeerManagerImpl::AddTxAnnouncement(const CNode& node, const GenTxid& gtxid,
{
AssertLockHeld(::cs_main); // For m_txrequest
NodeId nodeid = node.GetId();
- if (!node.HasPermission(PF_RELAY) && m_txrequest.Count(nodeid) >= MAX_PEER_TX_ANNOUNCEMENTS) {
+ if (!node.HasPermission(NetPermissionFlags::Relay) && m_txrequest.Count(nodeid) >= MAX_PEER_TX_ANNOUNCEMENTS) {
// Too many queued announcements from this peer
return;
}
const CNodeState* state = State(nodeid);
// Decide the TxRequestTracker parameters for this announcement:
- // - "preferred": if fPreferredDownload is set (= outbound, or PF_NOBAN permission)
+ // - "preferred": if fPreferredDownload is set (= outbound, or NetPermissionFlags::NoBan permission)
// - "reqtime": current time plus delays for:
// - NONPREF_PEER_TX_DELAY for announcements from non-preferred connections
// - TXID_RELAY_DELAY for txid announcements while wtxid peers are available
// - OVERLOADED_PEER_TX_DELAY for announcements from peers which have at least
- // MAX_PEER_TX_REQUEST_IN_FLIGHT requests in flight (and don't have PF_RELAY).
+ // MAX_PEER_TX_REQUEST_IN_FLIGHT requests in flight (and don't have NetPermissionFlags::Relay).
auto delay = std::chrono::microseconds{0};
const bool preferred = state->fPreferredDownload;
if (!preferred) delay += NONPREF_PEER_TX_DELAY;
if (!gtxid.IsWtxid() && m_wtxid_relay_peers > 0) delay += TXID_RELAY_DELAY;
- const bool overloaded = !node.HasPermission(PF_RELAY) &&
+ const bool overloaded = !node.HasPermission(NetPermissionFlags::Relay) &&
m_txrequest.CountInFlight(nodeid) >= MAX_PEER_TX_REQUEST_IN_FLIGHT;
if (overloaded) delay += OVERLOADED_PEER_TX_DELAY;
m_txrequest.ReceivedInv(nodeid, gtxid, preferred, current_time + delay);
@@ -997,7 +1073,9 @@ void PeerManagerImpl::InitializeNode(CNode *pnode)
assert(m_txrequest.Count(nodeid) == 0);
}
{
- PeerRef peer = std::make_shared<Peer>(nodeid);
+ // Addr relay is disabled for outbound block-relay-only peers to
+ // prevent adversaries from inferring these links from addr traffic.
+ PeerRef peer = std::make_shared<Peer>(nodeid, /* addr_relay = */ !pnode->IsBlockOnlyConn());
LOCK(m_peer_mutex);
m_peer_map.emplace_hint(m_peer_map.end(), nodeid, std::move(peer));
}
@@ -1015,7 +1093,7 @@ void PeerManagerImpl::ReattemptInitialBroadcast(CScheduler& scheduler)
if (tx != nullptr) {
LOCK(cs_main);
- RelayTransaction(txid, tx->GetWitnessHash());
+ _RelayTransaction(txid, tx->GetWitnessHash());
} else {
m_mempool.RemoveUnbroadcastTx(txid, true);
}
@@ -1512,6 +1590,11 @@ 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);
@@ -1525,59 +1608,49 @@ void PeerManagerImpl::RelayTransaction(const uint256& txid, const uint256& wtxid
});
}
-/**
- * Relay (gossip) an address to a few randomly chosen nodes.
- * We choose the same nodes within a given 24h window (if the list of connected
- * nodes does not change) and we don't relay to nodes that already know an
- * address. So within 24h we will likely relay a given address once. This is to
- * prevent a peer from unjustly giving their address better propagation by sending
- * it to us repeatedly.
- * @param[in] originator The peer that sent us the address. We don't want to relay it back.
- * @param[in] addr Address to relay.
- * @param[in] fReachable Whether the address' network is reachable. We relay unreachable
- * addresses less.
- * @param[in] connman Connection manager to choose nodes to relay to.
- */
-static void RelayAddress(const CNode& originator,
- const CAddress& addr,
- bool fReachable,
- const CConnman& connman)
+void PeerManagerImpl::RelayAddress(NodeId originator,
+ const CAddress& addr,
+ bool fReachable)
{
+ // We choose the same nodes within a given 24h window (if the list of connected
+ // nodes does not change) and we don't relay to nodes that already know an
+ // address. So within 24h we will likely relay a given address once. This is to
+ // prevent a peer from unjustly giving their address better propagation by sending
+ // it to us repeatedly.
+
if (!fReachable && !addr.IsRelayable()) return;
// Relay to a limited number of other nodes
// Use deterministic randomness to send to the same nodes for 24 hours
// at a time so the m_addr_knowns of the chosen nodes prevent repeats
uint64_t hashAddr = addr.GetHash();
- const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24 * 60 * 60));
+ const CSipHasher hasher = m_connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24 * 60 * 60));
FastRandomContext insecure_rand;
// Relay reachable addresses to 2 peers. Unreachable addresses are relayed randomly to 1 or 2 peers.
unsigned int nRelayNodes = (fReachable || (hasher.Finalize() & 1)) ? 2 : 1;
- std::array<std::pair<uint64_t, CNode*>,2> best{{{0, nullptr}, {0, nullptr}}};
+ std::array<std::pair<uint64_t, Peer*>, 2> best{{{0, nullptr}, {0, nullptr}}};
assert(nRelayNodes <= best.size());
- auto sortfunc = [&best, &hasher, nRelayNodes, &originator, &addr](CNode* pnode) {
- if (pnode->RelayAddrsWithConn() && pnode != &originator && pnode->IsAddrCompatible(addr)) {
- uint64_t hashKey = CSipHasher(hasher).Write(pnode->GetId()).Finalize();
+ LOCK(m_peer_mutex);
+
+ for (auto& [id, peer] : m_peer_map) {
+ if (RelayAddrsWithPeer(*peer) && id != originator && IsAddrCompatible(*peer, addr)) {
+ uint64_t hashKey = CSipHasher(hasher).Write(id).Finalize();
for (unsigned int i = 0; i < nRelayNodes; i++) {
if (hashKey > best[i].first) {
std::copy(best.begin() + i, best.begin() + nRelayNodes - 1, best.begin() + i + 1);
- best[i] = std::make_pair(hashKey, pnode);
+ best[i] = std::make_pair(hashKey, peer.get());
break;
}
}
}
};
- auto pushfunc = [&addr, &best, nRelayNodes, &insecure_rand] {
- for (unsigned int i = 0; i < nRelayNodes && best[i].first != 0; i++) {
- best[i].second->PushAddress(addr, insecure_rand);
- }
- };
-
- connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
+ for (unsigned int i = 0; i < nRelayNodes && best[i].first != 0; i++) {
+ PushAddress(*best[i].second, addr, insecure_rand);
+ }
}
void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& inv)
@@ -1628,14 +1701,14 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
// disconnect node in case we have reached the outbound limit for serving historical blocks
if (m_connman.OutboundTargetReached(true) &&
(((pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk()) &&
- !pfrom.HasPermission(PF_DOWNLOAD) // nodes with the download permission may exceed target
+ !pfrom.HasPermission(NetPermissionFlags::Download) // nodes with the download permission may exceed target
) {
LogPrint(BCLog::NET, "historical block serving limit reached, disconnect peer=%d\n", pfrom.GetId());
pfrom.fDisconnect = true;
return;
}
// Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
- if (!pfrom.HasPermission(PF_NOBAN) && (
+ if (!pfrom.HasPermission(NetPermissionFlags::NoBan) && (
(((pfrom.GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom.GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (m_chainman.ActiveChain().Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
)) {
LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold, disconnect peer=%d\n", pfrom.GetId());
@@ -2087,7 +2160,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()) {
@@ -2472,17 +2545,17 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (addr.IsRoutable())
{
LogPrint(BCLog::NET, "ProcessMessages: advertising address %s\n", addr.ToString());
- pfrom.PushAddress(addr, insecure_rand);
+ PushAddress(*peer, addr, insecure_rand);
} else if (IsPeerAddrLocalGood(&pfrom)) {
addr.SetIP(addrMe);
LogPrint(BCLog::NET, "ProcessMessages: advertising address %s\n", addr.ToString());
- pfrom.PushAddress(addr, insecure_rand);
+ PushAddress(*peer, addr, insecure_rand);
}
}
// Get recent addresses
m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make(NetMsgType::GETADDR));
- pfrom.fGetAddr = true;
+ peer->m_getaddr_sent = true;
}
if (!pfrom.IsInboundConn()) {
@@ -2641,7 +2714,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
pfrom.fDisconnect = true;
return;
}
- pfrom.m_wants_addrv2 = true;
+ peer->m_wants_addrv2 = true;
return;
}
@@ -2663,7 +2736,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
s >> vAddr;
- if (!pfrom.RelayAddrsWithConn()) {
+ if (!RelayAddrsWithPeer(*peer)) {
LogPrint(BCLog::NET, "ignoring %s message from %s peer=%d\n", msg_type, pfrom.ConnectionTypeAsString(), pfrom.GetId());
return;
}
@@ -2690,24 +2763,22 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
addr.nTime = nNow - 5 * 24 * 60 * 60;
- pfrom.AddAddressKnown(addr);
+ AddAddressKnown(*peer, addr);
if (m_banman && (m_banman->IsDiscouraged(addr) || m_banman->IsBanned(addr))) {
// Do not process banned/discouraged addresses beyond remembering we received them
continue;
}
bool fReachable = IsReachable(addr);
- if (addr.nTime > nSince && !pfrom.fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
- {
+ if (addr.nTime > nSince && !peer->m_getaddr_sent && vAddr.size() <= 10 && addr.IsRoutable()) {
// Relay to a limited number of other nodes
- RelayAddress(pfrom, addr, fReachable, m_connman);
+ RelayAddress(pfrom.GetId(), addr, fReachable);
}
// Do not store addresses outside our network
if (fReachable)
vAddrOk.push_back(addr);
}
m_addrman.Add(vAddrOk, pfrom.addr, 2 * 60 * 60);
- if (vAddr.size() < 1000)
- pfrom.fGetAddr = false;
+ if (vAddr.size() < 1000) peer->m_getaddr_sent = false;
if (pfrom.IsAddrFetchConn()) {
LogPrint(BCLog::NET, "addrfetch connection completed peer=%d; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
@@ -2729,7 +2800,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
bool fBlocksOnly = m_ignore_incoming_txs || (pfrom.m_tx_relay == nullptr);
// Allow peers with relay permission to send data other than blocks in blocks only mode
- if (pfrom.HasPermission(PF_RELAY)) {
+ if (pfrom.HasPermission(NetPermissionFlags::Relay)) {
fBlocksOnly = false;
}
@@ -2943,7 +3014,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
LOCK(cs_main);
- if (m_chainman.ActiveChainstate().IsInitialBlockDownload() && !pfrom.HasPermission(PF_DOWNLOAD)) {
+ if (m_chainman.ActiveChainstate().IsInitialBlockDownload() && !pfrom.HasPermission(NetPermissionFlags::Download)) {
LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom.GetId());
return;
}
@@ -3002,7 +3073,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(PF_RELAY)) || (pfrom.m_tx_relay == nullptr))
+ if ((m_ignore_incoming_txs && !pfrom.HasPermission(NetPermissionFlags::Relay)) || (pfrom.m_tx_relay == nullptr))
{
LogPrint(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom.GetId());
pfrom.fDisconnect = true;
@@ -3047,7 +3118,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// (older than our recency filter) if trying to DoS us, without any need
// for witness malleation.
if (AlreadyHaveTx(GenTxid(/* is_wtxid=*/true, wtxid))) {
- if (pfrom.HasPermission(PF_FORCERELAY)) {
+ if (pfrom.HasPermission(NetPermissionFlags::ForceRelay)) {
// Always relay transactions received from peers with forcerelay
// permission, even if they were already in the mempool, allowing
// the node to function as a gateway for nodes hidden behind it.
@@ -3055,7 +3126,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;
@@ -3070,7 +3141,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.nLastTXTime = GetTime();
@@ -3567,31 +3638,31 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
// Only send one GetAddr response per connection to reduce resource waste
- // and discourage addr stamping of INV announcements.
- if (pfrom.fSentAddr) {
+ // and discourage addr stamping of INV announcements.
+ if (peer->m_getaddr_recvd) {
LogPrint(BCLog::NET, "Ignoring repeated \"getaddr\". peer=%d\n", pfrom.GetId());
return;
}
- pfrom.fSentAddr = true;
+ peer->m_getaddr_recvd = true;
- pfrom.vAddrToSend.clear();
+ peer->m_addrs_to_send.clear();
std::vector<CAddress> vAddr;
- if (pfrom.HasPermission(PF_ADDR)) {
- vAddr = m_connman.GetAddresses(MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND);
+ if (pfrom.HasPermission(NetPermissionFlags::Addr)) {
+ vAddr = m_connman.GetAddresses(MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND, /* network */ std::nullopt);
} else {
vAddr = m_connman.GetAddresses(pfrom, MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND);
}
FastRandomContext insecure_rand;
for (const CAddress &addr : vAddr) {
- pfrom.PushAddress(addr, insecure_rand);
+ PushAddress(*peer, addr, insecure_rand);
}
return;
}
if (msg_type == NetMsgType::MEMPOOL) {
- if (!(pfrom.GetLocalServices() & NODE_BLOOM) && !pfrom.HasPermission(PF_MEMPOOL))
+ if (!(pfrom.GetLocalServices() & NODE_BLOOM) && !pfrom.HasPermission(NetPermissionFlags::Mempool))
{
- if (!pfrom.HasPermission(PF_NOBAN))
+ if (!pfrom.HasPermission(NetPermissionFlags::NoBan))
{
LogPrint(BCLog::NET, "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom.GetId());
pfrom.fDisconnect = true;
@@ -3599,9 +3670,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
return;
}
- if (m_connman.OutboundTargetReached(false) && !pfrom.HasPermission(PF_MEMPOOL))
+ if (m_connman.OutboundTargetReached(false) && !pfrom.HasPermission(NetPermissionFlags::Mempool))
{
- if (!pfrom.HasPermission(PF_NOBAN))
+ if (!pfrom.HasPermission(NetPermissionFlags::NoBan))
{
LogPrint(BCLog::NET, "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom.GetId());
pfrom.fDisconnect = true;
@@ -3816,8 +3887,8 @@ bool PeerManagerImpl::MaybeDiscourageAndDisconnect(CNode& pnode, Peer& peer)
peer.m_should_discourage = false;
} // peer.m_misbehavior_mutex
- if (pnode.HasPermission(PF_NOBAN)) {
- // We never disconnect or discourage peers for bad behavior if they have the NOBAN permission flag
+ if (pnode.HasPermission(NetPermissionFlags::NoBan)) {
+ // We never disconnect or discourage peers for bad behavior if they have NetPermissionFlags::NoBan permission
LogPrintf("Warning: not punishing noban peer %d!\n", peer.m_id);
return false;
}
@@ -4141,72 +4212,113 @@ void PeerManagerImpl::MaybeSendPing(CNode& node_to, Peer& peer, std::chrono::mic
}
}
-void PeerManagerImpl::MaybeSendAddr(CNode& node, std::chrono::microseconds current_time)
+void PeerManagerImpl::MaybeSendAddr(CNode& node, Peer& peer, std::chrono::microseconds current_time)
{
// Nothing to do for non-address-relay peers
- if (!node.RelayAddrsWithConn()) return;
-
- assert(node.m_addr_known);
+ if (!RelayAddrsWithPeer(peer)) return;
- LOCK(node.m_addr_send_times_mutex);
+ LOCK(peer.m_addr_send_times_mutex);
// Periodically advertise our local address to the peer.
if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload() &&
- node.m_next_local_addr_send < current_time) {
+ peer.m_next_local_addr_send < current_time) {
// If we've sent before, clear the bloom filter for the peer, so that our
// self-announcement will actually go out.
// This might be unnecessary if the bloom filter has already rolled
// over since our last self-announcement, but there is only a small
// bandwidth cost that we can incur by doing this (which happens
// once a day on average).
- if (node.m_next_local_addr_send != 0us) {
- node.m_addr_known->reset();
+ if (peer.m_next_local_addr_send != 0us) {
+ peer.m_addr_known->reset();
}
if (std::optional<CAddress> local_addr = GetLocalAddrForPeer(&node)) {
FastRandomContext insecure_rand;
- node.PushAddress(*local_addr, insecure_rand);
+ PushAddress(peer, *local_addr, insecure_rand);
}
- node.m_next_local_addr_send = PoissonNextSend(current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
+ peer.m_next_local_addr_send = PoissonNextSend(current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
}
// We sent an `addr` message to this peer recently. Nothing more to do.
- if (current_time <= node.m_next_addr_send) return;
+ if (current_time <= peer.m_next_addr_send) return;
- node.m_next_addr_send = PoissonNextSend(current_time, AVG_ADDRESS_BROADCAST_INTERVAL);
+ peer.m_next_addr_send = PoissonNextSend(current_time, AVG_ADDRESS_BROADCAST_INTERVAL);
- if (!Assume(node.vAddrToSend.size() <= MAX_ADDR_TO_SEND)) {
+ if (!Assume(peer.m_addrs_to_send.size() <= MAX_ADDR_TO_SEND)) {
// Should be impossible since we always check size before adding to
- // vAddrToSend. Recover by trimming the vector.
- node.vAddrToSend.resize(MAX_ADDR_TO_SEND);
+ // m_addrs_to_send. Recover by trimming the vector.
+ peer.m_addrs_to_send.resize(MAX_ADDR_TO_SEND);
}
// Remove addr records that the peer already knows about, and add new
// addrs to the m_addr_known filter on the same pass.
- auto addr_already_known = [&node](const CAddress& addr) {
- bool ret = node.m_addr_known->contains(addr.GetKey());
- if (!ret) node.m_addr_known->insert(addr.GetKey());
+ auto addr_already_known = [&peer](const CAddress& addr) {
+ bool ret = peer.m_addr_known->contains(addr.GetKey());
+ if (!ret) peer.m_addr_known->insert(addr.GetKey());
return ret;
};
- node.vAddrToSend.erase(std::remove_if(node.vAddrToSend.begin(), node.vAddrToSend.end(), addr_already_known),
- node.vAddrToSend.end());
+ peer.m_addrs_to_send.erase(std::remove_if(peer.m_addrs_to_send.begin(), peer.m_addrs_to_send.end(), addr_already_known),
+ peer.m_addrs_to_send.end());
// No addr messages to send
- if (node.vAddrToSend.empty()) return;
+ if (peer.m_addrs_to_send.empty()) return;
const char* msg_type;
int make_flags;
- if (node.m_wants_addrv2) {
+ if (peer.m_wants_addrv2) {
msg_type = NetMsgType::ADDRV2;
make_flags = ADDRV2_FORMAT;
} else {
msg_type = NetMsgType::ADDR;
make_flags = 0;
}
- m_connman.PushMessage(&node, CNetMsgMaker(node.GetCommonVersion()).Make(make_flags, msg_type, node.vAddrToSend));
- node.vAddrToSend.clear();
+ m_connman.PushMessage(&node, CNetMsgMaker(node.GetCommonVersion()).Make(make_flags, msg_type, peer.m_addrs_to_send));
+ peer.m_addrs_to_send.clear();
// we only send the big addr message once
- if (node.vAddrToSend.capacity() > 40) {
- node.vAddrToSend.shrink_to_fit();
+ if (peer.m_addrs_to_send.capacity() > 40) {
+ peer.m_addrs_to_send.shrink_to_fit();
+ }
+}
+
+void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, std::chrono::microseconds current_time)
+{
+ AssertLockHeld(cs_main);
+
+ if (m_ignore_incoming_txs) return;
+ if (!pto.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;
+
+ CAmount currentFilter = m_mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
+ static FeeFilterRounder g_filter_rounder{CFeeRate{DEFAULT_MIN_RELAY_TX_FEE}};
+
+ if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
+ // Received tx-inv messages are discarded when the active
+ // chainstate is in IBD, so tell the peer to not send them.
+ currentFilter = MAX_MONEY;
+ } else {
+ static const CAmount MAX_FILTER{g_filter_rounder.round(MAX_MONEY)};
+ if (pto.m_tx_relay->lastSentFeeFilter == 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;
+ }
+ }
+ if (current_time > pto.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) {
+ m_connman.PushMessage(&pto, CNetMsgMaker(pto.GetCommonVersion()).Make(NetMsgType::FEEFILTER, filterToSend));
+ pto.m_tx_relay->lastSentFeeFilter = filterToSend;
+ }
+ pto.m_tx_relay->m_next_send_feefilter = PoissonNextSend(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);
}
}
@@ -4255,7 +4367,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// MaybeSendPing may have marked peer for disconnection
if (pto->fDisconnect) return true;
- MaybeSendAddr(*pto, current_time);
+ MaybeSendAddr(*pto, *peer, current_time);
{
LOCK(cs_main);
@@ -4449,11 +4561,12 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
}
}
peer->m_blocks_for_inv_relay.clear();
+ }
- if (pto->m_tx_relay != nullptr) {
+ if (pto->m_tx_relay != nullptr) {
LOCK(pto->m_tx_relay->cs_tx_inventory);
// Check whether periodic sends should happen
- bool fSendTrickle = pto->HasPermission(PF_NOBAN);
+ bool fSendTrickle = pto->HasPermission(NetPermissionFlags::NoBan);
if (pto->m_tx_relay->nNextInvSend < current_time) {
fSendTrickle = true;
if (pto->IsInboundConn()) {
@@ -4578,7 +4691,6 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
}
}
}
- }
}
if (!vInv.empty())
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
@@ -4611,12 +4723,12 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// Detect whether this is a stalling initial-headers-sync peer
if (pindexBestHeader->GetBlockTime() <= GetAdjustedTime() - 24 * 60 * 60) {
if (current_time > state.m_headers_sync_timeout && nSyncStarted == 1 && (nPreferredDownload - state.fPreferredDownload >= 1)) {
- // Disconnect a peer (without the noban permission) if it is our only sync peer,
+ // Disconnect a peer (without NetPermissionFlags::NoBan permission) if it is our only sync peer,
// and we have others we could be using instead.
// Note: If all our peers are inbound, then we won't
// disconnect our sync peer for stalling; we have bigger
// problems if we can't get any outbound peers.
- if (!pto->HasPermission(PF_NOBAN)) {
+ if (!pto->HasPermission(NetPermissionFlags::NoBan)) {
LogPrintf("Timeout downloading headers from peer=%d, disconnecting\n", pto->GetId());
pto->fDisconnect = true;
return true;
@@ -4696,46 +4808,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
if (!vGetData.empty())
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
- //
- // Message: feefilter
- //
- if (pto->m_tx_relay != nullptr &&
- !m_ignore_incoming_txs &&
- pto->GetCommonVersion() >= FEEFILTER_VERSION &&
- gArgs.GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
- !pto->HasPermission(PF_FORCERELAY) // peers with the forcerelay permission should not filter txs to us
- ) {
- CAmount currentFilter = m_mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
- static FeeFilterRounder g_filter_rounder{CFeeRate{DEFAULT_MIN_RELAY_TX_FEE}};
- if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
- // Received tx-inv messages are discarded when the active
- // chainstate is in IBD, so tell the peer to not send them.
- currentFilter = MAX_MONEY;
- } else {
- static const CAmount MAX_FILTER{g_filter_rounder.round(MAX_MONEY)};
- if (pto->m_tx_relay->lastSentFeeFilter == 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;
- }
- }
- if (current_time > pto->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) {
- m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend));
- pto->m_tx_relay->lastSentFeeFilter = filterToSend;
- }
- pto->m_tx_relay->m_next_send_feefilter = PoissonNextSend(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);
- }
- }
+ MaybeSendFeefilter(*pto, current_time);
} // release cs_main
return true;
}