From 194c89baf9e0be0733d264e9371acab7467d6d13 Mon Sep 17 00:00:00 2001 From: marcus-pousette-hp Date: Thu, 28 May 2026 11:03:13 +0200 Subject: [PATCH 1/3] Prefer low-rtt announce relays --- lib/announcer.js | 15 ++++++++++++-- test/announces.js | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/lib/announcer.js b/lib/announcer.js index 42f7d8ef..5a53d2d7 100644 --- a/lib/announcer.js +++ b/lib/announcer.js @@ -8,6 +8,8 @@ const Persistent = require('./persistent') const { COMMANDS } = require('./constants') const MIN_ACTIVE = 3 +const MAX_ANNOUNCE_RELAYS = 3 +const RTT_CANDIDATE_WINDOW = 8 module.exports = class Announcer { constructor(dht, keyPair, target, opts = {}) { @@ -296,8 +298,17 @@ function resolved(ps) { } function pickBest(replies) { - // TODO: pick the ones closest to us RTT wise - return replies.slice(0, 3) + const candidates = replies.slice(0, RTT_CANDIDATE_WINDOW) + const ranked = candidates.map((reply, index) => ({ reply, index })) + + ranked.sort((a, b) => { + const ar = Number.isFinite(a.reply.rtt) ? a.reply.rtt : Infinity + const br = Number.isFinite(b.reply.rtt) ? b.reply.rtt : Infinity + + return ar - br || a.index - b.index + }) + + return ranked.slice(0, MAX_ANNOUNCE_RELAYS).map(({ reply }) => reply) } function noop() {} diff --git a/test/announces.js b/test/announces.js index 6a144099..edb00113 100644 --- a/test/announces.js +++ b/test/announces.js @@ -5,6 +5,7 @@ const messages = require('../lib/messages.js') const { swarm, toArray } = require('./helpers') const DHT = require('../') const HyperDHT = require('../') +const Announcer = require('../lib/announcer') const { COMMANDS } = require('../lib/constants.js') test('server listen and findPeer', async function (t) { @@ -193,6 +194,56 @@ test('server announces relay addrs', async function (t) { } }) +test('announcer prefers lower rtt among close-enough replies', async function (t) { + const keyPair = DHT.keyPair() + const target = DHT.hash(Buffer.from('rtt-ranked-announces')) + const rtts = [80, 70, 60, 50, 40, 30, 20, 10, 1, 2] + const replies = rtts.map((rtt, i) => { + return { + token: b4a.alloc(32, i), + rtt, + from: { + id: b4a.alloc(32, i + 1), + host: '127.0.0.1', + port: 10000 + i + }, + to: { + host: '127.0.0.1', + port: 20000 + i + } + } + }) + const announced = [] + const dht = { + firewalled: true, + destroyed: false, + findPeer() { + return { + closestReplies: replies, + closestNodes: replies.map((reply) => reply.from), + finished: () => Promise.resolve() + } + }, + request(req, to) { + t.is(req.command, COMMANDS.ANNOUNCE) + announced.push(to.port) + return Promise.resolve({ error: 0 }) + } + } + const announcer = new Announcer(dht, keyPair, target, { + signAnnounce: () => b4a.alloc(64) + }) + + await announcer._update() + + t.alike( + announced.sort((a, b) => a - b), + [10005, 10006, 10007], + 'announced to lowest-rtt replies inside the candidate window' + ) + t.absent(announced.includes(10008), 'ignored lower-rtt reply outside the candidate window') +}) + test('connect when we relay ourself', async function (t) { const testnet = await swarm(t) From 63251b82516d8637dc795459e61c74b3bff470b9 Mon Sep 17 00:00:00 2001 From: marcus-pousette-hp Date: Thu, 28 May 2026 12:01:43 +0200 Subject: [PATCH 2/3] Simplify announce relay rtt ranking --- lib/announcer.js | 7 +------ test/announces.js | 8 ++++---- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/lib/announcer.js b/lib/announcer.js index 5a53d2d7..b621805d 100644 --- a/lib/announcer.js +++ b/lib/announcer.js @@ -301,12 +301,7 @@ function pickBest(replies) { const candidates = replies.slice(0, RTT_CANDIDATE_WINDOW) const ranked = candidates.map((reply, index) => ({ reply, index })) - ranked.sort((a, b) => { - const ar = Number.isFinite(a.reply.rtt) ? a.reply.rtt : Infinity - const br = Number.isFinite(b.reply.rtt) ? b.reply.rtt : Infinity - - return ar - br || a.index - b.index - }) + ranked.sort((a, b) => a.reply.rtt - b.reply.rtt || a.index - b.index) return ranked.slice(0, MAX_ANNOUNCE_RELAYS).map(({ reply }) => reply) } diff --git a/test/announces.js b/test/announces.js index edb00113..cbd17069 100644 --- a/test/announces.js +++ b/test/announces.js @@ -197,7 +197,7 @@ test('server announces relay addrs', async function (t) { test('announcer prefers lower rtt among close-enough replies', async function (t) { const keyPair = DHT.keyPair() const target = DHT.hash(Buffer.from('rtt-ranked-announces')) - const rtts = [80, 70, 60, 50, 40, 30, 20, 10, 1, 2] + const rtts = [80, 70, 20, 20, 40, 20, 60, 10, 1, 2] const replies = rtts.map((rtt, i) => { return { token: b4a.alloc(32, i), @@ -237,9 +237,9 @@ test('announcer prefers lower rtt among close-enough replies', async function (t await announcer._update() t.alike( - announced.sort((a, b) => a - b), - [10005, 10006, 10007], - 'announced to lowest-rtt replies inside the candidate window' + announced, + [10007, 10002, 10003], + 'announced to lowest-rtt replies and kept reply order for equal rtt' ) t.absent(announced.includes(10008), 'ignored lower-rtt reply outside the candidate window') }) From af6ac6782dcfce32aec5fe8ebda1c06a5416faf1 Mon Sep 17 00:00:00 2001 From: marcus-pousette-hp Date: Thu, 28 May 2026 13:55:32 +0200 Subject: [PATCH 3/3] Tidy announce relay ranking --- lib/announcer.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/announcer.js b/lib/announcer.js index b621805d..240c4cb0 100644 --- a/lib/announcer.js +++ b/lib/announcer.js @@ -298,12 +298,12 @@ function resolved(ps) { } function pickBest(replies) { - const candidates = replies.slice(0, RTT_CANDIDATE_WINDOW) - const ranked = candidates.map((reply, index) => ({ reply, index })) - - ranked.sort((a, b) => a.reply.rtt - b.reply.rtt || a.index - b.index) - - return ranked.slice(0, MAX_ANNOUNCE_RELAYS).map(({ reply }) => reply) + return replies + .slice(0, RTT_CANDIDATE_WINDOW) + .map((reply, index) => ({ reply, index })) + .sort((a, b) => a.reply.rtt - b.reply.rtt || a.index - b.index) + .slice(0, MAX_ANNOUNCE_RELAYS) + .map(({ reply }) => reply) } function noop() {}