-
Notifications
You must be signed in to change notification settings - Fork 273
/
README.md
278 lines (223 loc) · 9.92 KB
/
README.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# Rendezvous Protocol
| Lifecycle Stage | Maturity | Status | Latest Revision |
|-----------------|---------------|--------|-----------------|
| 1A | Working Draft | Active | r3, 2021-07-12 |
Authors: [@vyzo]
Interest Group: [@daviddias], [@whyrusleeping], [@Stebalien], [@jacobheun], [@yusefnapora], [@vasco-santos]
[@vyzo]: https://github.com/vyzo
[@daviddias]: https://github.com/daviddias
[@whyrusleeping]: https://github.com/whyrusleeping
[@Stebalien]: https://github.com/Stebalien
[@jacobheun]: https://github.com/jacobheun
[@yusefnapora]: https://github.com/yusefnapora
[@vasco-santos]: https://github.com/vasco-santos
See the [lifecycle document][lifecycle-spec] for context about the maturity level
and spec status.
[lifecycle-spec]: https://github.com/libp2p/specs/blob/master/00-framework-01-spec-lifecycle.md
## Table of Contents
- [Rendezvous Protocol](#rendezvous-protocol)
- [Table of Contents](#table-of-contents)
- [Overview](#overview)
- [Use Cases](#use-cases)
- [Replacing ws-star-rendezvous](#replacing-ws-star-rendezvous)
- [Rendezvous and pubsub](#rendezvous-and-pubsub)
- [The Protocol](#the-protocol)
- [Registration Lifetime](#registration-lifetime)
- [Interaction](#interaction)
- [Spam mitigation](#spam-mitigation)
- [Protobuf](#protobuf)
- [Recommendations for Rendezvous Points configurations](#recommendations-for-rendezvous-points-configurations)
## Overview
The protocol described in this specification is intended to provide a
lightweight mechanism for generalized peer discovery. It can be used for
purposes like bootstrapping, real-time peer discovery, and application-specific
routing. Any node implementing the rendezvous protocol can act as a rendezvous
point, allowing the discovery of relevant peers in a decentralized manner.
## Use Cases
Depending on the application, the protocol could be used in the
following context:
- During bootstrap, a node can use known rendezvous points to discover
peers that provide critical services. For instance, rendezvous can
be used to discover circuit relays for connectivity-restricted
nodes.
- During initialization, a node can use rendezvous to discover
peers to connect with the rest of the application. For instance,
rendezvous can discover pubsub peers within a topic.
- In a real-time setting, applications can poll rendezvous points in
order to discover new peers in a timely fashion.
- In an application-specific routing setting, rendezvous points can be
used to progressively discover peers that can answer specific queries
or host shards of content.
### Replacing ws-star-rendezvous
We intend to replace ws-star-rendezvous with a few rendezvous daemons
and a fleet of p2p-circuit relays. Real-time applications will
utilize rendezvous both for bootstrap and in a real-time setting.
During bootstrap, rendezvous will be used to discover circuit relays
that provide connectivity for browser nodes. Subsequently, rendezvous
will be utilized throughout the application's lifetime for real-time peer
discovery by registering and polling rendezvous points.
This allows us to replace a fragile centralized component with a
horizontally scalable ensemble of daemons.
### Rendezvous and pubsub
Rendezvous can be naturally combined with pubsub for effective
real-time discovery. At a basic level, rendezvous can
bootstrap pubsub: nodes can utilize rendezvous to discover
their peers within a topic. Alternatively, pubsub can also be used to build
rendezvous services. In this scenario, several rendezvous points can federate
using pubsub for internal real-time distribution while still providing a simple
interface to clients.
## The Protocol
The rendezvous protocol provides facilities for real-time peer
discovery within application-specific namespaces. Peers connect to the
rendezvous point and register their presence in one or more
namespaces. It is not allowed to register arbitrary peers in a
namespace; only the peer initiating the registration can register
itself. The register message contains a serialized
[signed peer record](https://github.com/libp2p/specs/blob/377f05a/RFC/0002-signed-envelopes.md)
created by the peer, which others can validate.
Other nodes can discover peers registered with the rendezvous point by
querying the rendezvous point. The query specifies the
namespace for limiting application scope and, optionally, a maximum
number of peers to return. The namespace can be omitted in the query,
which asks for all peers registered to the rendezvous point.
The query can also include a cookie obtained from the response to a
previous query, such that only registrations that weren't included in
the previous response will be returned. This lets peers
progressively refresh their network view without overhead, simplifying
real-time discovery. It also allows for the pagination
of query responses so peers can manage large numbers of peer registrations.
The rendezvous protocol runs over libp2p streams using the protocol id `/rendezvous/1.0.0`.
### Registration Lifetime
An optional TTL parameter in
the `REGISTER` message controls the registration lifetime. If a TTL is
specified, then the registration persists until the TTL expires. If no
TTL was set, then a default of 2hrs is implied. There may be a rendezvous
point-specific upper bound on TTL, with a maximum value of 72hrs. If the
TTL of a registration is inadmissible, the rendezvous point may reject
the registration with an `E_INVALID_TTL` status.
Peers can refresh their registrations at any time with a new
`REGISTER` message; the TTL of the new message supersedes previous
registrations. Peers can also cancel existing registrations at any
time with an explicit `UNREGISTER` message. An `UNREGISTER` message does
**not** have an explicit response. `UNREGISTER` messages for a namespace
that a client is not registered for should be treated as a no-op.
The registration response includes the actual TTL of the registration,
so that peers know when to refresh.
### Interaction
Clients `A` and `B` connect to the rendezvous point `R` and register for namespace
`my-app` with a `REGISTER` message:
```
A -> R: REGISTER{my-app, {QmA, AddrA}}
R -> A: {OK}
B -> R: REGISTER{my-app, {QmB, AddrB}}
R -> B: {OK}
```
Client `C` connects and registers for namespace `another-app`:
```
C -> R: REGISTER{another-app, {QmC, AddrC}}
R -> C: {OK}
```
Another client `D` can discover peers in `my-app` by sending a `DISCOVER` message; the
rendezvous point responds with the list of current peer reigstrations and a cookie.
```
D -> R: DISCOVER{ns: my-app}
R -> D: {[REGISTER{my-app, {QmA, Addr}}
REGISTER{my-app, {QmB, Addr}}],
c1}
```
If `D` wants to discover all peers registered with `R`, then it can omit the namespace
in the query:
```
D -> R: DISCOVER{}
R -> D: {[REGISTER{my-app, {QmA, Addr}}
REGISTER{my-app, {QmB, Addr}}
REGISTER{another-app, {QmC, AddrC}}],
c2}
```
If `D` wants to poll for real-time discovery progressively, it can use
the cookie obtained from a previous response only ask for
new registrations.
So here we consider a new client `E` registering after the first query,
and a subsequent query that discovers just that peer by including the cookie:
```
E -> R: REGISTER{my-app, {QmE, AddrE}}
R -> E: {OK}
D -> R: DISCOVER{ns: my-app, cookie: c1}
R -> D: {[REGISTER{my-app, {QmE, AddrE}}],
c3}
```
### Spam mitigation
The protocol, as described so far, is susceptible to spam attacks from
adversarial actors who generate a large number of peer identities and
register under a namespace of interest (e.g., the relay namespace).
It is TBD how exactly the protocol will mitigate such attacks.
See <https://github.com/libp2p/specs/issues/341> for a discussion on this
topic.
### Protobuf
```protobuf
syntax = "proto2";
message Message {
enum MessageType {
REGISTER = 0;
REGISTER_RESPONSE = 1;
UNREGISTER = 2;
DISCOVER = 3;
DISCOVER_RESPONSE = 4;
}
enum ResponseStatus {
OK = 0;
E_INVALID_NAMESPACE = 100;
E_INVALID_SIGNED_PEER_RECORD = 101;
E_INVALID_TTL = 102;
E_INVALID_COOKIE = 103;
E_NOT_AUTHORIZED = 200;
E_INTERNAL_ERROR = 300;
E_UNAVAILABLE = 400;
}
message Register {
optional string ns = 1;
optional bytes signedPeerRecord = 2;
optional uint64 ttl = 3; // in seconds
}
message RegisterResponse {
optional ResponseStatus status = 1;
optional string statusText = 2;
optional uint64 ttl = 3; // in seconds
}
message Unregister {
optional string ns = 1;
// optional bytes id = 2; deprecated as per https://github.com/libp2p/specs/issues/335
}
message Discover {
optional string ns = 1;
optional uint64 limit = 2;
optional bytes cookie = 3;
}
message DiscoverResponse {
repeated Register registrations = 1;
optional bytes cookie = 2;
optional ResponseStatus status = 3;
optional string statusText = 4;
}
optional MessageType type = 1;
optional Register register = 2;
optional RegisterResponse registerResponse = 3;
optional Unregister unregister = 4;
optional Discover discover = 5;
optional DiscoverResponse discoverResponse = 6;
}
```
## Recommendations for Rendezvous Points configurations
Rendezvous points should have well-defined configurations to enable libp2p
nodes running the rendezvous protocol to have friendly defaults, as well as to
guarantee the security and efficiency of a Rendezvous point. This will be
particularly important in a federation, where rendezvous points should share
the same expectations.
Regarding the validation of registrations, rendezvous points should have the following:
- a minimum acceptable **ttl** of `2H`
- a maximum acceptable **ttl** of `72H`
- a maximum **namespace** length of `255`
Rendezvous points are also recommended to allow:
- a maximum of `1000` registration for each peer
- defend against trivial DoS attacks
- a maximum of `1000` peers should be returned per namespace query