mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-18 22:35:39 +01:00
Periodically make block-relay connections and sync headers
To make eclipse attacks more difficult, regularly initiate outbound connections and stay connected long enough to sync headers and potentially learn of new blocks. If we learn a new block, rotate out an existing block-relay peer in favor of the new peer. This augments the existing outbound peer rotation that exists -- currently we make new full-relay connections when our tip is stale, which we disconnect after waiting a small time to see if we learn a new block. As block-relay connections use minimal bandwidth, we can make these connections regularly and not just when our tip is stale. Like feeler connections, these connections are not aggressive; whenever our timer fires (once every 5 minutes on average), we'll try to initiate a new block-relay connection as described, but if we fail to connect we just wait for our timer to fire again before repeating with a new peer.
This commit is contained in:
@@ -3909,9 +3909,52 @@ void PeerManager::ConsiderEviction(CNode& pto, int64_t time_in_seconds)
|
||||
|
||||
void PeerManager::EvictExtraOutboundPeers(int64_t time_in_seconds)
|
||||
{
|
||||
// If we have any extra block-relay-only peers, disconnect the youngest unless
|
||||
// it's given us a block -- in which case, compare with the second-youngest, and
|
||||
// out of those two, disconnect the peer who least recently gave us a block.
|
||||
// The youngest block-relay-only peer would be the extra peer we connected
|
||||
// to temporarily in order to sync our tip; see net.cpp.
|
||||
// Note that we use higher nodeid as a measure for most recent connection.
|
||||
if (m_connman.GetExtraBlockRelayCount() > 0) {
|
||||
std::pair<NodeId, int64_t> youngest_peer{-1, 0}, next_youngest_peer{-1, 0};
|
||||
|
||||
m_connman.ForEachNode([&](CNode* pnode) {
|
||||
if (!pnode->IsBlockOnlyConn() || pnode->fDisconnect) return;
|
||||
if (pnode->GetId() > youngest_peer.first) {
|
||||
next_youngest_peer = youngest_peer;
|
||||
youngest_peer.first = pnode->GetId();
|
||||
youngest_peer.second = pnode->nLastBlockTime;
|
||||
}
|
||||
});
|
||||
NodeId to_disconnect = youngest_peer.first;
|
||||
if (youngest_peer.second > next_youngest_peer.second) {
|
||||
// Our newest block-relay-only peer gave us a block more recently;
|
||||
// disconnect our second youngest.
|
||||
to_disconnect = next_youngest_peer.first;
|
||||
}
|
||||
m_connman.ForNode(to_disconnect, [&](CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
|
||||
AssertLockHeld(::cs_main);
|
||||
// Make sure we're not getting a block right now, and that
|
||||
// we've been connected long enough for this eviction to happen
|
||||
// at all.
|
||||
// Note that we only request blocks from a peer if we learn of a
|
||||
// valid headers chain with at least as much work as our tip.
|
||||
CNodeState *node_state = State(pnode->GetId());
|
||||
if (node_state == nullptr ||
|
||||
(time_in_seconds - pnode->nTimeConnected >= MINIMUM_CONNECT_TIME && node_state->nBlocksInFlight == 0)) {
|
||||
pnode->fDisconnect = true;
|
||||
LogPrint(BCLog::NET, "disconnecting extra block-relay-only peer=%d (last block received at time %d)\n", pnode->GetId(), pnode->nLastBlockTime);
|
||||
return true;
|
||||
} else {
|
||||
LogPrint(BCLog::NET, "keeping block-relay-only peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n",
|
||||
pnode->GetId(), pnode->nTimeConnected, node_state->nBlocksInFlight);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
// Check whether we have too many outbound peers
|
||||
int extra_peers = m_connman.GetExtraFullOutboundCount();
|
||||
if (extra_peers > 0) {
|
||||
if (m_connman.GetExtraFullOutboundCount() > 0) {
|
||||
// If we have more outbound peers than we target, disconnect one.
|
||||
// Pick the outbound peer that least recently announced
|
||||
// us a new block, with ties broken by choosing the more recent
|
||||
@@ -3983,6 +4026,11 @@ void PeerManager::CheckForStaleTipAndEvictPeers()
|
||||
}
|
||||
m_stale_tip_check_time = time_in_seconds + STALE_CHECK_INTERVAL;
|
||||
}
|
||||
|
||||
if (!m_initial_sync_finished && CanDirectFetch(m_chainparams.GetConsensus())) {
|
||||
m_connman.StartExtraBlockRelayPeers();
|
||||
m_initial_sync_finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
Reference in New Issue
Block a user