Managing peers in libp2p-js

I’m trying to implement a simple p2p messaging infrastructure that will allow me to experiment with different blockchain consensus algorithms. For this to work I need to be able to relay messages between peers, but I don’t want a fully-connected topology as that wouldn’t be scalable. I stumbled upon libp2p and saw that is was being used by parties with similar goals (such as Polkadot).

I’ve tried using the examples on GitHub but what I don’t understand is how to manage peers using the discovery mechanism. The examples are a bit lacking in that department.

I have 3 events: peer:discover, peer:connect and peer:disconnect. peer:discovery gets invoked when a peer gets found. Using either Railing or MulticastDNS I am able to find other peers using this mechanism. I have tried storing the return value (a discovered peer) in a sort of key-value pair structure called PotentialPeers where the key is the PeerId of the peer.

I then presumably dial the newly discovered peer to establish a connection with it but this is where I run into problems. When I instantiate 2 peers on different ports they both discover each other, and then both try to dial each other. This leads to the following output:

[QmRQd68mqUv8bvFcCgTqMLGgxbeMysCSKDvsqvCCRW2PCu] socket running
[QmSEYKVqHYJEWw9uLBs7sf9V2jab9LLRQcHpJLCjnrTWCs] socket running
[QmRQd68mqUv8bvFcCgTqMLGgxbeMysCSKDvsqvCCRW2PCu] Discovered: QmRQd68mqUv8bvFcCgTqMLGgxbeMysCSKDvsqvCCRW2PCu
[QmSEYKVqHYJEWw9uLBs7sf9V2jab9LLRQcHpJLCjnrTWCs] Discovered: QmRQd68mqUv8bvFcCgTqMLGgxbeMysCSKDvsqvCCRW2PCu
[QmRQd68mqUv8bvFcCgTqMLGgxbeMysCSKDvsqvCCRW2PCu] Connected: QmRQd68mqUv8bvFcCgTqMLGgxbeMysCSKDvsqvCCRW2PCu
[QmSEYKVqHYJEWw9uLBs7sf9V2jab9LLRQcHpJLCjnrTWCs] Connected: QmRQd68mqUv8bvFcCgTqMLGgxbeMysCSKDvsqvCCRW2PCu
[QmRQd68mqUv8bvFcCgTqMLGgxbeMysCSKDvsqvCCRW2PCu] dialed QmRQd68mqUv8bvFcCgTqMLGgxbeMysCSKDvsqvCCRW2PCu using protocol: /hyper/1.0.0
[QmSEYKVqHYJEWw9uLBs7sf9V2jab9LLRQcHpJLCjnrTWCs] dialed QmRQd68mqUv8bvFcCgTqMLGgxbeMysCSKDvsqvCCRW2PCu using protocol: /hyper/1.0.0
[QmRQd68mqUv8bvFcCgTqMLGgxbeMysCSKDvsqvCCRW2PCu] Connected: QmRQd68mqUv8bvFcCgTqMLGgxbeMysCSKDvsqvCCRW2PCu

Here’s the code:

Where this.potentialPeers is an object so I can quickly lookup peers by PeerId.

As you can see, because both nodes are dialing each other I presume I’m establishing multiple connections. This, I think, is not desirable because I believe only one connection between two peers is enough.

What am I missing?

I had trouble with that too and still don’t know what I am missing.

My solution was to just keep a dictionary of peers->connections and listen on all connections from the same peer, but only write to the last one (set up listeners/handlers for all, but update the dictionary with the last so whenever the program is going to write something, it fetches the last one from the dictionary and only write to it).

This is good for a number of reasons you can imagine yourself (or I can write later if you want), and I don’t see any problems with it, but there are probably some. Anyway, it seems to be doing the job.