@peerbit/pubsub 5.4.4 → 5.4.6

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.
@@ -166,6 +166,7 @@ export declare class TopicControlPlane extends DirectStream<PubSubEvents> implem
166
166
  private hostOwnedShardRootsInFlight?;
167
167
  private hostOwnedShardRootsDirty;
168
168
  private readonly signedTopicRootCandidateClaims;
169
+ private readonly suppressedDepartedTopicRootCandidateClaims;
169
170
  private readonly topicRootCandidateClaimReplayFloors;
170
171
  private localSignedTopicRootCandidateClaim?;
171
172
  private topicRootCandidateClaimMaintenanceTimer?;
@@ -199,7 +200,7 @@ export declare class TopicControlPlane extends DirectStream<PubSubEvents> implem
199
200
  start(): Promise<void>;
200
201
  stop(): Promise<void>;
201
202
  addPeer(peerId: Libp2pPeerId, publicKey: PublicSignKey, protocol: string, connId: string): PeerStreams;
202
- protected _removePeer(publicKey: PublicSignKey): Promise<PeerStreams>;
203
+ protected _removePeer(publicKey: PublicSignKey): Promise<PeerStreams | undefined>;
203
204
  private maybeDisableAutoTopicRootCandidatesIfExternallyConfigured;
204
205
  private clearTopicRootCandidateClaimTimer;
205
206
  private clearSignedTopicRootCandidateState;
@@ -211,6 +212,7 @@ export declare class TopicControlPlane extends DirectStream<PubSubEvents> implem
211
212
  private pruneExpiredTopicRootCandidateClaims;
212
213
  private rebuildAutoTopicRootCandidatesFromClaims;
213
214
  private retainSignedTopicRootCandidateClaim;
215
+ private isDepartedTopicRootCandidateClaimSuppressed;
214
216
  private canAdvanceTopicRootCandidateClaimReplayFloor;
215
217
  private canRetainTopicRootCandidateClaimOrigin;
216
218
  private consumeTopicRootCandidateClaimVerifyBudget;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
package/dist/src/index.js CHANGED
@@ -134,9 +134,15 @@ const TOPIC_ROOT_CANDIDATE_CLAIM_VERIFY_REFILL_MS = 60_000;
134
134
  const TOPIC_ROOT_CANDIDATE_CLAIM_VERIFY_PEERS_MAX = 4_096;
135
135
  const sameCandidates = (left, right) => left.length === right.length &&
136
136
  left.every((candidate, index) => candidate === right[index]);
137
- // Topic-root queries may need to wait for the responder to finish opening an
138
- // outbound stream back to the requester after an inbound-only dial.
137
+ // Retain the previous 12 second allowance as one deadline for the complete
138
+ // peer-query phase. It must not multiply by peer count or retry count.
139
139
  const DEFAULT_TOPIC_ROOT_QUERY_TIMEOUT_MS = 12_000;
140
+ // A responder may need to open an outbound stream after an inbound-only dial.
141
+ // Bounded rounds leave enough time for that setup while still allowing a lost
142
+ // request or a newly-ready stream to be retried within the phase deadline.
143
+ const TOPIC_ROOT_QUERY_ROUND_TIMEOUT_MS = 3_000;
144
+ const TOPIC_ROOT_HOST_SCAN_TIMEOUT_MS = DEFAULT_TOPIC_ROOT_QUERY_TIMEOUT_MS;
145
+ const TOPIC_ROOT_HOST_SCAN_CONCURRENCY = 8;
140
146
  const DIRECT_SHARD_ROOT_CONFIRM_TIMEOUT_MS = 2_000;
141
147
  const DEFAULT_PUBSUB_FANOUT_CHANNEL_OPTIONS = {
142
148
  msgRate: 30,
@@ -218,6 +224,12 @@ export class TopicControlPlane extends DirectStream {
218
224
  hostOwnedShardRootsInFlight;
219
225
  hostOwnedShardRootsDirty = false;
220
226
  signedTopicRootCandidateClaims = new Map();
227
+ // A directly observed departure makes only that origin's current lease
228
+ // ineffective locally. This is not a component-wide withdrawal: claims learned
229
+ // only through relays keep their existing lease semantics. Keeping the verified
230
+ // bytes + replay floor prevents a relay from resurrecting the departed lease;
231
+ // the map is bounded by the same retained-origin cap as the claim map.
232
+ suppressedDepartedTopicRootCandidateClaims = new Map();
221
233
  // Active claims expire, but their per-origin timestamp floors survive for the
222
234
  // auto-mode lifecycle so a frozen wall clock cannot renew a replayed lease.
223
235
  // Retaining only the deterministic lowest origins keeps this state hard-bounded.
@@ -481,7 +493,7 @@ export class TopicControlPlane extends DirectStream {
481
493
  if (peer.isWritable) {
482
494
  void this.sendAutoTopicRootCandidates([peer]).catch(() => { });
483
495
  }
484
- if (!existingPeer) {
496
+ if (existingPeer !== peer) {
485
497
  peer.addEventListener("stream:outbound", sendWhenOutboundReady);
486
498
  peer.addEventListener("close", () => peer.removeEventListener("stream:outbound", sendWhenOutboundReady), { once: true });
487
499
  }
@@ -494,12 +506,31 @@ export class TopicControlPlane extends DirectStream {
494
506
  const protocol = this.peers.get(hash)?.protocol;
495
507
  const hadSignedPeer = [...this.peers.values()].some((peer) => peer.protocol === TOPIC_CONTROL_PLANE_PROTOCOL_V2_1);
496
508
  const removed = await super._removePeer(publicKey);
509
+ // A replacement may arrive after base removal but before this continuation.
510
+ if (!removed || this.peers.has(hash))
511
+ return;
512
+ let suppressedDepartedOrigin = false;
513
+ if (removed &&
514
+ this.autoTopicRootCandidates &&
515
+ protocol === TOPIC_CONTROL_PLANE_PROTOCOL_V2_1 &&
516
+ this.signedTopicRootCandidateClaims.has(hash)) {
517
+ const claim = this.signedTopicRootCandidateClaims.get(hash);
518
+ const suppressed = this.suppressedDepartedTopicRootCandidateClaims.get(hash);
519
+ suppressedDepartedOrigin =
520
+ !suppressed ||
521
+ suppressed.timestamp !== claim.timestamp ||
522
+ !bytesEqual(suppressed.bytes, claim.bytes);
523
+ this.suppressedDepartedTopicRootCandidateClaims.set(hash, {
524
+ bytes: claim.bytes,
525
+ timestamp: claim.timestamp,
526
+ });
527
+ }
497
528
  if (this.autoTopicRootCandidates &&
498
529
  (protocol === TOPIC_CONTROL_PLANE_PROTOCOL_V2_0 ||
499
530
  protocol === TOPIC_CONTROL_PLANE_PROTOCOL_V2_1)) {
500
531
  const hasSignedPeer = [...this.peers.values()].some((peer) => peer.protocol === TOPIC_CONTROL_PLANE_PROTOCOL_V2_1);
501
532
  this.rebuildAutoTopicRootCandidatesFromClaims(BigInt(Date.now()), {
502
- immediate: hadSignedPeer !== hasSignedPeer,
533
+ immediate: suppressedDepartedOrigin || hadSignedPeer !== hasSignedPeer,
503
534
  });
504
535
  }
505
536
  return removed;
@@ -538,6 +569,7 @@ export class TopicControlPlane extends DirectStream {
538
569
  clearSignedTopicRootCandidateState() {
539
570
  this.clearTopicRootCandidateClaimTimer();
540
571
  this.signedTopicRootCandidateClaims.clear();
572
+ this.suppressedDepartedTopicRootCandidateClaims.clear();
541
573
  this.topicRootCandidateClaimReplayFloors.clear();
542
574
  this.localSignedTopicRootCandidateClaim = undefined;
543
575
  this.topicRootCandidateClaimRefreshNotBefore = undefined;
@@ -749,6 +781,7 @@ export class TopicControlPlane extends DirectStream {
749
781
  for (const [origin, claim] of this.signedTopicRootCandidateClaims) {
750
782
  if (claim.expires <= now || claim.acceptUntil <= monotonicNow) {
751
783
  this.signedTopicRootCandidateClaims.delete(origin);
784
+ this.suppressedDepartedTopicRootCandidateClaims.delete(origin);
752
785
  changed = true;
753
786
  }
754
787
  }
@@ -768,7 +801,9 @@ export class TopicControlPlane extends DirectStream {
768
801
  ? []
769
802
  : [this.publicKeyHash]),
770
803
  ...legacyDirectCandidates,
771
- ...this.signedTopicRootCandidateClaims.keys(),
804
+ ...[...this.signedTopicRootCandidateClaims.entries()]
805
+ .filter(([origin, claim]) => !this.isDepartedTopicRootCandidateClaimSuppressed(origin, claim))
806
+ .map(([origin]) => origin),
772
807
  ]),
773
808
  ]
774
809
  .filter(isCanonicalTopicRootCandidate)
@@ -802,6 +837,7 @@ export class TopicControlPlane extends DirectStream {
802
837
  // because the retained maximum only decreases, it cannot re-enter.
803
838
  this.topicRootCandidateClaimReplayFloors.delete(highest);
804
839
  this.signedTopicRootCandidateClaims.delete(highest);
840
+ this.suppressedDepartedTopicRootCandidateClaims.delete(highest);
805
841
  if (highest === this.publicKeyHash) {
806
842
  this.localSignedTopicRootCandidateClaim = undefined;
807
843
  }
@@ -809,8 +845,14 @@ export class TopicControlPlane extends DirectStream {
809
845
  }
810
846
  this.topicRootCandidateClaimReplayFloors.set(origin, claim.timestamp);
811
847
  this.signedTopicRootCandidateClaims.set(origin, claim);
848
+ this.suppressedDepartedTopicRootCandidateClaims.delete(origin);
812
849
  return true;
813
850
  }
851
+ isDepartedTopicRootCandidateClaimSuppressed(origin, claim) {
852
+ const suppressed = this.suppressedDepartedTopicRootCandidateClaims.get(origin);
853
+ return (suppressed?.timestamp === claim.timestamp &&
854
+ bytesEqual(suppressed.bytes, claim.bytes));
855
+ }
814
856
  canAdvanceTopicRootCandidateClaimReplayFloor(origin, timestamp) {
815
857
  const floor = this.topicRootCandidateClaimReplayFloors.get(origin);
816
858
  if (floor !== undefined) {
@@ -871,7 +913,7 @@ export class TopicControlPlane extends DirectStream {
871
913
  this.topicRootCandidateClaimGlobalVerifyBudget.remaining -= 1;
872
914
  return true;
873
915
  }
874
- async importSignedTopicRootCandidateClaim(rawClaim, outerPeerHash) {
916
+ async importSignedTopicRootCandidateClaim(rawClaim, outerPeerHash, expectedPeer) {
875
917
  const lifecycleRevision = this.topicControlPlaneLifecycleRevision;
876
918
  if (rawClaim.byteLength === 0 ||
877
919
  rawClaim.byteLength > TOPIC_ROOT_CANDIDATE_CLAIM_MAX_BYTES) {
@@ -910,10 +952,30 @@ export class TopicControlPlane extends DirectStream {
910
952
  if (acceptanceDeadline === undefined) {
911
953
  return false;
912
954
  }
955
+ this.rebuildAutoTopicRootCandidatesFromClaims(now);
956
+ const retained = this.signedTopicRootCandidateClaims.get(origin);
957
+ if (outerPeerHash === origin &&
958
+ expectedPeer !== undefined &&
959
+ expectedPeer.protocol === TOPIC_CONTROL_PLANE_PROTOCOL_V2_1 &&
960
+ this.peers.get(outerPeerHash) === expectedPeer &&
961
+ lifecycleRevision === this.topicControlPlaneLifecycleRevision &&
962
+ this.autoTopicRootCandidates &&
963
+ this.started &&
964
+ !this.stopping &&
965
+ !this.topicControlPlaneStopping &&
966
+ retained?.timestamp === timestamp &&
967
+ bytesEqual(retained.bytes, rawClaim) &&
968
+ this.isDepartedTopicRootCandidateClaimSuppressed(origin, retained)) {
969
+ // These exact bytes were already verified and remain under the original
970
+ // monotonic acceptance deadline. A current authenticated origin stream is
971
+ // sufficient liveness evidence; do not advance the floor or lease.
972
+ this.suppressedDepartedTopicRootCandidateClaims.delete(origin);
973
+ this.rebuildAutoTopicRootCandidatesFromClaims(now, { immediate: true });
974
+ return false;
975
+ }
913
976
  if (!this.canAdvanceTopicRootCandidateClaimReplayFloor(origin, timestamp)) {
914
977
  return false;
915
978
  }
916
- this.rebuildAutoTopicRootCandidatesFromClaims(now);
917
979
  if (!this.consumeTopicRootCandidateClaimVerifyBudget(outerPeerHash)) {
918
980
  return false;
919
981
  }
@@ -933,7 +995,9 @@ export class TopicControlPlane extends DirectStream {
933
995
  !this.autoTopicRootCandidates ||
934
996
  !this.started ||
935
997
  this.stopping ||
936
- this.topicControlPlaneStopping) {
998
+ this.topicControlPlaneStopping ||
999
+ (expectedPeer !== undefined &&
1000
+ this.peers.get(outerPeerHash) !== expectedPeer)) {
937
1001
  return false;
938
1002
  }
939
1003
  if (!this.retainSignedTopicRootCandidateClaim(origin, {
@@ -985,6 +1049,7 @@ export class TopicControlPlane extends DirectStream {
985
1049
  }
986
1050
  }
987
1051
  const claims = [...this.signedTopicRootCandidateClaims.entries()]
1052
+ .filter(([origin, claim]) => !this.isDepartedTopicRootCandidateClaimSuppressed(origin, claim))
988
1053
  .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
989
1054
  .map(([, claim]) => claim.bytes);
990
1055
  await this.sendSignedTopicRootCandidateClaims(claims, signedStreams);
@@ -1483,27 +1548,68 @@ export class TopicControlPlane extends DirectStream {
1483
1548
  if (tracked) {
1484
1549
  return { root: tracked, authoritative: true };
1485
1550
  }
1486
- const resolvedThroughPeers = await this.resolveTopicRootThroughPeers(topic, options);
1487
- if (resolvedThroughPeers) {
1488
- // Unconfigured peer-query replies cannot override the locally
1489
- // deterministic root for internal shards in auto mode. Roots, resolvers,
1490
- // and trackers explicitly configured on this control plane are resolved
1491
- // above and remain authoritative. A leaf relying on a queried gateway for
1492
- // shard roots must first disable auto mode with setTopicRootCandidates([]).
1493
- return this.normalizePeerTopicRootState(topic, resolvedThroughPeers);
1551
+ if (options?.queryConnectedPeers === false) {
1552
+ return {
1553
+ root: this.topicRootControlPlane.resolveDeterministicTopicRoot(topic),
1554
+ authoritative: false,
1555
+ };
1494
1556
  }
1495
- const deterministic = this.topicRootControlPlane.resolveDeterministicTopicRoot(topic);
1496
- if (deterministic === this.publicKeyHash &&
1497
- this.autoTopicRootCandidates &&
1498
- this.getConnectedTopicRootTrackers().length > 0) {
1499
- for (let attempt = 0; attempt < 8; attempt++) {
1500
- await withAbort(delay(150 * (attempt < 4 ? 1 : 2), options), options?.signal);
1501
- const retried = await this.resolveTopicRootThroughPeers(topic, options);
1502
- if (retried) {
1503
- return this.normalizePeerTopicRootState(topic, retried);
1557
+ const deadlineController = new AbortController();
1558
+ const deadlineTimer = setTimeout(() => deadlineController.abort(new AbortError("topic root peer-query deadline reached")), DEFAULT_TOPIC_ROOT_QUERY_TIMEOUT_MS);
1559
+ deadlineTimer.unref?.();
1560
+ const querySignals = linkAbortSignals([
1561
+ options?.signal,
1562
+ deadlineController.signal,
1563
+ ]);
1564
+ try {
1565
+ let attempt = 0;
1566
+ for (;;) {
1567
+ throwIfAborted(querySignals.signal);
1568
+ // Preserve the immediate deterministic fallback when no queryable stream
1569
+ // exists at entry. Once a peer was queryable, keep the bounded readiness
1570
+ // window alive: later rounds re-snapshot streams that can become writable
1571
+ // after an inbound-only dial.
1572
+ if (attempt === 0 &&
1573
+ this.getConnectedTopicRootTrackers().length === 0) {
1574
+ break;
1575
+ }
1576
+ if (attempt > 0) {
1577
+ await withAbort(delay(150 * Math.min(attempt, 2), {
1578
+ signal: querySignals.signal,
1579
+ }), querySignals.signal);
1580
+ }
1581
+ attempt += 1;
1582
+ const resolvedThroughPeers = await this.resolveTopicRootThroughPeers(topic, {
1583
+ signal: querySignals.signal,
1584
+ timeoutMs: TOPIC_ROOT_QUERY_ROUND_TIMEOUT_MS,
1585
+ });
1586
+ if (resolvedThroughPeers !== undefined) {
1587
+ // Unconfigured peer-query replies cannot override the locally
1588
+ // deterministic root for internal shards in auto mode. Roots,
1589
+ // resolvers, and trackers explicitly configured on this control
1590
+ // plane are resolved above and remain authoritative. A leaf relying
1591
+ // on a queried gateway for shard roots must first disable auto mode
1592
+ // with setTopicRootCandidates([]).
1593
+ return this.normalizePeerTopicRootState(topic, resolvedThroughPeers);
1504
1594
  }
1505
1595
  }
1506
1596
  }
1597
+ catch (error) {
1598
+ // Candidate, lifecycle, and caller cancellation are terminal to this
1599
+ // invocation and must retain their exact reason. Only the private phase
1600
+ // deadline falls through to the same deterministic result as exhausted
1601
+ // peer queries.
1602
+ if (options?.signal?.aborted) {
1603
+ throw options.signal.reason ?? error;
1604
+ }
1605
+ if (!deadlineController.signal.aborted) {
1606
+ throw error;
1607
+ }
1608
+ }
1609
+ finally {
1610
+ clearTimeout(deadlineTimer);
1611
+ querySignals.clear();
1612
+ }
1507
1613
  return {
1508
1614
  root: this.topicRootControlPlane.resolveDeterministicTopicRoot(topic),
1509
1615
  authoritative: false,
@@ -1527,8 +1633,13 @@ export class TopicControlPlane extends DirectStream {
1527
1633
  this.maybeDisableAutoTopicRootCandidatesIfExternallyConfigured();
1528
1634
  }
1529
1635
  const candidateGeneration = this.getTopicRootCandidateGeneration();
1530
- const hasConnectedTrackers = this.getConnectedTopicRootTrackers().length > 0;
1531
- const cached = this.shardRootCache.get(shardTopic);
1636
+ const hasConnectedTrackers = options?.queryConnectedPeers !== false &&
1637
+ this.getConnectedTopicRootTrackers().length > 0;
1638
+ // A proactive local scan must not inherit an authoritative cache entry that
1639
+ // originated from a connected-peer reply under the same candidate generation.
1640
+ const cached = options?.queryConnectedPeers === false
1641
+ ? undefined
1642
+ : this.shardRootCache.get(shardTopic);
1532
1643
  if (cached && (cached.authoritative || !hasConnectedTrackers)) {
1533
1644
  return { root: cached.root, candidateGeneration };
1534
1645
  }
@@ -1569,7 +1680,7 @@ export class TopicControlPlane extends DirectStream {
1569
1680
  requestId = this.nextTopicRootQueryId >>> 0;
1570
1681
  } while (true);
1571
1682
  }
1572
- async sendDirectControlMessage(peer, pubsubMessage) {
1683
+ async sendDirectControlMessage(peer, pubsubMessage, signal) {
1573
1684
  const embedded = await this.createMessage(this.encodePubSubMessage(pubsubMessage), {
1574
1685
  mode: new SilentDelivery({
1575
1686
  to: [peer.publicKey.hashcode()],
@@ -1578,7 +1689,7 @@ export class TopicControlPlane extends DirectStream {
1578
1689
  priority: 1,
1579
1690
  skipRecipientValidation: true,
1580
1691
  });
1581
- await this.publishMessage(this.publicKey, embedded, [peer]);
1692
+ await this.publishMessage(this.publicKey, embedded, [peer], undefined, signal);
1582
1693
  }
1583
1694
  resolvePendingTopicRootQuery(message, responderPeerHash) {
1584
1695
  const pending = this.pendingTopicRootQueries.get(message.requestId);
@@ -1598,6 +1709,9 @@ export class TopicControlPlane extends DirectStream {
1598
1709
  return undefined;
1599
1710
  const expectedPeerHash = peer.publicKey.hashcode();
1600
1711
  const requestId = this.nextTopicRootRequestIdValue();
1712
+ const queryController = new AbortController();
1713
+ const querySignals = linkAbortSignals([signal, queryController.signal]);
1714
+ let timedOut = false;
1601
1715
  const responsePromise = new Promise((resolve) => {
1602
1716
  let settled = false;
1603
1717
  const settle = (root) => {
@@ -1609,13 +1723,15 @@ export class TopicControlPlane extends DirectStream {
1609
1723
  this.pendingTopicRootQueries.delete(requestId);
1610
1724
  }
1611
1725
  clearTimeout(timer);
1612
- if (signal && onAbort) {
1613
- signal.removeEventListener("abort", onAbort);
1614
- }
1726
+ querySignals.signal.removeEventListener("abort", onAbort);
1615
1727
  resolve(root);
1616
1728
  };
1617
- const onAbort = signal ? () => settle(undefined) : undefined;
1618
- const timer = setTimeout(() => settle(undefined), Math.max(1, Math.floor(timeoutMs)));
1729
+ const onAbort = () => settle(undefined);
1730
+ const timer = setTimeout(() => {
1731
+ timedOut = true;
1732
+ settle(undefined);
1733
+ queryController.abort(new AbortError("topic root query timed out"));
1734
+ }, Math.max(1, Math.floor(timeoutMs)));
1619
1735
  timer.unref?.();
1620
1736
  this.pendingTopicRootQueries.set(requestId, {
1621
1737
  expectedPeerHash,
@@ -1623,26 +1739,39 @@ export class TopicControlPlane extends DirectStream {
1623
1739
  resolve: settle,
1624
1740
  timer,
1625
1741
  });
1626
- if (signal && onAbort) {
1627
- signal.addEventListener("abort", onAbort, { once: true });
1628
- if (signal.aborted)
1629
- onAbort();
1630
- }
1742
+ querySignals.signal.addEventListener("abort", onAbort, { once: true });
1743
+ if (querySignals.signal.aborted)
1744
+ onAbort();
1631
1745
  });
1632
1746
  try {
1633
- await withAbort(this.sendDirectControlMessage(peer, new TopicRootQuery({ requestId, topic })), signal);
1634
- }
1635
- catch (error) {
1636
- const pending = this.pendingTopicRootQueries.get(requestId);
1637
- if (pending) {
1638
- this.pendingTopicRootQueries.delete(requestId);
1639
- clearTimeout(pending.timer);
1640
- pending.resolve(undefined);
1747
+ try {
1748
+ const sending = withAbort(this.sendDirectControlMessage(peer, new TopicRootQuery({ requestId, topic }), querySignals.signal), querySignals.signal);
1749
+ // A write can finish after the request is already on the wire (or stall
1750
+ // while opening the reverse stream). Let either a response or the same
1751
+ // query timeout release this await instead of extending the timeout around
1752
+ // the outbound send.
1753
+ await Promise.race([
1754
+ sending,
1755
+ responsePromise.then(() => undefined),
1756
+ ]);
1641
1757
  }
1642
- if (signal?.aborted)
1643
- throw error;
1758
+ catch (error) {
1759
+ const pending = this.pendingTopicRootQueries.get(requestId);
1760
+ if (pending && !timedOut) {
1761
+ this.pendingTopicRootQueries.delete(requestId);
1762
+ clearTimeout(pending.timer);
1763
+ pending.resolve(undefined);
1764
+ }
1765
+ if (signal?.aborted) {
1766
+ throw signal.reason ?? error;
1767
+ }
1768
+ }
1769
+ return await withAbort(responsePromise, signal);
1770
+ }
1771
+ finally {
1772
+ queryController.abort(new AbortError("topic root query settled"));
1773
+ querySignals.clear();
1644
1774
  }
1645
- return withAbort(responsePromise, signal);
1646
1775
  }
1647
1776
  async confirmDirectShardRoot(shardTopic, root, candidateGeneration, lifecycleRevision, signal) {
1648
1777
  this.assertTopicControlPlaneActive(lifecycleRevision);
@@ -1712,18 +1841,69 @@ export class TopicControlPlane extends DirectStream {
1712
1841
  if (peers.length === 0) {
1713
1842
  return undefined;
1714
1843
  }
1715
- for (let attempt = 0; attempt < 3; attempt++) {
1716
- for (const peer of peers) {
1717
- const resolved = await this.queryTopicRootFromPeer(peer, topic, DEFAULT_TOPIC_ROOT_QUERY_TIMEOUT_MS, options?.signal);
1718
- if (resolved) {
1719
- return resolved;
1844
+ const roundController = new AbortController();
1845
+ const roundTimeoutMs = Math.max(1, Math.floor(options?.timeoutMs ?? DEFAULT_TOPIC_ROOT_QUERY_TIMEOUT_MS));
1846
+ let roundTimedOut = false;
1847
+ const roundTimer = setTimeout(() => {
1848
+ roundTimedOut = true;
1849
+ roundController.abort(new AbortError("topic root query round timed out"));
1850
+ }, roundTimeoutMs);
1851
+ roundTimer.unref?.();
1852
+ const roundSignals = linkAbortSignals([
1853
+ options?.signal,
1854
+ roundController.signal,
1855
+ ]);
1856
+ const queries = peers.map((peer) => this.queryTopicRootFromPeer(peer, topic, roundTimeoutMs, roundSignals.signal));
1857
+ const unresolved = Symbol("unresolved topic root query");
1858
+ const results = peers.map(() => unresolved);
1859
+ // All requests start together, but the stable peer ordering remains the
1860
+ // conflict-resolution policy: a later answer is usable only after every
1861
+ // earlier peer has answered undefined or reached its round timeout.
1862
+ const prioritizedResult = new Promise((resolve, reject) => {
1863
+ let settled = false;
1864
+ const resolveInPeerOrder = () => {
1865
+ for (const result of results) {
1866
+ if (result === unresolved)
1867
+ return;
1868
+ if (result !== undefined) {
1869
+ settled = true;
1870
+ resolve(result);
1871
+ return;
1872
+ }
1720
1873
  }
1721
- }
1722
- if (attempt < 2) {
1723
- await withAbort(delay(150 * (attempt + 1), options), options?.signal);
1724
- }
1874
+ settled = true;
1875
+ resolve(undefined);
1876
+ };
1877
+ queries.forEach((query, index) => {
1878
+ query.then((root) => {
1879
+ if (settled)
1880
+ return;
1881
+ results[index] = root;
1882
+ resolveInPeerOrder();
1883
+ }, (error) => {
1884
+ if (settled)
1885
+ return;
1886
+ if (roundTimedOut && !options?.signal?.aborted) {
1887
+ results[index] = undefined;
1888
+ resolveInPeerOrder();
1889
+ return;
1890
+ }
1891
+ settled = true;
1892
+ reject(error);
1893
+ });
1894
+ });
1895
+ });
1896
+ try {
1897
+ return await prioritizedResult;
1898
+ }
1899
+ finally {
1900
+ clearTimeout(roundTimer);
1901
+ // Cancel response timers and in-flight sends for every losing query before
1902
+ // the winning root (or an abort) can leave this round.
1903
+ roundController.abort(new AbortError("topic root query round settled"));
1904
+ await Promise.allSettled(queries);
1905
+ roundSignals.clear();
1725
1906
  }
1726
- return undefined;
1727
1907
  }
1728
1908
  async ensureFanoutChannel(shardTopic, options) {
1729
1909
  const topic = shardTopic.toString();
@@ -2107,26 +2287,71 @@ export class TopicControlPlane extends DirectStream {
2107
2287
  if (!this.started)
2108
2288
  throw new NotStartedError();
2109
2289
  const lifecycleSignal = this.topicRootResolutionAbortController.signal;
2110
- return this.withTopicRootCandidateResolution(async ({ candidateGeneration, signal }) => {
2290
+ return this.withTopicRootCandidateResolution(async ({ signal }) => {
2111
2291
  const joins = [];
2292
+ const scanController = new AbortController();
2293
+ const scanTimer = setTimeout(() => {
2294
+ scanController.abort(new AbortError(`topic root host scan timed out after ${TOPIC_ROOT_HOST_SCAN_TIMEOUT_MS}ms`));
2295
+ }, TOPIC_ROOT_HOST_SCAN_TIMEOUT_MS);
2296
+ scanTimer.unref?.();
2297
+ const scanSignals = linkAbortSignals([signal, scanController.signal]);
2298
+ let nextShard = 0;
2299
+ let scanFailure;
2300
+ const scanWorker = async () => {
2301
+ try {
2302
+ for (;;) {
2303
+ if (scanFailure)
2304
+ return;
2305
+ throwIfAborted(scanSignals.signal);
2306
+ const shard = nextShard++;
2307
+ if (shard >= this.shardCount)
2308
+ return;
2309
+ const shardTopic = `${this.shardTopicPrefix}${shard}`;
2310
+ const resolved = await this.resolveShardRootState(shardTopic, {
2311
+ signal: scanSignals.signal,
2312
+ // Proactive hosting follows the generation-bound local control
2313
+ // plane. Connected-peer queries remain on the lazy open path;
2314
+ // asking every peer for every shard multiplies one stale-peer
2315
+ // timeout by the complete shard count.
2316
+ queryConnectedPeers: false,
2317
+ });
2318
+ throwIfAborted(scanSignals.signal);
2319
+ if (scanFailure || resolved.root !== this.publicKeyHash)
2320
+ continue;
2321
+ const joining = this.ensureFanoutChannel(shardTopic, {
2322
+ pin: true,
2323
+ root: resolved.root,
2324
+ rootCandidateGeneration: resolved.candidateGeneration,
2325
+ // The shared deadline bounds root discovery only. Preserve the
2326
+ // existing contract that joins already started are drained.
2327
+ signal,
2328
+ });
2329
+ void joining.catch(() => { });
2330
+ joins.push(joining);
2331
+ }
2332
+ }
2333
+ catch (error) {
2334
+ if (!scanFailure) {
2335
+ scanFailure = { error };
2336
+ // Do not make a sibling resolver consume the rest of the shared
2337
+ // deadline after this scan already has a terminal failure. Joins use
2338
+ // the outer signal and are intentionally drained below.
2339
+ scanController.abort(error);
2340
+ }
2341
+ }
2342
+ };
2112
2343
  try {
2113
- for (let i = 0; i < this.shardCount; i++) {
2114
- throwIfAborted(signal);
2115
- const shardTopic = `${this.shardTopicPrefix}${i}`;
2116
- const resolved = await this.resolveShardRootState(shardTopic, {
2117
- signal,
2118
- });
2119
- if (resolved.root !== this.publicKeyHash)
2120
- continue;
2121
- const joining = this.ensureFanoutChannel(shardTopic, {
2122
- pin: true,
2123
- root: resolved.root,
2124
- rootCandidateGeneration: resolved.candidateGeneration,
2125
- signal,
2126
- });
2127
- void joining.catch(() => { });
2128
- joins.push(joining);
2344
+ try {
2345
+ await Promise.all(Array.from({
2346
+ length: Math.min(TOPIC_ROOT_HOST_SCAN_CONCURRENCY, this.shardCount),
2347
+ }, () => scanWorker()));
2348
+ }
2349
+ finally {
2350
+ clearTimeout(scanTimer);
2351
+ scanSignals.clear();
2129
2352
  }
2353
+ if (scanFailure)
2354
+ throw scanFailure.error;
2130
2355
  await Promise.all(joins);
2131
2356
  }
2132
2357
  catch (error) {
@@ -2856,7 +3081,7 @@ export class TopicControlPlane extends DirectStream {
2856
3081
  const imported = [];
2857
3082
  const outerPeerHash = stream.publicKey.hashcode();
2858
3083
  for (const claim of pubsubMessage.claims) {
2859
- if (await this.importSignedTopicRootCandidateClaim(claim, outerPeerHash)) {
3084
+ if (await this.importSignedTopicRootCandidateClaim(claim, outerPeerHash, stream)) {
2860
3085
  imported.push(claim);
2861
3086
  }
2862
3087
  }