Skip to content

Commit 1393bf6

Browse files
committed
p2p: Evict outbound connections to -blocksonly peers when at full outbound maximum
...unless we are in -blocksonly mode ourselve or in ibd. If we had too many outbound peers not participating in tx relay, we would run into problems with getting own transaction relayed. This would also be bad for privacy and fee estimation. We evict non-txrelay peers only when all full outbound slots are filled to have peers in hypothetical situations where -blocksonly peers are the only ones available. Idea for this approach by ajtowns.
1 parent 4d7b787 commit 1393bf6

File tree

4 files changed

+29
-5
lines changed

4 files changed

+29
-5
lines changed

src/net.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,12 +2347,13 @@ void CConnman::StartExtraBlockRelayPeers()
23472347
}
23482348

23492349
// Return the number of peers we have over our outbound connection limit
2350+
// Returns 0 if we are at the limit, and a negative number if below.
23502351
// Exclude peers that are marked for disconnect, or are going to be
23512352
// disconnected soon (eg ADDR_FETCH and FEELER)
23522353
// Also exclude peers that haven't finished initial connection handshake yet
23532354
// (so that we don't decide we're over our desired connection limit, and then
23542355
// evict some peer that has finished the handshake)
2355-
int CConnman::GetExtraFullOutboundCount() const
2356+
int CConnman::GetFullOutboundDelta() const
23562357
{
23572358
int full_outbound_peers = 0;
23582359
{
@@ -2363,7 +2364,7 @@ int CConnman::GetExtraFullOutboundCount() const
23632364
}
23642365
}
23652366
}
2366-
return std::max(full_outbound_peers - m_max_outbound_full_relay, 0);
2367+
return full_outbound_peers - m_max_outbound_full_relay;
23672368
}
23682369

23692370
int CConnman::GetExtraBlockRelayCount() const

src/net.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1173,7 +1173,8 @@ class CConnman
11731173
// return a value less than (num_outbound_connections - num_outbound_slots)
11741174
// in cases where some outbound connections are not yet fully connected, or
11751175
// not yet fully disconnected.
1176-
int GetExtraFullOutboundCount() const;
1176+
// Returns 0 if we are at the target, and a negative number if below.
1177+
int GetFullOutboundDelta() const;
11771178
// Count the number of block-relay-only peers we have over our limit.
11781179
int GetExtraBlockRelayCount() const;
11791180

src/net_processing.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5183,7 +5183,8 @@ void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now)
51835183
}
51845184

51855185
// Check whether we have too many outbound-full-relay peers
5186-
if (m_connman.GetExtraFullOutboundCount() > 0) {
5186+
int full_outbound_delta{m_connman.GetFullOutboundDelta()};
5187+
if (full_outbound_delta > 0) {
51875188
// If we have more outbound-full-relay peers than we target, disconnect one.
51885189
// Pick the outbound-full-relay peer that least recently announced
51895190
// us a new block, with ties broken by choosing the more recent
@@ -5241,6 +5242,27 @@ void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now)
52415242
}
52425243
}
52435244
}
5245+
// If we are at the max full outbound limit but not above, check if any peers
5246+
// don't support tx relay (they might be in -blocksonly mode) - if so,
5247+
// evict the newest of them (highest Node Id) so we can fill the slot with a tx-relaying outbound peer
5248+
// This is not done if we are in -blocksonly mode ourselves or still in IBD,
5249+
// because then we don't care if our peer supports tx relay.
5250+
else if (full_outbound_delta == 0 && !m_opts.ignore_incoming_txs && !m_chainman.IsInitialBlockDownload()) {
5251+
std::optional<NodeId> node_to_evict;
5252+
m_connman.ForEachNode([&node_to_evict](CNode* node) {
5253+
if (!node->IsFullOutboundConn() || node->m_relays_txs) return;
5254+
if (!node_to_evict.has_value() || *node_to_evict < node->GetId()) {
5255+
node_to_evict = node->GetId();
5256+
}
5257+
});
5258+
if (node_to_evict.has_value()) {
5259+
LogPrint(BCLog::NET, "disconnecting full outbound peer not participating in tx relay: peer=%d\n", *node_to_evict);
5260+
m_connman.ForNode(*node_to_evict, [](CNode* node) {
5261+
node->fDisconnect = true;
5262+
return true;
5263+
});
5264+
}
5265+
}
52445266
}
52455267

52465268
void PeerManagerImpl::CheckForStaleTipAndEvictPeers()

src/test/fuzz/connman.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ FUZZ_TARGET(connman, .init = initialize_connman)
123123
});
124124
}
125125
(void)connman.GetAddedNodeInfo(fuzzed_data_provider.ConsumeBool());
126-
(void)connman.GetExtraFullOutboundCount();
126+
(void)connman.GetFullOutboundDelta();
127127
(void)connman.GetLocalServices();
128128
(void)connman.GetMaxOutboundTarget();
129129
(void)connman.GetMaxOutboundTimeframe();

0 commit comments

Comments
 (0)