I was going through to the Identify family of protocols to improve my own understanding of how it works.
Here are some notes:
The Identify message
The Identify message that we send to another peer is connection scoped AND contains roughly the following information:
- The protocols we support/have handlers for.
- The address of the remote peer that we are observing on the connection i.e.
- Our Public Key.
- The addresses we are listening on i.e.
* We include loopback addresses here ONLY if either the local address of the connection or the remote address of the connection are loopback addresses. The idea is that our loopback addresses are of interest to the other party ONLY if we are running on the same machine.
- Some auxiliary information like ProtocolVersion, AgentVersion etc. though I don’t think it’s used anywhere right now.
- The Delta i.e. what protocols have we newly added & removed support for.
All fields except the last field i.e. Delta are sent as part of the
Identify Push protocols whereas Delta and ONLY Delta is sent as part of the
Identify Delta protocol.
IDService supports three protocols:
When we form a new outbound connection with a peer, we open an
Identify stream with the peer & the peer sends us an Identify message. On receiving the Identify message(let’s call this a “reponse”), we:
- Remove the existing set of protocols supported by the remote peer in the peerstore and then add the protocols sent by the remote peer in the message.
- Update the public key for the remote peer in the peerstore.
- Add our observed address sent by the remote peer in the message to the set of observed addresses that the
IDServicemaintains. I’ve yet to dig into how these are used later on by the peer.
- Remove the current listen addresses of the remote peer from the peerstore and then add the listen addresses sent by the remote peer to the peerstore. If we are connected to the remote peer when we do this, we add them with a “permanent” TTL otherwise we add them with a TTL of 10 minutes.
When a remote peer forms a new inbound connection to us, it opens an
Identify stream with us -> we respond with an Identify message and it’s consumed on the remote peer exactly as described above.
Thus, peers on both side of the connection learn useful information about each other.
- Once we have successfully consumed an Identify message sent by a remote peer, we emit a
EvtPeerIdentificationCompletedevent on the event bus.
- If anything goes wrong in cosuming an Identify message/remote peer fails to send it, we emit a
EvtPeerIdentificationFailedevent on the event bus.
When we disconnect from a peer, the
IDService sets the TTL for the addresses of the peer to 10 minutes so they can evicted later if we don’t reconnect to the peer within that interval.
The set of addresses a peer listens on is not a constant. It’s important for peers we are connected to/peers in general to know our updated listen addresses so they can share it with others & use it for new connections. To accomplish this, we have the
Identify Push protocol:
- We currently poll the host addresses every minute & if we detect a change in the addresses, we craft an Identify message as described before. Among other things, it will include the new set of listen addresses. Note that this Identify message is a snapshot & not a delta.
- We then concurrently open an
Identify Pushstream to all peers we are connected to that support the
Identify Pushprotocol and send them the message.
- The peers that receive the message will consume the message in exactly the same way that they consume a response of the
- Work is currently underway for the Host to emit an
EvtLocalAddressesUpdatedevent when it’s listen addresses change & for the
Identify Pushto get triggered in response to that event. PR is at https://github.com/libp2p/go-libp2p/pull/747/files. The PR also replaces the current set of listen addresses we send with “Signed Peer Records” but that is outside the scope of this writeup.
- When a peer update’s the set of protocols it supports i.e. adds support for a protocol or removes support for a protocol, it emits an
EvtLocalProtocolsUpdatedevent on the event bus.
- In response to this event, we craft an Identify message with ONLY it’s Delta field initialized with the protocols that have been newly added/removed. This is not a snapshot.
- We then concurrently open an
Identify Deltastream to all peers we are connected to that support the
Identify Deltaprotocol and send them the message.
- On receiving an
Identify Deltamessage, the receiving peer adds/removes the protocols for the peer from the peerstore.
- It then emits an
EvtPeerProtocolsUpdatedevent to the event bus.
Identify Push &
Identify protocols can race with each other thus leading to a bad state in the peerstore for the peer. Work is currently underway at https://github.com/libp2p/go-libp2p/issues/823 to incrementally improve this.