Ideal Network Topology to achieve a shared pubsub topic in Heterogeneous runtime

We are building a P2P network to store and share contact & relationships info between peers.

There are three parties in the network: User, Application & Hub. Each party runs a node and has certain responsibilities and connectivity. We are using Helia for node creation and gossipsub for pubsub.

  1. Hub: These are Nodejs Helia nodes running in cloud, used by all participants to pin data for long-term storage.
  2. Users run a node in browser using Helia and indexeddb as blockstore. They store and retrieve data locally and periodically sync with hubs.
  3. Application developers can also run nodes which are nodejs+helia. they are used mostly for communication purposes, when application need to subscribe to a topic.

Each User and Application communicate with each other to perform Handshakes to exchange contacts and relationship info.

Handshakes:

  1. Link: A user wants to use the app from two different devices. Two Browser nodes should be able to subscribe to a common topic.
  2. Join: A user signs up for an app. Browser Node & App Node should be able to subscribe to a common topic.
  3. Relate: Two users want to connect to share contact info & app wants to observe the relationship events to maintain an index. Two Browser Nodes and One App node should be able to publish & subscribe to a common topic.

Connectivity assumptions:
All user nodes and app nodes dial the Hubs by default when they come online, creating a star topology.

What I have observed till now:
For two nodes to publish and subscribe to a topic they either need to be

  1. Directly connected (dialing PeerId)
  2. Connected via another node, but this requires the connector node to also be subscribed to the topic for message forwarding to work.

What I have done till now:

  1. Link: Since this is a communication between two browser nodes, we chose to go forward with using WebRTC transport, with the Hub acting as the Circuit Relay. We are exchanging PeerID using a Link Url
  2. Join: Since this is a communication between a browser node and an app node, we chose to use WebSocket transport, app embeds its PeerID in the app html which is used by the client to dial and make a connection
  3. Relate: This is a three-party handshake, 2 users and one app. We use the app node as the central node for this communication. Where user1 informs app about the topic noth users want to talk over, so that the app node subscribes to the desired topic and message forwarding starts working

I want to achieve the above three handshakes in the most efficient way possible, without each node having to dial each other explicitly. That would require them to know the PeerIDs, which seems non-trivial as a lot of the Browser nodes are transient.
Any advice on the overall design and how to improve it is appreciated

Detailed Doc for the design
Git Repo with current Implementation

1 Like

That sounds right.

One thing to note here is that the browser node still needs a way to resolve the PeerID to a Multiaddr that it will dial. You may be better off exchanging the Multiaddr (which contains the IP, port, protocol, peerID, and certificate hash).

Sounds like a good choice. At least until WebTransport and WebRTC Direct are more broadly supported.

Here too, I’d recommend embedding the multiaddr in your app so as to avoid having to do peer routing (mapping the peerID to the multiaddrs).

How do you define a handshake in this system?

Ultimately, libp2p peers (be it browsers, or node.js) communicate by having a direct connection to each other (or a relayed connection even though those are heavily constrained). To connect to each other (barring the details of NAT hole punching for the moment), they need a way to discover each other’s multiaddrs.

With transient browser nodes it can be a challenge to do this in a decentralised fashion, but if you are already leaning on GossipSub, I’d suggest taking a look at GitHub - libp2p/js-libp2p-pubsub-peer-discovery: A js-libp2p module that uses pubsub for mdns like peer discovery (I haven’t tried it personally)

There’s also a libp2p Rendezvous protocol, but it’s not implemented in js-libp2p (see GitHub - libp2p/js-libp2p-rendezvous: A javascript implementation of the rendezvous protocol for libp2p).