Skip to content

bitswap: runOnLimitedConnections has no effect — two call sites drop the flag #1124

Description

@NiKrause

Summary

@helia/bitswap documents runOnLimitedConnections, but setting it to true does not make bitswap work over a limited (circuit-relay) connection. Two independent places drop the flag, and each one alone is enough to break it — patching either has no effect, patching both makes it work.

Versions: @helia/bitswap 4.0.11, helia 7.1.7, libp2p 3.3.8, @libp2p/circuit-relay-v2 4.2.11. Two browsers (Chromium), meeting through a circuit relay.

Where the flag is lost

1. The registrar topology never notifies about limited connections.

src/network.js, start() registers a topology that does not set notifyOnLimitedConnection:

const topology = {
  onConnect: (peerId) => { this.safeDispatchEvent('peer:connected', { detail: peerId }) },
  ...
}

libp2p/src/registrar.js skips exactly that case:

if (connection.limits != null && topology.notifyOnLimitedConnection !== true) { /* skipped */ }

So bitswap never learns the peer exists and never asks it for anything.

2. sendMessage() dials without the flag.

src/network.js:

const stream = await this.libp2p.dialProtocol(peerId, BITSWAP_120, options)

options here is the queue job's options; this.runOnLimitedConnections is not merged in. handle() and findProviders()'s isDialable() both honour it — the call that actually asks a peer for a block is the one that does not.

Measured

Two browser nodes, no direct path possible (no DCUtR service and no /webrtc listen address), so the circuit is the only path they can ever have. The connection reports limits != null. One node adds a block; the other reads it by CID.

patch applied runOnLimitedConnections result
none true times out
topology only true times out
sendMessage only true times out
both true block arrives
both false (default) times out

The last row matters: with both fixed, the default behaviour is unchanged. Nothing starts crossing circuits unless the option asks for it.

Worth noting separately — the bitswap protocol stream itself opens fine over the circuit. Dialling /ipfs/bitswap/1.2.0 by hand with runOnLimitedConnection: true succeeds while a read is still timing out, which is what pointed at these two sites rather than at libp2p refusing the protocol.

Suggested patch

         const topology = {
+            notifyOnLimitedConnection: this.runOnLimitedConnections,
             onConnect: (peerId) => {
-            const stream = await this.libp2p.dialProtocol(peerId, BITSWAP_120, options);
+            const stream = await this.libp2p.dialProtocol(peerId, BITSWAP_120, {
+                ...options,
+                runOnLimitedConnection: this.runOnLimitedConnections
+            });

Why this matters for browsers

Two browsers behind carrier NAT cannot hole-punch reliably, and the circuit is often the only path they have. Today that means content cannot move between them at all through Helia, while everything else on the same connection — identify, ping, gossipsub, an application protocol declaring runOnLimitedConnection: true — works. The option exists to allow that trade; it just does not reach the code that would honour it.

Happy to open a PR with the two-line change and a test if that is useful.

Possibly related, though not the same thing: #253.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions