The various concepts of libp2p:
-
The
Transporttrait provides thedialandlisten_onmethods. Its purpose is to open connections to nodes by passing their multiaddresses. Implemented on things such asTcp,Websockets, orEitherTransport<A, B>. -
The
ConnectionUpgrade<S: AsyncRead + AsyncWrite>trait has anupgrademethod that will turn anSinto anOutput(associated type ofConnectionUpgrade). Also contains methods that will determine whether a remote supports this upgrade. Implemented onSecio,Multiplex, etc. -
The
StreamMuxertrait is implemented on objects that can be turned into either an incoming substream or an outgoing substream. Creating a substream (either incoming or outgoing) consumes the whole object, but the user can create multiple substreams by cloning it beforehand. As an example, theOutputassociated type ofMultiplexandYamuximplementsStreamMuxer, and can be cloned because it contains anArc. For convenience,StreamMuxeris also automatically implemented on any object that also implementsAsyncReadandAsyncWriteand the object will be considered as a single substream. -
If the
Outputof aConnectionUpgradeimplementsStreamMuxer, then a transport wrapped inside a connection upgrade will also implementTransport. In practice this means that for example the typeUpgradedNode<Tcp, Secio>also implementsTransport. If for example you want to dial a node and apply secio over it, calldialon thatUpgradedNode. Advanced features, such as adding new transports at runtime, or conditionnally enabling upgrades, can be done by combining modifiers. -
In order to actually perform muxing, the user has to wrap the
UpgradedNodeinto aConnectionReusestruct (note: name could change) AConnectionReuseobject implementsTransportand will keep and clone existing connections instead of opening new ones. It is likely that this object can only be used on top of anUpgradedNodewith muxing, but the only restriction is that the connection must be clonable, and it is not impossible that this mechanism could serve for other purposes (unit testing comes to mind). -
Intermediate layers such as secio or multiplex implement
ConnectionUpgrade, and have anOutputtype that implementsStreamMuxer, so that other additional upgrades can be built on top of them. On the other hand concrete non-intermediary-layer protocol implementations (such as ping, identify or p2p-circuit) also implementConnectionUpgrade, but have anOutputthat doesn't implement any specific trait. ThereforeUpgradedNode<..., SomeProtocol>will not implementTransport. Instead the meaning of theOutputtype for protocols is protocol-specific. -
The multiplex intermediate layer can be considered as an optimization when applied over a
Transport. Whenever you attempt to dial using a transport upgraded with multiplex, the muxer will attempt to spawn a new stream on an existing connection instead of actually dialing the node. -
The
p2p-circuitprotocol (ie. using nodes as proxy) takes the form of aP2pCircuitTransport<T>struct whereTis aTransportstored within theP2pCircuitTransport. This struct will apply some upgrades on thisT, and itself implements theTransporttrait. In practice, the user will generally create a stack of transports, then clone that stack and build aP2pCircuitTransportwith it, then join the stack and theP2pCircuitTransporttogether into one finalTransport. -
In parallel to the
TransportandConnectionUpgradetraits, thePeerstoretrait allows storing information about peers (by theirPeerId), and theRecordstoretrait allows storing general-purpose key-value data. Implementations of these two traits use interior mutability, and try to be as lock-free as possible, in order to be sharable byArc. -
Initializing a swarm of nodes that uses a Kademlia DHT is done by calling a function that sits on top of the
TransportandConnectionUpgradesystem described above. Amongst several things, you must pass to this function an implementation ofTransport, an implementation ofPeerstoreand an implementation ofRecordstore. TheTransportmust be clonable and will be used to listen and to dial nodes whenever Kademlia requires it. TheTransportshould include the wanted intermediary upgrades, such as secio and multiplex.Whenever we need to dial a node, the Kademlia DHT implementation will automatically dial the node three times (note: remember that thanks to multiplex this only results in one connection) and opens the identify, ping and kademlia protocol upgrades on the connections it receives and dials. Each of these connection upgrades has a different
Output, but the Kademlia-building function returns an object that provides a unified API that sits on top of these outputs. -
The objects passed to the Kademlia DHT creation function (transport, peer store and record store) are all meant to be clonable for a cheap cost (eg. by using
Arcs), so that the user can create a Kademlia DHT in parallel to another kind of DHT, or protocol (eg. all the IPFS protocols), if they wish to do so. -
The
peerstoreobject is generally (but not always) shared byArcthroughout the various parts of the architecture that need information about peers. This means that core operations such as pinging, discovering and identifying nodes are not redundant amongst the various parts. -
In order to create a swarm of nodes, some bootstrapping is required. This is done by adding known nodes to the peer store before calling the Kademlia-building function.