-
Notifications
You must be signed in to change notification settings - Fork 83
Description
This issue contains a draft of how to display to the user what smoldot is currently doing in terms of networking.
What I have in mind is: in the popup would be a button next to each chain, and clicking it opens another window that shows a visualization of the connectivity (what this issue is about).
Since the connectivity visualization has nothing clickable and will never have, we could also just display it while the user hovers the button instead of clicking.
Intro: how networking works
Connections
This section contains a small introduction of how the networking in smoldot (and Substrate/Polkadot) works.
A node tries to open connections (typically through WebSocket, but in principle can be anything) to other nodes. These connections can be in two different states: handshaking, or fully established. When we start opening a connection, it is initially in handshaking mode. After the handshake is finished, we know what the PeerId of the remote is, and the connection can be used. We don't know the PeerId of the remote of a connection until after it has finished its handshake.
If there is a problem, the connection shuts down. This can happen (and actually happens most frequently) when the connection is still in handshaking mode. For example, if you try to connect to a port that is closed, the connection shuts down while it is still handshaking.
A Substrate/Polkadot node can also receive incoming connections. It works exactly the same way as when it is the node that initiates the connection: the connection is first handshaking, during which we discover what the PeerId of the remote is, then the connection is fully established.
There is one difference between incoming and outgoing connections: for outgoing connections, while we don't know the actual PeerId before the handshake is finished, we know the expected PeerId. When we establish an outgoing connection, it is always with the intention to connect to a specific PeerId.
There can be multiple connections at the same time towards the same PeerId.
Substreams
Once a connection is fully established (i.e. has finished its handshake), substreams are opened within the connection. It is as if the connection was subdivided into multiple different connections (called substreams) that each do one thing. You have one substream to receive block announces, one substream to send transactions, etc.
Amongst these substreams, there is one substream that can be considered as the "main" one, which is the block announces substream. It is the first substream we open.
Just like connections, substreams are in two different states: handshaking, or fully opened.
Slots
In order for smoldot to know who to try to connect to, it has a certain number of slots and assigns PeerIds to these slots. Right now the number of slots is 4.
When a new chain is initialized, all of its slots are empty. When a slot is empty, smoldot picks a random PeerId amongst the list of PeerIds that it thinks exist, and attributes the slot to this PeerId. While a slot is filled with a PeerId, smoldot tries to connect to this PeerId and open substreams. If we know multiple different multiaddresses for a PeerId, smoldot will try all of them. If it thinks that it is impossible to establish a connection or open the block announces substream, the slot is un-assigned and will later be assigned to a different PeerId.
What I have described in this paragraph is actually "out slots". Smoldot/Substrate/Polkadot also has "in slots", but we can consider them as irrelevant here. They are used in order to prevent too many people from connecting, but knowing which PeerId has an "in slot" isn't very useful for the end user.
The UI
Here is what I have in mind for the connectivity visualization UI:
This box would show a list of PeerIds that are currently assigned to slots, and of PeerIds that were recently assigned to slots, and of PeerIds that we were recently connected to.
If smoldot has connectivity issues, the list of PeerIds will typically change quite rapidly. In order for the UI to be readable, the list should not reorder itself automatically and gaps should not disappear automatically. In other words, PeerIds should visually stay where they are. If a PeerId disappears from the list, it should leave an empty gap that can later be filled with a different PeerId.
Within each PeerId there's a list of multiaddresses of connections to this PeerId: fully established incoming connections, fully established outgoing connections, and handshaking outgoing connections (in which case we use the expected PeerId, as we don't know the actual one yet).
For each multiaddr we show not the state of the connection, but the state of the main substream.
We show a "handshaking" state either if the connection itself is handshaking, or if the block announces substream (i.e. the "main" substream) has not been opened yet.
We show a "fully established" state if the block announces substream is open.
We show a "recently closed" state if the connection itself has been closed recently (which, as I explain above, includes failed to reach the peer for example because the port is closed) or if the block announces substream has been closed recently. In both cases, we show the reason for this closing.
How to implement this
Smoldot will gain support for a JSON-RPC function that sends back networking events.
These networking events would be fed into a state machine that will then report which information should be shown in the UI.
This section is mostly empty because smoldot doesn't support the JSON-RPC function yet anyway. This is something that we will figure later.
