OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-proto-peer / test / membrane-holepunch-symmetry.test.js

35 lines · javascript ref:
// Regression guard for the firewalled↔firewalled holepunch fix (2026-07-06).
//
// Both the self-custody peer AND the bridge fronting it are typically NAT'd. Hyperswarm/hyperdht
// only completes a holepunch between two firewalled members if BOTH join client:true — a
// client:false member never sends outbound punch packets, so its NAT mapping never opens and the
// other side's packets are dropped. Proven empirically on two firewalled boxes: symmetric
// {server,client} connects in ~2s; asymmetric (peer server-only / bridge client-only) never opens
// (bridge logs cAtt>0 but cOpen:0). A real holepunch can't be reproduced in-process (testnet peers
// are on localhost, never firewalled — the membrane-serve e2e passes with EITHER config), so we
// assert the load-bearing join OPTIONS directly via a spy swarm.

import '../lib/bare-globals.js'
import test from 'brittle'
import b4a from 'b4a'
import { Peer } from '../lib/peer.js'

test('peer.serve joins its rendezvous topics symmetrically (client:true is load-bearing for NAT holepunch)', (t) => {
  const joins = []
  const fakeSwarm = {
    keyPair: { publicKey: b4a.alloc(32, 7) },
    on () {}, off () {},
    join (topic, opts) { joins.push({ topic, opts }); return { flushed: async () => {} } }
  }
  // serve() only touches this.did synchronously; corestore/_attachRpc are used inside the (unfired)
  // connection handler, so a minimal `this` is enough to exercise the join wiring.
  const fakePeer = { did: 'did:plc:holepunchsymmetry0000', corestore: {}, _attachRpc () {} }
  Peer.prototype.serve.call(fakePeer, fakeSwarm)

  t.is(joins.length, 2, 'serve joins BOTH the serverKey topic and the DID discovery topic')
  for (const j of joins) {
    t.is(j.opts.server, true, 'joins as server (announce)')
    t.is(j.opts.client, true, 'joins as client — REQUIRED so a firewalled peer punches outbound')
  }
})