fix(overlay): score peers in id order with injected PRNG

getScore draws from Application::getPrng. addPeers, getPeerWithTree and
getPeerWithLedger collect and sort by peer id before scoring so draws
do not follow unordered overlay traversal.
This commit is contained in:
Nicholas Dudfield
2026-09-18 11:41:49 +07:00
parent 605eefd921
commit 8e2907f231
2 changed files with 50 additions and 28 deletions

View File

@@ -44,6 +44,7 @@
#include <algorithm>
#include <memory>
#include <vector>
#include <mutex>
#include <numeric>
#include <sstream>
@@ -3018,20 +3019,27 @@ PeerImp::checkValidation(
static std::shared_ptr<PeerImp>
getPeerWithTree(OverlayImpl& ov, uint256 const& rootHash, PeerImp const* skip)
{
std::shared_ptr<PeerImp> ret;
int retScore = 0;
std::vector<std::shared_ptr<PeerImp>> candidates;
ov.for_each([&](std::shared_ptr<PeerImp>&& p) {
if (p->hasTxSet(rootHash) && p.get() != skip)
{
auto score = p->getScore(true);
if (!ret || (score > retScore))
{
ret = std::move(p);
retScore = score;
}
}
candidates.push_back(std::move(p));
});
std::sort(
candidates.begin(),
candidates.end(),
[](auto const& lhs, auto const& rhs) { return lhs->id() < rhs->id(); });
std::shared_ptr<PeerImp> ret;
int retScore = 0;
for (auto& p : candidates)
{
auto score = p->getScore(true);
if (!ret || (score > retScore))
{
ret = std::move(p);
retScore = score;
}
}
return ret;
}
@@ -3046,20 +3054,27 @@ getPeerWithLedger(
LedgerIndex ledger,
PeerImp const* skip)
{
std::shared_ptr<PeerImp> ret;
int retScore = 0;
std::vector<std::shared_ptr<PeerImp>> candidates;
ov.for_each([&](std::shared_ptr<PeerImp>&& p) {
if (p->hasLedger(ledgerHash, ledger) && p.get() != skip)
{
auto score = p->getScore(true);
if (!ret || (score > retScore))
{
ret = std::move(p);
retScore = score;
}
}
candidates.push_back(std::move(p));
});
std::sort(
candidates.begin(),
candidates.end(),
[](auto const& lhs, auto const& rhs) { return lhs->id() < rhs->id(); });
std::shared_ptr<PeerImp> ret;
int retScore = 0;
for (auto& p : candidates)
{
auto score = p->getScore(true);
if (!ret || (score > retScore))
{
ret = std::move(p);
retScore = score;
}
}
return ret;
}
@@ -3433,7 +3448,7 @@ PeerImp::getScore(bool haveItem) const
// Penalty for unknown latency; should be roughly spRandomMax
static const int spNoLatency = 8000;
int score = rand_int(spRandomMax);
int score = rand_int(app_.getPrng(), spRandomMax);
if (haveItem)
score += spHaveItem;

View File

@@ -21,6 +21,7 @@
#include <xrpld/core/JobQueue.h>
#include <xrpld/overlay/Overlay.h>
#include <xrpld/overlay/PeerSet.h>
#include <algorithm>
namespace ripple {
@@ -73,12 +74,18 @@ PeerSetImpl::addPeers(
std::vector<ScoredPeer> pairs;
pairs.reserve(overlay.size());
overlay.foreach([&](auto const& peer) {
auto const score = peer->getScore(hasItem(peer));
pairs.emplace_back(score, std::move(peer));
});
overlay.foreach(
[&](auto const& peer) { pairs.emplace_back(0, std::move(peer)); });
std::sort(
pairs.begin(),
pairs.end(),
[](ScoredPeer const& lhs, ScoredPeer const& rhs) {
return lhs.second->id() < rhs.second->id();
});
for (auto& pair : pairs)
pair.first = pair.second->getScore(hasItem(pair.second));
std::stable_sort(
pairs.begin(),
pairs.end(),
[](ScoredPeer const& lhs, ScoredPeer const& rhs) {