libp2p / libp2p/go-libp2p

Proposal: a radically simpler Peerstore

Open
#2,355 21 comments 12 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

effort/weeks exp/expert kind/discussion
Dominant language
Go
Stars
6.9k
Forks
1.3k
Avg merge
13d 21h
Merged PRs (30d)
1

Description

Observation: The current Peerstore does a lot of things, but it doesn’t any of them well.

Problems:

  • It’s a giant interface (32 methods in total (!!!), plus 2 for the CertifiedAddressBook).
  • Entries are GC’ed when the peer disconnects.
  • It’s trying to offer applications a range of options to store peer-related data, without offering options to persist this data beyond the time a peer disconnects.
  • It doesn’t keep track of any metrics (e.g. regarding peer addresses stored).
  • SupportsProtocol doesn’t distinguish between Identify having completed and not, leading to complexity in applications (example).

For example, this shows up:

  • In QUIC / TLS: it can’t be used to store session tickets for session resumption / 0-RTT.
  • In Kademlia: it can’t be used to store peer / provider records.

This is a proposal to radically shrink the peerstore, such that it offers only what is needed to dial connections. Applications running on top of QUIC, and even transports like QUIC that want to use 0-RTT, will need to come up with their own data structures to store peer-related data. This is inevitable, since different applications will have different needs regarding persisting data when a peer disconnects, and different heuristics for limiting the size of these data structures.

In particular, we’ll get rid of the following components:

  1. PeerMetadata: Only used to save the agent / protocol version sent in Identify. There’s no real reason to save that information in the first place.
  2. Metrics: Only used to store RTT statistics. Arguably, that’s not a per-peer, but a per-connection (or rather, per path, if dealing with multipath transports) property. We should consider exposing the RTT on the Connection interface.
  3. ProtoBook: Used to store the protocols supported by this peer (as learned via Identify). Takes up huge amounts of storage, for little benefit. Protocols that need a list of peers supporting their protocol can easily subscribe to the respective EventBus notification. [^1]

The KeyBook will be radically simplified to only allow storing of the public key.

As a result, this leaves us with a peer store that only stores:

  1. addresses
  2. public keys
  3. certified peer records (in their serialized form)

It basically becomes an address book, and maybe we should honor that fact by renaming it accordingly.

The following changes will make it a lot more smarter and more useful:

  • Don’t GC on disconnect. Keep a scoring function of how valuable an entry is, and GC based on that. An entry is valuable, if we’ve connected to a peer multiple times, the node has been online for a long time, or an application tells us that a peer is (based on some application-defined metric, not sure yet how exactly this would work).
  • Keep track if an address is received securely (e.g. in a signed peer record, on an encrypted connection to that peer, or if we dialed / accepted a connection on that address and completed the handshake). If so, we could ignore all unverified addresses.
  • Keep stats on how well addresses work in practice, by tracking attempted and successful connection attempts on a per-address basis. This can be fed into the dialing logic to speed up future dials.

We could consider removing the Peerstore interface. This is (mostly) a libp2p-internal component. In particular, it does not make sense to implement a datastore-backed version of it (it might however be interesting to be able to serialize the current state, so it can be restored easily).

[^1]: Note that this breaks an optimization for Host.NewStream, which currently picks the first supported protocol from a list of protocols. This is fine, since 1. worst-case, this results in an extra round-trip, 2. it is a rare use-case and 3. the application can track which protocols a peer speaks and then open a stream with just that protocol, speeding up things by 1 RTT compared to the status quo.

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.

Research direction

Start by reviewing the Peerstore interface and its KeyBook, PeerMetadata, Metrics, and ProtoBook components, then inspect the Host.NewStream behavior and p2p/host/autorelay/relay_finder.go example referenced in the issue. Before implementation, establish the replacement scope and migration plan; done means the agreed peerstore redesign is implemented without the listed responsibilities.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
networking
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.