@decentnetwork/peer 0.1.129 → 0.1.130

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.
Files changed (2) hide show
  1. package/dist/peer.js +36 -2
  2. package/package.json +1 -1
package/dist/peer.js CHANGED
@@ -968,7 +968,7 @@ export class Peer {
968
968
  uint32ToLe(friendAddress.nospam),
969
969
  appPayload
970
970
  ]);
971
- const routes = await this.#discoverFriendRoutes(friendAddress.publicKey);
971
+ const routes = await this.#discoverFriendRoutes(friendAddress.publicKey, true);
972
972
  this.#debugLog(`friend route discovery done routes=${routes.length}`);
973
973
  if (routes.length === 0) {
974
974
  // The direct net_crypto send needs a known endpoint for the target; to
@@ -2928,10 +2928,35 @@ export class Peer {
2928
2928
  // Ignore invalid offline payloads.
2929
2929
  }
2930
2930
  }
2931
- async #discoverFriendRoutes(friendPublicKey) {
2931
+ /**
2932
+ * @param userInitiated skips the budget. Adding a friend must not wait on a
2933
+ * throttle meant for background upkeep.
2934
+ */
2935
+ async #discoverFriendRoutes(friendPublicKey, userInitiated = false) {
2932
2936
  if (!this.#keyPair) {
2933
2937
  throw new Error("Peer is not started");
2934
2938
  }
2939
+ // Same per-friend budget as #discoverAndCacheFriendEndpoint, enforced HERE
2940
+ // for the same reason: this is the THIRD time today the cost simply moved
2941
+ // to whichever caller was not gated. #sendOnionDhtPk's call sites were
2942
+ // throttled, so the sweep underneath them became the top crypto entry
2943
+ // instead — 17.9% of wall on gfax, climbing (20% -> 27% over ten minutes)
2944
+ // rather than settling, because the DHT-PK path kept a FLAT 25s interval
2945
+ // while the endpoint path had already been given backoff.
2946
+ //
2947
+ // A gate inside the function cannot be bypassed by a call site added later.
2948
+ const routeKey = `routes:${carrierIdFromPublicKey(friendPublicKey)}`;
2949
+ if (!userInitiated) {
2950
+ const misses = this.#onionLookupMisses.get(routeKey) ?? 0;
2951
+ const budget = Math.min(DHT_PK_ANNOUNCE_COOLDOWN_MS * Math.max(1, misses), ONION_LOOKUP_MAX_BACKOFF_MS);
2952
+ const since = Date.now() - (this.#onionLookupCooldown.get(routeKey) ?? 0);
2953
+ if (since < budget) {
2954
+ this.#debugLog(`route discovery for ${routeKey} skipped: ${Math.round(since / 1000)}s ` +
2955
+ `since last (budget ${Math.round(budget / 1000)}s, misses ${misses})`);
2956
+ return [];
2957
+ }
2958
+ this.#onionLookupCooldown.set(routeKey, Date.now());
2959
+ }
2935
2960
  const searchKey = createEphemeralKeyPair();
2936
2961
  const routes = [];
2937
2962
  const routeSeen = new Set();
@@ -3075,6 +3100,15 @@ export class Peer {
3075
3100
  }
3076
3101
  }
3077
3102
  }
3103
+ // Miss accounting drives the backoff above. Without it the budget stays at
3104
+ // its 25s floor forever and the gate does nothing for the friends that
3105
+ // actually cost us — the ones that never resolve.
3106
+ if (!userInitiated) {
3107
+ if (routes.length > 0)
3108
+ this.#onionLookupMisses.delete(routeKey);
3109
+ else
3110
+ this.#onionLookupMisses.set(routeKey, (this.#onionLookupMisses.get(routeKey) ?? 0) + 1);
3111
+ }
3078
3112
  return routes;
3079
3113
  }
3080
3114
  async #discoverAndCacheFriendEndpoint(friendId, searchPublicKey) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/peer",
3
- "version": "0.1.129",
3
+ "version": "0.1.130",
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",