@decentnetwork/peer 0.1.7 → 0.1.9
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 +40 -4
- package/package.json +1 -1
package/dist/peer.js
CHANGED
|
@@ -1915,6 +1915,27 @@ export class Peer {
|
|
|
1915
1915
|
.sort((a, b) => this.#nodeScore(`${b.host}:${b.port}`) - this.#nodeScore(`${a.host}:${a.port}`))
|
|
1916
1916
|
.slice(0, MAX_SELF_ANNOUNCE_TARGETS);
|
|
1917
1917
|
const zeroPing = new Uint8Array(32);
|
|
1918
|
+
// Fresh ephemeral keypair for THIS announce sweep. Matches toxcore
|
|
1919
|
+
// onion_client.c::do_announce which uses Onion_Client.temp_*_key
|
|
1920
|
+
// — a per-client ephemeral pair regenerated on each round — as the
|
|
1921
|
+
// announce sender, NOT the real identity key.
|
|
1922
|
+
//
|
|
1923
|
+
// The bug we just hit: before this fix, runSelfAnnounce used
|
|
1924
|
+
// this.#keyPair (real identity) as both senderPublicKey AND
|
|
1925
|
+
// searchPublicKey. Bootstrap nodes reject `isStored=2` when
|
|
1926
|
+
// sender == search because the protocol's slot-allocation assumes
|
|
1927
|
+
// the announcing party can be revoked by knowing the secret of
|
|
1928
|
+
// the sender pubkey; if that's our long-lived identity, every
|
|
1929
|
+
// bootstrap conservatively refuses. Observed in the wild as
|
|
1930
|
+
// selfAnnounceStoredOn=0 across 9 bootstrap nodes on both a
|
|
1931
|
+
// public-IP VPS and a NAT'd Mac — identical zero, not an
|
|
1932
|
+
// environmental issue.
|
|
1933
|
+
//
|
|
1934
|
+
// searchPublicKey stays as our real identity (so peers querying
|
|
1935
|
+
// for our pubkey find this slot). dataPublicKey also stays as
|
|
1936
|
+
// #announceDataKey.publicKey (so peers can encrypt onion-data
|
|
1937
|
+
// requests to us). Only the sender envelope rotates.
|
|
1938
|
+
const announceSender = createEphemeralKeyPair();
|
|
1918
1939
|
const candidates = [];
|
|
1919
1940
|
for (const node of targets) {
|
|
1920
1941
|
if (!node.pk)
|
|
@@ -1936,9 +1957,17 @@ export class Peer {
|
|
|
1936
1957
|
// stabilize self-announce in ~10s on a healthy network. Old serial
|
|
1937
1958
|
// walk took (per-node-timeout × N targets × 2 steps) ≈ 16 × 5s × 2
|
|
1938
1959
|
// = 160s worst case before a single isStored=2 response.
|
|
1960
|
+
// Reset counter at start so dhtHealth can distinguish "never ran" (-1)
|
|
1961
|
+
// from "ran but stored on 0 nodes" (0). The latter means our UDP
|
|
1962
|
+
// path is reaching bootstrap nodes but they're refusing to store
|
|
1963
|
+
// us — that's a wire-level problem (auth, network) we want to see.
|
|
1964
|
+
this.#lastSelfAnnounceStoredCount = 0;
|
|
1939
1965
|
for (let i = 0; i < candidates.length; i += SELF_ANNOUNCE_BATCH_SIZE) {
|
|
1940
1966
|
if (Date.now() >= deadlineMs) {
|
|
1941
1967
|
this.#debugLog("self announce stopped at deadline");
|
|
1968
|
+
// Even on early return, the count is live: storedNodes is what
|
|
1969
|
+
// we got so far.
|
|
1970
|
+
this.#lastSelfAnnounceStoredCount = storedNodes.length;
|
|
1942
1971
|
return storedNodes;
|
|
1943
1972
|
}
|
|
1944
1973
|
const wave = candidates.slice(i, i + SELF_ANNOUNCE_BATCH_SIZE);
|
|
@@ -1946,8 +1975,8 @@ export class Peer {
|
|
|
1946
1975
|
const step1Settled = await Promise.allSettled(wave.map((c) => this.#sendAnnounceAndWait({
|
|
1947
1976
|
node: c.node,
|
|
1948
1977
|
nodePublicKey: c.nodePk,
|
|
1949
|
-
senderPublicKey:
|
|
1950
|
-
senderSecretKey:
|
|
1978
|
+
senderPublicKey: announceSender.publicKey,
|
|
1979
|
+
senderSecretKey: announceSender.secretKey,
|
|
1951
1980
|
pingId: zeroPing,
|
|
1952
1981
|
searchPublicKey: this.#keyPair.publicKey,
|
|
1953
1982
|
dataPublicKey: this.#announceDataKey.publicKey,
|
|
@@ -1970,8 +1999,12 @@ export class Peer {
|
|
|
1970
1999
|
const step2Settled = await Promise.allSettled(step1Hits.map(({ c, resp1 }) => this.#sendAnnounceAndWait({
|
|
1971
2000
|
node: c.node,
|
|
1972
2001
|
nodePublicKey: c.nodePk,
|
|
1973
|
-
|
|
1974
|
-
|
|
2002
|
+
// Step2 MUST be re-encrypted to the bootstrap by the SAME
|
|
2003
|
+
// ephemeral sender that step1 used — bootstrap matches the
|
|
2004
|
+
// ping_id against the sender envelope of the request that
|
|
2005
|
+
// issued it. Use the same announceSender as step1.
|
|
2006
|
+
senderPublicKey: announceSender.publicKey,
|
|
2007
|
+
senderSecretKey: announceSender.secretKey,
|
|
1975
2008
|
pingId: resp1.pingOrDataPublicKey,
|
|
1976
2009
|
searchPublicKey: this.#keyPair.publicKey,
|
|
1977
2010
|
dataPublicKey: this.#announceDataKey.publicKey,
|
|
@@ -1989,6 +2022,9 @@ export class Peer {
|
|
|
1989
2022
|
}
|
|
1990
2023
|
if (final.isStored === 2) {
|
|
1991
2024
|
storedNodes.push(c.node);
|
|
2025
|
+
// Keep dhtHealth.selfAnnounceStoredOn live within the loop,
|
|
2026
|
+
// not just at the end, so we see growth in real time.
|
|
2027
|
+
this.#lastSelfAnnounceStoredCount = storedNodes.length;
|
|
1992
2028
|
}
|
|
1993
2029
|
const discovered = parsePackedNodes(final.nodes);
|
|
1994
2030
|
if (discovered.length > 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decentnetwork/peer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
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",
|