@decentnetwork/peer 0.1.117 → 0.1.119
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/peer.js +92 -17
- package/package.json +1 -1
package/dist/peer.js
CHANGED
|
@@ -32,7 +32,9 @@ const TURN_RELAY_SERVERS = [
|
|
|
32
32
|
{ host: "tokyo.fi.chat", port: 3478, username: "allcom", password: "allcompass" }
|
|
33
33
|
];
|
|
34
34
|
const ANNOUNCE_WAIT_TIMEOUT_MS = readEnvInt("DECENT_ANNOUNCE_WAIT_TIMEOUT_MS", 4000);
|
|
35
|
-
|
|
35
|
+
// 24 (was 12): with distance-ordered walking a lookup needs headroom to
|
|
36
|
+
// recurse past a first wave of dead close-in-XOR-space entries.
|
|
37
|
+
const MAX_FRIEND_ROUTE_ATTEMPTS = readEnvInt("DECENT_FRIEND_ROUTE_MAX_ATTEMPTS", 24);
|
|
36
38
|
// How many in-flight announce step1 requests to fan out at once. Toxcore
|
|
37
39
|
// pipelines all 12 of its onion clients in parallel; we batch up to this
|
|
38
40
|
// many concurrent #sendAnnounceAndWait calls so the worst-case walk drops
|
|
@@ -2886,9 +2888,53 @@ export class Peer {
|
|
|
2886
2888
|
const searchKey = createEphemeralKeyPair();
|
|
2887
2889
|
const routes = [];
|
|
2888
2890
|
const routeSeen = new Set();
|
|
2891
|
+
// The friend's announce lives on the ~8 nodes XOR-CLOSEST to their key
|
|
2892
|
+
// (toxcore onion_client). The old queue order (nodeScore) never converged
|
|
2893
|
+
// toward those nodes in our mostly-NAT'd table — 12 attempts burned on
|
|
2894
|
+
// responsive-but-far nodes, so lookups for native friends returned 0
|
|
2895
|
+
// routes and DHTPK could never be delivered. Sort by XOR distance to the
|
|
2896
|
+
// target; per-wave we still guarantee a couple of bootstraps so at least
|
|
2897
|
+
// one responder returns closer nodes to recurse on.
|
|
2898
|
+
const pkCache = new Map();
|
|
2899
|
+
const nodePkBytes = (node) => {
|
|
2900
|
+
if (!node.pk)
|
|
2901
|
+
return null;
|
|
2902
|
+
let v = pkCache.get(node.pk);
|
|
2903
|
+
if (v === undefined) {
|
|
2904
|
+
try {
|
|
2905
|
+
const b = base58ToBytes(node.pk);
|
|
2906
|
+
v = b.length === 32 ? b : null;
|
|
2907
|
+
}
|
|
2908
|
+
catch {
|
|
2909
|
+
v = null;
|
|
2910
|
+
}
|
|
2911
|
+
pkCache.set(node.pk, v);
|
|
2912
|
+
}
|
|
2913
|
+
return v;
|
|
2914
|
+
};
|
|
2915
|
+
const xorCloser = (a, b) => {
|
|
2916
|
+
for (let i = 0; i < 32; i++) {
|
|
2917
|
+
const da = a[i] ^ friendPublicKey[i];
|
|
2918
|
+
const db = b[i] ^ friendPublicKey[i];
|
|
2919
|
+
if (da !== db)
|
|
2920
|
+
return da - db;
|
|
2921
|
+
}
|
|
2922
|
+
return 0;
|
|
2923
|
+
};
|
|
2924
|
+
const byDistance = (x, y) => {
|
|
2925
|
+
const px = nodePkBytes(x);
|
|
2926
|
+
const py = nodePkBytes(y);
|
|
2927
|
+
if (!px || !py)
|
|
2928
|
+
return px ? -1 : py ? 1 : 0;
|
|
2929
|
+
const c = xorCloser(px, py);
|
|
2930
|
+
if (c !== 0)
|
|
2931
|
+
return c;
|
|
2932
|
+
return this.#nodeScore(`${y.host}:${y.port}`) - this.#nodeScore(`${x.host}:${x.port}`);
|
|
2933
|
+
};
|
|
2934
|
+
const bootstrapIdSet = new Set(this.#opts.bootstrapNodes.map((n) => `${n.host}:${n.port}`));
|
|
2889
2935
|
const queue = dedupeNodes(this.#knownNodes.length > 0 ? this.#knownNodes : this.#opts.bootstrapNodes)
|
|
2890
2936
|
.filter((n) => !this.#isNodeBlacklisted(`${n.host}:${n.port}`))
|
|
2891
|
-
.sort(
|
|
2937
|
+
.sort(byDistance);
|
|
2892
2938
|
const friendId = carrierIdFromPublicKey(friendPublicKey);
|
|
2893
2939
|
const visited = new Set();
|
|
2894
2940
|
let attempts = 0;
|
|
@@ -2903,25 +2949,32 @@ export class Peer {
|
|
|
2903
2949
|
// 4-10s parallel waves).
|
|
2904
2950
|
while (queue.length > 0 && attempts < maxAttempts && routes.length < 8) {
|
|
2905
2951
|
const batch = [];
|
|
2906
|
-
|
|
2907
|
-
const node = queue.shift();
|
|
2952
|
+
const takeInto = (node) => {
|
|
2908
2953
|
const nodeId = `${node.host}:${node.port}`;
|
|
2909
|
-
if (visited.has(nodeId)
|
|
2910
|
-
|
|
2954
|
+
if (visited.has(nodeId))
|
|
2955
|
+
return false;
|
|
2956
|
+
const nodePk = nodePkBytes(node);
|
|
2957
|
+
if (!nodePk) {
|
|
2958
|
+
visited.add(nodeId);
|
|
2959
|
+
return false;
|
|
2911
2960
|
}
|
|
2912
2961
|
visited.add(nodeId);
|
|
2913
|
-
let nodePk;
|
|
2914
|
-
try {
|
|
2915
|
-
nodePk = base58ToBytes(node.pk);
|
|
2916
|
-
}
|
|
2917
|
-
catch {
|
|
2918
|
-
continue;
|
|
2919
|
-
}
|
|
2920
|
-
if (nodePk.length !== 32) {
|
|
2921
|
-
continue;
|
|
2922
|
-
}
|
|
2923
2962
|
attempts += 1;
|
|
2924
2963
|
batch.push({ node, nodePk, sendBack: randomBytes(8) });
|
|
2964
|
+
return true;
|
|
2965
|
+
};
|
|
2966
|
+
if (attempts === 0) {
|
|
2967
|
+
let bootstrapsTaken = 0;
|
|
2968
|
+
for (const node of queue) {
|
|
2969
|
+
if (bootstrapsTaken >= 2 || attempts >= maxAttempts)
|
|
2970
|
+
break;
|
|
2971
|
+
if (bootstrapIdSet.has(`${node.host}:${node.port}`) && takeInto(node))
|
|
2972
|
+
bootstrapsTaken++;
|
|
2973
|
+
}
|
|
2974
|
+
}
|
|
2975
|
+
queue.sort(byDistance);
|
|
2976
|
+
while (queue.length > 0 && batch.length < FRIEND_ROUTE_BATCH_SIZE && attempts < maxAttempts) {
|
|
2977
|
+
takeInto(queue.shift());
|
|
2925
2978
|
}
|
|
2926
2979
|
if (batch.length === 0) {
|
|
2927
2980
|
break;
|
|
@@ -3110,8 +3163,30 @@ export class Peer {
|
|
|
3110
3163
|
return storedNodes;
|
|
3111
3164
|
}
|
|
3112
3165
|
waves += 1;
|
|
3113
|
-
// Pull the closest unvisited candidates for this wave.
|
|
3166
|
+
// Pull the closest unvisited candidates for this wave. Wave 1 reserves
|
|
3167
|
+
// slots for the BOOTSTRAP nodes: XOR-closest entries in our table are
|
|
3168
|
+
// mostly dead NAT'd peers, so a purely distance-ordered walk burned its
|
|
3169
|
+
// whole deadline before ever asking the only guaranteed-public,
|
|
3170
|
+
// always-on nodes. Announce storage capacity is large (toxcore keeps
|
|
3171
|
+
// ~160 entries, evicting furthest), so in this small network the fleet
|
|
3172
|
+
// WILL store us when asked — and every peer's lookup walk reaches the
|
|
3173
|
+
// fleet, so an announce stored there is universally findable.
|
|
3114
3174
|
const wave = [];
|
|
3175
|
+
if (waves === 1) {
|
|
3176
|
+
const bootstrapIdSet = new Set(this.#opts.bootstrapNodes.map((n) => `${n.host}:${n.port}`));
|
|
3177
|
+
for (let qi = 0; qi < queue.length && wave.length < 4;) {
|
|
3178
|
+
const c = queue[qi];
|
|
3179
|
+
const id = `${c.node.host}:${c.node.port}`;
|
|
3180
|
+
if (bootstrapIdSet.has(id) && !visited.has(id)) {
|
|
3181
|
+
visited.add(id);
|
|
3182
|
+
wave.push(c);
|
|
3183
|
+
queue.splice(qi, 1);
|
|
3184
|
+
}
|
|
3185
|
+
else {
|
|
3186
|
+
qi++;
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
}
|
|
3115
3190
|
while (queue.length > 0 && wave.length < SELF_ANNOUNCE_BATCH_SIZE) {
|
|
3116
3191
|
const c = queue.shift();
|
|
3117
3192
|
const id = `${c.node.host}:${c.node.port}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decentnetwork/peer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.119",
|
|
4
4
|
"description": "Pure TypeScript port of Elastos Carrier (toxcore-derived) P2P messaging. DHT, onion routing, TCP relay, FlatBuffers app payloads, Express offline relay. Wire-compatible with iOS Beagle and the Carrier C SDK.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|