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
- Relay connections OK. At startup,
relay-connected fires for 5 relays across these IDs: 2ec1..., 6b11..., 17ba..., 1e7d..., 37cf..., 0da2..., a8de..., 77bc....
- 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.
- 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
Hypotheses (please confirm/rule out)
- 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.
- 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.
- 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.
- 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:
- Create a writable Hyperdrive,
put() a small file.
swarm.join(drive.discoveryKey, { server: true, client: false }).
await relay.seed(drive.key.toString('hex'), { replicas: 3, timeout: 10000 }).
- Observe
seed-accepted from multiple relays.
- Poll
drive.core.peers for 30 seconds.
- 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.
Summary
When using
HiveRelayClientfromp2p-hiverelay@0.4.2against 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.lengthstays at0indefinitely, so pins are not actually replicated — they're only "accepted but pending."Environment
p2p-hiverelay@0.4.2(HiveRelayClientfromp2p-hiverelay/client)hyperdrive@13.3.2hyperswarm@4.17.0corestore@7.9.20.2497(Bare)pearbrowser-desktop(a desktop fork ofbigdestiny2/PearBrowser) publishing Hyperdrive sitesIntegration
Follows the canonical example in
examples/pear-app/index.jsverbatim — sharedswarm+storepassed intoHiveRelayClient:The drive is a standard writable Hyperdrive:
new Hyperdrive(store.namespace(uniqueId)), content written withput()before publishing.Observed
relay-connectedfires for 5 relays across these IDs:2ec1...,6b11...,17ba...,1e7d...,37cf...,0da2...,a8de...,77bc....relay.seed(driveKeyHex, { replicas: 3, timeout: 10000 }), 3 relays emitseed-acceptedwithin ~1–2 seconds — the signed seed request is successfully accepted.drive.core.peersfor 30 seconds waiting for any remote peer to reachremoteLength >= localLength. After the timeout:drive.core.peers.length === 0discoveryKey.Expected
After
seed-accepted, each accepting relay should join the drive'sdiscoveryKeyon 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 beforerelay.seed(), so we are announcing and discoverable.HiveRelayClientshares ourswarm+store(not separate instances), per the pear-app example.put()before publishing.driveKeyHexpassed torelay.seed()is the drive's public key hex (drive.key.toString('hex')).Hypotheses (please confirm/rule out)
seed-accepted.client/index.js:425-427, the seed request payload derives a discovery key viasodium.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.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.jsverbatim with the versions above:put()a small file.swarm.join(drive.discoveryKey, { server: true, client: false }).await relay.seed(drive.key.toString('hex'), { replicas: 3, timeout: 10000 }).seed-acceptedfrom multiple relays.drive.core.peersfor 30 seconds.drive.core.peers.length === 0and 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-acceptedalone is not a durability signal, but users want a reliable indicator that their content is truly pinned. If the intended signal is "watchdrive.core.peersfor a relay peer reachingremoteLength >= localLength", then the current behavior is a bug. If there's a different API — e.g. apin-completeevent 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.