js-libp2p-gossipsub icon indicating copy to clipboard operation
js-libp2p-gossipsub copied to clipboard

example doesn't work in the browser (insufficent peers)

Open uriva opened this issue 1 year ago • 3 comments

Uncaught (in promise) Error: PublishError.InsufficientPeers
    at GossipSub.publish (index.ts:2074:13)
import { webRTC, webRTCDirect } from "@libp2p/webrtc";

import { bootstrap } from "@libp2p/bootstrap";
import { circuitRelayTransport } from "libp2p/circuit-relay";
import { createLibp2p } from "libp2p";
import { gossipsub } from "@chainsafe/libp2p-gossipsub";
import { identifyService } from "libp2p/identify";
import { kadDHT } from "@libp2p/kad-dht";
import { mplex } from "@libp2p/mplex";
import { noise } from "@chainsafe/libp2p-noise";
import { webSockets } from "@libp2p/websockets";
import { webTransport } from "@libp2p/webtransport";
import { yamux } from "@chainsafe/libp2p-yamux";

export const start = async () => {
  // Create our libp2p node
  const libp2p = await createLibp2p({
    // transports allow us to dial peers that support certain types of addresses
    transports: [
      webSockets(),
      webTransport(),
      webRTC(),
      webRTCDirect(),
      circuitRelayTransport({
        // use content routing to find a circuit relay server we can reserve a
        // slot on
        discoverRelays: 1,
      }),
    ],
    connectionEncryption: [noise()],
    streamMuxers: [yamux(), mplex()],
    peerDiscovery: [
      bootstrap({
        list: [
          "/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
          "/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
          "/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp",
          "/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa",
          "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt",
        ],
      }),
    ],
    services: {
      pubsub: gossipsub({}),
      identify: identifyService(),
      dht: kadDHT({ clientMode: true }),
    },
  });

  libp2p.addEventListener("peer:discovery", (evt) => {
    const peerInfo = evt.detail;
    console.log(`Found peer ${peerInfo.id.toString()}`);
    libp2p.dial(peerInfo.id).catch((err) => {
      console.log(`Could not dial ${peerInfo.id.toString()}`, err);
    });
  });

  libp2p.addEventListener("peer:connect", (evt) => {
    const peerId = evt.detail;
    console.log(`Connected to ${peerId.toString()}`);
  });

  libp2p.addEventListener("peer:disconnect", (evt) => {
    const peerId = evt.detail;
    console.log(`Disconnected from ${peerId.toString()}`);
  });

  console.log(`libp2p id is ${libp2p.peerId.toString()}`);

  libp2p.services.pubsub.addEventListener("message", (message) => {
    console.log(
      `${message.detail.topic}:`,
      new TextDecoder().decode(message.detail.data),
    );
  });
  libp2p.services.pubsub.subscribe("fruit");

  setInterval(() => {
    libp2p.services.pubsub.publish("fruit", new TextEncoder().encode("banana"));
  }, 2000);

  return libp2p;
};

uriva avatar Jul 18 '23 12:07 uriva

I'm also seeing this. A complete working end-to-end example with libp2p would be great

x48115 avatar Jul 29 '23 18:07 x48115

It seems that the browser nodes are not being subscribed to the topic, those bootstrap nodes are not subscribed to the fruit topic and so you would need to be running other - in this case browser - nodes which are subscribed to the fruit topic which would be discoverable by Kademlia (you could utilize the protocol prefix to ensure only your nodes are discovered).

You could take a look at the universal connectivity example example for more detailed usage of gossipsub for browser nodes.

maschad avatar Jul 29 '23 19:07 maschad

I met the same problem. After debugging, I realized that the subscribe operation of node1 does not use rpc to add a topic in node2. This is because there is no link established between node1 and node2. So just add another node's information (directPeers) in the gossipsub's constructor parameter.

const createNode1 = async () => {
    const node = await createLibp2p({
        addresses: {
            listen: ['/ip4/127.0.0.1/tcp/0']
        },
        transports: [tcp()],
        streamMuxers: [yamux(), mplex()],
        connectionEncryption: [noise()],
        services: {
            // we add the Pubsub module we want
            pubsub: gossipsub({
                allowPublishToZeroPeers: true,
                awaitRpcMessageHandler: true,
            })
        }
    })
    return node
}
const node1 = await createNode1()

const createNode2 = async () => {
    const node = await createLibp2p({
        addresses: {
            listen: ['/ip4/127.0.0.1/tcp/0']
        },
        transports: [tcp()],
        streamMuxers: [yamux(), mplex()],
        connectionEncryption: [noise()],
        services: {
            // we add the Pubsub module we want
            pubsub: gossipsub({
                allowPublishToZeroPeers: true,
                directPeers: [{id: node1.peerId, addrs: node1.getMultiaddrs()}]
            })
        }
    })
    return node
}
const node2 = await createNode2()

jiakun9707 avatar Aug 04 '23 16:08 jiakun9707