Changeset View
Changeset View
Standalone View
Standalone View
src/net.cpp
Show First 20 Lines • Show All 922 Lines • ▼ Show 20 Lines | static bool CompareNodeBlockRelayOnlyTime(const NodeEvictionCandidate &a, | ||||
if (a.fRelevantServices != b.fRelevantServices) { | if (a.fRelevantServices != b.fRelevantServices) { | ||||
return b.fRelevantServices; | return b.fRelevantServices; | ||||
} | } | ||||
return a.nTimeConnected > b.nTimeConnected; | return a.nTimeConnected > b.nTimeConnected; | ||||
} | } | ||||
static bool CompareNodeAvailabilityScore(const NodeEvictionCandidate &a, | |||||
const NodeEvictionCandidate &b) { | |||||
// Equality can happen if the nodes have no score or it has not been | |||||
// computed yet. | |||||
if (a.availabilityScore != b.availabilityScore) { | |||||
return a.availabilityScore < b.availabilityScore; | |||||
} | |||||
return a.nTimeConnected > b.nTimeConnected; | |||||
} | |||||
//! Sort an array by the specified comparator, then erase the last K elements. | //! Sort an array by the specified comparator, then erase the last K elements. | ||||
template <typename T, typename Comparator> | template <typename T, typename Comparator> | ||||
static void EraseLastKElements(std::vector<T> &elements, Comparator comparator, | static void EraseLastKElements(std::vector<T> &elements, Comparator comparator, | ||||
size_t k) { | size_t k) { | ||||
std::sort(elements.begin(), elements.end(), comparator); | std::sort(elements.begin(), elements.end(), comparator); | ||||
size_t eraseSize = std::min(k, elements.size()); | size_t eraseSize = std::min(k, elements.size()); | ||||
elements.erase(elements.end() - eraseSize, elements.end()); | elements.erase(elements.end() - eraseSize, elements.end()); | ||||
} | } | ||||
Show All 37 Lines | EraseLastKElementsIf(vEvictionCandidates, CompareNodeBlockRelayOnlyTime, 8, | ||||
[](NodeEvictionCandidate const &n) { | [](NodeEvictionCandidate const &n) { | ||||
return !n.fRelayTxes && n.fRelevantServices; | return !n.fRelayTxes && n.fRelevantServices; | ||||
}); | }); | ||||
// Protect 4 nodes that most recently sent us novel blocks. | // Protect 4 nodes that most recently sent us novel blocks. | ||||
// An attacker cannot manipulate this metric without performing useful work. | // An attacker cannot manipulate this metric without performing useful work. | ||||
EraseLastKElements(vEvictionCandidates, CompareNodeBlockTime, 4); | EraseLastKElements(vEvictionCandidates, CompareNodeBlockTime, 4); | ||||
// Protect up to 128 nodes that have the highest avalanche availability | |||||
// score. | |||||
EraseLastKElementsIf(vEvictionCandidates, CompareNodeAvailabilityScore, 128, | |||||
[](NodeEvictionCandidate const &n) { | |||||
return !std::isinf(n.availabilityScore); | |||||
deadalnix: Maybe having a thresold is enough? Like `n.availabilityScore > 0` ? Do we really want to… | |||||
FabienAuthorUnsubmitted Done Inline ActionsI planned to do something similar as a replacement for D9862. For now a score of 0 either means that the node was never selected or the score was not updated yet, and you want to protect only for the latter case. So my idea was to apply a penalty to the nodes that were never selected so that their score will be negative, and filter using availabilityScore >= 0; I can use the same filter here. Fabien: I planned to do something similar as a replacement for D9862. For now a score of 0 either means… | |||||
}); | |||||
// Protect the half of the remaining nodes which have been connected the | // Protect the half of the remaining nodes which have been connected the | ||||
// longest. This replicates the non-eviction implicit behavior, and | // longest. This replicates the non-eviction implicit behavior, and | ||||
// precludes attacks that start later. | // precludes attacks that start later. | ||||
// Reserve half of these protected spots for localhost peers, even if | // Reserve half of these protected spots for localhost peers, even if | ||||
// they're not longest-uptime overall. This helps protect tor peers, which | // they're not longest-uptime overall. This helps protect tor peers, which | ||||
// tend to be otherwise disadvantaged under our eviction criteria. | // tend to be otherwise disadvantaged under our eviction criteria. | ||||
size_t initial_size = vEvictionCandidates.size(); | size_t initial_size = vEvictionCandidates.size(); | ||||
size_t total_protect_size = initial_size / 2; | size_t total_protect_size = initial_size / 2; | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | std::vector<NodeEvictionCandidate> vEvictionCandidates; | ||||
} | } | ||||
bool peer_relay_txes = false; | bool peer_relay_txes = false; | ||||
bool peer_filter_not_null = false; | bool peer_filter_not_null = false; | ||||
if (node->m_tx_relay != nullptr) { | if (node->m_tx_relay != nullptr) { | ||||
LOCK(node->m_tx_relay->cs_filter); | LOCK(node->m_tx_relay->cs_filter); | ||||
peer_relay_txes = node->m_tx_relay->fRelayTxes; | peer_relay_txes = node->m_tx_relay->fRelayTxes; | ||||
peer_filter_not_null = node->m_tx_relay->pfilter != nullptr; | peer_filter_not_null = node->m_tx_relay->pfilter != nullptr; | ||||
} | } | ||||
NodeEvictionCandidate candidate = { | NodeEvictionCandidate candidate = { | ||||
node->GetId(), | node->GetId(), | ||||
node->nTimeConnected, | node->nTimeConnected, | ||||
node->nMinPingUsecTime, | node->nMinPingUsecTime, | ||||
node->nLastBlockTime, | node->nLastBlockTime, | ||||
node->nLastProofTime, | node->nLastProofTime, | ||||
node->nLastTXTime, | node->nLastTXTime, | ||||
HasAllDesirableServiceFlags(node->nServices), | HasAllDesirableServiceFlags(node->nServices), | ||||
peer_relay_txes, | peer_relay_txes, | ||||
peer_filter_not_null, | peer_filter_not_null, | ||||
node->nKeyedNetGroup, | node->nKeyedNetGroup, | ||||
node->m_prefer_evict, | node->m_prefer_evict, | ||||
node->addr.IsLocal()}; | node->addr.IsLocal(), | ||||
node->m_avalanche_state | |||||
? node->m_avalanche_state->getAvailabilityScore() | |||||
: -std::numeric_limits<double>::infinity()}; | |||||
vEvictionCandidates.push_back(candidate); | vEvictionCandidates.push_back(candidate); | ||||
} | } | ||||
} | } | ||||
const std::optional<NodeId> node_id_to_evict = | const std::optional<NodeId> node_id_to_evict = | ||||
SelectNodeToEvict(std::move(vEvictionCandidates)); | SelectNodeToEvict(std::move(vEvictionCandidates)); | ||||
if (!node_id_to_evict) { | if (!node_id_to_evict) { | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 2,164 Lines • Show Last 20 Lines |
Maybe having a thresold is enough? Like n.availabilityScore > 0 ? Do we really want to protect trully aweful peers?