libp2p / libp2p/go-libp2p

The Switch

Open
#364 2 comments 0 reactions 1 assignee View on GitHub

@bigs is already working on this.

Since Jun 20, 2018.

need/community-input
Dominant language
Go
Stars
6.9k
Forks
1.3k
Avg merge
13d 21h
Merged PRs (30d)
1

Description

# Overview

Currently, we have two interfaces:

1. The Network, defined in go-libp2p-net and implemented in go-libp2p-swarm.
2. The Host, defined in go-libp2p-host and implemented in go-libp2p.

The current distinction is as follows:

* The Network manages connections and streams.
* The Host does stream protocol negotiation and dispatches incoming streams to the right handler based on its protocol.

# Warts

There are, however, some warts in this split:

1. The names are a bit wonky. The Host really should be called a Switch (it switches based on stream protocols). Additionally, the Network is more like an Interface.
2. The Host does protocol muxing however, go-libp2p-net (Network) streams have protocols attached to them. We do this so the Host doesn't have to wrap streams and manage these wrapped streams. That is, it can simply "set" the protocol on a Network level stream. However, this is just weird.
3. The Host manages routing (mapping peer IDs -> multiaddrs). However, it has no direct way of informing the Network of these mappings because `Network.DialPeer` doesn't accept multiaddrs. Instead, it stashes the results of the routing in the peerstore and then tells the network to dial the peer. This, for example, means we currenty search for peer addresses up-front before dialing instead of searching for better and better addresses in the background while dialing.
4. The Host doesn't re-expose everything from the Network so users have to call `Host.Network()` to access network-level functionality. However, this *also* means they can screw things up by, e.g., calling `Network.SetStreamHandler` (overriding the one set by the host).

There are also a few warts in the interfaces:

1. The Host exposes a "ConnManager" service. While useful, it feels odd to expose it on the Host this way.
2. The Host exposes a bunch of protocol muxing functions that provide no way to manage protocol handler conflicts. It also exposes the internal muxer (a concrete struct) directly.
3. `Host.Connect` accepts a PeerInfo and then immediately adds the addresses to a peerstore then calls `Network.Dial(peer)` (not specifying the addresses). As a user, I'd expect it to *use* the addresses I specify.
4. The Network's interface exposes Juan's [goprocess](https://github.com/jbenet/goprocess) abstraction (and the host doesn't). In theory, this allows users to attach "processes" to the swarm that get shutdown on close. However, this is a very opinionated abstraction that has not received wide adoption, even within our own systems. IMO, a less opinionated/intrusive approach would be to point users towards a general-purpose service manager that manages "processes" top-down.
5. We abuse contexts all over the place for closing services. Contexts exist for request cancellation, that's why they don't provide any form of "wait until this thing has been shut down" feature. As it is, using them to close services is redundant with the service's own `Close` methods and confusing to users.

# Proposals (ish)

I'd like to take a "clean slate" approach to figure out the best solution assuming we could just start over. In practice, we'll have to find a way to avoid breaking everything but hopefully we can strike a happy balance.

1. Merge the host and the network into a single switch, moving everything that doesn't fit to a higher libp2p "node". This change does kind of rub me the wrong way because there *is* a clear split however, we already violate that split in practice by attaching protocols to Network-level streams.
2. Stretch: Get rid of all traces of go-process and context abuse.
3. Make sure our new approach maps cleanly onto a daemon interface.

---

This is far from a complete proposal. Unfortunately, I'm really not sure how to proceed. Hopefully, we can at least get this discussion started.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.