Skip to content

Public relays accept signed seed requests but never connect to pull content (0 peers synced) #2

Description

@bigdestiny2

Summary

When using HiveRelayClient from p2p-hiverelay@0.4.2 against the public relay network, signed seed requests are accepted by multiple relays but no relay ever dials our Hyperswarm to pull the drive content. drive.core.peers.length stays at 0 indefinitely, so pins are not actually replicated — they're only "accepted but pending."

Environment

  • p2p-hiverelay@0.4.2 (HiveRelayClient from p2p-hiverelay/client)
  • hyperdrive@13.3.2
  • hyperswarm@4.17.0
  • corestore@7.9.2
  • Pear runtime 0.2497 (Bare)
  • macOS 15.6.1
  • App: pearbrowser-desktop (a desktop fork of bigdestiny2/PearBrowser) publishing Hyperdrive sites

Integration

Follows the canonical example in examples/pear-app/index.js verbatim — shared swarm + store passed into HiveRelayClient:

import { HiveRelayClient } from 'p2p-hiverelay/client'

const relay = new HiveRelayClient({ swarm, store })
await relay.start()

// ...when publishing a site:
await swarm.join(drive.discoveryKey, { server: true, client: false })
const acceptances = await relay.seed(driveKeyHex, { replicas: 3, timeout: 10000 })

The drive is a standard writable Hyperdrive: new Hyperdrive(store.namespace(uniqueId)), content written with put() before publishing.

Observed

  1. Relay connections OK. At startup, relay-connected fires for 5 relays across these IDs: 2ec1..., 6b11..., 17ba..., 1e7d..., 37cf..., 0da2..., a8de..., 77bc....
  2. Seed accepted. On relay.seed(driveKeyHex, { replicas: 3, timeout: 10000 }), 3 relays emit seed-accepted within ~1–2 seconds — the signed seed request is successfully accepted.
  3. No peers ever connect. We then watch drive.core.peers for 30 seconds waiting for any remote peer to reach remoteLength >= localLength. After the timeout:
    • drive.core.peers.length === 0
    • No relay ever dials our swarm on the drive's discoveryKey.
    • HiveRelay connection state still shows 5 active relay sessions throughout the 30s wait.

Expected

After seed-accepted, each accepting relay should join the drive's discoveryKey on Hyperswarm and actively replicate the drive to completion, so the pin is durable.

What we've verified on our side

  • swarm.join(drive.discoveryKey, { server: true, client: false }) is called before relay.seed(), so we are announcing and discoverable.
  • HiveRelayClient shares our swarm + store (not separate instances), per the pear-app example.
  • The Hyperdrive is writable and has content put() before publishing.
  • 5 relay sessions remain connected throughout the 30s wait window (not a churn/disconnect issue).
  • driveKeyHex passed to relay.seed() is the drive's public key hex (drive.key.toString('hex')).

Hypotheses (please confirm/rule out)

  1. Accept-but-defer by design. Relays may only record the seed request in their distributed registry and wait for passive discovery (someone else announcing the discoveryKey) rather than proactively dialing the publisher. If so, a brand-new drive with no other peers will never get pulled.
  2. Silent reputation/quota gating. Relays may gate active pulls by keypair reputation or quota and silently drop requests from unknown publishers while still emitting seed-accepted.
  3. discoveryKey mismatch. In client/index.js:425-427, the seed request payload derives a discovery key via sodium.crypto_generichash(32, appKeyBuf). Hypercore derives its discoveryKey differently (HMAC-BLAKE2b keyed by a fixed namespace over the public key). If relays look for the drive on the DHT using the generic-hash value, they'd look in the wrong place and never find our swarm announcement, which uses the real Hypercore discoveryKey.
  4. Public relay network is experimental / read-only for unknown publishers. If so, this should be documented so integrators don't ship UIs that imply durable pinning when none is happening.

Hypothesis 3 is the one we'd most like confirmed or refuted — it would explain all observed symptoms (accept succeeds because it's a pure payload check, but no peer ever connects because the DHT lookup key is wrong).

Reproduction

Follow examples/pear-app/index.js verbatim with the versions above:

  1. Create a writable Hyperdrive, put() a small file.
  2. swarm.join(drive.discoveryKey, { server: true, client: false }).
  3. await relay.seed(drive.key.toString('hex'), { replicas: 3, timeout: 10000 }).
  4. Observe seed-accepted from multiple relays.
  5. Poll drive.core.peers for 30 seconds.
  6. Observe drive.core.peers.length === 0 and no connection attempts from any relay.

Question for the maintainers

Is there a canonical client-side way to distinguish "this pin is actually replicated and durable" from "accepted but pending"?

Our UI currently shows honest copy ("accepted but not pulled") because seed-accepted alone is not a durability signal, but users want a reliable indicator that their content is truly pinned. If the intended signal is "watch drive.core.peers for a relay peer reaching remoteLength >= localLength", then the current behavior is a bug. If there's a different API — e.g. a pin-complete event emitted by relays once they've fully pulled the content — please point us at it.

Thanks for the excellent work on this — happy to provide logs, traces, or test against a patched build if useful.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions